86 lines
4.0 KiB
JSON
86 lines
4.0 KiB
JSON
{
|
|
"task_id": "DEV-000037",
|
|
"task_revision": 1,
|
|
"architecture_revision": "ADR-0004",
|
|
"base_repo_revision": "03dde8c1961f214fbb5ebdefa131eb38fd0bef57",
|
|
"risk_tier": "E",
|
|
"intent": "Replicate verified production PostgreSQL backups to the private NAS as authenticated encrypted artifacts, with a DPAPI-protected recovery key and tested restore path, without using docker-test.",
|
|
"requirement_ids": ["CONSTITUTION-1.3.36", "USER-DOCKER-PROD-ONLY"],
|
|
"allowed_change_scope": {
|
|
"modules": [],
|
|
"paths": [
|
|
"deploy/windows/Sync-PostgresBackupToNas.ps1",
|
|
"deploy/windows/Test-PostgresBackupFromNas.ps1",
|
|
"deploy/windows/Register-PostgresBackupNasTask.ps1",
|
|
"docs/CREDENTIALS_AND_SECRETS.md",
|
|
"docs/DEPLOYMENT.md",
|
|
"dev/ACTIVE_TASK.json",
|
|
"dev/tasks/DEV-000037-encrypted-offhost-backup.json"
|
|
]
|
|
},
|
|
"forbidden_change_scope": {
|
|
"paths": [
|
|
"architecture/**",
|
|
"ci/**",
|
|
".gitea/**",
|
|
"cmd/**",
|
|
"contracts/**",
|
|
"modules/**",
|
|
"database/**",
|
|
"security/**",
|
|
"deploy/docker-compose*.yml"
|
|
]
|
|
},
|
|
"allowed_architecture_delta": {
|
|
"new_cross_module_dependencies": 0,
|
|
"new_canonical_owners": 0,
|
|
"new_privileges": 0,
|
|
"new_operator_dependencies": 1
|
|
},
|
|
"dependencies": {
|
|
"operator": ["GnuPG 2.4+ already installed on the authorized Windows backup workstation"]
|
|
},
|
|
"contracts": {
|
|
"consume": ["DEV-000035 verified PostgreSQL backup directory", "SSH key to docker.cin.su", "authenticated NAS session", "Windows DPAPI CurrentUser"],
|
|
"may_change": []
|
|
},
|
|
"semantic_owner": "none; disaster-recovery transport only",
|
|
"canonical_state": ["none; backup artifacts are exported recovery copies"],
|
|
"state_transitions": ["verified local backup -> encrypted off-host copy -> decrypt-and-restore verified copy"],
|
|
"side_effects_and_privileges": ["reads completed production backup artifacts over SSH", "writes encrypted artifacts to the private NAS", "stores a random recovery passphrase as CurrentUser DPAPI ciphertext outside Git", "registers a current-user scheduled task"],
|
|
"persistence_and_migrations": ["no database migration", "encrypted .gpg artifact plus non-secret JSON manifest on NAS", "no automatic deletion or retention policy"],
|
|
"failure_retry_restart": ["NAS completion is indicated only after ciphertext and manifest are atomically renamed", "existing matching artifacts are idempotently retained", "temporary plaintext is confined to a validated per-run Windows temp directory and removed on exit", "scheduled retries run at logon and daily", "failed remote restore checks remove only their generated temporary directory"],
|
|
"assumptions": [
|
|
"The authorized Windows user retains access to both the SSH alias docker and the private NAS share",
|
|
"GnuPG 2.4+ remains installed on that workstation",
|
|
"The DPAPI profile and NAS are independent from the production Docker host",
|
|
"docker-test remains prohibited"
|
|
],
|
|
"acceptance_scenarios": [
|
|
"the latest completed production backup is copied and source hashes are checked before encryption",
|
|
"NAS contains ciphertext and a non-secret manifest but no plaintext PostgreSQL dump",
|
|
"the recovery passphrase is random and stored only as DPAPI ciphertext outside the repository",
|
|
"ciphertext decrypts and reproduces the source archive hash",
|
|
"the decrypted off-host copy passes SHA-256 checks and an isolated PostgreSQL restore on docker.cin.su",
|
|
"daily and logon triggers are registered for the current user",
|
|
"no backup is automatically deleted",
|
|
"exact diff validation observes only declared paths"
|
|
],
|
|
"required_tests": [
|
|
"PowerShell parser",
|
|
"architecture preflight",
|
|
"exact diff scope",
|
|
"source SHA-256 validation",
|
|
"GnuPG encrypt/decrypt round trip",
|
|
"NAS ciphertext hash validation",
|
|
"isolated restore from decrypted NAS artifact",
|
|
"scheduled task registration and manual invocation",
|
|
"production health",
|
|
"CI"
|
|
],
|
|
"terminal_gap_states": [
|
|
"BLOCKED_BY_MISSING_CAPABILITY",
|
|
"BLOCKED_BY_CONFLICT"
|
|
]
|
|
}
|