Documentation
¶
Overview ¶
Package config holds the resolved configuration for opening a Cloudstic repository: which store to talk to, which credentials unlock it, and how the client should behave.
It is the boundary between how configuration is *expressed* — command-line flags, environment variables, a profiles YAML file — and how a repository is *opened*. Values here are fully resolved: a store URI has been chosen, and secret references have already been read into the credentials they name. Nothing in this package performs I/O against a store or a cloud provider; pkg/open does that, and takes these values as input.
The split matters for what it costs to import. This package depends only on pkg/profile and pkg/secretref, so reading a profiles file and resolving it into a configuration — to validate it, display it, or hand it to something else — pulls in no cloud SDK. Constructing a store from that configuration necessarily does, which is why construction lives in pkg/open (RFC 0022 §7).
Zero values are the correct defaults. A Client{Store: …} with nothing else set behaves the way the cloudstic CLI behaves with no flags passed, which is why packfiles are expressed as DisablePackfile rather than Packfile: the client enables them by default, so a positive field would silently turn them off for every caller who did not think to mention them.
Index ¶
- Constants
- func DefaultAuthTokenRef(provider, name string) string
- func ResolveValue(ctx context.Context, r *secretref.Resolver, key, inline, ref string) (string, error)
- func SourceURIForProvider(provider string) (string, error)
- type B2
- type Backup
- type Client
- type Field
- type FieldSet
- type Google
- type KMS
- type OneDrive
- type S3
- type SFTP
- type Source
- type SourceURI
- type Store
- type StoreURI
- type Unlock
Constants ¶
const ( ProviderGoogle = "google" ProviderOneDrive = "onedrive" )
Auth providers, as written in a profiles file's `provider:` field.
Variables ¶
This section is empty.
Functions ¶
func DefaultAuthTokenRef ¶
DefaultAuthTokenRef returns the secret reference an auth entry's OAuth token is stored under when the user names no location: a token in the config directory's managed store, keyed by provider and entry name.
An empty name yields the "default" entry, which is what an auth entry created implicitly by `cloudstic backup gdrive` uses.
func ResolveValue ¶
func ResolveValue(ctx context.Context, r *secretref.Resolver, key, inline, ref string) (string, error)
ResolveValue returns the effective value of a profile field that may be given either inline or as a scheme://path secret reference.
An inline value wins and short-circuits: the reference is not consulted, and a broken reference alongside an inline value is not an error. When neither is set the result is the empty string, which callers read as "the profile says nothing about this field".
key names the profiles-file entry and appears in the error, so a failure says which entry to go fix rather than only which backend refused.
func SourceURIForProvider ¶
SourceURIForProvider returns the source URI that authenticates a provider without addressing any particular content.
The provider name and the source scheme are not the same word — Google's provider is "google" but its scheme is "gdrive" — and the URI deliberately carries no drive name or path. Both cloud sources resolve a drive name eagerly during construction, so naming one here would make authenticating depend on a drive existing, which is backwards: you authenticate in order to find out which drives there are.
Types ¶
type Backup ¶
type Backup struct {
Source Source
// Tags are recorded on the snapshot and are what `forget -tag` filters on.
Tags []string
// IgnoreEmpty skips writing a snapshot when nothing changed.
IgnoreEmpty bool
// AuthRef names the profiles-file auth entry that supplied the cloud
// credentials in Source, or that should. MergeProfileBackup reads it and
// records the entry it used, so the resolved configuration says where the
// credentials came from.
AuthRef string
DryRun bool
Verbose bool
}
Backup is the resolved configuration for one backup run: what to read, and how to record it.
Zero values are the correct defaults, as elsewhere in this package: a Backup with only Source set behaves the way `cloudstic backup` behaves with no flags beyond -source.
func ApplyProfileAuth ¶
ApplyProfileAuth folds a named auth entry's credentials into base, after checking the entry's provider against what the source's scheme requires.
The provider rule is the reason this is exported rather than left inside MergeProfileBackup: a gdrive source needs a "google" entry and a onedrive source a "onedrive" one, and a caller pairing them the other way should get an error rather than an unauthenticated run. Anything acting on a profiles file needs that check, including code that writes an auth entry before using it.
func MergeProfileBackup ¶
func MergeProfileBackup(base Backup, decided FieldSet, name string, cfg *profile.Config) (Backup, error)
MergeProfileBackup returns base with profile name's backup settings folded in underneath it: every field the caller has already decided is left alone, and the rest come from the profile.
decided names the fields the caller owns, using the same FieldSet as MergeProfileStore — one set may name both store and backup fields, since a caller usually resolves both from one mechanism.
An auth_ref on the profile, or FieldAuthRef among the decided fields with base naming one, supplies the cloud credentials. Its provider must match the source's scheme: pointing a Google Drive source at a OneDrive auth entry is an error rather than a silently unauthenticated run.
This is the counterpart to MergeProfileStore and applies the same precedence. The two are separate functions because a profile's store is shared between profiles by name while its backup settings are its own, so a caller resolving a store by name (`cloudstic store verify`) needs the first without the second.
type Client ¶
type Client struct {
Store Store
Unlock Unlock
DisablePackfile bool
Quiet bool
JSON bool
// Verbose asks the reporter for per-item detail. It is a presentation
// choice, which is why it lives here and on the reporter rather than as an
// option on each operation.
Verbose bool
}
Client is the resolved configuration for opening a repository client.
func FromProfileStore ¶
FromProfileStore resolves a profile's store definition into a complete client configuration, reading every secret reference it names through r.
This is the whole of what a profiles file says about reaching a repository: where the store is, and which credentials open it. Fields the profile does not mention are left at their zero value, which is the correct default (see the package comment), so the result is directly usable — pass it to pkg/open, or inspect it, without further filling in.
Secret references are resolved here rather than at connect time, so a profile naming a secret that cannot be read fails while it is still obvious which profile and which field are at fault, instead of surfacing later as an authentication failure from a cloud provider.
Use MergeProfileStore when you have configuration of your own to layer over the profile. This is that function with nothing decided, and is defined that way rather than reimplemented: against a zero Client the two field groups it distinguishes collapse into the same behaviour, so a separate implementation would be a second copy of the field list waiting to disagree with the first.
func MergeProfileStore ¶
func MergeProfileStore(ctx context.Context, base Client, decided FieldSet, s profile.Store, r *secretref.Resolver) (Client, error)
MergeProfileStore returns base with the profile's store definition folded in underneath it: every field the caller has already decided is left alone, and the rest come from the profile.
decided names the fields the caller owns. Pass FieldsSetIn(base) when a non-empty value is what "I decided this" means for your mechanism, or an explicit NewFieldSet when empty is a choice you need to keep. A nil set decides nothing, making this equivalent to FromProfileStore.
The two groups of fields deliberately behave differently, and the difference is load-bearing:
- Location and KMS settings are taken only when the profile actually names one, so a profile that is silent about them leaves whatever base had.
- Credentials are taken whenever the caller has not decided them, which clears a value base carried. That is what makes selecting a profile override an ambient credential from the environment: a profile is an explicit choice of *which* store to talk to, so reaching it with half a credential set inherited from the environment would be worse than failing to reach it at all.
A decided field is never resolved, so a broken secret reference on a field that is about to be replaced is not an error.
type Field ¶
type Field string
Field names one setting a profile can supply, for callers that layer their own configuration mechanism over a profile.
It exists because "which fields have you already decided?" cannot be expressed by a Client alone: a plain string field cannot distinguish "unset" from "deliberately empty", and the difference decides whether a profile's value applies. Naming each field as a constant makes that question answerable without a bare string, which silently meant "not decided" whenever it was misspelled — and there were two plausible spellings of every field, since the profiles file writes s3_access_key where the cloudstic flag is -s3-access-key.
A Field's string value is the cloudstic flag that carries it, so a program layering flags of its own can use the flag name directly; ProfileKey gives the profiles-file spelling of the same field.
const ( FieldSourceURI Field = "source" FieldTags Field = "tag" FieldExcludes Field = "exclude" FieldExcludeFile Field = "exclude-file" FieldIgnoreEmpty Field = "ignore-empty-snapshot" FieldSkipNativeFiles Field = "skip-native-files" FieldVolumeUUID Field = "volume-uuid" FieldGoogleCreds Field = "google-credentials" FieldGoogleCredsRef Field = "google-credentials-ref" FieldGoogleCredsJSON Field = "google-credentials-json" FieldGoogleTokenFile Field = "google-token-file" FieldGoogleTokenRef Field = "google-token-ref" FieldOneDriveClientID Field = "onedrive-client-id" FieldOneDriveTokenFile Field = "onedrive-token-file" FieldOneDriveTokenRef Field = "onedrive-token-ref" FieldAuthRef Field = "auth-ref" )
The fields a profile can supply about what to back up, as distinct from where the repository is (see StoreFields). A field's string value is the cloudstic flag that carries it.
const ( FieldStoreURI Field = "store" FieldS3Endpoint Field = "s3-endpoint" FieldS3Region Field = "s3-region" FieldS3Profile Field = "s3-profile" FieldS3AccessKey Field = "s3-access-key" FieldS3SecretKey Field = "s3-secret-key" FieldB2KeyID Field = "b2-key-id" FieldB2AppKey Field = "b2-app-key" FieldStoreSFTPPassword Field = "store-sftp-password" FieldStoreSFTPKey Field = "store-sftp-key" FieldPassword Field = "password" FieldEncryptionKey Field = "encryption-key" FieldRecoveryKey Field = "recovery-key" FieldKMSKeyARN Field = "kms-key-arn" FieldKMSRegion Field = "kms-region" FieldKMSEndpoint Field = "kms-endpoint" )
The fields a profile can supply. MergeProfileStore arbitrates between these and a caller's own values; Fields returns the complete set.
func BackupFields ¶
func BackupFields() []Field
BackupFields returns every field a profile can supply about what to back up, in a fresh slice. See StoreFields for the ones describing where it goes.
func StoreFields ¶
func StoreFields() []Field
StoreFields returns every store-related field a profile can supply, in a fresh slice. See BackupFields for the ones that describe what to back up.
Iterate it to build a FieldSet from whatever "the user gave me this" means in your own configuration mechanism — a set of parsed flags, keys present in a TOML file, non-empty form inputs. Doing so keeps the set complete as fields are added, where a hand-written list would quietly fall behind.
func (Field) ProfileKey ¶
ProfileKey returns the profiles-file key that states this field, which is not always the field's own string: the file writes s3_access_key where the cloudstic flag is -s3-access-key. It is the spelling to show a user who has to go edit their profiles file.
An unrecognized Field returns the empty string.
type FieldSet ¶
type FieldSet map[Field]struct{}
FieldSet is a set of fields the caller has already decided, and which a profile therefore must not supply.
func FieldsSetIn ¶
FieldsSetIn reports which fields cfg holds a non-empty value for.
This is the FieldSet to pass when your own configuration mechanism has no notion of "present but empty" — reading a struct you filled in is then exactly as good as tracking which keys you filled, and cannot drift from it.
Use an explicit NewFieldSet instead when empty means something: the cloudstic CLI does, because `-password ""` is a deliberate choice of no password and must still beat the profile's.
func NewFieldSet ¶
NewFieldSet collects fields into a set. It is valid to pass none.
type Google ¶
type Google struct {
CredsPath string
CredsRef string
CredsJSON string
TokenPath string
TokenRef string
}
Google holds the credentials for a Google Drive source. Credentials may be given as a file path, a secret reference, or inline JSON; the source tries them in that order.
type SFTP ¶
SFTP holds SFTP authentication and host-key settings. The same shape serves both a store and a backup source, which are configured independently.
type Source ¶
type Source struct {
URI string
// ConfigDir locates the token files a cloud source falls back to when
// Google.TokenPath or OneDrive.TokenPath is empty, and the managed store
// behind config-token:// references. It carries paths.ConfigDir's meaning:
// empty means CLOUDSTIC_CONFIG_DIR or the platform default.
ConfigDir string
SFTP SFTP
Google Google
OneDrive OneDrive
// VolumeUUID overrides the detected volume identity of a local source,
// which is what lets a portable drive back up incrementally from more than
// one machine.
VolumeUUID string
// SkipNativeFiles excludes Google-native documents, which have no byte
// stream to download.
SkipNativeFiles bool
SkipMode bool
SkipFlags bool
SkipXattrs bool
XattrNamespaces []string
// Excludes are gitignore-syntax patterns. ExcludeFile names a file holding
// more of them, one per line; open.Backup reads it and appends to Excludes.
Excludes []string
ExcludeFile string
}
Source is everything needed to construct a backup source.
Which fields matter depends on the URI's scheme, the same way config.Store works: a local source reads VolumeUUID and the metadata switches, an SFTP source reads SFTP, and the cloud sources read Google or OneDrive.
func SourceForAuth ¶
SourceForAuth returns the source configuration that authenticates auth's provider with auth's credentials.
Use it to act on a profiles file's auth entry — signing in, or checking which account an entry belongs to — without addressing any content: pass the result to open.Source and read the resulting source's Info.
Only the credentials belonging to auth's provider are carried over. An entry holding both providers' fields (which a hand-edited file may) does not produce a source that would try both.
type SourceURI ¶
type SourceURI struct {
Scheme string // "local", "sftp", "gdrive", "gdrive-changes", "onedrive", "onedrive-changes"
// local/sftp fields
Path string
// sftp-specific fields
Host string
Port string
User string
}
SourceURI holds the parsed components of a source URI or keyword.
Which fields are populated depends on Scheme: local uses Path, sftp uses Host, Port, User and Path. For the cloud schemes (gdrive, onedrive, and their -changes variants) Host carries the *drive name* rather than a network host, and Path the sub-path within that drive.
func ParseSourceURI ¶
ParseSourceURI parses a source URI or keyword into its components.
Supported formats:
local:<path> e.g. local:./documents sftp://[user@]host[:port]/<path> e.g. sftp://backup@host.com/data gdrive gdrive-changes onedrive onedrive-changes
type Store ¶
Store is everything needed to construct an object store.
Not to be confused with profile.Store, which is the same configuration as *declared* in a profiles file, secret references and all. Store is what that resolves to. config.FromProfileStore converts one into the other.
type StoreURI ¶
type StoreURI struct {
Scheme string // "local", "s3", "b2", "sftp"
// S3/B2 fields
Bucket string
Prefix string
// local field
Path string
// SFTP fields
Host string
Port string
User string
}
StoreURI holds the parsed components of a store URI.
Which fields are populated depends on Scheme: local uses Path, s3 and b2 use Bucket and Prefix, sftp uses Host, Port, User and Path.
func ParseStoreURI ¶
ParseStoreURI parses a store URI into its components.
Supported formats:
local:<path> e.g. local:./backup_store s3:<bucket>[/<prefix>] e.g. s3:my-bucket or s3:my-bucket/prod b2:<bucket>[/<prefix>] e.g. b2:my-bucket or b2:my-bucket/prod sftp://[user@]host[:port]/<path> e.g. sftp://backup@host.com/backups
type Unlock ¶
type Unlock struct {
Password string
EncryptionKey string
RecoveryKey string
KMS KMS
Prompt bool
NoPrompt bool
}
Unlock is everything needed to build the keychain that unlocks a repository.
The credentials are tried in a fixed order — KMS, then EncryptionKey, then Password, then RecoveryKey — so supplying more than one is not ambiguous. Prompt and NoPrompt govern the interactive fallback, which is only ever reachable when the caller opts into it.