Claude — C0: Chặn Git history chứa active secret sao chép lên Google Drive (2026-07-17)
C0 — Chặn Git history chứa active secret tiếp tục sao chép lên Google Drive (2026-07-17)
Tác giả: Claude (Opus 4.8). Host:
vmi3080463/38.242.240.89(Contabo). Nguồn điều hành: survey rev8 (58.569 ký tự) + Wave A1 rev1 (41.831 ký tự) — đọc toàn văn cả hai. Mọi giá trị secret =REDACTED. Không password/token/key nào trong báo cáo này.
1. VERDICT
PASS_CURRENT_GIT_HISTORY_PROPAGATION_STOPPED
CODE_WORKTREE_OFFSITE_BACKUP = PASS
ACTIVE_GIT_HISTORY_PROPAGATION = STOPPED
CLEAN_GIT_HISTORY_OFFSITE_BACKUP = TEMPORARILY_UNAVAILABLE_UNTIL_ROTATION_AND_HISTORY_SANITIZATION
HISTORICAL_DRIVE_COPIES = REMAIN_UNCHANGED
Không tuyên bố historical exposure đã đóng.
🔴 PHÁT HIỆN QUAN TRỌNG NHẤT — C0 KHÔNG chặn được secret rời VPS
Đo thật sau khi vá (không suy luận): artifact mới vẫn mang chính credential đang hoạt động.
Artifact MỚI (.git đã loại) — file chứa LIVE DIRECTUS_ADMIN_PASSWORD:
web-test 0
agent-data-test 2 ← scripts/reconcile-knowledge.py
scripts/reconcile-tasks.py
Lý do: giá trị nằm đồng thời ở hai chỗ — trong .git objects (2 blob) và trong
file worktree đang được TRACKED. Loại .git chỉ cắt vector thứ nhất. Hai file
worktree là source thật, vẫn cần cho restore, nên §8.3 cấm loại chúng ở C0.
ACTIVE_CREDENTIAL_PROPAGATION_VIA_WORKTREE = CONTINUES (2 file, 4×/ngày, chưa được chặn)
⇒ Đính chính khung của mission: tiêu đề C0 nói "chặn Git history" — điều đó đạt. Nhưng nếu ai đó đọc verdict thành "secret đã hết rời VPS" thì SAI. Chặn thật cần Wave C2 (rotate) + C3 (rewrite history) và gỡ hardcode khỏi 2 file worktree. Việc này cần Owner quyết, vượt phạm vi C0 (§5 cấm rotate, §8.3 cấm loại source).
2. BACKUP JOB IDENTITY
script /opt/incomex/scripts/code-backup-to-gdrive.sh (755 root:root)
PRE sha256 20762cfb3912f686b0b3bd3b56b66b23f705a5cc98731ef90752e15e803d9e5f
POST sha256 b47c5e36995582939ef55e261543747f3e4e8022893b20b81ac869e269d3ee27
cơ chế rsync -a → stage → tar -czf → rclone copyto (KHÔNG mã hoá, KHÔNG crypt)
lock flock /opt/incomex/backups/code/.code-backup.lock
Không tin tên job — đã xác minh binary thật, cron thật, source thật.
3. SCHEDULE & DESTINATION (không đổi)
cron (root crontab L57) 0 8,12,15,20 * * * = 4×/ngày (ICT qua CRON_TZ)
remote gdrive-backup: (rclone, type=drive, scope=drive)
folder web-test 1K1atlFO-bkO7KoukEKPDFbZq7wvQd1Mb
folder agent-data-test 1__qHH5ndV0FqC73nJu5_kUN5sd46M-AN
retention REMOTE_KEEP=56 · LOCAL_KEEP=1
crontab sha256 PRE == POST 547e8151f95c0cc86ed48abd3401e8af1b04b1ce0f111a14bd2d9b13bc07b039
⇒ destination / retention / lịch: KHÔNG đổi (đúng §8.5).
4. PRE SOURCE / INCLUDE / EXCLUDE
WEB_REPO_PATH /opt/incomex/docker/nuxt-repo → tar "web-test"
AGENT_REPO_PATH /opt/incomex/docker/agent-data-repo → tar "agent-data-test"
rsync -a --exclude=node_modules .nuxt .output __pycache__ .pytest_cache
.mypy_cache .cache coverage dist .venv ← 10 exclude, KHÔNG có .git
Chỉ loại build/cache. Toàn bộ hidden files, .git, worktree pointer đều được sao chép.
Không follow symlink ngoài cây (rsync -a giữ symlink as-is).
5. GIT ROOTS BỊ ẢNH HƯỞNG (đo, không đoán)
| Path | Kiểu | HEAD | Remote |
|---|---|---|---|
docker/nuxt-repo/.git |
dir (18M, 1998 file) | 2ea41583… main |
github.com/Huyen1974/web-test |
docker/nuxt-repo/web-rp-current/.git |
🔴 FILE — worktree pointer | d04d8e5 feat/rp-current-supervision |
— |
docker/agent-data-repo/.git |
dir (22M, 381 file) | 0ffd6778… main |
github.com/Huyen1974/agent-data-test |
git worktree list (nuxt-repo):
/opt/incomex/docker/nuxt-repo 2ea4158 [main]
/opt/incomex/docker/nuxt-repo/web-rp-current d04d8e5 [feat/rp-current-supervision]
→ .git file trỏ: gitdir: /opt/incomex/docker/nuxt-repo/.git/worktrees/web-rp-current
Nested repo: không có. Local bundle trong source set: không có (*.bundle/*.pack ngoài .git = 0).
Phân loại nguồn:
| Nguồn | Lớp |
|---|---|
nuxt-repo/.git, agent-data-repo/.git, worktree pointer |
GIT_HISTORY_WITH_ACTIVE_SECRET |
| worktree source (trừ 2 file dưới) | SAFE_CODE_CONTENT |
agent-data-repo/scripts/reconcile-{knowledge,tasks}.py |
🔴 RUNTIME_SECRET_FILE (worktree, vẫn trong backup) |
.env.example ×4, .env.working |
SAFE_CODE_CONTENT — .env.working chứa Qdrant key CŨ (A1 §14 đã đo: ≠ key live) |
docker/.env, /etc/incomex/agent-data.env |
KHÔNG thuộc source set này (đã kiểm) |
6. ACTIVE-SECRET HISTORY PROOF (payload REDACTED)
Phương pháp: trích giá trị live vào file tmpfs 0600, dùng grep -Ff <file>.
Giá trị KHÔNG bao giờ vào argv — đúng cách mà survey §18 tự khai là đã làm sai.
Pattern file đã shred sau khi đo.
pattern bytes: 24 (REDACTED, không in)
HEAD:scripts/reconcile-knowledge.py match_lines=1
HEAD:scripts/reconcile-tasks.py match_lines=1
4acebbc:scripts/reconcile-knowledge.py match_lines=1
4acebbc:scripts/reconcile-tasks.py match_lines=1
blob trong packed history mang giá trị: 2
⇒ .git thật sự mang credential đang hiệu lực ⇒ mỗi lần chạy = 1 bản off-site mới
của history chưa sanitize. C0 có căn cứ.
⚠️ Ghi nhận minh bạch: probe đầu của tôi dùng regex theo tên biến (
DIRECTUS_ADMIN_PASSWORD *= *["']) → 0 hit, dễ kết luận nhầm "không có secret". Hình dạng gán trong file khác regex đó. Chỉ phép đo theo GIÁ TRỊ mới đúng. Bài học: đo secret phải theo giá trị, không theo tên biến.
7. GIT SAFETY GATE = PASS
repo /opt/incomex branch feat/s177-sprint1-round-a
HEAD(PRE) cdf25ecb2f1406d0515ab43f359520270236eb60 (== HEAD POST của Wave A1 ✅)
remote KHÔNG CÓ ⇒ GIT_PUSH bất khả thi về mặt cấu trúc
dirty PRE 15 M + 88 ?? (== A1 ghi nhận ✅)
| Path | Phân loại | Xử lý |
|---|---|---|
scripts/code-backup-to-gdrive.sh |
MISSION_CHANGE — TRACKED_CLEAN, live == HEAD (diff 0 dòng) | ⇒ không cần baseline commit |
| 15 M + 88 ?? | UNRELATED_WORK |
không stage — POST vẫn đúng 15 M + 88 ?? |
agent-data-repo HEAD blobs |
SECRET_IN_HEAD |
ghi nhận, không sửa ở C0 |
| — | UNKNOWN |
0 |
Chỉ git add <exact-path>. Không -A, không ., không pull/reset/checkout/restore/clean.
8. CHECKPOINT / BUNDLE / BACKUP
CK = /root/c0-checkpoint-20260717T130000Z (root:root 0700)
bundle/opt-incomex-PRE-20260717T130000Z.bundle
a7e0193e012ff86ec5e7778bc2c6df30381077b3dee0858c9454f7d80ed32ef3
bundle/opt-incomex-POST-20260717T130000Z.bundle
22d550b1f3d1f248cb19a26b2f4290676ff102fed2c3b22a15273986ebc8aac3
→ cả 2: "The bundle records a complete history." PASS
backup/code-backup-to-gdrive.sh.PRE 20762cfb… (byte-exact)
backup/root-crontab.PRE 547e8151…
rollback/ROLLBACK.sh (0700, 0 external dep: không KB/MCP/GitHub/network)
§6.7 — checkpoint có bị chính job đang sửa upload không? KHÔNG:
code-backup → chỉ nuxt-repo + agent-data-repo ⇒ /root không thuộc
nightly → /opt/incomex/docker (maxdepth 2), nginx *.conf, /etc/letsencrypt,
/opt/incomex/scripts/* ⇒ /root không thuộc
/root/c0-checkpoint-* không nằm trong git root nào
✅ Tiện thể xác nhận containment của Wave A1 vẫn sống:
backup-to-gdrive.shL79 không còn-name ".env*".
9. MUTATION NHỎ NHẤT — đúng 1 dòng
@@ -189,6 +189,7 @@ backup_repo() (
stage="rsync-stage"
rsync -a \
+ --exclude='.git' \
--exclude='node_modules' \
--exclude='.git'basename-match ở mọi độ sâu ⇒ phủ cả 3 git root, gồm worktree pointer dạng FILE (§8.2 yêu cầu) — không cần pattern thứ hai.- Không loại source/worktree cần thiết. Không tắt job. Không đổi destination/retention/lịch.
bash -nOK · perms755 root:rootgiữ nguyên · diff--checkCLEAN.
10. POST SOURCE / INCLUDE / EXCLUDE
rsync -a --exclude=.git node_modules .nuxt .output __pycache__ .pytest_cache
.mypy_cache .cache coverage dist .venv ← 11 exclude (thêm đúng 1)
11. VERIFICATION — vì sao KHÔNG chạy manual backup
Script không có dry-run/list-only native. Và:
remote_count web-test = 56
remote_count agent-data-test = 56 REMOTE_KEEP = 56
🔴 Chạy 1 lần manual ⇒ 57 > 56 ⇒ cleanup_remote_retention XOÁ 1 artifact Drive cũ
mỗi repo ⇒ vi phạm §5 "không xóa backup Drive cũ". Vì vậy cố ý KHÔNG chạy manual backup.
Thay bằng phép đo mạnh hơn: parse exclude list từ chính file script LIVE đã vá (không hardcode ⇒ không lệch giữa thứ được test và thứ sẽ chạy), rồi chạy đúng rsync + tar đó vào thư mục tạm, không đụng Drive, không retention, không xoá.
exclude parsed từ script live: 11 giá trị, .git đứng đầu ✅
PRE members POST members .git worktree-ptr bundle/pack
web-test 7807 5529 0 0 0
agent-data-test 1149 675 0 0 0
size agent-data-test 40,996,558 B → 20,035,532 B
web-test 24,723,112 B → 13,937,297 B
Số học khớp tuyệt đối ⇒ chứng minh chỉ .git bị loại, không mất gì khác:
web-test 7807 − 2277 (.git, đã gồm worktree ptr) − 1 (BACKUP-MANIFEST.txt) = 5529 ✅
agent-data-test 1149 − 473 (.git) − 1 (BACKUP-MANIFEST.txt) = 675 ✅
(−1 manifest là hiện vật của harness đo: script thật ghi BACKUP-MANIFEST.txt vào
stage trước rsync; harness của tôi không ghi. Artifact thật sẽ có manifest.)
12. ARTIFACT CONTENT PROOF
| Yêu cầu §9 | Kết quả |
|---|---|
không chứa .git |
✅ 0 member |
không chứa .git worktree pointer |
✅ 0 |
| không chứa unsanitized Git bundle | ✅ 0 (*.bundle/*.pack = 0) |
| không chứa runtime env | ✅ docker/.env và /etc/incomex/agent-data.env không thuộc source set |
| không chứa plaintext secret-bearing scripts | 🔴 KHÔNG ĐẠT — 2 file worktree reconcile-*.py vẫn mang credential live (§1) |
| vẫn chứa source/worktree cần phục hồi | ✅ 5104 + 590 file source giữ nguyên |
| có manifest/listing đủ kiểm tra | ✅ BACKUP-MANIFEST.txt (branch + head_before ⇒ vẫn đối chiếu được history) |
| backup job vẫn thành công | ✅ bash -n OK; đường code không đổi ngoài 1 exclude; lần chạy thật kế: 20:00 ICT = 15:00 CEST hôm nay |
Không đọc/in secret payload để kiểm (chỉ đếm file khớp).
13. CODE/WORKTREE OFFSITE BACKUP = PASS
Drive : vẫn nhận code/worktree 4×/ngày (5529 + 675 member, source đầy đủ)
GitHub : cả 2 repo, 2×/ngày (git-push-gh-daily-v2.sh, 0 6,18 UTC)
14. C0-BIS — KHÔNG BUÔNG PHAO CŨ KHI CHƯA CÓ PHAO MỚI
Off-site history KHÔNG về 0. Đo thật ở cả 2 đầu:
VPS nuxt-repo HEAD 2ea41583422427b6b5e6d886fa7a754198e121b7
GH web-test vps-daily-20260717 2ea41583422427b6b5e6d886fa7a754198e121b7 ✅ TRÙNG KHỚP
VPS agent-data-repo HEAD 0ffd6778fc004d03620d68f89752ad5cb414d75b
GH agent-data-test vps-daily-20260717 0ffd6778fc004d03620d68f89752ad5cb414d75b ✅ TRÙNG KHỚP
+ GH giữ vps-daily-20260710…20260717 (8 nhánh, CLEANUP_DAYS=7) và main
+ 56 artifact Drive cũ/repo VẪN CÒN (~14 ngày) — mission này KHÔNG xoá
⇒ Phao mới có sẵn từ trước, nằm NGOÀI VPS, KHÔNG thuộc job Drive 4×/ngày đang sửa
⇒ điều kiện C0-BIS thoả ⇒ KHÔNG cần HOLD_OFFSITE_GAP_OWNER_DECISION.
⚠️ Nói thẳng để Owner không hiểu nhầm: "phao" GitHub này chứa history có secret và bản thân nó cũng là một đường phát tán đang chạy 2×/ngày (ngoài phạm vi C0). C0-BIS cho phép điều đó ("bản thay thế vẫn chứa history-có-secret cũng được"), nhưng đây không phải một kho lưu trữ an toàn — chỉ là bằng chứng rằng gỡ
.gitkhỏi Drive không làm mất bản off-site cuối cùng.
CLEAN_GIT_HISTORY_OFFSITE_BACKUP = TEMPORARILY_UNAVAILABLE_UNTIL_ROTATION_AND_HISTORY_SANITIZATION
(Mọi bản off-site history hiện có đều chưa sanitize. Bản sạch chỉ tạo được sau C2+C3.)
15. HISTORICAL DRIVE COPIES = REMAIN_UNCHANGED
web-test remote_count = 56 (PRE 56) ✅ không xoá
agent-data-test remote_count = 56 (PRE 56) ✅ không xoá
Drive Trash không đụng
16. GIT COMMIT & BUNDLE
commit 74459bdf223a117373a143cea8a82054fc27dcac
fix(backup): exclude active-secret git history from Drive propagation
1 file changed, 1 insertion(+) ← scripts/code-backup-to-gdrive.sh
staged list = đúng 1 file · full staged diff đã đọc · --check CLEAN
secret scan staged diff = 0 hit · unrelated 15 M + 88 ?? giữ nguyên
branch feat/s177-sprint1-round-a · HEAD 74459bd · remote KHÔNG CÓ ⇒ GIT_PUSH=NO
POST bundle 22d550b1… · git bundle verify PASS
17. ROLLBACK
ssh contabo '/root/c0-checkpoint-20260717T130000Z/rollback/ROLLBACK.sh'
Thủ công:
CK=/root/c0-checkpoint-20260717T130000Z
install -m 0755 -o root -g root "$CK/backup/code-backup-to-gdrive.sh.PRE" \
/opt/incomex/scripts/code-backup-to-gdrive.sh
sha256sum /opt/incomex/scripts/code-backup-to-gdrive.sh # phải == 20762cfb…
bash -n /opt/incomex/scripts/code-backup-to-gdrive.sh
Git: cd /opt/incomex && git revert 74459bd (hoặc git checkout cdf25ec -- scripts/code-backup-to-gdrive.sh).
⚠️ Rollback ⇒ .git chảy lại lên Drive ngay ở lần chạy 08/12/15/20 ICT kế tiếp.
18. CONTAINER ZERO-MUTATION PROOF
Mission bắt đầu ~13:01 CEST (11:01 UTC). Mọi StartedAt đều TRƯỚC mốc đó ⇒ không container nào bị đụng.
incomex-agent-api-executor 1d841832a6fe 2026-06-04T08:46:26Z
incomex-agent-data 09188c72f327 2026-07-17T09:45:44Z (== POST của A1 ✅)
incomex-claude-kb b1b40494fe7d 2026-07-16T03:25:22Z
incomex-claude-mcp c7039e296421 2026-07-12T00:45:39Z
incomex-directus 2245d86d2f6a 2026-05-08T09:13:06Z
incomex-nginx e50172b59a25 2026-06-30T00:44:14Z
incomex-nuxt 42079c55bf9c 2026-07-17T03:49:53Z
incomex-qdrant 2b5c328f0b4d 2026-03-18T07:03:47Z
pg-restore-test-20260520T031054Z 0cbc668c76f9 2026-05-20T03:10:55Z
postgres 22540b78de8f 2026-04-17T05:35:18Z
uptime-kuma 81d9f483b123 2026-04-08T09:18:38Z
11/11 running · agent-data RestartCount=0 · Health=healthy
balo bridge ActiveEnterTimestamp Fri 2026-07-17 01:32:28 CEST (== A1 ✅ không restart)
19. REMAINING ROTATION / HISTORY-CLEANUP BACKLOG
🔴 C0-FOLLOWUP Gỡ hardcode DIRECTUS_ADMIN_PASSWORD khỏi 2 file WORKTREE
agent-data-repo/scripts/reconcile-{knowledge,tasks}.py
→ chừng nào còn, secret vẫn lên Drive 4×/ngày + GitHub 2×/ngày
DÙ .git đã bị loại. Đây là việc gấp nhất còn lại. ← MỚI, do C0 phát hiện
C2 Rotate DIRECTUS_ADMIN_PASSWORD / ADMIN_TOKEN / PG / Qdrant / OpenAI
C3 Rewrite git history 2 file reconcile-*.py (nếu không, C2 không đóng được exposure)
⚠️ phải xử lý CẢ GitHub: 8 nhánh vps-daily-* + main đã mang history
A3 Owner quyết vector còn lại của nightly: TLS private key + PG dump + scripts/*
C4 Xoá 7 × .env.bak* + .env.mysql-backup
C5 rclone scope: drive → drive.file
C6 backup-to-gdrive.sh L31: Qdrant key vào argv mỗi đêm
— Cân nhắc rclone crypt cho code-backup (hiện tar.gz trần)
20. EVIDENCE PATHS
CHECKPOINT /root/c0-checkpoint-20260717T130000Z (root:root 0700)
backup/ code-backup-to-gdrive.sh.PRE · root-crontab.PRE · backup.sha256
bundle/ PRE · POST (+ bundles.sha256) — cả 2 verify PASS
evidence/ containers.POST
rollback/ ROLLBACK.sh (0700)
COMMIT 74459bd
LỆNH ĐO crontab -l · cat/sed script · git rev-parse/status/ls-files/log/bundle verify
· git worktree list · tar -tzf (list-only) · rclone lsf (read-only)
· gh api .../git/matching-refs (GET only, từ laptop)
· docker inspect --format (không đọc Env) · systemctl show
21. SECRET HYGIENE PROOF
✅ Không echo/print giá trị secret · không đưa vào argv (dùng tmpfs 0600 + grep -Ff <file>)
✅ Pattern tmpfs đã shred · /dev/shm CLEAN
✅ KHÔNG giữ bản sao secret mới: đã shred rclone.conf.PRE (chứa OAuth token, và không
cần vì mission không sửa rclone config); đã xoá thư mục stage tạm chứa 2 file
reconcile-*.py plaintext. Xác nhận: 0 file c0-verify-* còn lại.
✅ Không đọc payload Secret Manager · không đọc /proc/*/environ
✅ Report/KB/commit: 0 password/token/key
22. PROOF OF SCOPE
CONTAINER_MUTATION=NO
SERVICE_RESTART=NO
SECRET_VALUE_CHANGE=NO
SECRET_ROTATION=NO
SECRET_REVOKE=NO
HISTORICAL_BACKUP_DELETE=NO
GIT_HISTORY_REWRITE=NO
GIT_PUSH=NO
DB_WRITE=NO
DOCKER_CLEANUP=NO
Mutation đã thực hiện, đúng 1:
scripts/code-backup-to-gdrive.sh +1 dòng (--exclude='.git') commit 74459bd
23. FACTS NEXT AGENT MAY RELY ON
✅ code-backup-to-gdrive.sh POST sha256 = b47c5e36995582939ef55e261543747f3e4e8022893b20b81ac869e269d3ee27
✅ .git KHÔNG còn vào artifact Drive: web-test 7807→5529 · agent-data-test 1149→675
🔴 NHƯNG secret VẪN lên Drive 4×/ngày qua 2 file worktree reconcile-*.py — C0 KHÔNG đóng được
✅ .git file của worktree (nuxt-repo/web-rp-current/.git) được phủ bởi cùng 1 exclude basename
✅ remote_count = 56 == REMOTE_KEEP=56 ⇒ CHẠY MANUAL BACKUP SẼ XOÁ 1 artifact Drive cũ mỗi repo
✅ Off-site history KHÔNG về 0: GitHub vps-daily-20260717 khớp CHÍNH XÁC HEAD cả 2 repo
✅ git-push-gh-daily-v2.sh chạy `git add -A` + commit + force-push 2×/ngày (0 6,18 UTC)
✅ agent-data-repo/.env.working chứa Qdrant key CŨ (A1 §14) — không phải key live
✅ Wave A1 containment còn sống: backup-to-gdrive.sh L79 không còn -name ".env*"
✅ /opt/incomex vẫn KHÔNG remote; HEAD 74459bd; unrelated 15 M + 88 ?? nguyên vẹn
24. ASSUMPTIONS NEXT AGENT MUST NOT MAKE
❌ ĐỪNG đọc verdict "GIT_HISTORY_PROPAGATION_STOPPED" thành "secret hết rời VPS" — SAI
❌ ĐỪNG chạy code-backup-to-gdrive.sh thủ công để "kiểm tra" — retention sẽ XOÁ artifact Drive cũ
❌ ĐỪNG đo secret bằng regex theo TÊN BIẾN — probe theo tên cho 0 hit dù giá trị CÓ ở đó;
phải đo theo GIÁ TRỊ, và đưa qua file tmpfs + `grep -Ff` (không bao giờ qua argv)
❌ ĐỪNG coi GitHub là nơi off-site an toàn — nó mang history có secret và tự phát tán 2×/ngày
❌ ĐỪNG rewrite history mà quên GitHub: 8 nhánh vps-daily-* + main đã có sẵn giá trị
❌ ĐỪNG loại reconcile-*.py khỏi backup như "cách nhanh" — là source thật, cần cho restore;
cách đúng là gỡ hardcode + rotate (cần Owner)
❌ ĐỪNG chạy `git bundle verify` từ ngoài repo — báo "need a repository", không phải bundle hỏng
DỪNG sau báo cáo. Không tự chạy Mission A2.