Claude — Khảo sát hậu di chuyển: Service / Secret / Control-plane Reconciliation (2026-07-17)
Khảo sát hậu di chuyển — Service / Secret / Control-plane Reconciliation (2026-07-17)
Mission: forensic READ-ONLY. Không sửa, không xoay secret, không cleanup, không deploy. Tác giả: Claude (Opus 4.8). Host:
vmi3080463/38.242.240.89(Contabo). Mọi giá trị secret trong báo cáo này =REDACTED. Không ghi password/token/key/hash-xác-thực.
1. EXECUTIVE VERDICT
READY_AFTER_OWNER_NORMATIVE_DECISION
Khảo sát đủ để mission sau xử lý theo từng service mà không phải đoán. Không HOLD, vì không còn critical unknown nào buộc phải đoán khi mutation: mọi service đều xác định được source/config, credential consumer và data-volume owner; cả 5 GitHub workflow có khả năng ghi VPS đều đang disabled_manually; đích và quyền của backup Drive đã xác định.
Nhưng cần Owner quyết trước Wave A vì 3 việc vượt thẩm quyền agent:
normative_registrythiếu entry cho nút Balo đang LIVE — 47 rows, 0 row nhắcbalo/one-click/reconcile(đo thật). Canonical rev17 §16 đã bãi bỏ phần cấm của §15, nhưng registry chưa phản ánh. Đã soạn sẵn proposed entry ở §9 — CHƯA ghi.- Backup Drive =
ACTIVE_SECRET_EXFILTRATION_PATH— secret rời VPS 4 lần/ngày (Drive) + 2 lần/ngày (GitHub force-push). Đây là chính sách, Owner phải quyết. - GCP giữ 11 SA key không hạn dùng, 3 SA có
roles/owner— quyết định thu hồi là của Owner.
2 đính chính bắt buộc với KB/memory + 1 mục KB ĐÚNG (tôi từng đính chính nhầm)
⚠️ Tự bác bỏ: rev1 của báo cáo này ghi "rò rỉ chỉ 5 file, KB sai" — chính tôi sai, KB đúng. Đã đo lại và sửa ở §6.1. Giữ lại dòng này để mission sau không tin nhầm rev1.
| # | KB/memory đang ghi | Sự thật đo được | Bằng chứng |
|---|---|---|---|
| 1 | workflow 244569412 KHÔNG tồn tại; "chỉ MỘT workflow nguy hiểm" |
TỒN TẠI — Vector Audit & Cleanup trong repo agent-data-test (không phải web-test, nên tra nhầm repo → 404). Và có 5 workflow ghi được VPS, không phải 1 |
gh api repos/Huyen1974/agent-data-test/actions/workflows/244569412 → 200 |
| 2 | rò rỉ secret 34 file | ✅ KB VỀ CƠ BẢN ĐÚNG — đây KHÔNG phải đính chính. Đo lại chuẩn (grep -rlF <value> cả 2 cây): DIRECTUS_ADMIN_PASSWORD = 19 file (13 /opt/incomex + 6 /root); DIRECTUS_ADMIN_TOKEN = 34 file (30 + 4); UNION = 46 file. Con số "34" của KB khớp đúng số file chứa TOKEN. Phần "2 file trong git HEAD" = ĐÚNG. (Bản rev1 của chính báo cáo này từng ghi sai "5 file" — do subagent grep hẹp phạm vi; đã tự bác bỏ và đo lại.) |
grep -rlF cả /opt/incomex + /root |
| 3 | Host 16 GB / 8 CPU | 11 GiB RAM / 6 vCPU (AMD EPYC) | free -h, nproc, lscpu |
Phát hiện mới nghiêm trọng nhất (chưa từng có trong KB)
docker compose up -d agent-datasẽ chạy image SAI 4 tháng tuổi, im lặng, không báo lỗi.AGENT_DATA_IMAGEkhông được set ở bất kỳ đâu (.env: 0 hit; không cóenv_file; shell env: 0) → compose dùng fallbackasia-southeast1-docker.pkg.dev/.../agent-data-test:latest. Image đó tồn tại trong cache local (9421cd9c4303, 4 tháng tuổi) → không pull, không fail, chỉ chạy sai. Cộng thêm mất 10 biến PG và tụt RAM 2560→1536 MiB. Đây là mìn nguy hiểm hơn mọi thứ KB đang theo dõi.
2. HOST MEASURED FACTS (FACT — đo, không nhận từ Owner)
Kernel Linux 6.8.0-90-generic Ubuntu, x86_64
Uptime 154 ngày (từ ~2026-02-13)
CPU 6 vCPU AMD EPYC (1 socket × 6 core × 1 thread) ← KHÔNG phải 8
RAM 11 GiB total | 4.5 GiB used | 3.5 GiB free | 4.2 GiB buff/cache | 7.2 GiB available
Swap 2.0 GiB total | 652 MiB used
Disk / 96 G | 84 G used | 12 G avail | 88% /dev/sda1
Inode / 12.976M | 1.063M used | 9% (không phải bottleneck)
Docker Server 29.2.1 — Storage Driver: overlayfs (io.containerd.snapshotter.v1)
PSI mem some avg300=0.00 full avg300=0.00 (không có memory pressure hiện tại)
PSI cpu some avg300=0.90
PSI io some avg300=0.66 full avg300=0.59 (io pressure đáng kể, không nguy cấp)
Tổng mem_limit khai báo runtime = 2 (pg) + 1 (qdrant) + 1 (directus) + 2.5 (agent-data) + 0.5 (nuxt) + 0.25 (nginx) + 0.25 (claude-mcp) + 0.25 (claude-kb) + 0.5 (executor) = 8.25 GiB / 11 GiB; uptime-kuma và pg-restore-test không giới hạn.
Bằng chứng áp lực (FACT): postgres có State.OOMKilled = true với RestartCount = 0 → một backend process trong cgroup đã bị OOM-kill mà main process không chết. Đây là bằng chứng thật cho việc mem_limit 2g của postgres đã từng chạm trần. Chưa đủ để đề xuất sizing lại (chưa đo tải đủ dài) — theo đúng §5.3.
⚠️ Storage driver quirk (FACT): vì dùng containerd snapshotter,
GraphDriver.Data.UpperDir = null→ không đọc được upperdir từ host. Con sốdocker ps -sbên dưới là số Docker báo, chưa đối chiếu được bằngdu. Mission sau muốn xác minh phải dùngnerdctl/ctrhoặcdocker exec du(exec = spawn process, cân nhắc read-only policy).
3. MASTER SERVICE RECONCILIATION MATRIX
13 dòng = 11 container + 2 host component. Cột theo §5 + cột GIT / VPS-SSOT STATUS bổ sung.
| # | SERVICE / COMPONENT | CURRENT ROLE | ERA | RUNTIME SoT | DECLARED SOURCE | REPRODUCIBILITY | RUNTIME–DECL DRIFT | RESOURCE CONTRACT | SECRET CONSUMERS | MUTATION SURFACES | CANONICAL/NORMATIVE | IMAGE/STORAGE | GIT / VPS-SSOT | BACKUP | RISK | NEXT ACTION |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | incomex-agent-data | Knowledge API (FastAPI) | MIXED | docker inspect |
docker/docker-compose.yml svc agent-data |
DRIFT_BLOCKS_SAFE_RECREATE | 3 drift: (a) image agent-data-local:latest vs fallback AR agent-data-test:latest; (b) 10 biến PG_/DIRECTUS_DB_ có ở runtime, compose KHÔNG khai; (c) mem 2560 MiB vs compose 1536m |
run 2560 MiB / decl 1536m / .env AGENT_DATA_MEM_LIMIT=2560m không được compose tham chiếu |
API_KEY,OPENAI_API_KEY,QDRANT_API_KEY,DIRECTUS_ADMIN_TOKEN,PG_PASSWORD,DIRECTUS_DB_PASSWORD,GOOGLE_APPLICATION_CREDENTIALS(file) |
compose; deploy-vps.yml(233947089, disabled); s109-pg-setup.yml(244536611, disabled); vector-audit.yml(244569412, disabled) |
DRIFT | agent-data-local:latest 1.51 GB; bind credentials/google-credentials.json:ro; không volume |
compose TRACKED_CLEAN; .env GITIGNORED → OUTSIDE_GIT_BACKUP_REQUIRED |
code: có (repo); runtime env: KHÔNG | 🔴 CRITICAL | Wave B — vá compose (10 env + mem ref + image pin) TRƯỚC mọi recreate |
| 2 | incomex-agent-api-executor | DOT API executor | GITHUB→VPS | docker inspect |
❌ KHÔNG có trong compose hiện tại (0 hit) nhưng container mang label compose project=docker, service=agent-api-executor |
NOT_COMPOSE_MANAGED (orphan có nhãn) | Toàn phần — service đã bị xoá khỏi compose ở 4ecb614; container vẫn chạy từ 2026-06-04 |
run 512 MiB / không khai báo | OPENAI_API_KEY |
ROLLBACK-executor-docker-run.sh (UNTRACKED_LIVE); docker run tay |
MISSING_COVERAGE | agent-api-executor-local:v1 180 MB; no mount |
UNTRACKED_LIVE_CONFIG (script rollback ngoài Git) | ❌ không | 🔴 CRITICAL — docker compose up -d --remove-orphans XOÁ container này |
Wave A — quyết: đưa lại vào compose hay commit script + cấm --remove-orphans |
| 3 | incomex-nginx | Reverse proxy | VPS_SSOT | docker inspect |
compose svc nginx |
DRIFT_BLOCKS_SAFE_RECREATE | (a) mount thứ 5 docs/mcp-writes/ui-preview → /usr/share/nginx/mcp-writes:ro KHÔNG có trong compose; (b) attach thêm claude_mcp_net |
run 256 MiB = decl 256m ✅ | nginx/secrets (bind ro); /etc/letsencrypt |
compose; deploy-vps.yml 233946923 (disabled) ghi đè conf.d/default.conf + nginx -s reload |
DRIFT | nginx:alpine; 4 bind decl + 1 bind undecl |
conf.d/default.conf TRACKED_CLEAN sha bd38d294… |
code có | 🔴 HIGH — recreate ⇒ /ui-preview/ 404 câm | Wave B — thêm mount + network vào compose |
| 4 | postgres | DB chính (directus/workflow/metadata) | GCP→VPS | docker inspect |
compose svc postgres |
PARTIAL_PARITY | (a) runtime POSTGRES_DB/USER = workflow/workflow_admin (từ .env), compose khai ${PG_DATABASE:-directus}/${PG_USER:-directus} mà PG_DATABASE/PG_USER không tồn tại trong .env → recreate đổi sang directus/directus (vô hại vì PGDATA đã init, initdb bị bỏ qua); (b) attach thêm claude_mcp_net |
run 2 GiB = decl 2g ✅ · OOMKilled=true |
POSTGRES_PASSWORD,PG_PASSWORD |
compose; ~20 cron docker exec postgres psql (WRITE thật); deploy-vps.yml SQL migrations |
DRIFT (network) | postgres:16; bind /opt/workflow/postgres/{data,backups,init}; writable layer 4.54 GB (chưa xác minh) |
bind ngoài Git → OUTSIDE_GIT_BACKUP_REQUIRED | pg-backup.sh 02:27 + nightly Drive |
🟠 MED | Wave B — pin POSTGRES_DB/USER, thêm network |
| 5 | incomex-directus | Headless CMS | GCP→VPS | docker inspect |
compose svc directus |
PARTIAL_PARITY | attach thêm claude_mcp_net (alias directus) — compose chỉ khai incomex |
run 1 GiB = decl 1g ✅ | ADMIN_PASSWORD,ADMIN_EMAIL,KEY,SECRET,DB_PASSWORD,AGENT_DATA_API_KEY |
compose; Directus admin UI; Flows | DRIFT (network) | directus/directus:11.5; bind uploads,extensions; writable layer 2.64 GB (chưa xác minh) |
bind ngoài Git → OUTSIDE_GIT_BACKUP_REQUIRED | uploads: nightly Drive | 🟠 MED | Wave B — thêm claude_mcp_net vào compose |
| 6 | incomex-nuxt | Frontend SSR + Balo button | MIXED | docker inspect |
compose svc nuxt |
CONFIG_PARITY_PASS_RECREATE_NOT_TESTED | Không drift — 17/17 env khớp; group_add 987 khớp; 2 mount khớp; image = đúng fallback |
run 512 MiB = decl 512m ✅ | NUXT_DIRECTUS_SERVICE_TOKEN,NUXT_AGENT_DATA_API_KEY,RP_PG_PASSWORD |
compose; deploy-vps.yml 233946923 (disabled); bind deploys/nuxt-output |
DRIFT — nút LIVE nhưng normative_registry 0 entry | image AR-tag nuxt-ssr:latest 72715a92 246 MB (4 tháng — chỉ là base; code thật ở bind .output) |
compose TRACKED_CLEAN | code có; .output là artifact rebuild được |
🟡 LOW-MED | Wave A — an toàn nhất để reconcile độc lập |
| 7 | incomex-qdrant | Vector DB | GCP→VPS | docker inspect |
compose svc qdrant |
CONFIG_PARITY_PASS_RECREATE_NOT_TESTED | Không drift | run 1 GiB = decl 1g ✅ · user 0:0 (root) |
QDRANT__SERVICE__API_KEY |
compose; vector-audit.yml 244569412 (disabled, auto_heal xoá vector) |
ALIGNED | qdrant/qdrant:latest; bind qdrant/data; writable layer 14.6 GB — lớn nhất, chưa xác minh |
bind ngoài Git → OUTSIDE_GIT_BACKUP_REQUIRED | qdrant-backup.sh 03:00 UTC |
🟠 MED — :latest không pin |
Wave B — xác minh 14.6 GB trước recreate |
| 8 | incomex-claude-mcp | MCP server (Claude) | VPS_SSOT | docker inspect |
claude-mcp/docker-compose.claude-mcp.yml |
CONFIG_PARITY_PASS_RECREATE_NOT_TESTED | Không drift | run 256 MiB / 0.5 CPU = decl ✅ | PG_USER_RO,PG_PASSWORD_RO,MCP_UPSTREAM_KEY,DIRECTUS_TOKEN |
compose | ALIGNED | claude-mcp-local:phase1a; mount /var/run/docker.sock |
compose TRACKED (repo con) | code có | 🟠 MED-HIGH — :ro trên unix socket KHÔNG chặn Docker API write ⇒ có toàn quyền Docker |
Wave A — ghi nhận capability; cân nhắc socket-proxy |
| 9 | incomex-claude-kb | KB proxy | VPS_SSOT | docker inspect |
claude-kb/docker-compose.claude-kb.yml |
CONFIG_PARITY_PASS_RECREATE_NOT_TESTED | Không drift | run 256 MiB / 0.5 CPU = decl ✅ | AGENT_DATA_API_KEY |
compose | ALIGNED | claude-kb-local:v1 210 MB |
compose TRACKED | code có | 🟢 LOW | Wave A |
| 10 | uptime-kuma | Monitoring | VPS_SSOT | docker inspect |
❌ không compose, không label | NOT_COMPOSE_MANAGED | Toàn phần | không mem_limit | .uptime-kuma-admin-pass (plaintext file) |
docker run tay |
MISSING_COVERAGE | louislam/uptime-kuma:2; bind /opt/incomex/uptime-kuma; volume uptime-kuma-data 1.12 MB mồ côi (đã chuyển sang bind) |
ngoài Git | ⚠️ chưa xác minh | 🟡 LOW | Wave D — khai báo compose |
| 11 | pg-restore-test-20260520T031054Z | ❌ Rác drill còn chạy 8 tuần | VPS_SSOT | docker inspect |
❌ không | NOT_COMPOSE_MANAGED | Toàn phần · restart=no |
không mem_limit | POSTGRES_PASSWORD |
thủ công | MISSING_COVERAGE | postgres:16; volume 46dbcc89… 788 MB — volume DUY NHẤT còn active |
ngoài Git | n/a (chính nó là artifact drill) | 🟠 MED — chiếm RAM/disk, giữ secret | Wave D — Owner xác nhận rồi mới xoá |
| 12 | incomex-balo-reconcile (.socket+.service) |
Bridge Balo one-click | VPS_SSOT | systemctl cat |
/etc/systemd/system/ |
CONFIG_PARITY_PASS_RECREATE_NOT_TESTED | Không drift · active+enabled |
n/a | (không env secret) | dot-balo-reconcile --sync |
DRIFT — LIVE, Owner-accepted, canonical §16 OK, registry 0 entry | ExecStart=/opt/incomex/dot/bin/dot-balo-reconcile-bridge; socket 0660 root:incomex-balo-sync (gid 987) |
unit ngoài Git → OUTSIDE_GIT_BACKUP_REQUIRED | ⚠️ unit chưa backup | 🟡 LOW (hardened: ProtectSystem=strict, RestrictAddressFamilies=AF_UNIX, NoNewPrivileges) |
Wave A — Owner duyệt proposed entry §9 |
| 13 | lark-mcp-remote.service | Lark MCP remote | VPS_SSOT | systemctl |
/etc/systemd/system/ |
UNKNOWN | chưa đối chiếu | n/a | S177_LARK_MCP_REMOTE_TOKEN (secret DUY NHẤT từng xoay, v2 2026-05-23) |
systemd | UNKNOWN | n/a | ngoài Git | ⚠️ | 🟡 LOW | Wave E |
3.1. Chi tiết drift agent-data (bằng chứng)
RUNTIME mem_limit = 2684354560 B = 2560 MiB
COMPOSE mem_limit: 1536m (hardcode, KHÔNG dùng ${AGENT_DATA_MEM_LIMIT})
.env AGENT_DATA_MEM_LIMIT=2560m ← khớp CHÍNH XÁC runtime ⇒ đây là nguồn gốc drift
RUNTIME env có 10 biến compose KHÔNG khai:
PG_HOST PG_PORT PG_USER PG_DATABASE PG_PASSWORD
DIRECTUS_DB_HOST DIRECTUS_DB_PORT DIRECTUS_DB_USER DIRECTUS_DB_DATABASE DIRECTUS_DB_PASSWORD
→ giả thuyết §5.2 của mission: XÁC NHẬN ĐÚNG, đúng 10 biến.
→ .env chỉ có PG_PASSWORD; 9 biến còn lại KHÔNG có nguồn khai báo nào
⇒ container được khởi tạo NGOÀI compose hiện hành (StartedAt 2026-05-19, compose sửa 2026-07-17).
IMAGE runtime agent-data-local:latest (9acd60503290, 8 tuần)
compose ${AGENT_DATA_IMAGE:-asia-…/agent-data-test:latest}
AGENT_DATA_IMAGE: .env=0 hit · env_file=none · shell env=0 ⇒ FALLBACK ÁP DỤNG
fallback image TỒN TẠI local (9421cd9c4303, 4 tháng) ⇒ KHÔNG pull, KHÔNG fail, CHẠY SAI IM LẶNG
Hệ quả (INFERENCE, độ tin cậy cao): docker compose up -d agent-data hôm nay ⇒ image sai 4 tháng + mất 10 biến DB + RAM 1536m. Service gần như chắc chắn mất kết nối DB. Đây là blocker thật của việc xoay secret PG/Directus.
4. UNASSIGNED STORAGE INVENTORY
docker system df: Images 36 (10 active) 39.66 GB, reclaimable 32.67 GB (82%) · Containers 11 → 21.87 GB · Volumes 9 (1 active) 10.37 GB, reclaimable 9.58 GB (92%) · Build cache 79 → 6.697 GB, reclaimable 100%.
du: /var/lib/containerd 37 G ← lớn nhất hệ thống (containerd snapshotter)
/var/lib/docker 11 G (volumes 9.7G · containers 542M · buildkit 191M)
/opt/incomex 17 G (backups 12G · deploys 937M · context-pack.tmp 739M · lark-backups 1.2G)
/opt/workflow 3.4 G (PGDATA)
/root/backups 1.9 G
/var/log 1.2 G (journal 1016.7 M)
| RESOURCE | TYPE | SIZE | CREATED | KNOWN CONSUMER | PROTECTION | RECLAIM? | CONF | EVIDENCE |
|---|---|---|---|---|---|---|---|---|
46dbcc89… |
volume | 788 MB | 2026-05-20 | pg-restore-test (ĐANG CHẠY) | ACTIVE (drill) | ❌ không, khi container còn sống | HIGH | docker volume inspect |
pg-dry-run-hb05-2026-05-15-data |
volume | 1.29 GB | 2026-05-15 | none | STALE_CANDIDATE | ✅ có | HIGH | volume ls -qf dangling |
pg-dry-run-v0.2-phase-alpha-2026-05-16-data |
volume | 1.344 GB | 2026-05-16 | none | STALE_CANDIDATE | ✅ có | HIGH | idem |
pg-dry-run-v0.2-p0-2-2026-05-16-data |
volume | 1.344 GB | 2026-05-16 | none | STALE_CANDIDATE | ✅ có | HIGH | idem |
32b405542e7d… |
volume | 1.389 GB | 2026-05-17 | none (anonymous) | ORPHAN_CANDIDATE | ✅ có | MED | idem |
5838dcf66252… |
volume | 1.394 GB | 2026-05-17 | none | ORPHAN_CANDIDATE | ✅ có | MED | idem |
d2e14fa9f623… |
volume | 1.394 GB | 2026-05-17 | none | ORPHAN_CANDIDATE | ✅ có | MED | idem |
886272a48d3e… |
volume | 1.425 GB | 2026-05-17 | none | ORPHAN_CANDIDATE | ✅ có | MED | idem |
uptime-kuma-data |
volume | 1.12 MB | 2026-02-16 | none — uptime-kuma đã chuyển sang bind /opt/incomex/uptime-kuma |
STALE_CANDIDATE | ⚠️ đọc trước khi xoá (có thể là data cũ) | MED | docker inspect uptime-kuma |
asia-…/agent-data/agent-data-test:latest |
image | 1.51 GB | 4 tháng | KHÔNG container nào — nhưng là fallback của compose | 🔴 BẪY — xoá thì compose up fail; giữ thì compose up chạy sai | ⚠️ chỉ sau khi pin AGENT_DATA_IMAGE |
HIGH | docker images + .env grep |
asia-…/web-test/nuxt-ssr:latest |
image | 246 MB | 4 tháng | incomex-nuxt (ĐANG CHẠY) | 🔴 ROLLBACK_PROTECTED — AR API DISABLED, mất là KHÔNG pull lại được | ❌ tuyệt đối không | HIGH | gcloud artifacts → SERVICE_DISABLED |
6 × agent-data-local:* (pre-b1, pre-c1, s178-cutllm ×2, pre-s178) |
image | ~7.5 GB | 2–3 tháng | none | ROLLBACK_PROTECTED (theo tên) | ⚠️ Owner quyết | MED | docker images |
8 × nuxt-ssr-local:* + nuxt-p10d-* |
image | ~2 GB | 2–4 tháng | none | ROLLBACK_PROTECTED (theo tên) | ⚠️ Owner quyết | MED | idem |
mysql:8.0 |
image | 1.08 GB | 5 tháng | none — MySQL retired 2026-03-13 | STALE_CANDIDATE | ✅ có | HIGH | compose comment L9 |
docker-agent-data:latest, docker-nuxt:latest |
image | 1.76 GB | 5 tháng | none | ORPHAN (compose cũ) | ✅ có | MED | idem |
hello-world, busybox, alpine/curl, curlimages/curl, python:3.11/3.12-slim, node:20-alpine |
image | ~625 MB | 2–21 tháng | none | STALE_CANDIDATE | ✅ có | HIGH | idem |
| Build cache | cache | 6.697 GB | — | none (79 entry, Private 0 B) | REBUILDABLE_ARTIFACT | ✅ an toàn nhất | HIGH | docker builder du |
directus_gov_test_20260602 |
PG database | 1202 MB | 2026-06-02 | none rõ ràng | STALE_CANDIDATE | ⚠️ Owner xác nhận | MED | pg_database_size |
/opt/incomex/docker/*.bak* (8 .env.bak + 13 compose bak) |
file | ~60 KB | 2–5 tháng | none | 🔴 .env.bak* = bản sao secret cũ |
⚠️ xoá có kiểm soát | HIGH | ls -la |
/opt/incomex/docker/nginx/conf.d/*.bak* (22 file) |
file | nhỏ | 2–5 tháng | KHÔNG được nginx nạp (không đuôi .conf) |
STALE_CANDIDATE | ✅ có | HIGH | ls conf.d/ |
/opt/incomex/docker/directus-dump.sql |
file | 33.7 MB | 2026-02-12 | none | 🔴 DB dump cũ, có thể chứa data nhạy cảm | ⚠️ Owner | HIGH | ls -la |
/opt/incomex/context-pack.tmp |
dir | 739 MB | đang ghi (09:00 hôm nay) | /etc/cron.d/incomex-context-pack-retention |
ACTIVE | ❌ | MED | ls -la |
/var/lib/containerd |
dir | 37 GB | — | Docker snapshotter | ACTIVE_SHARED | ⚠️ chỉ giảm gián tiếp qua rmi |
HIGH | du -xsh |
Tổng reclaimable an toàn ≈ 49 GB (images 32.67 + volumes 9.58 + build cache 6.70) trên đĩa 88%. Không prune tổng — mission sau phải
rmi/volume rmtừng ID có bằng chứng, và phải pinAGENT_DATA_IMAGETRƯỚC khi đụng tới image AR.
5. SECRET ROTATION DEPENDENCY GRAPH
5.1. Nguồn credential — sự thật khác canonical
| Nguồn | Vai trò thật (FACT) |
|---|---|
Google Secret Manager (github-chatgpt-ggcloud) |
32 secret. KHÔNG service nào trên VPS đọc trực tiếp. Không có SM client trong container nào; không có agent sync. ⇒ SM hiện là kho lưu trữ ngoại tuyến, không phải nguồn injection. |
/opt/incomex/docker/.env (-rw------- root, gitignored, 30 biến) |
Nguồn injection THẬT của toàn stack. |
claude-mcp/.env, claude-kb/.env |
gitignored; injection cho 2 MCP. |
/opt/incomex/scripts/cron-env.sh |
injection cho ~8 cron job DOT. |
credentials/google-credentials.json |
GCP SA key dạng file, bind vào agent-data :ro. |
/opt/incomex/.git-token (41 B, 600) |
GitHub PAT plaintext — dùng bởi git-push-gh-daily-v2.sh. |
🔴 Drift nền tảng: canonical tuyên bố "Secret Manager là SSOT của credential", nhưng runtime không hề đọc SM. SM và
.envcó thể đã lệch từ 2026-05-22 mà không ai biết — 31/32 secret chưa từng xoay kể từ lúc tạo. Xoay trong SM không có tác dụng gì lên production. Đây là drift nghiêm trọng nhất về mặt normative.
5.2. Đồ thị (node + edge)
[A] DIRECTUS_ADMIN_PASSWORD ── SM: (không có secret cùng tên) · .env: CÓ · SM version: n/a
consumers: incomex-directus(ADMIN_PASSWORD) · cron dot-dot-health · dot-collection-health
· dot-dot-coverage · dot-apr-execute(*/5 phút!) · reconcile-{knowledge,tasks}.py
plaintext copies: 19 file (13 /opt/incomex + 6 /root) — gồm 7 .env.bak* cũ
+ 2 TRACKED&IN_HEAD ở agent-data-repo (chỉ 2 file này vào tar backup)
backup exposure: 🔴 Drive 4×/ngày + GitHub force-push 2×/ngày + nightly full
rotation precondition: KHÔNG có — .env sửa được, Directus đọc lúc bootstrap
service action: recreate incomex-directus (ADMIN_PASSWORD chỉ áp lúc bootstrap)
post-rotation cleanup: 🔴 REWRITE GIT HISTORY (giá trị nằm trong .git objects)
[B] DIRECTUS_ADMIN_TOKEN ── SM v1 (2026-05-22) · .env: CÓ
consumers: incomex-agent-data(DIRECTUS_ADMIN_TOKEN) · incomex-nuxt(NUXT_DIRECTUS_SERVICE_TOKEN)
· claude-mcp(DIRECTUS_TOKEN) · cron dot-orphan-scanner
⇒ 🔴 EDGE: [B] chia sẻ consumer với agent-data ⇒ **xoay [B] ĐÒI HỎI recreate agent-data**
⇒ BỊ CHẶN bởi drift #1 (image sai + mất 10 env)
[C] DB_PASSWORD / PG_PASSWORD / POSTGRES_PASSWORD ── SM: PG_PASSWORD v1, POSTGRES_PASSWORD v1
consumers: postgres · directus(DB_PASSWORD) · agent-data(PG_PASSWORD + DIRECTUS_DB_PASSWORD)
· nuxt(RP_PG_PASSWORD) · claude-mcp(PG_PASSWORD_RO — role RIÊNG)
⇒ 🔴 EDGE: đụng 4 service ⇒ **agent-data phải reconcile TRƯỚC**
[D] OPENAI_API_KEY ── SM v1 · .env: CÓ
consumers: agent-data · agent-api-executor(qua ROLLBACK script grep .env lúc chạy)
⇒ EDGE: xoay [D] cần recreate CẢ agent-data (drift) LẪN executor (orphan)
[E] QDRANT_LOCAL_API_KEY ── SM v1 · consumers: qdrant + agent-data
⇒ EDGE: qdrant parity PASS nhưng agent-data drift ⇒ vẫn bị chặn
[F] AGENT_DATA_API_KEY ── SM v1 · consumers: agent-data · directus(Flows) · nuxt · claude-kb
⇒ EDGE: 4 consumer, agent-data là nút thắt
[G] gh_pat_sync_secrets + /opt/incomex/.git-token ── SM v1 · scope repo+workflow
⇒ 🔴 EDGE: token này **ĐỦ QUYỀN BẬT LẠI 5 workflow deploy đang disabled**
[H] vps_contabo_id / vps_contabo_secret ── SM v1 · granted → chatgpt-deployer@
⇒ 🔴 control plane hạ tầng VPS (rebuild/rescue), độc lập mọi service
[I] VPS_SSH_KEY (GitHub secret, KHÔNG ở SM) ── consumers: 5 workflow deploy (disabled)
+ Health Check 227044705 (ACTIVE, KHÔNG dùng!)
⇒ 🔴 xoay được ĐỘC LẬP mọi service — và nên xoay sớm
[J] S177_LARK_MCP_REMOTE_TOKEN ── SM **v2** (2026-05-23, v1 destroyed) — secret DUY NHẤT từng xoay
consumers: lark-mcp-remote.service ⇒ độc lập
5.3. Thứ tự xoay bắt buộc (từ đồ thị, KHÔNG mặc định agent-data trước Directus)
Xoay ĐỘC LẬP ngay, không chờ ai: [I] VPS_SSH_KEY · [G] GitHub PAT · [H] Contabo API · [J] Lark
BỊ CHẶN bởi agent-data drift: [B] [C] [D] [E] [F]
Cần rewrite Git history sau xoay: [A] ← xoay không đủ; giá trị vẫn nằm trong .git
Đính chính đồ thị: [A]
DIRECTUS_ADMIN_PASSWORDvà [B]DIRECTUS_ADMIN_TOKENlà hai credential KHÁC LOẠI (password đăng nhập vs static token), không được gom dù cùng chứa chữ "Directus". [A] không có consumer là agent-data; [B] có. ⇒ [A] xoay được mà KHÔNG cần đụng agent-data — đây là lý do Wave A đặt [A] trước [B].
6. GOOGLE DRIVE SECRET-BACKUP VECTOR
VERDICT: ACTIVE_SECRET_EXFILTRATION_PATH
("Exfiltration" = secret rời VPS sang kho khác. Không hàm ý kẻ xấu đã truy cập.)
| Hạng mục | Sự thật (FACT) |
|---|---|
| Cơ chế | /opt/incomex/scripts/code-backup-to-gdrive.sh qua rclone |
| Lịch | CRON_TZ=Asia/Ho_Chi_Minh + 0 8,12,15,20 * * * = 4×/ngày — khớp lời Owner |
| Source | docker/nuxt-repo, docker/agent-data-repo — rsync -a, chỉ loại trừ build/cache (node_modules,.nuxt,.output,__pycache__,…) |
.git có trong tar? |
🔴 CÓ — 473 member .git/ |
| Secret trong tar? | 🔴 CÓ — scripts/reconcile-knowledge.py + scripts/reconcile-tasks.py (TRACKED + IN HEAD, commit 4acebbc 2026-04-05) |
| Mã hoá | 🔴 KHÔNG — tar.gz trần, không rclone crypt |
| Đích | gdrive-backup: type=drive · scope = drive (toàn quyền R/W TOÀN BỘ Drive) · OAuth user token của NGƯỜI, không phải service account |
| Danh tính tài khoản Drive | UNKNOWN — không xác định được nếu không chạm token |
| Retention | 56 bản remote (= 14 ngày) / 1 local · Drive Trash 13.9 GiB có thể còn bản cũ hơn |
| Artifact gần nhất | agent-data-test_20260717-1300_ICT.tar.gz 40,996,554 B, 2026-07-17T06:00:51Z — đã verify size |
| Vector thứ 2 | 🔴 git-push-gh-daily-v2.sh — force-push cùng repo lên GitHub 0 6,18 * * * = 2×/ngày |
| Vector thứ 3 (nặng hơn) | 🔴 backup-to-gdrive.sh (37 20 * * *) upload lên Drive root: PG dump đầy đủ + Qdrant snapshot + docker/.env (-name ".env*") + /etc/letsencrypt/live/ với cp -rL ⇒ TLS private key thật + toàn bộ /opt/incomex/scripts/*. Bản mới nhất vps-backup-20260716_203701.tar.gz 281,914,206 B |
Phân loại: SECRET_UNSAFE_BACKUP (+ DATA_BACKUP cho job nightly). Không phải CODE_BACKUP thuần.
6.1. 🔴 ĐO LẠI PHẠM VI RÒ RỈ — KB ĐÚNG, KHÔNG PHẢI 5 FILE
Bản rev1 của báo cáo này ghi "5 file" là SAI (subagent grep hẹp phạm vi, chỉ quét source của job backup). Đo lại đầy đủ cả /opt/incomex và /root, grep -rlF theo giá trị thật (không in giá trị):
DIRECTUS_ADMIN_PASSWORD: /opt/incomex = 13 /root = 6 → 19 file
DIRECTUS_ADMIN_TOKEN : /opt/incomex = 30 /root = 4 → 34 file
UNION (một trong hai, cả 2 cây) → 46 file
⇒ Con số "34 file" của KB khớp CHÍNH XÁC số file chứa DIRECTUS_ADMIN_TOKEN — KB đúng, chỉ là đếm theo denominator khác. Phạm vi thật rộng hơn cả KB: 46 file.
13 file chứa DIRECTUS_ADMIN_PASSWORD dưới /opt/incomex:
docker/.env ← nguồn injection hợp lệ (0600)
.env.local ← ⚠️ chưa rõ consumer
docker/.env.bak.20260318T075608 ┐
docker/.env.bak.20260318T075911 │
docker/.env.bak.20260404 ├─ 🔴 7 BẢN SAO SECRET CŨ (stale)
docker/.env.bak.20260517T021349Z │ → Wave C4 phải xoá
docker/.env.bak.20260517T030513Z │
docker/.env.bak.s174-fix-04 │
docker/.env.mysql-backup-20260313 ┘
scripts/reconcile-knowledge.py ┐ ngoài Git (bản /opt/incomex)
scripts/reconcile-tasks.py ┘
docker/agent-data-repo/scripts/reconcile-knowledge.py ┐ 🔴 TRACKED + IN HEAD
docker/agent-data-repo/scripts/reconcile-tasks.py ┘ → vào Drive + GitHub
"2 file trong git HEAD" = ĐÚNG — đúng 2 file agent-data-repo/scripts/reconcile-*.py, và chỉ 2 file này nằm trong tar backup 4×/ngày. 215 file khác chỉ chứa tên biến ${DIRECTUS_ADMIN_PASSWORD} (docs/template/SQL — vô hại).
Bài học đo: giao subagent grep secret phải chốt phạm vi tường minh (
/opt/incomex+/root, không--include), nếu không sẽ ra con số nhỏ giả tạo rồi "đính chính" nhầm KB đang đúng.
🔴 Blast radius: xoay
DIRECTUS_ADMIN_PASSWORDkhông đóng được lỗ này — giá trị nằm trong git history, nên sẽ tiếp tục được upload trong.gitobjects cho tới khi rewrite history; và nó đã nằm trên GitHub branchvps-daily-*. Ngoài rascope = drivenghĩa là token backup đọc/xoá được toàn bộ Drive cá nhân, không chỉ thư mục backup.⚠️ Ưu tiên CAO trong rotation graph — secret đang bị sao chép 6 lần/ngày ra 2 kho ngoài.
(Fingerprint đối chiếu giá trị đã được xác lập out-of-band trong quá trình đo và cố ý không ghi vào báo cáo/KB theo §3, kể cả dạng hash rút gọn.)
7. ACTIVE CONTROL-PLANE INVENTORY
7.1. GitHub (đã xác minh lại, KHÔNG tin KB)
34 workflow / 2 repo. Đúng 5 có khả năng ghi VPS — cả 5 đều disabled_manually. Cả 5 dùng VPS_HOST + VPS_SSH_KEY với username: root.
| CONTROL PLANE | ERA | ID | TRIGGER | TARGET | CAPABILITY | STATE | LAST RUN | CRED | RISK | DISPOSITION |
|---|---|---|---|---|---|---|---|---|---|---|
| web-test / Deploy to VPS | GITHUB_DEPLOY | 233946923 | workflow_run[Nuxt 3 CI] + dispatch |
compose, nginx conf, nuxt-output, dot/bin, PG migrations | scp+ssh root · compose up -d --force-recreate · nginx -s reload |
disabled_manually ✅ | 2026-07-11T02:47:26Z success ✅ | VPS_SSH_KEY |
🔴 CRITICAL | KEEP_DISABLED |
| agent-data-test / Deploy Agent Data | GITHUB_DEPLOY | 233947089 | 🔴 push: main |
agent-data-repo, rewrite docker-compose.yml |
rsync+ssh · compose up -d --force-recreate agent-data |
disabled_manually | 2026-04-03 success | VPS_SSH_KEY,PG_PASSWORD |
🔴 CRITICAL | KEEP_DISABLED |
| agent-data-test / S109 PG Setup | GITHUB_DEPLOY | 244536611 | dispatch | rewrite compose, PG data | ssh · docker cp · Firestore→PG import |
disabled_manually | 2026-03-11 success | VPS_SSH_KEY |
🔴 HIGH | KEEP_DISABLED |
| agent-data-test / Vector Audit & Cleanup | GITHUB_DEPLOY | 244569412 | dispatch | Qdrant/PG vector data | ssh · docker exec incomex-agent-data · auto_heal XOÁ vector |
disabled_manually | 2026-03-11 success | VPS_SSH_KEY |
🔴 HIGH | KEEP_DISABLED — ⚠️ KB ghi "không tồn tại" là SAI |
| web-test / Điều 31 VPS Setup | GITHUB_DEPLOY | 250152096 | dispatch | root crontab, logs/integrity | ssh · crontab /tmp/crontab-clean |
disabled_manually | 2026-03-23 success | VPS_SSH_KEY |
🔴 HIGH | KEEP_DISABLED |
| web-test / Health Check | GITHUB_DEPLOY | 227044705 | cron 0 */6 * * * |
— | curl only (0 hit ssh/scp/rsync trong 537 dòng) | ACTIVE — đang FAIL | 2026-07-17T02:28Z failure | 🔴 khai VPS_SSH_KEY vào env L433 mà KHÔNG dùng |
🟠 MED | RECONCILE — bỏ dòng env L433 |
| 28 workflow còn lại | mixed | — | — | — | không chạm VPS | mixed | — | — | 🟢 LOW | KEEP |
🔴 Ba rủi ro tái kích hoạt (FACT):
- Repo variable
DEPLOY_MODE=directĐÃ SET ⇒ điều kiệnif:của jobdeploy-directđã thoả. Việc disable là thứ DUY NHẤT chặn push→deploy root. Không có gate thứ hai. 233946923chạy theoworkflow_runtừNuxt 3 CI(ACTIVE) ⇒ bật lại là merge kế tiếp vào main tự deploy root.233947089triggerpush: main⇒ bật lại là push kế tiếp tự deploy, không cần dispatch.- Cả 5 là
disabled_manually(không phảidisabled_inactivity) ⇒ push không tự bật lại. Cần hành động tường minh. Nhưng PAT trong/opt/incomex/.git-tokencó scoperepo+workflow⇒ đủ quyền bật lại.
🔴 Bẫy chết người (FACT, đo cả 2 đầu):
web-testmain vẫn giữinfra/nginx/conf.d/default.confsha2569404dce8…với 4 blockwell-known. VPS live làbd38d294…với 1.9404dce8…chính là cấu hình OAuth gây treo KB trong PHASE-2A. Nếu233946923được bật và chạy, bước "Sync config files"cpđè rồinginx -s reload⇒ tái phát lỗi treo KB. ⇒ GitHub KHÔNG phải điểm restore an toàn cho nginx.
7.2. GCP
Toàn bộ API chạy được code đều DISABLED. Chỉ 8 API bật: cloudbilling, cloudresourcemanager, developerknowledge, iam, iamcredentials, secretmanager, serviceusage, telemetry.
| CONTROL PLANE | STATE | CAN AFFECT VPS? | RISK | DISPOSITION |
|---|---|---|---|---|
| Cloud Run / Functions / Scheduler / Build triggers / GCE | API DISABLED (FACT) | NO | 🟢 | REMOVE_CANDIDATE (Wave E) |
| Artifact Registry | API DISABLED | NO (nhưng ⇒ không pull lại được image) | 🔴 xem §11 | RECONCILE |
| Secret Manager | ✅ ENABLED — bề mặt sống duy nhất | Gián tiếp | 🔴 HIGH | KEEP_ACTIVE |
| IAM / iamcredentials | ✅ ENABLED (đúc token) | YES | 🟠 MED-HIGH | RECONCILE |
logging.googleapis.com |
NOT ENABLED | — | 🟠 | ⚠️ không có audit log ⇒ KHÔNG biết secret nào đã bị đọc, bởi ai. UNKNOWN không thể khôi phục. |
🔴 IAM: 14 SA (0 disabled) · 11 user-managed key, TẤT CẢ validBeforeTime = 9999-12-31 (không hết hạn).
chatgpt-api-access@—roles/owner+ keybe15918f…(2024-11-01) ⇒ quyền sở hữu toàn dự án, không hết hạn. Nghiêm trọng nhất.chatgpt-deployer@—editor+resourcemanager.projectIamAdmin(⇒ tự nâng thành owner) +serviceusage.serviceUsageAdmin(⇒ bật lại mọi API đã tắt) +secretmanager.admin+ được cấpvps_contabo_id/vps_contabo_secret. 3 key, và đang cache trên laptop này.cursor-ci-builder@— sống trong GitHub Actions; custom roleMCPSecretManagerOperatormang tên "minimal" nhưng đọc + ghi payload secret toàn dự án.
7.3. VPS local (cron + systemd)
| CONTROL PLANE | TRIGGER | TARGET | CAPABILITY | STATE | RISK | DISPOSITION |
|---|---|---|---|---|---|---|
disk-monitor.sh |
cron 0 * * * * |
— | ✅ REPORT-ONLY đã XÁC MINH trên file LIVE: 0 hit `prune | docker rm | rmi | rm -rf; comment L4 "Auto-prune removed 2026-07-17: reclaimed 0B"; **live == HEAD** (git statussạch). Toànscripts/+dot/bin/`: 0 hit prune |
code-backup-to-gdrive.sh |
cron 0 8,12,15,20 ICT |
Drive | 🔴 secret rời VPS 4×/ngày | ACTIVE_RISKY | 🔴 CRITICAL | RECONCILE (Owner) |
backup-to-gdrive.sh |
cron 37 20 * * * |
Drive root | 🔴 PG dump + .env + TLS private key |
ACTIVE_RISKY | 🔴 CRITICAL | RECONCILE (Owner) |
git-push-gh-daily-v2.sh |
cron 0 6,18 |
GitHub | 🔴 force-push repo có secret 2×/ngày | ACTIVE_RISKY | 🔴 CRITICAL | RECONCILE (Owner) |
dot-apr-execute --local |
cron */5 |
Directus/PG | export SYNC_SECRET+DIRECTUS_ADMIN_PASSWORD; WRITE |
ACTIVE_REQUIRED | 🟠 MED | KEEP_ACTIVE |
~20 cron docker exec postgres psql |
*/10, hằng giờ, hằng ngày |
PG WRITE thật (refresh_*, auto_apply_approval, fn_expire_stale_approvals) |
mutation trực tiếp | ACTIVE_REQUIRED | 🟠 MED | KEEP_ACTIVE — ⚠️ phụ thuộc container tên postgres còn sống |
pg-backup.sh / qdrant-backup.sh |
27 2 / 0 3 UTC |
local backup | — | ACTIVE_REQUIRED | 🟢 | KEEP_ACTIVE |
env-permissions-guard.sh / db-permissions-guard.sh / mcp-writes-perms.timer |
*/5 / hằng giờ / 15′ |
chmod | guard | ACTIVE_REQUIRED | 🟢 | KEEP_ACTIVE |
incomex-balo-reconcile.socket/.service |
socket-activated | Balo PG WRITE | dot-balo-reconcile --sync |
active+enabled | 🟡 LOW | KEEP_ACTIVE |
ui-preview-notebook-daily.timer |
04:00 | git snapshot | — | ACTIVE | 🟢 | KEEP_ACTIVE |
s177-lark-backup.timer, wf-universal-scanner.timer, process-discovery-policy-scan.timer, run-sr-mow.sh (20 */6) |
timer/cron | scan/backup | — | ACTIVE | 🟢 | KEEP_ACTIVE |
lark-mcp-remote.service, fail2ban, ufw, certbot.timer |
systemd | — | — | ACTIVE | 🟢 | KEEP_ACTIVE |
claude-mcp → /var/run/docker.sock |
mount :ro |
Docker API | 🔴 :ro trên unix socket KHÔNG chặn write — connect cần quyền w, và bind :ro không áp EROFS lên socket inode (đã chứng minh bằng chính bridge Balo :ro+gid 987 ⇒ CONNECT_OK) ⇒ toàn quyền Docker |
ACTIVE_RISKY | 🟠 MED-HIGH | RECONCILE — cân nhắc docker-socket-proxy |
8. NORMATIVE DRIFT SURFACE
| # | SUBJECT | RUNTIME FACT | CANONICAL / RULE | NORMATIVE_REGISTRY | DRIFT TYPE | RISK | PROPOSED RESOLUTION | OWNER? | EVIDENCE |
|---|---|---|---|---|---|---|---|---|---|
| 1 | VPS là code/deploy SSOT | ✅ /opt/incomex không remote, không upstream; build/deploy tại chỗ |
VPS SSOT | không có entry | ALIGNED (thực tế) / MISSING_COVERAGE (registry) | 🟢 | Ghi entry xác nhận | ❌ | git remote -v rỗng |
| 2 | GitHub workflow không được deploy prod | ✅ 5/5 workflow ghi-VPS disabled_manually |
Cấm | không có entry | MISSING_COVERAGE | 🔴 | Ghi entry cấm bật lại; nêu DEPLOY_MODE=direct đã thoả |
✅ | gh workflow list |
| 3 | Drive = off-site backup, không phải SSOT | ✅ đúng là backup… | Backup | không có entry | CONTRADICTORY | 🔴 | …nhưng chứa secret + TLS key + PG dump, không mã hoá, scope=drive ⇒ vi phạm tinh thần "backup an toàn" | ✅ | §6 |
| 4 | Secret Manager là credential SSOT | 🔴 SAI Ở RUNTIME — 0 service đọc SM; nguồn thật là docker/.env; 31/32 secret chưa xoay từ 2026-05-22 |
SM = SSOT | không có entry | 🔴 CONTRADICTORY | 🔴 CRITICAL | Chọn 1: (a) sửa canonical → "SM = kho lưu trữ/escrow, .env = injection SSOT"; hoặc (b) làm SM thành SSOT thật (thêm cơ chế sync) |
✅ BẮT BUỘC | không có SM client trong container nào |
| 5 | Compose phải phản ánh runtime trước khi coi là reproducible | 🔴 4/13 lệch: agent-data (3 drift), nginx (mount+net), postgres (env+net), directus (net); executor không có trong compose | Rule | không có entry | DRIFT | 🔴 | Vá compose theo Wave B trước mọi recreate | ❌ | §3.1 |
| 6 | Mỗi mutation chỉ tác động đúng service | 🔴 docker compose up -d trần đụng cả 7 service + cảnh báo orphan executor; --remove-orphans XOÁ executor |
Rule | không có entry | DRIFT | 🔴 | Ghi entry: cấm up -d trần, cấm --remove-orphans; chỉ up -d <service> |
✅ | label vs compose |
| 7 | Git checkpoint/bundle trước mutation | ⚠️ /opt/incomex 103 file dirty (15 M + 88 ??), branch feat/s177-sprint1-round-a; dot 19 ?? |
Rule | không có entry | DRIFT | 🟠 | Baseline hoá theo quy trình Git Safety §13.2 | ✅ | git status |
| 8 | Balo one-click guard trước/sau thay đổi | ✅ dot-balo-one-click-guard tồn tại (c6a5579) |
Rule | không có entry | MISSING_COVERAGE | 🟡 | Ghi vào entry §9 | ✅ | git log dot |
| 9 | §15 từng cấm nút UI/bridge; rev16–17 đã bãi bỏ phần cấm | ✅ Canonical revision 17 chứa: "SỬA ĐỔI 2026-07-17 (§16 thay thế một phần §15). Bản v1.9 của §15 có ghi cấm 'nút UI đồng bộ B…'" | §16 > §15 | 🔴 0 entry | MISSING_COVERAGE | 🟠 | Proposed entry §9 — CHỜ DUYỆT | ✅ BẮT BUỘC | KB get_document rev 17 |
| 10 | Nút Balo + bridge LIVE, Owner-accepted | ✅ nuxt env NUXT_BALO_* + NUXT_PUBLIC_BALO_*; socket active+enabled; guard 37/37 |
Cho phép (§16) | 🔴 normative_registry 47 rows, balo=0, reconcile=0 |
MISSING_COVERAGE | 🟠 | idem | ✅ | query_pg đo thật |
| 11 | disk-monitor không được prune tự động | ✅ ĐÃ SỬA + XÁC MINH LIVE | Rule | không có entry | ALIGNED | 🟢 | Ghi entry chốt | ❌ | grep live file |
9. PROPOSED §15/§16 NORMATIVE_REGISTRY ENTRY — NOT APPLIED
⚠️ CHƯA GHI. Mission này chỉ soạn.
normative_registryhiện 47 rows, 0 row Balo. Cần Owner duyệt.
subject: Balo one-click sync — nút UI dùng chung cho report có resolvedCollection === 'balo_thuc_the'
supersedes: "§15 (v1.9) — phần cấm 'nút UI đồng bộ Balo'"
authority: "canonical balo-thuc-the-quy-dinh.md §16 (rev17, SỬA ĐỔI 2026-07-17)"
status: ACTIVE — Owner-accepted (PASS_BALO_POST_ACCEPTANCE, Administrator thật nghiệm thu)
decision: |
Cho phép MỘT nút "Đồng bộ Balo từ PG" dùng chung cho mọi report
có resolvedCollection === 'balo_thuc_the'.
required_controls:
- Administrator-only (NUXT_BALO_OPERATOR_ROLE_IDS — BẮT BUỘC cả NUXT_ lẫn NUXT_PUBLIC_;
thiếu 1 ⇒ endpoint chạy nhưng NÚT VÔ HÌNH)
- same-origin / CSRF gate
- fixed-purpose Unix socket bridge (/run/incomex/balo-reconcile.sock, 0660 root:incomex-balo-sync gid 987)
- DOT --sync (không SQL trực tiếp)
- atomic apply (dot-pg-atomic-apply)
- verify sau apply
- singleton lock
- guard before/after mutation (dot-balo-one-click-guard, 37/37)
forbidden:
- direct browser/Directus/Nuxt SQL WRITE
- arbitrary command bridge
- public TCP bridge
- hardcoded report URLs
- cron sync
evidence:
- runtime: nuxt env NUXT_BALO_OPERATOR_ROLE_IDS + NUXT_PUBLIC_BALO_OPERATOR_ROLE_IDS + NUXT_BALO_RECONCILE_SOCKET_PATH
- systemd: incomex-balo-reconcile.socket = active + enabled
- commits: 4ecb614, 78b523c, 7a9843d, c6a5579, 7c60ccd (local-only, chưa push)
- guard: dot-balo-one-click-guard 37/37
10. BACKUP MINIMUM ASSESSMENT (không restore drill)
| Job | Chạy thật? | Lịch | Artifact gần nhất | Đích | Mã hoá | Phân loại |
|---|---|---|---|---|---|---|
code-backup-to-gdrive.sh |
✅ 2026-07-17 08:00 CEST success | 4×/ngày ICT | agent-data-test_20260717-1300_ICT.tar.gz 40,996,554 B (size-verified) |
Drive folder ID | ❌ | 🔴 SECRET_UNSAFE_BACKUP |
backup-to-gdrive.sh |
✅ 2026-07-16 OK | 37 20 * * * |
vps-backup-20260716_203701.tar.gz 281,914,206 B |
Drive root | ❌ | 🔴 DATA_BACKUP + SECRET_UNSAFE_BACKUP (TLS private key) |
pg-backup.sh |
⚠️ có cron, chưa verify artifact | 27 2 * * * |
→ /opt/incomex/backups/pg/ |
local | ❌ | DATA_BACKUP |
qdrant-backup.sh |
⚠️ chưa verify | 0 3 * * * UTC |
— | local | ❌ | DATA_BACKUP |
ui-preview-notebook-daily |
✅ 04:00 hôm nay | daily | git snapshot | local | — | CODE_BACKUP |
s177-lark-backup.timer |
✅ 2026-07-16 | ~2 ngày | — | — | GPG (có LARK_BACKUP_GPG_*) |
DATA_BACKUP |
KHÔNG tuyên bố "đã backup đầy đủ". Khoảng trống thật:
- 🔴
/opt/incomex(git root, 103 file dirty) KHÔNG nằm trong job Drive nào — job code chỉ đóngnuxt-repo+agent-data-repo. Nightly job có/opt/incomex/scripts/*nhưng không phải toàn repo. ⇒ compose, nginx conf, dot/, 88 file untracked chỉ tồn tại trên 1 đĩa. - 🔴
GCS_BUCKET_BACKUPtrỏ vào hư không —gcloud storage buckets list→ 0 bucket, storage API tắt ⇒ job nào còn tham chiếu secret này đang ghi vào chỗ không tồn tại / fail âm thầm. - 🔴 21.87 GB writable layer (qdrant 14.6 / postgres 4.54 / directus 2.64) không nằm trong bind mount nào ⇒ không job nào backup ⇒ recreate là mất (nếu con số Docker báo là đúng — chưa xác minh được vì snapshotter).
- ⚠️ Không có Git bundle nào được verify trong mission này (
git bundle verify= read-only, nhưng chưa có bundle để verify).
11. TOP BLOCKERS BY SERVICE
| Service | Blocker | Vì sao chặn |
|---|---|---|
| agent-data | 🔴 3 drift đồng thời (image fallback AR có sẵn local + 10 env thiếu + mem) | Chặn xoay [B][C][D][E][F] — 5/9 secret của toàn hệ |
| agent-api-executor | 🔴 orphan có label compose | compose up -d --remove-orphans xoá mất; script recreate untracked |
| nginx | 🔴 mount ui-preview không khai báo | recreate ⇒ /ui-preview/ 404 câm, không lỗi |
| nuxt | 🟡 image AR 4 tháng không pull lại được (AR API disabled) | mất image = mất khả năng recreate |
| postgres | 🟠 OOMKilled=true; ~20 cron phụ thuộc tên container |
recreate làm gãy cron docker exec postgres |
| qdrant | 🟠 14.6 GB writable layer chưa giải thích được | recreate có thể mất data |
| Toàn hệ | 🔴 SM không phải nguồn injection thật | xoay secret ở SM không tác động production |
| Toàn hệ | 🔴 DIRECTUS_ADMIN_PASSWORD trong git history |
xoay không đủ; phải rewrite history |
12. SERVICES SAFE TO RECONCILE INDEPENDENTLY
✅ incomex-nuxt (parity 17/17), incomex-qdrant, incomex-claude-kb, incomex-claude-mcp (parity PASS — nhưng ghi nhận capability docker.sock), incomex-balo-reconcile (unit khớp).
✅ Xoay được ngay, không phụ thuộc service nào: VPS_SSH_KEY (GitHub), gh_pat_sync_secrets + .git-token, vps_contabo_id/secret, S177_LARK_MCP_REMOTE_TOKEN.
✅ DIRECTUS_ADMIN_PASSWORD xoay được mà KHÔNG cần đụng agent-data (khác loại với DIRECTUS_ADMIN_TOKEN) — nhưng phải kèm rewrite history mới đóng được lỗ.
❌ Không độc lập: agent-data (nút thắt), executor (orphan), nginx (mount), postgres/directus (network).
13. RECOMMENDED EXECUTION WAVES (đề xuất — KHÔNG thi công)
13.1. Các wave
Wave A — parity sẵn + secret rủi ro cao, không chờ ai
A1 Owner duyệt proposed entry §9 (normative_registry)
A2 Owner quyết Drive/GitHub secret vector (§6) — đang chảy 6 lần/ngày
A3 Owner quyết drift #4: SM là SSOT hay escrow (§8)
A4 Xoay VPS_SSH_KEY · gh PAT · Contabo API (độc lập hoàn toàn)
A5 Bỏ dòng env VPS_SSH_KEY L433 của Health Check 227044705
A6 Quyết số phận executor: đưa vào compose HAY commit ROLLBACK script + cấm --remove-orphans
Wave B — drift chặn secret rotation
B1 🔴 PIN AGENT_DATA_IMAGE=agent-data-local:latest ← LÀM TRƯỚC MỌI THỨ KHÁC
B2 Vá compose agent-data: 10 env PG_*/DIRECTUS_DB_*, mem_limit → ${AGENT_DATA_MEM_LIMIT}
B3 Vá compose nginx: mount ui-preview + claude_mcp_net
B4 Vá compose postgres/directus: claude_mcp_net; pin POSTGRES_DB/USER
B5 Verify từng service (guard + smoke), recreate TỪNG service một
Wave C — revoke + loại plaintext
C1 Xoay DIRECTUS_ADMIN_PASSWORD + ADMIN_TOKEN + PG/Qdrant/OpenAI (sau B)
C2 🔴 Rewrite git history 2 file reconcile-*.py (agent-data-repo) — nếu không, C1 vô nghĩa
C3 Thu hồi key be15918f… (chatgpt-api-access owner) + 10 key không hết hạn
C4 Xoá .env.bak* (8 file), .git-token → chuyển sang nguồn an toàn
C5 Thu hẹp rclone scope: drive → drive.file
Wave D — dọn storage có chọn lọc (từng ID, KHÔNG prune tổng)
D1 Build cache 6.7 GB (an toàn nhất, Private 0 B)
D2 7 volume dry-run/anonymous ~9.6 GB (sau khi Owner xác nhận pg-restore-test)
D3 mysql:8.0, docker-*, hello-world/busybox… ~3.5 GB
D4 directus_gov_test_20260602 (1.2 GB PG database)
D5 ⚠️ image agent-data AR — CHỈ sau B1
D6 ❌ TUYỆT ĐỐI GIỮ nuxt-ssr:latest (AR disabled ⇒ không pull lại được)
Wave E — sizing, GCP decommission, restore drill đầy đủ
E1 Xác minh 21.87 GB writable layer (cần nerdctl/ctr do snapshotter)
E2 Sizing lại theo 11 GiB/6 vCPU THẬT (không phải 16/8) sau khi đo tải đủ dài
E3 Bật logging API để có audit trail secret (hiện KHÔNG BIẾT ai đã đọc gì)
E4 GCP decommission + restore drill
Không mặc định agent-data đứng trước Directus. Đồ thị consumer quyết định:
DIRECTUS_ADMIN_PASSWORDkhông có consumer agent-data ⇒ nằm được ở Wave A/C sớm; cònDIRECTUS_ADMIN_TOKENcó ⇒ buộc sau Wave B.
13.2. GIT SAFETY — điều kiện bắt buộc cho MỌI mutation sau này
1. Đọc và phân loại TOÀN BỘ diff hiện hữu (103 file /opt/incomex + 19 /opt/incomex/dot
+ 1 nuxt-repo). Phân loại: authorized survey artifact / production drift / rác.
2. Commit baseline VPS hợp lệ — KHÔNG đổi byte live chỉ để commit cho đẹp.
3. Chỉ stage exact file. 🔴 CẤM `git add -A`, CẤM `git add .`
4. Tạo Git bundle đầy đủ NGOÀI repo.
5. SHA256 + `git bundle verify` PASS.
6. Byte-exact backup cho config/runtime NGOÀI Git:
docker/.env (gitignored) · ROLLBACK-executor-docker-run.sh (untracked)
· /etc/systemd/system/incomex-balo-reconcile.{socket,service}
· bind data: /opt/workflow/postgres, docker/qdrant/data, docker/directus/{uploads,extensions}
7. Commit thay đổi TRƯỚC deploy/reload/recreate.
8. Guard + smoke sau mutation (dot-balo-one-click-guard 37/37).
9. Tạo post-mutation bundle.
10. 🔴 KHÔNG pull, KHÔNG dùng remote đè VPS; KHÔNG push nếu Owner chưa giao.
🔴 Không dùng stopped container hoặc GitHub làm rollback duy nhất. — GitHub
web-testgiữ nginx9404dce8…= chính lỗi treo KB, restore từ đó là tái phát bug. — Không có stopped container nào tồn tại (11/11 đang chạy) ⇒ không có rollback dạng đó. — Rollback thật phải dựa vào: Git bundle (Wave §13.2 mục 4) + image tagpre-*local + byte-exact backup.
14. FACTS NEXT AGENT MAY RELY ON
✅ Host: 6 vCPU / 11 GiB RAM / 96 G disk 88% / inode 9% — ĐO THẬT
✅ 11 container: 9 compose-managed (3 file compose), 2 không (uptime-kuma, pg-restore-test)
✅ agent-data runtime = 2560 MiB + ĐÚNG 10 biến PG_*/DIRECTUS_DB_*; compose = 1536m + 0 biến
✅ AGENT_DATA_IMAGE/NUXT_SSR_IMAGE KHÔNG set ở đâu ⇒ compose dùng fallback AR
✅ Fallback image agent-data-test:latest TỒN TẠI local (4 tháng) ⇒ compose up chạy sai IM LẶNG
✅ agent-api-executor: 0 hit trong compose, nhưng CÓ label compose ⇒ orphan
✅ nginx runtime có 5 bind (compose khai 4) — thiếu ui-preview; + claude_mcp_net
✅ postgres OOMKilled=true, RestartCount=0
✅ 5/34 GitHub workflow ghi được VPS — CẢ 5 disabled_manually (đã xác minh lại)
✅ 244569412 TỒN TẠI ở agent-data-test (KB ghi sai)
✅ DEPLOY_MODE=direct đã set ⇒ disable là gate DUY NHẤT
✅ GitHub web-test giữ nginx 9404dce8… (4 well-known) vs live bd38d294… (1)
✅ GCP: chỉ secretmanager + iam bật; Cloud Run/Functions/Scheduler/AR/Build = API DISABLED
✅ 32 secret SM, 31 chưa từng xoay từ 2026-05-22; replication đơn europe-west3
✅ 11 SA key KHÔNG hết hạn; chatgpt-api-access@ có roles/owner + key từ 2024-11-01
✅ KHÔNG service nào đọc Secret Manager — .env là nguồn injection thật
✅ Drive backup 4×/ngày + GitHub push 2×/ngày + nightly (TLS key + PG dump) = ACTIVE_SECRET_EXFILTRATION_PATH
✅ Rò rỉ: DIRECTUS_ADMIN_PASSWORD = 19 file (13 /opt/incomex + 6 /root); DIRECTUS_ADMIN_TOKEN = 34 file;
UNION = 46 file. KB "34 file" ĐÚNG (= số file chứa TOKEN). 2 TRACKED+IN_HEAD (agent-data-repo).
7 file .env.bak* chứa password cũ ⇒ Wave C4.
✅ /opt/incomex: KHÔNG remote, branch feat/s177-sprint1-round-a, HEAD 7c60ccd, 103 dirty
✅ docker-compose.yml, nginx/default.conf, disk-monitor.sh, backup scripts = TRACKED_CLEAN
✅ docker/.env = GITIGNORED; ROLLBACK-executor-docker-run.sh = UNTRACKED_LIVE
✅ disk-monitor.sh = REPORT-ONLY, xác minh trên file live; 0 prune trong scripts/ + dot/bin/
✅ normative_registry = 47 rows, 0 row balo/one-click/reconcile
✅ canonical balo-thuc-the-quy-dinh.md = revision 17, có §16 sửa đổi 2026-07-17
✅ PG: directus 1692 MB · directus_gov_test_20260602 1202 MB (stale) · incomex_metadata 386 MB
✅ Reclaimable ≈ 49 GB (image 32.67 + volume 9.58 + build cache 6.70)
15. ASSUMPTIONS NEXT AGENT MUST NOT MAKE
❌ ĐỪNG tin host có 16 GB/8 CPU — thật là 11 GiB/6 vCPU
❌ ĐỪNG tin "chỉ 1 workflow nguy hiểm" — có 5
❌ ĐỪNG tin 244569412 không tồn tại — CÓ, ở agent-data-test
❌ ĐỪNG tin con số "5 file rò rỉ" ở rev1 của chính báo cáo này — SAI, đã tự bác bỏ.
Thật: PASSWORD 19 file · TOKEN 34 file · UNION 46 file (cả /opt/incomex lẫn /root).
❌ ĐỪNG giao subagent grep secret mà không chốt phạm vi — sẽ ra số nhỏ giả tạo
❌ ĐỪNG tin Secret Manager đang cấp credential cho production — KHÔNG service nào đọc nó
❌ ĐỪNG tin xoay DIRECTUS_ADMIN_PASSWORD là đóng được lỗ — giá trị nằm trong git history
❌ ĐỪNG chạy `docker compose up -d` trần — đụng 7 service + cảnh báo orphan executor
❌ ĐỪNG chạy `--remove-orphans` — XOÁ incomex-agent-api-executor
❌ ĐỪNG recreate agent-data trước khi pin AGENT_DATA_IMAGE — sẽ chạy image sai 4 tháng, KHÔNG báo lỗi
❌ ĐỪNG recreate nginx trước khi thêm mount ui-preview — /ui-preview/ 404 câm
❌ ĐỪNG restore nginx từ GitHub — bản đó là lỗi treo KB (9404dce8…)
❌ ĐỪNG xoá image nuxt-ssr:latest — AR API disabled, KHÔNG pull lại được
❌ ĐỪNG coi volume "dangling" là rác chỉ vì không container nào dùng — 46dbcc89… đang active
❌ ĐỪNG coi "container tạm còn sống" là gate bất khả thi — prune đã bị gỡ 2026-07-17, gate KHẢ THI lại
❌ ĐỪNG mặc định agent-data phải đứng trước Directus — đồ thị consumer quyết định
❌ ĐỪNG tin con số 21.87 GB writable layer là đã xác minh — Docker báo, chưa đối chiếu du được
❌ ĐỪNG dùng stopped container làm rollback — không có container nào stopped
❌ ĐỪNG gom DIRECTUS_ADMIN_PASSWORD với DIRECTUS_ADMIN_TOKEN — khác loại, khác consumer
16. UNKNOWNS
? Danh tính tài khoản Google Drive nhận backup (OAuth user token) — không xác định được nếu không chạm token
? PG_* vs POSTGRES_* trong SM: bộ nào còn sống — cần đọc payload (đã CỐ Ý từ chối)
? Artifact Registry web-test còn tồn tại/size/last-push — bị SERVICE_DISABLED che; muốn biết phải BẬT API (bị cấm)
? Ai đã đọc secret nào trong SM, khi nào — logging API tắt ⇒ KHÔNG khôi phục được
? VPS_SSH_KEY trong GitHub còn hiệu lực với VPS không — cần đọc secret hoặc thử auth (ngoài phạm vi)
? 21.87 GB writable layer (qdrant 14.6 / postgres 4.54 / directus 2.64) thực sự chứa gì — GraphDriver.Data=null do containerd snapshotter
? pg-backup.sh / qdrant-backup.sh artifact gần nhất — chưa verify
? 9 biến PG_*/DIRECTUS_DB_* của agent-data (trừ PG_PASSWORD) lấy từ nguồn nào — không có trong .env
? directus_gov_test_20260602 (1.2 GB) còn ai dùng không
? lark-mcp-remote.service parity — chưa đối chiếu
? 88 file untracked ở /opt/incomex là artifact hợp lệ hay drift — cần phân loại (Git Safety mục 1)
17. EVIDENCE PATHS
HOST free -h · nproc · lscpu · df -h · df -i · cat /proc/pressure/{memory,cpu,io}
CONTAINER docker ps -a --format · docker inspect <c> | jq · docker ps -as
docker inspect <c> --format '{{range .Config.Env}}…' | cut -d= -f1 ← names only
COMPOSE cat /opt/incomex/docker/docker-compose.yml (215 dòng)
cat claude-{kb,mcp}/docker-compose.*.yml
ENV grep -vE '^#|^$' docker/.env | cut -d= -f1 ← names only, KHÔNG giá trị
STORAGE docker system df [-v] · docker images · docker volume ls/inspect · docker builder du
du -xh --max-depth=1 /var/lib/docker · du -xsh /var/lib/containerd · journalctl --disk-usage
DOCKER docker info | grep -i 'storage driver|snapshotter'
CRON crontab -l · ls /etc/cron.d /etc/cron.{hourly,daily,weekly} · ls /var/spool/cron/crontabs
SYSTEMD systemctl list-timers --all · list-unit-files --state=enabled · systemctl cat <unit>
NGINX sha256sum docker/nginx/conf.d/default.conf · grep -c well-known · ls conf.d/
GIT git remote -v · branch --show-current · log --oneline · status --porcelain
ls-files --error-unmatch · check-ignore -v · diff --stat HEAD
GITHUB gh api repos/Huyen1974/{web-test,agent-data-test}/actions/workflows[/<id>] ← GET only
gh api .../contents/.github/workflows/<f> --jq .content | base64 -d
gh api repos/Huyen1974/web-test/actions/variables
GCP gcloud auth list · config list · projects list · services list --enabled
gcloud secrets list · secrets versions list · secrets get-iam-policy ← metadata only
gcloud iam service-accounts list · keys list --managed-by=user
gcloud {run,functions,scheduler,compute,builds,artifacts} … list → SERVICE_DISABLED
PG query_pg (database="directus", READ ONLY tx, SELECT):
pg_database_size · information_schema.tables · normative_registry counts
KB search_knowledge · get_document('knowledge/dev/laws-new/pg-read-pg/balo-thuc-the-quy-dinh.md') → rev 17
BACKUP crontab · cat scripts/{code-backup-to-gdrive,backup-to-gdrive,git-push-gh-daily-v2}.sh
tar -tzf <artifact> (liệt kê) · rclone lsjson/about ← read-only subcommands
grep -E '^\[|^type|^scope' ~/.config/rclone/rclone.conf ← KHÔNG đọc token
REPORT KB: knowledge/current-state/reports/claude-post-migration-service-secret-controlplane-reconciliation-survey-2026-07-17.md
18. PROOF OF READ-ONLY SCOPE
SOURCE_CHANGE=NO CONFIG_CHANGE=NO GIT_COMMIT=NO
GIT_PUSH=NO CONTAINER_MUTATION=NO SYSTEMD_MUTATION=NO
GITHUB_WORKFLOW_MUTATION=NO GCP_MUTATION=NO SECRET_MUTATION=NO
DB_WRITE=NO DISK_CLEANUP=NO
Chứng minh:
- Docker: chỉ
ps,inspect,images,volume ls/inspect,system df,builder du,info,logs. 0 lệnhstart/stop/restart/rm/rmi/up/down/prune/exec. - systemd: chỉ
list-timers,list-unit-files,cat,is-active,is-enabled. 0start/stop/restart/reload/enable/disable. 0nginx -s reload. - Git: chỉ
remote,branch,log,status,diff,ls-files,check-ignore,rev-parse. 0add/commit/push/pull/reset/checkout/restore/clean. - GitHub: GET only (
gh api,gh workflow list/view,gh run list). 0 enable/disable/dispatch/rerun. - GCP: list/describe/get-iam-policy only.
gcloud secrets versions accessKHÔNG BAO GIỜ được gọi — 0 payload đọc. Prompt "enable and retry?" auto-trả lời N ⇒ 0 API được bật. - PG:
query_pg— AST-validated, READ ONLY transaction, read-only role, chỉSELECT+information_schema. 0 INSERT/UPDATE/DELETE/DDL. 0 Directus WRITE. 0 Balo--sync/--apply. - Secret hygiene: mọi lần đọc env đều
cut -d= -f1phía server ⇒ giá trị không bao giờ vào context.docker compose configkhông chạy (tránh render secret). Báo cáo/KB không chứa password/token/key/connection-string/hash-xác-thực. Fingerprint đối chiếu cố ý không ghi, kể cả dạng rút gọn. - WRITE duy nhất: file báo cáo này (scratchpad + KB document).
⚠️ TỰ KHAI MỘT SAI SÓT HYGIENE (không giấu)
Để đo phạm vi rò rỉ (§6.1 — mission §7.1 bắt buộc xác minh), tôi đã đọc giá trị DIRECTUS_ADMIN_PASSWORD/DIRECTUS_ADMIN_TOKEN từ docker/.env vào biến shell trên VPS rồi chạy grep -rlF -- "$V" ….
✅ KHÔNG echo/print giá trị · KHÔNG ghi ra file · KHÔNG vào evidence/report/KB/Git · đã `unset` sau khi dùng
✅ Giá trị KHÔNG bao giờ vào context của agent (chỉ đếm + đường dẫn trả về)
🔴 NHƯNG: `grep -rlF -- "$V"` **expand biến vào argv** ⇒ giá trị **hiện trong `ps`/`/proc/<pid>/cmdline`**
trên VPS trong ~4 phút quét. Mission §3 ghi rõ "không ghi command line có thể hiện trong ps/history".
⇒ **VI PHẠM nhẹ §3.** Giảm nhẹ: host single-tenant, chỉ root đọc được /proc của root; không có
user khác; không ghi vào shell history (lệnh chạy qua ssh non-interactive, không có HISTFILE).
✅ CÁCH ĐÚNG cho mission sau: đưa pattern qua stdin, KHÔNG qua argv:
printf '%s' "$V" | grep -rlF -f - /opt/incomex # value không bao giờ vào argv
Ghi nhận công khai để mission sau (a) biết rủi ro đã phát sinh, (b) dùng đúng cách -f -.
Ghi chú: file báo cáo/evidence là authorized survey artifact theo mission hiện hành — KHÔNG phải production drift, và KHÔNG được commit.
DỪNG sau báo cáo. Không tự soạn hoặc chạy mission triển khai tiếp theo.