# Backup provider contract — the interface every backup/restore provider must implement. # Consumed by op.nu to build and execute archive commands generically. # Each provider declares its binary, features, environment requirements, and # the exact subcommands + flags needed for each operation. let _Features = { tags | Bool | doc "Supports --tag key=value on snapshot create" | default = true, ui | Bool | doc "Has built-in web UI (e.g. kopia server start --ui)" | default = false, verify | Bool | default = true, mount | Bool | doc "Supports FUSE mount of snapshots" | default = false, encryption | Bool | doc "Encrypts snapshots end-to-end (non-negotiable for this stack)" | default = true, compression | Bool | default = false, dedup | [| 'none, 'per_repo, 'global |] | default = 'per_repo, streaming | Bool | doc "Supports backup from stdin (pg_dump pipe, etc.)" | default = false, } in let _Env = { required | Array String | doc "Must be set before any operation", optional | Array String | default = [], } in let _Connection = { required | Bool | doc "Must call connect before backup (kopia=true, restic=false)" | default = false, status_subcmd | String | optional | doc "Subcommand to check if already connected", connect_subcmd | String | optional | doc "Subcommand to establish connection to the repo", state_file | String | optional | doc "Filename stored under ops_dir for per-workspace connection state (e.g. '.kopia-config')", s3_flags | { bucket | String | optional, endpoint | String | optional, prefix | String | optional, } | default = {}, } in let _BackupCmd = { subcmd | String | doc "Subcommand (may contain spaces, e.g. 'snapshot create')", repo_flag | String | optional | doc "Flag for repository URL; absent if config-file based", tag_flag | String | optional | doc "Flag for a single tag entry (repeated per tag)", snapshot_id_regex | String | doc "Regex with named group 'id' to extract snapshot ID from stdout", } in let _RestoreCmd = { subcmd | String, repo_flag | String | optional, target_flag | String | doc "Flag for restore destination; empty string = positional arg", } in let _ListCmd = { subcmd | String, repo_flag | String | optional, tag_flag | String | optional, } in let _ForgetCmd = { subcmd | String | doc "Subcommand that removes old snapshots", repo_flag | String | optional, tag_flag | String | optional | doc "Scope forget to a specific tag (workspace isolation)", keep_last_flag | String | optional | doc "Absent when retention is controlled via policy_subcmd", keep_monthly_flag | String | optional, keep_yearly_flag | String | optional, extra_flags | Array String | default = [], policy_subcmd | String | optional | doc "If set, run policy subcommand before forget (kopia model)", policy_keep_flags | { keep_latest | String | default = "--keep-latest", keep_monthly | String | default = "--keep-monthly", keep_annual | String | default = "--keep-annual", } | optional, } in let _VerifyCmd = { subcmd | String, repo_flag | String | optional, } in # EncryptionRequired contract: provider features must include encryption=true. # A BackupPolicy referencing a provider that does not encrypt fails at # `nickel export` time, not at runtime — this is how the non-negotiable # E2E encryption invariant is enforced. let _EncryptionRequired = std.contract.from_validator (fun value => if value.features.encryption == true then 'Ok else 'Error { message = "BackupProvider lacks 'encryption in features (E2E encryption is non-negotiable)", } ) in { BackupProvider = { name | String | doc "Provider identifier — must match the directory name under extensions/providers/backup/", binary | String | doc "CLI binary invoked for all operations", features | _Features | default = {}, env | _Env, connection | _Connection | default = {}, mount_capable | Bool | doc "Convenience flag mirroring features.mount" | default = false, streaming_capable | Bool | doc "Convenience flag mirroring features.streaming" | default = false, commands = { backup | _BackupCmd, restore | _RestoreCmd, list | _ListCmd, forget | _ForgetCmd, verify | _VerifyCmd | optional, }, }, # Apply this contract to provider definitions to enforce E2E encryption. EncryptionRequired = _EncryptionRequired, }