# GeoIntel Release Runbook ## Scope This runbook releases GeoIntel for Belgium and the Belgian North Sea. Mol and the Kempen remain regression references. A successful release never implies that every theme is operational in every jurisdiction; the coverage API and source provenance remain authoritative. The repository version is stored in `VERSION`. The current release is `v1.0.0`. ## Mandatory preconditions - clean `main` worktree at the commit being released; - secure non-default PostGIS password in the Tower `.env`; - existing local AI model only when the AI image is enabled; - recent checksum-verified backup with SHA-256 storage inventory; - Docker, `ssh-keygen`, Python 3.11, Node 20 and Bash available; - one Alembic head and no unsupported metric represented as successful. No command in this runbook downloads AI weights or implicitly deletes application data. ## Repository gate ```bash python -m compileall backend/app cd backend && python -m pytest cd ../frontend && npm run test:unit && npm run typecheck && npm run build cd .. bash scripts/run_readiness_check.sh cd backend && python -m alembic heads python -m alembic upgrade head --sql cd .. bash -n scripts/live_migration_smoke.sh docker compose config ``` ## Immutable deployment On the Codex workstation: ```powershell .\scripts\deploy_tower.ps1 ``` On Tower: ```bash cd /mnt/user/appdata/geointel docker inspect --format \ '{{index .Config.Labels "org.opencontainers.image.version"}} {{index .Config.Labels "org.opencontainers.image.revision"}}' \ geointel curl -fsS http://127.0.0.1:1202/health/ready bash scripts/live_migration_smoke.sh ``` ## Backup and recovery proof Create an immutable backup. The SHA-256 inventory can take several minutes on large storage: ```bash bash scripts/backup_release_state.sh \ --container geointel \ --output-root /mnt/user/appdata/geointel/backups \ --release-id v1.0.0 \ --storage-path /mnt/user/appdata/geointel/storage \ --models-path /mnt/user/appdata/geointel/models \ --inventory-mode sha256 ``` Verify and restore only into an automatically generated temporary database: ```bash bash scripts/verify_release_backup.sh \ --backup-dir /mnt/user/appdata/geointel/backups/v1.0.0 \ --container geointel bash scripts/restore_release_backup_smoke.sh \ --backup-dir /mnt/user/appdata/geointel/backups/v1.0.0 \ --container geointel \ --confirm-isolated-restore bash scripts/verify_release_upgrade_smoke.sh \ --backup-dir /mnt/user/appdata/geointel/backups/v1.0.0 \ --container geointel \ --confirm-isolated-upgrade ``` The restore and upgrade scripts refuse the production database name and remove their generated verification database. ## Fresh install, browser and data operations ```bash bash scripts/verify_release_fresh_install.sh \ geointel-all-in-one:-ai bash scripts/run_rc8_release_journeys.sh \ http://127.0.0.1:1202 artifacts/releases/v1.0.0/rc8 bash scripts/run_rc9_ux_audit.sh \ http://127.0.0.1:1202 artifacts/releases/v1.0.0/rc9 bash scripts/run_rc10_data_operations_audit.sh \ artifacts/releases/v1.0.0/rc10 ``` The RC10 command is read-only and runs cleanup in dry-run mode only. ## Supply-chain evidence ```bash bash scripts/audit_python_dependencies.sh cd frontend && npm audit --audit-level=high cd .. bash scripts/generate_container_sbom.sh \ geointel-all-in-one:-ai \ artifacts/releases/v1.0.0/geointel-sbom.spdx.json bash scripts/scan_container_image.sh \ geointel-all-in-one:-ai \ artifacts/releases/v1.0.0/container-vulnerabilities.json ``` The complete vulnerability report remains evidence. The executable policy gate fails on reachable fixed HIGH/CRITICAL findings. ## Rollback proof The rollback command reuses persistent paths and never downgrades Alembic: ```bash bash deploy/unraid/rollback-dockerman-container.sh curl -fsS http://127.0.0.1:1202/health/ready bash deploy/unraid/deploy-release.sh curl -fsS http://127.0.0.1:1202/health/ready ``` For a future backward-incompatible migration, restore the verified pre-release backup instead of running an older image against a newer schema. ## Tag and signed package Create an SSH-signed Git tag at the accepted clean commit. Use a configured release key; never add the private key to the repository: ```bash git -c gpg.format=ssh \ -c user.signingkey=/secure/path/release-key \ tag -s v1.0.0 -m "GeoIntel v1.0.0" git push origin v1.0.0 ``` Place the collected evidence files in an ignored package directory and create the detached SSH signature plus complete checksum inventory: ```bash python scripts/build_release_package.py build \ --output-dir artifacts/releases/v1.0.0 \ --release-id v1.0.0 \ --image-name geointel-all-in-one:-ai \ --image-id sha256: \ --image-revision \ --signing-key /secure/path/release-key python scripts/build_release_package.py verify \ --package-dir artifacts/releases/v1.0.0 ``` The builder refuses a dirty worktree, a tag not pointing at `HEAD`, a mismatched image revision, missing evidence, symlinks, checksum drift or an invalid signature. ## Safe cleanup and shutdown Stop only the temporary smoke container by its generated name; normal scripts already clean it automatically. To stop GeoIntel without deleting persistent data: ```bash docker stop geointel ``` Do not use broad Docker volume pruning. Application cleanup remains dry-run by default and requires the exact confirmation, recent backup and delete ceiling documented in `DATA_OPERATIONS_RUNBOOK.md`.