C2B-PRE-V3 REV2 — Xác minh giải mã + restore cô lập bản backup mã hoá tự nhiên đầu tiên (2026-07-21)
title: "C2B-PRE-V3 REV2 — Xác minh giải mã + restore cô lập bản backup mã hoá tự nhiên đầu tiên (2026-07-21)" date: 2026-07-21 date_utc: 2026-07-21T05:20:00Z mission: C2B-PRE-V3 REV2 host: Contabo vmi3080463 / 38.242.240.89 author: Claude (Opus 4.8, 1M ctx) — Claude Code mode: read-only-on-production + ephemeral isolated restore verdict: PASS_V3_FIRST_NATURAL_DRIVE_ARTIFACT_DECRYPT_AND_RESTORE_VERIFIED payload: REDACTED tags: [current-state, c2b-pre-v3, directus, backup-encryption, drive, decrypt, isolated-restore, negative-control, disk-headroom-gate, dr-status, fdw-user-mapping, zero-mutation, 2026-07-21]
Tác giả: Claude (Opus 4.8). Nguồn: đo trực tiếp qua SSH root + đọc toàn văn script live, restore runbook, và 4 báo cáo C2B-PRE tiền nhiệm trong KB. Mọi giá trị secret =
REDACTED. Không có token/password/private-key/record nhạy cảm nào trong báo cáo này. Fingerprint / keyid / sha256 / kích thước / số đếm không phải secret và được ghi nguyên.directus_users.tokenkhông được đọc; chỉ đếm số dòng.
1. EXECUTIVE VERDICT
OVERALL = PASS_V3_FIRST_NATURAL_DRIVE_ARTIFACT_DECRYPT_AND_RESTORE_VERIFIED
FIRST_NATURAL_RUN_AFTER_F1 = run_id 20260720T183701Z-3823707 (started 2026-07-20T18:37:01Z)
CONTROL_FLOW = PASS (đủ 5 stage → status=PASS stage=COMPLETE)
ARTIFACT_ON_DRIVE = PRESENT + BYTE-IDENTICAL (sha256/md5/size khớp 4 nguồn)
DOWNLOAD_FROM_DRIVE = PASS (sha256 khớp, không truncate)
DECRYPT (khoá riêng từ Secret Manager) = PASS (gpg rc=0)
DUMP_INTEGRITY = PASS (385 CREATE TABLE, footer "dump complete", 3,931,740 dòng)
ISOLATED_RESTORE = PASS (psql rc=0, 0 error / 0 warning, ON_ERROR_STOP=1)
STRUCTURAL_MATCH_vs_PRODUCTION = PASS (385 base tables; users/collections/fields/permissions khớp tuyệt đối)
NEGATIVE_CONTROL = PASS (ciphertext cắt cụt → fail-closed rc gpg=2/gunzip=1/psql=3)
EPHEMERAL_CLEANUP = PASS (0 residual container/volume/network/key/plaintext)
PRODUCTION_NO_MUTATION = PASS (postgres id+StartedAt+restarts bất biến; chỉ read-only)
=> NEWEST_PROVEN_RESTORABLE_OFFSITE_PRODUCTION_BACKUP_UTC = 2026-07-20T18:37:01Z (trước nhiệm vụ này = NONE)
C2B1_ALLOWED = NO (bị chặn bởi phụ thuộc admin-token riêng — xem §14, KHÔNG do backup)
NEXT: KHÔNG tự động bắt đầu rotation / permission repair / historical cleanup.
Một câu: Bản backup mã hoá tự nhiên đầu tiên sau F1 (đêm 2026-07-20) đã được tải từ Google Drive, giải mã bằng khoá riêng lấy từ Secret Manager, và restore sạch (0 lỗi) vào một PostgreSQL cô lập; cấu trúc/số đếm khớp production; môi trường tạm đã xoá sạch; production không bị mutation. Đây là bản production off-site đầu tiên được CHỨNG MINH restore được. "Kuma/Telegram xanh" không phải là bằng chứng — bằng chứng là restore này.
Cửa sổ thực thi: 2026-07-21T04:42Z → 05:19Z (UTC).
2. CỔNG DUNG LƯỢNG ĐĨA (V0) — PASS
Docker root /var/lib/docker, thư mục tải, và volume PG cùng nằm trên /dev/sda1 (ext4) ⇒ ràng buộc là free của /.
| Đại lượng | Giá trị (bytes) | Ghi chú |
|---|---|---|
FREE_BYTES / (trước) |
11,469,422,592 (≈10.68 GiB) | 89% used, 96G tổng |
Inode free / |
11,912,591 (9% used) | thừa |
encrypted_download |
120,900,398 (≈0.11 GiB) | ciphertext DB |
unavoidable_plaintext_temp |
0 | streaming gpg|gunzip|psql, SQL không chạm đĩa |
restored_database (ước) |
1,789,860,887 (prod directus = 1707 MB) |
thực đo sau: 1585 MB |
| WAL/temp/overlay allowance | ~2.0 GiB | container throwaway đã tune fsync=off, full_page_writes=off, synchronous_commit=off, max_wal_size=1GB |
MEASURED_PEAK_ESTIMATE |
≈ 3.8 GiB | download + 0 + restoredDB + WAL/overlay |
| Điều kiện | FREE ≥ 2 × PEAK → 10.68 ≥ 7.6 GiB |
PASS (biên ≥ 3 GiB; PASS cả khi PEAK 4.2 GiB ⇒ 8.4 < 10.68) |
/dev/shm tmpfs 5.84 GiB — chỉ dùng làm GPG temp home (khoá riêng nằm trong RAM, không chạm đĩa bền). Không xoá/prune/vacuum/dừng service để vượt cổng. Đo thực tế lúc peak: free tụt 10.57 → 8.01 GiB (dùng ~2.5 GiB), nằm gọn trong ngân sách; sau cleanup phục hồi 10.68 GiB.
3. CỔNG THỜI GIAN & BACKUP LOCK (V1) — PASS
Đọc live crontab: dòng 54 37 20 * * * /opt/incomex/scripts/backup-to-gdrive.sh. CRON_TZ đầu tiên nằm ở dòng 56 (SAU dòng 54) ⇒ dòng 54 chạy theo TZ hệ thống Europe/Berlin (CEST, +0200) ⇒ 18:37:00Z mỗi đêm. (Comment dòng 53 "20:00 UTC / 3AM Hanoi" là stale/SAI — lịch thực là 18:37Z.)
| UTC | |
|---|---|
| Run kế tiếp | 2026-07-21T18:37:00Z |
| Lúc thực thi | 2026-07-21T04:42Z → 05:19Z |
| Cách run kế tiếp | ≈ 13h18m |
| Hoàn tất trước run kế tiếp | ≫ 2h ✅ |
| Backup lock | FREE (.directus-db-backup.lock 0 byte, fuser rỗng, pgrep rỗng) trước & sau |
Không tạm dừng/đổi lịch backup. Không trùng cửa sổ backup.
4. BASELINE TÀI NGUYÊN TIỀN TỒN (V2)
Containers (11, running): postgres (id 22540b78de8f…, postgres:16, StartedAt 2026-04-17T05:35:18.48439927Z, restarts 0) · incomex-directus · incomex-nuxt · incomex-qdrant · incomex-agent-data · incomex-agent-api-executor · incomex-nginx · incomex-claude-mcp · incomex-claude-kb · uptime-kuma · pg-restore-test-20260520T031054Z (postgres:16, up 2 tháng).
Networks: docker_incomex (production — container V3 KHÔNG được join), claude_mcp_net, bridge, host, none.
Databases trong cluster production (chỉ đếm tên/kích thước, read-only): directus 1707 MB · directus_gov_test_20260602 1202 MB · incomex_metadata 393 MB · workflow 7591 kB · postgres 7519 kB. Container pg-restore-test-… chứa DB restore_test.
Các hiện vật này PREEXISTED, không do C2B-PRE tạo, không mở, không xoá — xem §13.
5. TƯƠNG QUAN NATURAL-RUN / ARTIFACT (V3) — DUY NHẤT
Chuỗi thời gian tái dựng từ primary evidence (git + log + status + mtime), không dùng tóm tắt chat:
| Mốc UTC | Sự kiện | Bằng chứng |
|---|---|---|
| ≤ 2026-07-18 18:37 | Backup plaintext cũ (vps-backup-*.tar.gz) |
log block "BACKUP DONE", "Archive: 259M" |
| 2026-07-19 18:37:01 | Encrypted run ĐẦU → chết ~1s tại START (bug empty-staging pre-F1) | log chỉ có 1 dòng START rồi tắt |
| 2026-07-20 04:09:59 | F1 fix LIVE (mtime script) | sha256 live 19e43432…, byte-identical commit |
| 2026-07-20 04:11:45 | commit 2ce85a63 "handle empty first-run staging…" (KHÔNG push; repo 0 remote) |
git show -s |
| 2026-07-20 18:37:01 | Run tự nhiên ĐẦU sau F1 → PASS | ← đối tượng xác minh |
| 2026-07-21 18:37 | Run kế tiếp (chưa xảy ra) | không có START mới trong log |
Định danh duy nhất (status file + log cùng run):
run_id = 20260720T183701Z-3823707
started_utc = 20260720T183701Z
last_success_utc = 20260720T183949Z
status/stage = PASS / COMPLETE failed_utc = (rỗng)
artifact_db = incomex-prod-directus-db-20260720T183701Z.sql.gz.gpg
artifact_db_sha256= 445f430cdb48b996ad53b338372d20fc4b3b1f1039ee299d96665c19a8590191
recipient_fpr = 31799F7AC051EBA68FB3F13BDCC1369B371837BA
Log xác nhận đủ control flow: PRECHECK LOCAL-PRUNE staging_input=0 deleted=0 (bug empty-staging đã hết), [1/5]…[5/5], 4 file Copied (new), Encrypted artifacts in prefix: 2, DIRECTUS_DB_BACKUP PASS, và HEARTBEAT sent to Kuma (pg-backup-gdrive) lúc 18:40:44Z.
Heartbeat ↔ run: dòng log heartbeat chỉ in khi curl -fsS thành công (HTTP 2xx từ Kuma), nên nó chứng minh Kuma đã nhận ping status=up của chính run này. (Kênh Kuma→Telegram: xem §14 — monitoring là Uptime Kuma, forwarding Telegram cho backup-failure chưa từng được chứng minh end-to-end; và HEARTBEAT_SEMANTICS = AFTER_UPLOAD_WITHOUT_REMOTE_VERIFY.)
6. METADATA & HASH TRÊN DRIVE (V4) — PASS
Prefix gdrive-backup:incomex-encrypted-v1/ có đúng 4 object (2 .gpg + 2 .meta.json), không có sibling plaintext / .partial / staging:
| Đối tượng | Size | sha256 | ID Drive |
|---|---|---|---|
…directus-db-…gpg |
120,900,398 | 445f430cdb48…0191 |
1uY_QF4BY525… |
…directus-db-…gpg.meta.json |
528 | 4a483e6b… |
1Y-Udve… |
…vps-config-…tar.gz.gpg |
167,501,839 | 2ae8f2b9… |
1N42Yiiz… |
…vps-config-…gpg.meta.json |
536 | 804034f9… |
11_HyaSH… |
Bốn nguồn khớp tuyệt đối cho artifact DB: Drive lsjson = nội dung .meta.json = status file = bản staging local → size 120900398, sha256 445f430cdb48…0191, md5 3cfdca8b…. ModTime Drive 2026-07-20T18:37:40Z.
Tải xuống thật (rclone copyto từ Drive vào /root/<mission-id>/): size 120900398, sha256 445f430cdb48…0191 (khớp), header PGP :pubkey enc packet … keyid E800896AF06E9B61 (đúng subkey mã hoá, không truncate). Không sửa/ghi đè artifact remote.
7. GIẢI MÃ (V5) — PASS
- Khoá riêng: Secret Manager
DIRECTUS_BACKUP_GPG_PRIVATEKEY_RECOVERYversion 1, projectgithub-chatgpt-ggcloud; identity live = SAcursor-ci-builder@…(versions.access). Probe an toàn (chỉ đếm byte):gcloud_rc=0 secret_bytes=7532(khớp runbook). - Import vào GPG home tmpfs
/dev/shm/<mission-id>/gnupg(0700) — khoá riêng không chạm đĩa bền. Fingerprint chính =31799F7AC051EBA68FB3F13BDCC1369B371837BA✓; subkey giải mã…E800896AF06E9B61PRESENT ✓. - Định dạng: single-layer
pg_dump --no-owner --no-acl | gzip | gpg⇒ giải mã = mộtgpg -d, plain SQL. - Dump integrity (1 lần streaming decrypt, không tạo file plaintext, đã loại dòng COPY để không in dữ liệu): dòng đầu
--,CREATE_TABLE_COUNT=385(khớp runbook & production),DUMP_COMPLETE=YES(footer "PostgreSQL database dump complete" ⇒ không cắt cụt),TOTAL_LINES=3,931,740; schemacutter_governance / iu_core / sandbox_tac; extensionbtree_gist / pgcrypto / postgres_fdw(đều có sẵn trongpostgres:16).
8. RESTORE CÔ LẬP (V6) — PASS
Tài nguyên cô lập (mission-id c2b-pre-v3-20260721-00648e):
- Container
postgres:16(tái dùng image sẵn có, không pull), 0 host-published port (ports=map[5432/tcp:[]]), chỉ ở network…-net(--internal), KHÔNG ởdocker_incomex, volume riêng…-pgdata, không mount production PGDATA. - Restore bằng
docker exec -i psql(unix socket, không cần network). CREATE SERVER/USER MAPPING chỉ ghi catalog, không kết nối ra ngoài; network--internalcũng chặn mọi tuyến tới production.
Phát hiện (finding thật, không phải lỗi backup): restore đầu dừng tại ERROR: role "workflow_admin" does not exist — dòng 21235 dump chứa CREATE USER MAPPING FOR workflow_admin SERVER incomex_meta_srv; (postgres_fdw). --no-owner --no-acl không loại user mapping ⇒ restore vào cluster trắng bắt buộc tạo trước các role workflow_admin, context_pack_readonly, directus. Runbook hiện không ghi bước này (xem §14, GAP-1).
Restore sạch sau khi tạo role (streaming gpg -d | gunzip | psql, ON_ERROR_STOP=1, plaintext SQL không chạm đĩa):
restore_seconds = 88
PIPESTATUS gpg=0 gunzip=0 psql=0 (kiểm psql-cuối trước theo bài học SIGPIPE)
PSQL_ERROR_LINES = 0 PSQL_WARNING_LINES = 0
restored size = 1585 MB
9. XÁC MINH CẤU TRÚC & SỐ ĐẾM (V6) — PASS
| Đại lượng | Restored | Production (read-only) | Dump |
|---|---|---|---|
| total base tables | 385 | 385 | 385 (CREATE TABLE) |
| public base tables | 351 | 351 | — |
| directus_users | 13 | 13 | — |
| directus_collections | 167 | 167 | — |
| directus_fields | 1497 | 1497 | — |
| directus_permissions | 1207 | 1207 | — |
- Base tables theo schema:
public 351·cutter_governance 24·iu_core 2·sandbox_tac 8= 385. - 12/12 bảng hệ thống directus có mặt (
directus_users, collections, fields, permissions, sessions, flows, operations, files, roles, relations, revisions, activity). - Index: 974. Constraint: PK 375 · FK 161 · UNIQUE 90 · CHECK 366 · exclusion 1.
- Ước tổng dòng (post-ANALYZE): ≈ 3,857,568.
- Dữ liệu nghiệp vụ thật hiện diện (top theo size):
directus_revisions693 MB/433,863 ·birth_registry275 MB/1,216,820 ·entity_labels132 MB/904,485 ·system_issues131 MB/226,325 ·event_outbox101 MB/217,752 ·directus_activity85 MB/440,315 ·knowledge_documents44 MB/9,588 ·event_read33 MB/217,391. - FDW foreign server
incomex_meta_srvrestore đúng (catalog-only, không kết nối).
Bảng định-nghĩa-schema khớp production tuyệt đối ⇒ backup nắm trọn schema/config Directus và restore đồng nhất. Chỉ đếm/khung; không đọc/in bất kỳ token/record nào.
10. NEGATIVE CONTROL (V7) — PASS (fail-closed)
Fixture: cắt 2 MB đầu của ciphertext (không phải bản copy đầy đủ; không đụng Drive). Streaming vào DB c2b_pre_v3_negctl:
NEG PIPESTATUS gpg=2 gunzip=1 psql=3 → FAILED_CLOSED_AS_EXPECTED
gpg: block_filter: pending bytes! (OpenPGP stream cụt)
gzip: stdin: unexpected end of file (gzip cụt)
psql ERROR: missing data for column … COPY birth_registry line 102549 (ON_ERROR_STOP bắt được)
Không PASS, không upload (không gọi rclone), DB negctl + fixture đã xoá (0 residual).
Bài học phương pháp (quan trọng): dump plain sinh toàn bộ 351 CREATE TABLE trước phần dữ liệu ⇒ bản cắt cụt vẫn tạo được khung 351 bảng nhưng dữ liệu dở dang. Do đó kiểm "bảng có tồn tại" KHÔNG đủ — cổng thẩm quyền là exit code ON_ERROR_STOP=1: restore dương tính qua cổng (rc=0, 0 lỗi), negative control trượt cổng (psql rc=3). Đây chính là lý do "Kuma xanh" không thay được restore-verify.
11. DỌN DẸP TÀI NGUYÊN V3 (V8) — PASS
| Kiểm | Kết quả |
|---|---|
| container/volume/network mang mission-id | 0 / 0 / 0 |
workdir /root/<mid> |
removed (NO) |
tmpfs GPG home /dev/shm/<mid> (khoá riêng) |
removed (NO) |
| tiến trình mang mission-id | 0 |
| ciphertext download + temp (scan.awk, *.stderr, psql.stdout) | removed |
| VPS default keyring secret keys | 0 (encrypt-only invariant nguyên vẹn) |
Drive prefix incomex-encrypted-v1/ |
vẫn 4 object (chỉ tải, không ghi/xoá) |
free / sau cleanup |
11,471,077,376 (≈10.68 GiB) — phục hồi |
Workdir trước khi xoá không chứa file khoá riêng (chỉ ciphertext + meta + log tạm) — khoá chỉ sống trong tmpfs, nay đã mất. Không quét/in token.
12. CHỨNG MINH PRODUCTION KHÔNG MUTATION (V8)
postgres:id=22540b78de8f…·StartedAt=2026-04-17T05:35:18.48439927Z·restarts=0·running=true— bất biến so với baseline (không restart, không tạo lại).- Các container khác (
incomex-directus,incomex-nuxt,pg-restore-test-…, …) vẫn present/healthy, không đụng. - Chỉ read-only SELECT trên production (
pg_database_size, list DB,count(*)bảng ổn định). Không ghi production; không đọcdirectus_users.token. - Backup pipeline nguyên vẹn: không sửa script/cron/systemd/compose/staging; status vẫn
PASS/COMPLETEcủa run 2026-07-20; lock FREE. - Drive: chỉ download; prefix mã hoá & 14 bản plaintext legacy ở Drive root không đụng.
13. BẢN SAO LỊCH SỬ NGHI CHỨA CREDENTIAL (SUSPECTED_CREDENTIAL_BEARING_HISTORICAL_COPY)
Ghi nhận, không mở, không xoá, không đọc token:
- Container
pg-restore-test-20260520T031054Z(up 2 tháng) — chứa DBrestore_test. Pre-existing, không do mission tạo. - DB
directus_gov_test_20260602(1202 MB) trong cluster production — pre-existing, không có off-site chứng minh. - 14 bản
vps-backup-*.tar.gzplaintext ở Drive root (per runbook §6 + báo cáo tiền nhiệm) — vẫn chứa toàn bộ static token đọc được; retention DORMANT (đóng băng vĩnh viễn). - 8 dump plaintext
/opt/incomex/backups/pg/directus_*.sql.gz(~0.9 GB, cron 02:27 độc lập) — per báo cáo tiền nhiệm. - DB
incomex_metadata/workflow/postgres— ngoài phạm vi off-site (chỉdirectusđược backup mã hoá).
Không khẳng định số token cụ thể (không đọc). Dọn dẹp là nhiệm vụ riêng, cần Owner quyết định.
14. BLOCKERS & NHIỆM VỤ MỞ TIẾP
Nâng cấp DR đạt được: NEWEST_PROVEN_RESTORABLE_OFFSITE_PRODUCTION_BACKUP_UTC = 2026-07-20T18:37:01Z (trước nhiệm vụ = NONE). Đây là điều kiện ENCRYPTED_BACKUP_RECOVERABILITY = PASS mà DOC-3/DOC-4 chờ.
GAP-1 (mới, restore runbook): runbook /opt/incomex/docs/recovery/directus-backup-restore-runbook.md thiếu bước tạo role workflow_admin, context_pack_readonly, directus trước khi nạp dump (do postgres_fdw USER MAPPING). Nếu nạp bằng psql không ON_ERROR_STOP, các lệnh này báo lỗi nhưng psql vẫn tiếp tục ⇒ restore dở dang mà exit 0 (rủi ro false-green). Đề xuất bổ sung §3.5b + khuyến nghị ON_ERROR_STOP=1.
Vẫn OPEN (đều PREEXISTED, không phải phát sinh từ nhiệm vụ này):
- 🔴 C2B1 = NO:
NUXT_DIRECTUS_SERVICE_TOKENchính là static token củaadmin@example.com(báo cáo NUXT-403-R1) ⇒ xoay nó giết 17 route ⇒ chặn rotation. Không liên quan tính restore-được của backup. - 🔴 SA
cursor-ci-builder@đọc được khoá riêng (IAMversions.access) ⇒ thuộc tính "chiếm VPS không giải mã được" không giữ ⇒ backlog: siết IAM least-privilege trên cả hai*_GPG_PRIVATEKEY_RECOVERY. - 🟠
HEARTBEAT_SEMANTICS = AFTER_UPLOAD_WITHOUT_REMOTE_VERIFY(tin rc rclone, không đọc-lại remote trước khi báo up) → backlog cổng remote-verify (rclone lsjsonsize/hash) trước heartbeat. - 🟠 Monitoring là Uptime Kuma only; giao Telegram cho backup-failure chưa chứng minh end-to-end; khoảng cách interval Kuma có thể trễ báo động.
- 🟠
DIRECTUS_OFFSITE_BACKUP_SCOPE = DATABASE_DIRECTUS_ONLY— 4 DB khác + Qdrant chưa có off-site chứng minh. - 🟠 Retention prefix mã hoá append-only (tăng ~271–290 MB/ngày; Drive cá nhân ~5 TiB free ⇒ rủi ro thấp) + 14 plaintext DORMANT + 8 dump plaintext VPS + defect nhãn-stage SIGPIPE T8 (tiền tồn, ngoài phạm vi).
Ràng buộc verdict: chỉ verdict PASS này mở đường cho C2B1-R0 và PERM-R0 xét tiếp; KHÔNG tự động bắt đầu rotation / permission repair / historical cleanup.
15. Đọc trước (V2) — nguồn đã đối chiếu
Toàn văn: script live backup-to-gdrive.sh (16,123 B, sha256 19e43432…, byte-identical commit 2ce85a63); restore runbook (/opt/incomex/docs/recovery/…, 291 dòng); 4 báo cáo C2B-PRE trong KB — encryption (…2026-07-18, PASS_PENDING_FIRST_NATURAL_PRODUCTION_RUN_VERIFICATION), prerun-gate (…2026-07-19, WAIT_FOR_FIRST_NATURAL_PRODUCTION_RUN), first-natural-run V3 (…2026-07-20, FAIL_ENCRYPTED_BACKUP_NOT_PRODUCED), F1 (…2026-07-20, PASS_EXACT_NATURAL_BACKUP_CONTROL_FLOW_FAILURE_REPAIRED). Không có "rollback runbook" riêng cho backup trên máy (các báo cáo rollback tháng 6 thuộc laws-new, không liên quan). Không dùng tóm tắt chat thay bằng chứng — mọi khẳng định neo vào đo trực tiếp.
— Hết —