Documentation
¶
Overview ¶
Package open constructs live objects from resolved configuration: an object store from a store URI and its credentials, a keychain from a set of unlock credentials, and a repository client from both.
It is the other half of pkg/config. That package answers "what did the user configure"; this one answers "connect to it". The split is what decides import cost: pkg/config depends on nothing heavier than YAML parsing, so reading and validating a profiles file is cheap, while constructing an S3 or KMS client necessarily links a cloud SDK and only a caller who does that pays for it (RFC 0022 §7).
Everything the constructors need from the outside world is passed in rather than reached for. The debug sink is a writer the caller supplies, the progress reporter is a value the caller chooses, and whether an interactive password prompt is available at all is the caller's decision — this package never inspects the process's own stdin, because a library's answer to "can I prompt?" is not the same as a terminal program's.
Index ¶
- func BackupOptions(cfg config.Backup) ([]cloudstic.BackupOption, error)
- func Client(ctx context.Context, cfg config.Client, opts ...Option) (*cloudstic.Client, error)
- func FromProfile(ctx context.Context, path, name string, opts ...Option) (*cloudstic.Client, error)
- func Keychain(ctx context.Context, cfg config.Unlock, opts ...Option) (keychain.Chain, error)
- func Source(ctx context.Context, cfg config.Source, opts ...Option) (source.Source, error)
- func Store(ctx context.Context, cfg config.Store, opts ...Option) (store.ObjectStore, error)
- type BackupJob
- type Option
- func WithBackendWrapper(fn func(store.ObjectStore) (store.ObjectStore, error)) Option
- func WithDebugWriter(w io.Writer) Option
- func WithDecided(cfg config.Client, decided config.FieldSet) Option
- func WithLogger(w io.Writer) Option
- func WithPasswordPrompt(resolve, wrap func() (string, error)) Option
- func WithReporter(r cloudstic.Reporter) Option
- func WithSecretResolver(r *secretref.Resolver) Option
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BackupOptions ¶
func BackupOptions(cfg config.Backup) ([]cloudstic.BackupOption, error)
BackupOptions returns the client options describing how to record a backup, including the exclude hash derived from cfg's patterns.
Prefer Backup, which constructs the source from the same resolved patterns. This exists for a caller supplying its own source.Source implementation, which must then apply cfg.Source.Excludes itself for the hash to mean anything.
func Client ¶
Client opens a repository client on the store described by cfg, unlocked with the credentials cfg names.
func FromProfile ¶
FromProfile opens a repository client on the store that profile name selects in the profiles file at path.
An empty path means the default location — profiles.yaml inside the config directory, honouring CLOUDSTIC_CONFIG_DIR (profile.DefaultPath) — so a program reading a user's profiles finds the same file the cloudstic CLI would, rather than a second one that silently disagrees.
This is the one-call form of profile.Load → Config.StoreFor → config.MergeProfileStore → Client. Configuration of your own goes in through WithDecided, which layers it over the profile with the same precedence the cloudstic CLI applies to its flags. Drop to the explicit sequence when you need the resolved configuration itself — to display it, diff it, or decide something from it before connecting; that cannot be done afterwards, since the client this returns is already connected.
A profile that names no store is an error here, because a client needs one. Config.StoreFor reports that case as a nil store without an error, for callers that have another way to reach the repository.
func Keychain ¶
Keychain assembles the credential chain that unlocks a repository, in the order the client should try them.
The order is the contract: KMS, then a raw platform key, then a password, then a recovery mnemonic, then an interactive prompt. Each is tried against the repository's key slots and the first that opens one wins, so a caller supplying several is not ambiguous — it is a preference list.
A prompt is appended only when WithPasswordPrompt supplied one *and* the configuration allows it: either nothing else is available, or a prompt was asked for explicitly, and NoPrompt is not set. A caller that supplies no prompt gets a chain that can fail but can never block waiting for input.
func Source ¶
Source constructs the backup source described by cfg.
The result is ready to hand to Client.Backup. Exclude patterns are applied by the source itself as it walks, so a caller building a source directly gets the same filtering a backup would — but see Backup, which additionally reads cfg.ExcludeFile and derives the snapshot's exclude hash from the same list.
Secret references in the credentials are resolved by the source when it authenticates, through the resolver WithSecretResolver names.
Types ¶
type BackupJob ¶
type BackupJob struct {
Source source.Source
Options []cloudstic.BackupOption
}
BackupJob is a source paired with the options that describe how to record what it yields.
The two travel together because they share one derived value: the snapshot's exclude hash must be the hash of exactly the patterns the source is filtering on. Returning them separately, or deriving the hash at a second call site, is how they come to disagree — and the engine reads a mismatch as "the exclude patterns changed", forcing a full rescan (or, worse, missing one).
func Backup ¶
Backup constructs the source and options for one backup run.
cfg.Source.ExcludeFile is read here, once, and its patterns appended to cfg.Source.Excludes — so the source filters on the full list and the exclude hash covers the same list. That hash is what the engine compares against the previous snapshot's to decide between an incremental and a full rescan, which is why deriving it is this package's job and not a caller's.
type Option ¶
type Option func(*options)
Option configures how a store, keychain, or client is opened.
These are behaviour knobs supplied by the caller, deliberately separate from the pkg/config value types: configuration describes a repository and can be serialized, compared, and round-tripped, while these carry writers, callbacks, and interfaces that cannot.
func WithBackendWrapper ¶
func WithBackendWrapper(fn func(store.ObjectStore) (store.ObjectStore, error)) Option
WithBackendWrapper wraps the constructed backend before the repository layers are applied on top of it, for a caller adding its own quota, rate-limit, metrics, or fault-injection decorator.
This is the supported place to intervene in the store chain. The repository decorators themselves stay internal because their composition order is a correctness and security invariant (RFC 0022 §4a); wrapping the backend underneath them carries no such hazard.
func WithDebugWriter ¶
WithDebugWriter logs every store operation to w.
The writer is supplied rather than created here because it is usually shared with a progress reporter, so that operation logs and progress output do not interleave.
func WithDecided ¶
WithDecided layers configuration of the caller's own over the profile: every field named in decided is taken from cfg, and the profile supplies the rest.
This is what makes FromProfile usable by a program that has a second configuration mechanism — command-line flags, its own file, a form — rather than only by one that has nothing but the profile. Without it, such a caller had to abandon FromProfile and rebuild the four steps by hand, and the cloudstic CLI itself was the clearest example of a caller it could not serve.
Pass config.FieldsSetIn(cfg) as decided when a non-empty value is what "I decided this" means for your mechanism. Pass an explicit config.NewFieldSet when empty is itself a choice you need to keep.
Precedence is the same rule config.MergeProfileStore documents, including that a decided field's secret reference is never read — so a broken reference on a field you are replacing is not an error. That is the reason this is an option on FromProfile rather than a hook that edits the resolved configuration afterwards, which could not skip the resolution.
func WithLogger ¶
WithLogger sends the client's debug output — its own and that of the engine and store layers it drives — to w.
This is distinct from WithDebugWriter, which traces individual store operations. A caller that wants both passes both; they are separate because per-operation tracing is far noisier than the component diagnostics, and is often wanted on its own.
func WithPasswordPrompt ¶
WithPasswordPrompt makes an interactive password prompt available as a last-resort credential, used only when the configuration leaves no other way in (or asks for a prompt explicitly) and does not forbid prompting.
resolve is called to unlock an existing repository; wrap is called to choose a password for a new key slot, and should confirm it.
Supplying these is what makes prompting possible at all. That is the caller's decision to make: this package cannot tell whether a prompt would reach a human, and guessing by inspecting os.Stdin would be wrong for every caller that is not a terminal program.
func WithReporter ¶
WithReporter sets the progress reporter the client reports through. Without one the client reports nothing.
func WithSecretResolver ¶
WithSecretResolver reads the scheme://path secret references a profile names through r, instead of through the built-in backend set.
Supply one to register a scheme the built-ins do not cover — a Vault or cloud-secret-manager backend — or, in a test, to resolve references without touching a real keychain. backends.Default returns a fresh map, so the usual shape is to add to it rather than replace it.
This affects only the profile-reading entry points. Store, Keychain and Client take configuration whose secrets are already resolved.