Claude — C2A: Directus bootstrap admin rotation readiness + no-op rollback drill (2026-07-18)
C2A — Directus bootstrap admin: rotation readiness + controlled no-op rollback drill (2026-07-18)
Tác giả: Claude (Opus 4.8). Host:
vmi3080463/38.242.240.89(Contabo). Nguồn điều hành: survey rev8 + Wave A1 rev1 + C0 rev1 + C1 rev1 — đọc toàn văn cả bốn, cộng đo live. Mọi giá trị secret =REDACTED. Không password/token/key/hash nào trong báo cáo này. Owner đã cấpGO_C2A_ROLLBACK_DRILLsau khi mọi read-only gate PASS.
1. EXECUTIVE VERDICT
C2_ROTATION_READY_AWAITING_OWNER_GO_FOR_C2B
DIRECTUS_ADMIN_TOPOLOGY = VERIFIED_SINGLE_BOOTSTRAP_ADMIN
DIRECTUS_AUTH_SAFETY = PASS
DIRECTUS_STATIC_TOKEN = AUTH_FULL_ADMIN_PASS
ADMIN_STATIC_TOKEN_EXPOSURE = CURRENT_AND_HISTORICAL_FOUND
ADMIN_SESSION_DEPENDENTS = IDENTIFIED (+ NO_CRITICAL_MACHINE_DEPENDENCY_FOUND)
DIRECTUS_BOOTSTRAP_REAPPLY= CLEARED_NO_REAPPLY
DIRECTUS_CONSUMER_ROUNDTRIP = PASS
DIRECTUS_SM_READINESS = NON_AMBIGUOUS
DIRECTUS_ROLLBACK_PATH_B = PROVEN_BY_STATIC_TOKEN_NOOP_DRILL
OFF_VPS_GCP_ACCESS = VERIFIED (caveat: cached credential — xem §24)
VPS_SSOT_GIT_SAFETY = PASS
C2B_SCOPE = ROTATE_PASSWORD_AND_STATIC_TOKEN_AS_ONE_ADMIN_CREDENTIAL_SET
🔴 Ba phát hiện mới, chưa từng có trong KB
-
pg_dumpđêm nào cũng mang static token admin rời VPS.backup-to-gdrive.shL43 chạydocker exec postgres pg_dump -U directus -d directus→ gzip → Drive root, không mã hoá. Directus 11.5 lưu static token plaintext trongdirectus_users.token(đo bằng giá trị: fingerprint token trong DB trùng khít token trongdocker/.env). ⇒ mỗi đêm một bản admin token mới lên Drive. Các báo cáo trước chỉ soi.env/ TLS key / PG-dump-như-dữ-liệu; chưa ai nối chuỗi "PG dump ⇒ chứadirectus_users.token⇒ admin token bị đẩy off-site". -
Bất đối xứng password vs token — hai đường rò khác nhau, cần hai cách vá khác nhau.
Password Static token Lưu trong DB argon2idhash (97 B)🔴 plaintext Trong git history 🔴 2 object (agent-data-repo) ✅ 0 Trong git HEAD 0 (C1 đã gỡ) 0 Trong PG dump → Drive ✅ không (chỉ hash) 🔴 có, mỗi đêm File plaintext hiện hành 21 🔴 37 ⇒ Rewrite git history (C3) không đụng được token. Rotate token không đụng được password trong git. Phải làm cả hai, và đó là lý do C2B bắt buộc gộp thành một credential set.
-
dot-apr-execute— cron*/5— đang HỎNG âm thầm. Log 9.2 MB toàncurl: (7) Failed to connect to localhost port 8055. Nóexport DIRECTUS_ADMIN_PASSWORDnhưng chưa bao giờ chạm được Directus (Directus không publish port ra host). ⇒ tiền đề "có consumer password chạy mỗi 5 phút" là SAI; không có phụ thuộc auth 5-phút nào. (Đây là lỗi production độc lập, ngoài phạm vi C2A — chỉ ghi nhận.)
Không tuyên bố đã đóng exposure. C2A không đổi password, không rotate token.
2. SOURCES READ
claude-post-migration-service-secret-controlplane-reconciliation-survey-2026-07-17.mdrev8 (58.569 ký tự, toàn văn)claude-wave-a1-agent-data-image-compose-env-hardening-2026-07-17.mdrev1 (41.831 ký tự, toàn văn)claude-c0-stop-git-history-drive-propagation-2026-07-17.mdrev1 (18.870 ký tự, toàn văn)claude-c1-remove-directus-admin-hardcode-current-source-2026-07-17.mdrev1 (15.480 ký tự, toàn văn)- Evidence gốc: source thật của Directus 11.5.1 trong image đang chạy (bootstrap, users service, authentication service, rate-limiter, users controller, CLI), PG read-only, docker inspect, crontab, wrappers, gcloud metadata.
Không dựa vào memory ở bất kỳ điểm nào mâu thuẫn với report/live evidence.
3. OWNER BOOTSTRAP CONTEXT
admin@example.com là bootstrap Administrator đang vận hành. nmhuyen@gmail.com tồn tại nhưng chưa vận hành
được. Chưa có bảng nhân sự. C2A không triển khai kiến trúc tương lai nào; không đổi email/role/policy;
không tạo admin thứ hai; không đụng nmhuyen@gmail.com.
4. GIT SAFETY GATE = PASS
/opt/incomex branch feat/s177-sprint1-round-a HEAD 2b086472 remote KHÔNG CÓ ⇒ push bất khả thi
/opt/incomex/docker/agent-data-repo branch main HEAD 7f13207f remote github.com/Huyen1974/agent-data-test status CLEAN
dirty /opt/incomex: 104 (15 M + 89 ??) == đúng trạng thái C1 POST ⇒ KHÔNG drift
Phân loại: MISSION_CHANGE=0 (báo cáo đi KB, không commit) · VERIFIED_LIVE_BASELINE (docker/.env, protected file)
· UNRELATED_WORK=104 (giữ nguyên) · SECRET_IN_HEAD=0 · UNKNOWN=0
Bundles (root-only, VPS-only, ngoài Drive/GitHub/KB):
opt-incomex-PRE.bundle 962a2cfec9cbff3bae46050c6c13962a3d2e94f410c7823c270044db10dafa6c
agent-data-repo-PRE.bundle 8d86073409e7786feee8f4fb1a80cd65c71df1d07464ae1da888c61ef30166c5
git bundle verify: cả 2 = "The bundle records a complete history" ⇒ PASS
🔴 Bundle /opt/incomex chứa password lịch sử trong git object ⇒ root-only /root, đã kiểm:
code-backup-to-gdrive.sh và backup-to-gdrive.sh có 0 tham chiếu /root; checkpoint không nằm trong git root nào.
C2A không tạo commit nào. GIT_COMMIT=NO, GIT_PUSH=NO.
5. DIRECTUS VERSION
image directus/directus:11.5 package.json version = 11.5.1
container incomex-directus 2245d86d2f6a StartedAt 2026-05-08T09:13:06Z Health=healthy RestartCount=0
⇒ Dùng Directus 11 policies model, không dùng schema role cũ.
6. BOOTSTRAP ADMIN IDENTITY + UNIQUENESS
BOOTSTRAP_ADMIN_EMAIL = admin@example.com
BOOTSTRAP_ADMIN_ID = 6abdec55-d911-44df-af96-3cf60b9654af
status=active provider=default role=a40a1070-0b62-4a7e-b2c0-bd4bce9d41ac (Administrator)
password=present(argon2id) token=present tfa_secret=NULL
BOOTSTRAP_ADMIN_FULL_ACCESS = true
FULL_ADMIN_USER_COUNT = 1 (trên tổng 13 user)
Chuỗi chứng minh theo đúng model 11 (không suy đoán):
directus_policies : 8 policy, ĐÚNG 1 có admin_access=t → 8a613123-2538-4943-9d67-b6d261a4789c "Administrator"
directus_access : policy 8a613123 gắn vào ĐÚNG 1 hàng, role=a40a1070, user=NULL
(không có hàng nào gắn admin policy trực tiếp cho user)
directus_users : ĐÚNG 1 user có role=a40a1070 → admin@example.com
directus_roles : 9 role, parent=NULL toàn bộ ⇒ không có kế thừa role làm rò admin
⇒ ADMIN_TOPOLOGY = VERIFIED_SINGLE_BOOTSTRAP_ADMIN. Không có second independent admin.
7. nmhuyen@gmail.com — METADATA ONLY, KHÔNG ĐỔI
id=ae44e653-df5d-4a3c-bf6e-714485b616d2 status=active provider=default
role=NULL policies=none password=present(argon2id 97) token=present(32B) tfa=NULL
last_access = never (PRE == POST, không đổi)
⇒ Có password và static token, nhưng không role, không policy ⇒ token đó xác thực được nhưng
không có quyền gì ngoài Public policy. Không phải rollback identity.
NMHUYEN_ACCOUNT = UNCHANGED_METADATA_ONLY — C2A chỉ đọc.
8. EFFECTIVE ROLE / POLICY / ADMIN_ACCESS PROOF
Chứng minh hiệu lực thật, không chỉ metadata: gọi API bằng static token.
GET /users/me 200 id=6abdec55… email=admin@example.com role.name=Administrator
GET /policies 200 rows=8 admin_policies=['Administrator']
GET /users 200 rows=13 (đọc được TOÀN BỘ user)
GET /roles 200 rows=9
GET /server/info 200 keys=[extensions, project, queryLimit, rateLimit, rateLimitGlobal, version, websocket]
Vì sao 200 ở /policies chỉ có thể nghĩa là admin: directus_permissions có 1207 hàng nhưng
0 hàng cho directus_policies|directus_access|directus_users|directus_roles ⇒ không tồn tại grant
non-admin nào cho các collection này. Thêm: /server/info trả 7 key mở rộng (non-admin chỉ nhận project).
9. TFA STATUS
DIRECTUS_TFA_STATUS = DISABLED
tfa_secret IS NULL cho CẢ 13 user (không riêng admin)
Code path xác nhận (services/authentication.js): if (user.tfa_secret && !options?.otp) throw InvalidOtpError
⇒ tfa_secret NULL ⇒ không cần OTP. Không HOLD_ADMIN_TFA_ENABLED_OWNER_ACTION.
updateMany chặn sửa tfa_secret thủ công ⇒ drill không thể vô tình đổi TFA.
10. PASSWORD POLICY
directus_settings.auth_password_policy = NULL
Directus container env: KHÔNG có biến AUTH_PASSWORD_POLICY
PASSWORD_POLICY = KNOWN → KHÔNG CÓ CHÍNH SÁCH NÀO ĐƯỢC ÁP
Chứng minh từ source đang chạy (services/users.js checkPasswordPolicy):
const { auth_password_policy: policyRegExString } = await settingsService.readSingleton({...});
if (!policyRegExString) { return; } // ← NULL ⇒ thoát sớm, không kiểm gì
⇒ Directus chấp nhận mọi password. Không đoán theo tài liệu mặc định.
11. LOGIN-ATTEMPT / LOCKOUT / RATE-LIMIT
directus_settings.auth_login_attempts = 25
RATE_LIMITER_ENABLED = "false" (compose) ⇒ không rate-limit HTTP chung
loginAttemptsLimiter = createRateLimiter('RATE_LIMITER', { duration: 0 }) ← store mặc định = MEMORY
Ngữ nghĩa thật, đọc từ services/authentication.js:
.consume(user.id)chạy mọi lần đăng nhập (kể cả thành công), trướcprovider.login().duration: 0⇒ điểm không bao giờ tự hết hạn.- Khi hết điểm:
UPDATE directus_users SET status='suspended'— khoá tài khoản, không phải chỉ chặn tạm. - Nhưng khi login thành công:
await loginAttemptsLimiter.set(user.id, 0, 0)⇒ reset về 0.
⇒ LOCKOUT_POLICY = KNOWN: 25 lần thất bại LIÊN TIẾP ⇒ suspended. Bộ đếm trong RAM, reset khi
Directus restart. C2A thực hiện 0 lần login sai (mission cấm; §25 cũng cấm). Rủi ro lockout = 0.
12. STATIC TOKEN — PRESENCE, AUTH, EFFECTIVE ACCESS
STATIC_TOKEN_AUTH = PASS
STATIC_TOKEN_EFFECTIVE_ACCESS = FULL_ADMIN
STATIC_TOKEN_ROLLBACK_CANDIDATE= YES
token length = 64 B (giá trị REDACTED)
🔴 Đo bằng GIÁ TRỊ (không tin tên biến), khoá HMAC ngẫu nhiên, giá trị không bao giờ vào argv:
dotenv.DIRECTUS_ADMIN_TOKEN len=64 fp=X ┐
agent-data.DIRECTUS_ADMIN_TOKEN len=64 fp=X ├ TRÙNG KHÍT
nuxt.NUXT_DIRECTUS_SERVICE_TOKEN len=64 fp=X │
directus_users.token (admin) len=64 fp=X ┘ ⇒ Directus 11.5 lưu static token PLAINTEXT trong DB
claude-mcp.DIRECTUS_TOKEN len=32 fp=Y ⇒ = token của user tac-agent, KHÁC admin
⇒ Đính chính quan trọng cho C2B: claude-mcp KHÔNG dùng admin token ⇒ rotate admin token
không làm gãy claude-mcp. Consumer thật của admin token: agent-data, nuxt, cron
dot-orphan-scanner + dot-misclass-scanner (qua cron-env.sh).
Stateless đã chứng minh: sessions 73 → 73 và last_access không đổi qua toàn bộ probe
⇒ static-token auth không tạo session, không cập nhật last_access.
13. STATIC-TOKEN EXPOSURE SCAN
13.1 Methodology
Giá trị → file tmpfs 0600 → grep -rlF -f <file>. Giá trị KHÔNG bao giờ vào argv (đúng cách mà
survey §18 tự khai đã làm sai). Pattern shred bằng trap EXIT. Chỉ in đường dẫn + số đếm, không in nội dung.
13.2 Verdict
ADMIN_STATIC_TOKEN_EXPOSURE = CURRENT_AND_HISTORICAL_FOUND (37 file hiện hành)
| Vùng | Hits | Ghi chú |
|---|---|---|
/opt/incomex (trừ backups/.git/node_modules) |
18 | gồm .env.local, docker/.env, 5 × .env.bak*, data/tac/gate-b-*/token.txt, 9 evidence JSON |
/opt/incomex/backups |
12 | PG dump prod-directus-*.sql (T5–2026) + 2 inspect JSON |
/root |
6 | 🔴 /root/.bashrc, 3 PG dump, 2 file backup Wave A1 (hợp lệ) |
/etc |
1 | /etc/incomex/agent-data.env (protected, hợp lệ) |
| git object (cả 3 repo, full history) | 0 | ✅ token KHÔNG ở trong git ⇒ không lên GitHub |
| Live process env | 5 pid | agent-data (uvicorn+3 python), nuxt (node) |
Khớp chéo với survey: survey đo TOKEN = 34 file (30 /opt/incomex + 4 /root). Tôi đo
30 /opt/incomex (khớp chính xác) + 6 /root — chênh đúng 2 file là
wave-a1-checkpoint/backup/{dotenv,agent-data.env}.PRE tạo sau khi survey chạy. ⇒ nhất quán, giải thích được.
13.3 Hai đường rò đáng lo nhất
- 🔴 PG dump:
backup-to-gdrive.shL43pg_dump -U directus -d directus→ Drive root, không mã hoá. DB chứa token plaintext ⇒ token rời VPS mỗi đêm. Các dump T5 trên đĩa chứa CHÍNH token hiện hành ⇒ token chưa từng được xoay kể từ ít nhất 2026-05-16. - 🔴
/root/.bashrc:107export DIRECTUS_ADMIN_TOKEN=…⇒ mọi shell root tương tác mang token trong env. Đã kiểm thực nghiệm: shell non-interactive (ssh của tôi) KHÔNG có, vì L6[ -z "$PS1" ] && returnchặn trước.
13.4 Vùng CHƯA quét (khai báo trung thực)
- Artifact Drive (56 code-backup/repo + 14 nightly): KHÔNG tải về — tải sẽ tạo thêm bản sao secret trên đĩa.
Suy luận có cơ sở: nightly chứa PG dump ⇒ gần như chắc chắn chứa token. KHÔNG tuyên bố là đã đo.
- Drive Trash (13.9 GiB)
- Nhánh GitHub vps-daily-*: không fetch (fetch = mang secret về). Suy luận: git object = 0 ở cả 3 repo
⇒ token KHÔNG ở trong bất kỳ nhánh nào — đây là suy luận MẠNH vì GitHub chỉ nhận từ chính 2 repo này.
- File nhị phân/nén (grep --binary-files=without-match bỏ qua)
⇒ Dùng CURRENT_AND_HISTORICAL_FOUND, không dùng NOT_FOUND_IN_EXHAUSTIVE_SCOPE.
14. POTENTIALLY-VALID SESSION INVENTORY (PRE)
POTENTIALLY_VALID_SESSIONS = 73 (100% thuộc admin@example.com; 0 session của user khác)
TTL = 7 ngày (REFRESH_TOKEN_TTL); expires ∈ [2026-07-18 16:00Z, 2026-07-25 10:00Z]
| n | ip | user_agent | Diễn giải |
|---|---|---|---|
| 65 | 172.18.0.5 |
Python-urllib/3.11 |
agent-data → 2 session mỗi 6h = reconcile cron |
| 6 | 172.18.0.6 |
node |
nuxt, cụm một lần 2026-07-17 04:01–05:28 (ngày deploy Balo) |
| 2 | 38.242.240.89 |
curl/8.5.0 |
host, 2026-07-17 03:55–03:58 |
0 session có user-agent trình duyệt ⇒ không có người nào đang đăng nhập Directus admin UI.
Mẫu tạo session khớp tuyệt đối cron 0 */6 CEST (04/10/16/22 UTC, đúng 2/lần) + cụm 10 session lúc
2026-07-17 20 UTC = chính mission C1 (auth smoke + dry-run). Sessions hết hạn bị dọn ở mỗi lần login
(DELETE FROM directus_sessions WHERE expires < now()).
15. SESSION / MACHINE DEPENDENCY ASSESSMENT
ADMIN_SESSION_DEPENDENTS = IDENTIFIED → NO_CRITICAL_MACHINE_DEPENDENCY_FOUND
| Consumer | Cơ chế | Có phụ thuộc session cũ? |
|---|---|---|
reconcile-{tasks,knowledge} |
password login mỗi lần chạy | ❌ tạo session MỚI mỗi run, không tái dùng |
agent-data |
static token | ❌ stateless (đã chứng minh) |
nuxt |
static token | ❌ stateless; 6 session là rác một lần |
claude-mcp |
token tac-agent | ❌ không liên quan admin |
dot-orphan-scanner, dot-misclass-scanner |
DIRECTUS_ADMIN_TOKEN |
❌ stateless |
dot-dot-health, dot-collection-health, dot-apr-health, dot-dot-coverage |
password login | ❌ login mới mỗi run (02–05h) |
dot-apr-execute (*/5) |
🔴 HỎNG — không chạm được Directus | ❌ không phải consumer |
⇒ Không HOLD_CRITICAL_SESSION_DEPENDENCY_UNMAPPED. Xoá session = không làm gãy service nào.
Đã chứng minh sau drill: xoá sạch 75 session, reconcile dry-run vẫn PASS và tự tạo lại 2 session.
16. docker/.env VALUE-LOCATION PROOF (PAYLOAD REDACTED)
Đo bằng giá trị, HMAC khoá ngẫu nhiên (đã shred):
dotenv.DIRECTUS_ADMIN_PASSWORD len=23 fp=P ┐
protected.DIRECTUS_PASSWORD len=23 fp=P ├ MỘT giá trị duy nhất, ba nơi
directus(container).ADMIN_PASSWORD len=23 fp=P ┘
dotenv.DIRECTUS_ADMIN_EMAIL len=17 fp=E == directus.ADMIN_EMAIL (= "admin@example.com")
⇒ docker/.env DIRECTUS_ADMIN_PASSWORD chính là password đang hiệu lực, và chính là giá trị
trong protected file của C1. Không có VALUES_DIFFER.
17. EFFECTIVE COMPOSE / ENV INJECTION
Đọc raw YAML (không docker compose config — tránh render secret; và v5.0.2 không có --no-interpolate):
directus:
image: directus/directus:11.5
environment:
ADMIN_EMAIL: ${DIRECTUS_ADMIN_EMAIL}
ADMIN_PASSWORD: ${DIRECTUS_ADMIN_PASSWORD} # ← CÓ inject
KEY: ${DIRECTUS_KEY} SECRET: ${DIRECTUS_SECRET}
RATE_LIMITER_ENABLED: "false"
Runtime container env (chỉ đọc TÊN): ADMIN_EMAIL, ADMIN_PASSWORD đều có mặt.
Runtime variable name = ADMIN_PASSWORD (không phải DIRECTUS_ADMIN_PASSWORD).
Không có ADMIN_TOKEN trong container ⇒ static token không do bootstrap seed; được đặt sau qua UI/API.
18. ENTRYPOINT / BOOTSTRAP RE-APPLY ANALYSIS
DIRECTUS_BOOTSTRAP_PASSWORD_BEHAVIOR = BOOTSTRAP_ONLY_NO_REAPPLY
Entrypoint: ["docker-entrypoint.sh"]
Cmd: /bin/sh -c ": && node cli.js bootstrap && pm2-runtime start ecosystem.config.cjs ;"
⇒ bootstrap chạy mỗi lần container khởi động. Nhưng đọc source thật trong image đang chạy
(@directus/api/dist/cli/commands/bootstrap/index.js):
if ((await isInstalled()) === false) {
await installDatabase(database); await runMigrations(database,'latest');
if (skipAdminInit == null) { await createDefaultAdmin(schema); } // ← CHỈ ở nhánh này
} else {
logger.info('Database already initialized, skipping install');
await runMigrations(database, 'latest'); // ← KHÔNG đụng user
}
createDefaultAdmingọiusersService.createOne(...)— CREATE, không bao giờ UPDATE.isInstalled()=inspector.hasTable('directus_collections')⇒ DB đã cài ⇒ luôn vào nhánhelse.- Không cron/helper nào re-apply:
greptoànscripts/+dot/bin/+ crontab ⇒ 0 đường re-apply.
⇒ Restart Directus KHÔNG ghi đè password. C2B không bắt buộc phải sửa docker/.env trong cùng
transaction để rotation "dính" — nhưng vẫn PHẢI sửa, vì:
(a) nếu DB bị re-init/khôi phục từ đầu, bootstrap sẽ dùng ADMIN_PASSWORD cũ;
(b) docker/.env là bản plaintext của giá trị cũ ⇒ để lại là để lại chìa đã lộ.
⇒ Không HOLD_DIRECTUS_ENV_REAPPLY_CONFLICT.
19. CURRENT PASSWORD CONSUMER PATH
/etc/incomex/reconcile/directus-admin.env (root:root 0600, dir 0700, 44 B, dạng DIRECTUS_PASSWORD='<val>')
→ /opt/incomex/scripts/reconcile-{knowledge,tasks}.sh
· gate: file tồn tại + readable + mode==600 + owner==root (thiếu ⇒ exit 3)
· set -a ; . "$ENVFILE" ; set +a
· gate: biến rỗng ⇒ exit 3
· docker cp <script>.py incomex-agent-data:/tmp/…
· docker exec -e DIRECTUS_PASSWORD incomex-agent-data python3 /tmp/….py ← CHỈ TÊN BIẾN
→ reconcile-*.py : os.environ.get("DIRECTUS_PASSWORD","") ; rỗng ⇒ exit 3 (fail-closed, không fallback)
Cron: 0 */6 * * * (Europe/Berlin) ⇒ 00/06/12/18 CEST
Consumer password khác (qua cron-env.sh → docker/.env): dot-dot-health 03:00, dot-collection-health 04:00,
dot-apr-health 04:30, dot-dot-coverage CN 02:00, dot-apr-execute */5 (hỏng).
20. DISPOSABLE CONSUMER ROUND-TRIP
CONSUMER_ENV_ROUNDTRIP = PASS
Đường đo đúng semantic production, giá trị giả dùng một lần, shred ngay, không gửi tới Directus,
không đụng protected file thật:
protected test file (0600 root) → gate perm/owner → set -a; . file; set +a → docker exec -e DIRECTUS_PASSWORD
→ tiến trình trong container → so fingerprint HMAC.
| Case | Charset | Kết quả |
|---|---|---|
| A | alphanumeric | ROUNDTRIP_PASS |
| B | $ ` " \ ! # & ; | * () {} [] space % ^ @ ~ + = |
ROUNDTRIP_PASS |
| C | chứa dấu nháy đơn ' |
FAIL-CLOSED (đúng như thiết kế) |
Case C chi tiết: . file báo unexpected EOF while looking for matching ', biến unbound, set -u bắt,
wrapper exit 3. ⇒ Không cắt xén âm thầm, không giá trị sai lệch.
🔴 Ràng buộc C2B rút ra: candidate password không được chứa '. Mọi ký tự đặc biệt khác an toàn.
(Không ép [A-Za-z0-9] — policy không đòi, và B đã chứng minh không cần.)
21. EXTRACTED PRODUCTION-VALUE LOGIN PROOF (§16 — chống vòng luẩn quẩn)
Chạy sau Owner GO, ngay trước drill, bằng đúng helper và đúng loader sẽ dùng cho drill:
EXTRACTED_CURRENT_PASSWORD_AUTH = PASS
LOGIN_CHECK | login_http=200 | me_http=200 | id=6abdec55-… | email=admin@example.com | logout_http=204 | MATCH=True
sessions 75 → 75 (login tạo 1, logout xoá 1 ⇒ net 0)
⇒ Giá trị trích ra thật sự mở được khoá trước khi dùng nó để set. Không HOLD_EXTRACTED_VALUE_MISMATCH.
22. SECRET MANAGER — PROJECT / RESOURCE / IAM (METADATA ONLY)
project github-chatgpt-ggcloud (812872501910, ACTIVE) · 32 secret · replication user-managed europe-west3
SM_PASSWORD_MAPPING = UNAMBIGUOUS_NEW_RESOURCE_REQUIRED
SM_STATIC_TOKEN_MAPPING = EXACT_EXISTING_RESOURCE
| Kết quả | |
|---|---|
DIRECTUS_ADMIN_TOKEN |
TỒN TẠI — 1 version, enabled, createTime 2026-05-22T10:44Z, chưa từng xoay |
DIRECTUS_ADMIN_PASSWORD |
NOT_FOUND |
| rotation policy | không có (cả secret lẫn project) |
| IAM cấp secret | không có binding riêng ⇒ kế thừa project |
| quyền của Owner | roles/owner (+ iam.serviceAccountTokenCreator, workloadIdentityPool*) |
Quy ước đặt tên SM phản chiếu chính xác tên biến .env (AGENT_DATA_API_KEY, PG_PASSWORD,
QDRANT_LOCAL_API_KEY, DIRECTUS_KEY, DIRECTUS_SECRET…) ⇒ tên mới không mơ hồ = DIRECTUS_ADMIN_PASSWORD.
Quyền C2B (create secret / add version / access version / read metadata) đã đủ qua roles/owner
⇒ không cần tăng IAM. C2A không tạo/không thêm version/không sửa IAM.
23. SM AUTO-APPLY / ROTATION / VERSION POLICY
SM_LATEST_AUTO_APPLY = NO
Không service nào đọc SM (survey §5.1, tái xác nhận: không SM client trong container, không agent sync)
⇒ không có automation lấy latest rồi tự áp ⇒ không conflict C2B.
🔴 Mặt trái: SM chưa từng được đối chiếu với runtime ⇒ chưa chắc restore đúng giá trị đang chạy.
C2A cố ý không đọc payload nên không thể khẳng định SM DIRECTUS_ADMIN_TOKEN v1 == token live.
⇒ C2B phải đối chiếu (HMAC read-back) trước khi coi SM là recovery source.
24. OFF-VPS OWNER ACCESS
OFF_VPS_GCP_ACCESS = VERIFIED (kèm caveat bên dưới)
Bằng chứng đo trực tiếp từ laptop Owner, không phải VPS:
active account = nmhuyen@gmail.com (user principal, KHÔNG phải service account)
project = github-chatgpt-ggcloud → describe OK, secrets list OK (32), IAM read OK
project role = roles/owner
VPS identity = cursor-ci-builder@…iam.gserviceaccount.com ⇒ ĐƯỜNG TRUY CẬP ĐỘC LẬP với VPS
⚠️ Caveat trung thực: đây là credential đã cache trên laptop. Nó chứng minh quyền truy cập off-VPS đang hoạt động, nhưng không chứng minh Owner đăng nhập lại được nếu mất laptop. Checklist Owner nên làm một lần (không gửi payload vào chat/report):
- Mở trình duyệt, đăng nhập Google Cloud bằng tài khoản cá nhân.
- Mở đúng project
github-chatgpt-ggcloud. - Xem metadata một secret (không mở payload).
- Xác nhận không phụ thuộc session/key chỉ nằm trên VPS.
25. ROLLBACK METHOD DESIGN
ROLLBACK_PATH_B = STATIC_TOKEN_METHOD_IDENTIFIED_SECRET_SAFE → PROVEN_BY_STATIC_TOKEN_NOOP_DRILL
auth method static token của chính bootstrap admin (Authorization: Bearer, dựng trong process memory)
endpoint PATCH http://incomex-directus:8055/users/6abdec55-…?fields=id,email,status
payload {"password": "<value>"} ← ĐÚNG MỘT FIELD
target 6abdec55-d911-44df-af96-3cf60b9654af
permission FULL_ADMIN (đã chứng minh §8)
helper /root/c2a-work/c2a-rollback.py (0700) — sha256 08fa8cf836986c72…
3 mode: verify (GET) · login-check (login→me→logout) · apply (PATCH)
token nguồn STDIN duy nhất → KHÔNG argv, KHÔNG env host, KHÔNG log
password nguồn protected file → set -a → docker exec -e DIRECTUS_PASSWORD (CHỈ TÊN) → os.environ
API verify chỉ đọc HTTP status + id/email/status; body bị loại bỏ; header không bao giờ log
🔴 Directus CLI bị loại có căn cứ: node cli.js users passwd --email <value> --password <value>
⇒ CLI_ARGV_SECRET_UNSAFE = YES ⇒ không dùng. ?fields=id,email,status được thêm để static token
không thể xuất hiện trong response body.
❌ Không direct SQL. ❌ Không sửa hash bằng SQL.
26. SECRET-IN-ARGV / HEADER / LOG SAFETY PROOF
✅ Không echo/print/log bất kỳ giá trị secret nào
✅ Token: chỉ qua stdin (`sed … | docker exec -i …`) — chưa từng vào argv, chưa từng vào env của shell host
✅ Password: chỉ qua `docker exec -e NAME` (name-only) — value không vào argv
✅ grep secret: luôn `-f <tmpfs file>` — KHÔNG literal trong argv (sửa đúng lỗi survey §18 tự khai)
✅ Không `curl -H "Authorization: Bearer <token>"`
✅ Không ghi raw docker inspect Env · không ghi raw request/response · không bật HTTP verbose
✅ Không đọc payload Secret Manager (0 lần `secrets versions access`)
✅ HMAC key ngẫu nhiên 32 B trong tmpfs, đã `shred` ⇒ fingerprint MỘT CHIỀU, vô dụng ngoài phiên này
✅ trap EXIT shred mọi pattern file · /dev/shm CLEAN sau mission
Kiểm chứng sau mission:
ps -eo args | grep -F -f <pattern> → CLEAN (0 hit)
docker logs directus/agent-data --tail 400 → 0 hit secret
/dev/shm → CLEAN
in-container helper /tmp/c2a-* → đã xoá
27. READ-ONLY READINESS GATES (tất cả PASS trước khi xin GO)
ADMIN_TOPOLOGY=VERIFIED_SINGLE_BOOTSTRAP_ADMIN NMHUYEN_ACCOUNT=UNCHANGED_METADATA_ONLY
TFA_STATUS=KNOWN_AND_MANAGEABLE (DISABLED) PASSWORD_POLICY=KNOWN (none enforced)
LOCKOUT_POLICY=KNOWN (25 consecutive → suspend) STATIC_TOKEN_AUTH=PASS
STATIC_TOKEN_EFFECTIVE_ACCESS=FULL_ADMIN STATIC_TOKEN_EXPOSURE=CLASSIFIED
ADMIN_SESSION_DEPENDENTS=NO_CRITICAL_DEPENDENCY BOOTSTRAP_REAPPLY_BEHAVIOR=KNOWN
CONSUMER_ENV_ROUNDTRIP=PASS SM_MAPPING=NON_AMBIGUOUS
SM_AUTO_APPLY=NONE ROLLBACK_PATH_B=SECRET_SAFE_METHOD_IDENTIFIED
GIT_SAFETY_GATE=PASS SAFE_WINDOW=AVAILABLE
CONTAINER_PRE_SNAPSHOT=COMPLETE SECRET_HYGIENE=PASS
BALO_GUARD_PRE=PASS (37/37)
28. OWNER GO REQUEST AND RESPONSE
In ra: "C2A_ROLLBACK_DRILL_READY — OWNER GO REQUIRED" + tóm tắt đầy đủ §23 của mission
Owner trả lời: GO_C2A_ROLLBACK_DRILL (chuỗi chính xác, không suy diễn từ "ok" mơ hồ)
Side effect đã công bố trước khi xin GO: PATCH password sẽ xoá toàn bộ ~75 session.
29. SAFE WINDOW + NO-OP ROLLBACK DRILL
SAFE_WINDOW = 2026-07-18 13:51 → 18:00 CEST (cửa sổ giữa hai lần reconcile)
đo live: reconcile 0 */6 CEST → lần kế 18:00 · git-push-gh 0 6,18 CEST → 18:00
code-backup 15:00 CEST (ICT 20:00) · nightly 20:37 CEST
dot-hc-executor / run-sr-mow / hc-executor-verify: 0 tham chiếu Directus auth
Lúc bắt đầu drill: 0 job reconcile/backup/push đang chạy
DRILL START = 14:10:47 CEST PATCH ghi nhận trong log Directus lúc 12:10:49Z = 14:10:49 CEST
Revalidate ngay trước drill (§24): helper sha256 khớp ở cả 3 vị trí · protected file fingerprint và
sha256 == PRE · admin active (không suspended) · static token PASS · password login PASS.
APPLY | http=200 | id=6abdec55-… | email=admin@example.com | status=active APPLY_RC=0
Log Directus: PATCH /users/6abdec55-…?fields=id,email,status 200 222ms ← ĐÚNG 1 lần, ĐÚNG 1 user
30. TIMEOUT / AMBIGUOUS-RESULT HANDLING
Không phát sinh. PATCH trả 200 trong 222 ms, APPLY_RC=0, không timeout, không kết quả mơ hồ.
Cây quyết định §26 (kiểm password → kiểm token → kiểm metadata → không retry mù) đã sẵn sàng nhưng không cần dùng.
DRILL_RESULT_INCONCLUSIVE_* không áp dụng.
31. PRE / POST ADMIN METADATA
PRE POST
id 6abdec55-d911-44df-af96-3cf60b9654af == 6abdec55-d911-44df-af96-3cf60b9654af
email admin@example.com == admin@example.com
status active == active
provider default == default
role a40a1070-0b62-4a7e-b2c0-bd4bce9d41ac == a40a1070-0b62-4a7e-b2c0-bd4bce9d41ac
tfa_secret present false == false
token present true == true
password hash length 97 == 97
ADMIN_ID_PRE=POST ✅
ADMIN_EMAIL_PRE=POST ✅
ADMIN_ROLE_POLICIES_PRE=POST ✅ (policy topology đo lại: vẫn 1 admin policy / 1 role / 1 user)
ADMIN_STATUS_PRE=POST ✅
ADMIN_TFA_PRE=POST ✅
ADMIN_STATIC_TOKEN_FINGERPRINT_PRE=POST ✅ 9e2f904336904179 == 9e2f904336904179
CURRENT_PASSWORD_PLAINTEXT_CHANGED = NO (pw.dotenv & pw.protected fp c7c676f81ed8b19d PRE==POST,
protected_file_sha256 c1e2824b… PRE==POST)
🔑 Bằng chứng WRITE thật sự đã xảy ra (không phải no-op giả):
password ARGON2 HASH PRE 3c3751541e585bdc → POST 931cfcf4885ed88a *** ĐỔI ***
Cùng plaintext, salt argon2 mới ⇒ Directus thật sự đã ghi lại password. Đây chính là điều biến drill thành bằng chứng có giá trị: đường ghi đã được thực thi đầu-cuối, mà plaintext không đổi.
32. CURRENT PASSWORD LOGIN PROOF (POST)
CURRENT_PASSWORD_AUTH = PASS
LOGIN_CHECK | login_http=200 | me_http=200 | id=6abdec55-… | email=admin@example.com | logout_http=204 | MATCH=True
Dùng chính giá trị plaintext cũ, trích bằng chính helper/loader — đăng nhập được sau drill.
33. STATIC TOKEN PRE / POST
STATIC_TOKEN_AUTH_POST = PASS
VERIFY | http=200 | id=6abdec55-… | email=admin@example.com | status=active | role=Administrator
fingerprint DB token PRE 9e2f904336904179 == POST 9e2f904336904179
fingerprint .env token PRE 9e2f904336904179 == POST 9e2f904336904179
STATIC_TOKEN_PASSWORD_RESET_BEHAVIOR = STATIC_TOKEN_SURVIVES_PASSWORD_RESET_PROVEN
⇒ Phao rollback vẫn nguyên vẹn sau khi đổi password. Đây là điều kiện tiên quyết để C2B dám rotate password.
34. RECONCILE DRY-RUN PROOFS (POST)
RECONCILE_TASKS_DRY_RUN = PASS rc=0 "Tasks: 10 synced, 0 missing · Comments: 75 synced, 0 missing · All in sync!"
RECONCILE_KNOWLEDGE_DRY_RUN = PASS rc=0 "All in sync!" · "Created: 0 (would create)"
Chạy trong env cron-equivalent: env -i HOME=/root LOGNAME=root PATH=/usr/bin:/bin SHELL=/bin/sh
FATAL=0 · Traceback=0 · strict HTTP-401/403 & auth-failure markers = 0 · WRITE = 0
⚠️ Ghi nhận minh bạch: lần grep đầu của tôi báo "71 error markers" ở reconcile-knowledge. Đó là
dương tính giả do chính regex của tôi — 401/403 khớp id tài liệu Directus (id=401, id=2403)
và tên file fix-permissions-403-report. Đếm chặt theo word-boundary/ngữ cảnh HTTP = 0. Tôi kiểm lại
thay vì báo cáo một lỗi không tồn tại, và cũng không lặng lẽ bỏ qua nó.
35. SESSION BEHAVIOR RESULT
PASSWORD_RESET_SESSION_BEHAVIOR = ALL_OBSERVED_SESSIONS_INVALIDATED
sessions: 75 (trước PATCH) → 0 (sau PATCH) → 2 (sau reconcile dry-run, cả 2 từ 172.18.0.5 Python-urllib)
Dự đoán trước khi chạy, từ source (services/users.js):
else if (data['password'] !== undefined || data['email'] !== undefined) {
await this.clearUserSessions(keys, this.accountability?.session);
}
// excludeSession undefined ⇒ DELETE FROM directus_sessions WHERE user IN (keys)
Vì drill xác thực bằng static token (không có session), accountability.session = undefined
⇒ xoá sạch, không chừa. Đúng như dự đoán.
⇒ Bài học vận hành cho C2B: đổi password và đổi email đều xoá session. Nếu C2B thực hiện từ một
session (password login) thì session đang dùng sẽ được chừa lại — khác hành vi với static token.
Và: payload C2B chỉ được chứa password; kèm email sẽ nhân đôi tác động ngoài ý muốn.
36. BALO GUARD
BALO_ONE_CLICK_GUARD = PASS | checks=37 (PRE 37/37 == POST 37/37)
"PASS fingerprint unchanged by read-only probes"
37. KB / MCP READ HEALTH
KB_MCP_READ_HEALTH = PASS
list_documents ✅ · batch_read (full) ✅ · search_knowledge semantic ✅ · agent-data /health = 200
38. CONTAINER / SERVICE ZERO-TOUCH
CONTAINER_IDS_PRE=POST ✅ 11/11 SAME_ID (không recreate)
STARTED_AT_PRE=POST ✅ diff containers.DRILL_PRE vs POST/FINAL = IDENTICAL (0 dòng khác)
OTHER_SERVICE_MUTATION = 0
SERVICE_RESTART = NO DIRECT_DB_WRITE = NO
Thao tác duy nhất chạm container: docker cp + docker exec vào incomex-agent-data (đúng hành vi wrapper
thường ngày) và docker exec postgres psql read-only SELECT. Không restart/recreate gì.
⚠️ Nhiễu nền phải khai báo (KHÔNG do mission gây ra): incomex-nuxt tự restart trong lúc tôi làm
read-only — RestartCount 7 → 9, StartedAt 10:10:23Z → 11:51:59Z, cùng container ID.
ExitCode=0 · OOMKilled=false · RestartPolicy=unless-stopped
⇒ tiến trình THOÁT SẠCH rồi bị Docker khởi động lại — không phải crash, không phải OOM, không liên quan auth
(các 403 trong log Directus là thiếu quyền Public policy trên /items/pages…, không dính admin credential)
Vì vậy phép chứng minh zero-touch dùng container ID cho cả 11 (bắt recreate) cộng StartedAt/RestartCount, và bọc drill bằng ảnh chụp sát hai đầu. Trong đúng cửa sổ drill, cả 11 container identical, kể cả nuxt. 🔴 Đây là vấn đề production độc lập đáng điều tra riêng (nuxt tự thoát ~1–2 giờ/lần).
39. C2B LOCKED SCOPE
C2B_SCOPE = ROTATE_PASSWORD_AND_STATIC_TOKEN_AS_ONE_ADMIN_CREDENTIAL_SET
Bắt buộc theo §12/§29 vì ADMIN_STATIC_TOKEN_EXPOSURE = CURRENT_AND_HISTORICAL_FOUND
(37 file hiện hành + mọi PG dump + Drive nightly). Không được mặc định password-only.
40. C2B SEQUENCE DESIGN — THIẾT KẾ, KHÔNG THỰC HIỆN
1. Giữ static token CŨ làm phao rollback tạm thời (đã chứng minh sống sót qua password reset).
2. Sinh candidate password thoả policy (không policy) — 🔴 KHÔNG chứa dấu nháy đơn `'` (§20 case C).
3. Round-trip candidate qua exact consumer path → PASS trước khi đụng Directus.
4. Tạo SM secret MỚI `DIRECTUS_ADMIN_PASSWORD` + add version (Owner có roles/owner, đủ quyền).
5. Read-back HMAC PASS (đối chiếu SM ↔ giá trị định áp — vá luôn khoảng trống "SM chưa từng đối chiếu").
6. PATCH /users/<id> {"password": …} bằng static token cũ — CHỈ field password.
7. Materialize protected cache: ghi lại /etc/incomex/reconcile/directus-admin.env (atomic, 0600 root).
8. Cập nhật `docker/.env` DIRECTUS_ADMIN_PASSWORD (bootstrap KHÔNG re-apply, nhưng đây là bản plaintext
của chìa cũ + là nguồn nếu DB bị re-init) — trong cùng transaction credential.
9. Login PASS bằng password mới.
10. reconcile-{tasks,knowledge} --dry-run PASS + dot-*-health consumers PASS.
11. CHỈ KHI đường password chắc chắn → rotate static token (PATCH token).
12. Ghi token mới vào SM `DIRECTUS_ADMIN_TOKEN` version mới (nếu Owner duyệt).
13. New static token /users/me PASS.
14. Old static token bị từ chối (đúng 1 lần đo).
15. Old password bị từ chối — ĐÚNG MỘT LẦN, ở cuối (nhớ: 25 fail liên tiếp ⇒ suspend; 1 lần là an toàn).
16. Cleanup phao tạm + shred key.
Sau C2B: C3 rewrite git history (2 object password) + xử lý nhánh GitHub; C4 xoá .env.bak* + evidence JSON
+ token.txt + sửa /root/.bashrc; quyết định retention Drive (dump cũ vẫn mang token cũ).
🔴 Cảnh báo cho C2B: rotate password không vô hiệu hoá static token, và rotate token không vô hiệu hoá password trong git history. Chỉ làm cả hai + sanitize mới đóng được exposure.
41. FUTURE PERSONNEL / IDENTITY SSOT BACKLOG
Ghi nhận, không triển khai: bảng nhân sự làm SSOT danh tính → ánh xạ sang Directus user/role/policy →
bootstrap admin trở thành break-glass hoặc bị vô hiệu hoá. Dữ liệu hữu ích C2A để lại cho việc đó:
nmhuyen@gmail.com đã active + có password + có token nhưng role NULL ⇒ chỉ cần cấp policy là dùng được,
không cần tạo user mới. 7 user agent.* đang suspended nhưng vẫn giữ static token.
42. GIT COMMITS AND BUNDLES
COMMITS = 0 (báo cáo đi thẳng KB; không stage, không commit, không push)
BUNDLES : opt-incomex-PRE 962a2cfe… · agent-data-repo-PRE 8d860734… — cả 2 verify PASS
root-only /root/c2a-checkpoint-…/bundle, ngoài Drive/GitHub/KB
HEAD PRE == HEAD POST : /opt/incomex 2b086472 · agent-data-repo 7f13207f
dirty /opt/incomex PRE == POST : 104 (15 M + 89 ??) — unrelated work giữ nguyên
43. EVIDENCE PATHS
CHECKPOINT /root/c2a-checkpoint-20260718T110800Z (root:root 0700)
INTERIM-STATE.md (0600, không chứa giá trị secret)
bundle/{opt-incomex,agent-data-repo}-PRE.bundle + bundles.sha256 (verify PASS)
evidence/containers.{PRE,DRILL_PRE,POST,FINAL}
evidence/fingerprints.{PRE,POST}
work/c2a-rollback.py (sha256 08fa8cf836986c72…)
WORKDIR /root/c2a-work/{c2a-fp.py, c2a-rollback.py, scan-*.txt} (0700)
KEY work/mission-hmac.key → ĐÃ SHRED sau POST ⇒ fingerprint một chiều, vô dụng ngoài phiên
LỆNH ĐO docker exec postgres psql -tA (SELECT read-only) · docker inspect --format (names/StartedAt)
· docker exec incomex-directus cat/sed/grep <source .js trong image> (đọc source thật)
· grep -rlF -f <tmpfs pattern> · git rev-list --objects --all | git cat-file --batch | grep -cF -f
· git bundle create/verify · gcloud secrets list/describe/versions list/get-iam-policy (metadata only)
· crontab -l · systemctl · dot-balo-one-click-guard
44. PAYLOAD = REDACTED PROOF
Báo cáo này chứa: tên biến, độ dài byte, fingerprint HMAC-SHA256 rút gọn 16 hex (khoá ngẫu nhiên
32 B đã shred), và REDACTED. Không password, không token, không API key, không hash xác thực,
không connection string, không TLS key.
Fingerprint không đảo ngược được và vô dụng ngoài phiên này — chúng chỉ chứng minh quan hệ bằng/khác
giữa các giá trị tại thời điểm đo.
KẾT THÚC BẮT BUỘC — SCOPE PROOF
DIRECTUS_NEW_PASSWORD_APPLIED = NO (chỉ set lại CHÍNH plaintext hiện hành)
DIRECTUS_PASSWORD_PLAINTEXT_CHANGED = NO
DIRECTUS_STATIC_TOKEN_ROTATED = NO DIRECTUS_STATIC_TOKEN_REVOKED = NO
DIRECTUS_SESSIONS_REVOKED = NO (không chủ động thu hồi; 75 session bị xoá là TÁC DỤNG PHỤ
tất yếu của password PATCH, đã công bố trước khi xin GO)
DIRECTUS_EMAIL_CHANGE = NO DIRECTUS_ROLE_POLICY_CHANGE = NO
DIRECTUS_USER_CREATION = NO NMHUYEN_ACCOUNT_CHANGE = NO
TFA_CHANGE = NO PERSONNEL_TABLE_CHANGE = NO
SECRET_MANAGER_MUTATION = NO RUNTIME_ENV_CHANGE = NO
DOCKER_ENV_CHANGE = NO CONTAINER_MUTATION = NO
SERVICE_RESTART = NO DIRECT_DB_WRITE = NO
PRODUCTION_RECONCILE_WRITE = NO PRODUCTION_DRIVE_BACKUP_RUN = NO
GITHUB_PUSH = NO GIT_HISTORY_REWRITE = NO
HISTORICAL_BACKUP_DELETE = NO DOCKER_CLEANUP = NO
GIT_COMMIT = NO
Mutation đã thực hiện, ĐÚNG MỘT:
PATCH /users/6abdec55-d911-44df-af96-3cf60b9654af?fields=id,email,status {"password": <giá trị hiện hành>}
→ HTTP 200, 222 ms — password hash được ghi lại (salt mới), plaintext KHÔNG đổi
→ tác dụng phụ tất yếu: 75 directus_sessions bị xoá (đã phục hồi bình thường: reconcile tự tạo lại)
FACTS NEXT AGENT MAY RELY ON
✅ admin@example.com = 6abdec55-d911-44df-af96-3cf60b9654af, full-admin DUY NHẤT (1/13)
✅ 1 policy admin_access=t (8a613123) → gắn 1 role (a40a1070) → 1 user. Roles KHÔNG có parent.
✅ TFA tắt toàn bộ 13 user · auth_password_policy=NULL (KHÔNG policy) · auth_login_attempts=25
✅ Lockout = 25 fail LIÊN TIẾP ⇒ status='suspended'; login thành công RESET bộ đếm; duration:0; store=memory
✅ Directus 11.5.1 lưu static token PLAINTEXT trong directus_users.token (đo bằng giá trị)
✅ .env DIRECTUS_ADMIN_TOKEN == directus_users.token(admin) == agent-data == nuxt
✅ claude-mcp DIRECTUS_TOKEN = token của tac-agent, KHÔNG phải admin ⇒ rotate admin token không gãy claude-mcp
✅ Static token auth STATELESS: không tạo session, không cập nhật last_access
✅ bootstrap chạy mỗi lần start NHƯNG createDefaultAdmin chỉ khi isInstalled()==false ⇒ KHÔNG re-apply
✅ PATCH password ⇒ clearUserSessions ⇒ xoá TOÀN BỘ session của user (trừ session của chính caller nếu có)
✅ Static token SỐNG SÓT qua password reset (đã chứng minh bằng drill)
✅ Protected file dùng dạng DIRECTUS_PASSWORD='<val>' ⇒ giá trị chứa `'` sẽ FAIL-CLOSED (exit 3)
✅ Mọi ký tự đặc biệt khác round-trip PASS qua set -a → docker exec -e
✅ SM: DIRECTUS_ADMIN_TOKEN CÓ (v1, chưa xoay); DIRECTUS_ADMIN_PASSWORD KHÔNG CÓ; Owner = roles/owner
✅ Không service nào đọc SM ⇒ SM_LATEST_AUTO_APPLY=NO
✅ nmhuyen@gmail.com: active, password + token CÓ, role NULL, chưa từng login
✅ dot-apr-execute (*/5) HỎNG: không kết nối được localhost:8055 ⇒ KHÔNG phải consumer Directus
✅ Reconcile tạo session MỚI mỗi run ⇒ xoá session cũ vô hại
✅ backup-to-gdrive.sh L43 pg_dump directus ⇒ static token plaintext rời VPS mỗi đêm, không mã hoá
✅ /root/.bashrc:107 export DIRECTUS_ADMIN_TOKEN (chỉ ảnh hưởng shell TƯƠNG TÁC; non-interactive bị L6 chặn)
ASSUMPTIONS NEXT AGENT MUST NOT MAKE
❌ ĐỪNG coi C2A đã đóng exposure — KHÔNG đổi password, KHÔNG rotate token
❌ ĐỪNG gộp password và token thành một đường rò: password ở GIT HISTORY, token ở PG DUMP. Khác nhau hoàn toàn.
❌ ĐỪNG nghĩ rewrite git history (C3) sẽ dọn được static token — token có 0 object trong git
❌ ĐỪNG nghĩ rotate token dọn được password — password nằm trong git object + GitHub
❌ ĐỪNG dùng `directus users passwd` CLI — password vào argv (CLI_ARGV_SECRET_UNSAFE=YES)
❌ ĐỪNG gửi kèm `email` trong payload PATCH password — cũng kích hoạt clearUserSessions
❌ ĐỪNG sinh candidate password chứa dấu nháy đơn `'` — protected-file format sẽ fail-closed
❌ ĐỪNG thử password sai để "kiểm tra" — 25 lần liên tiếp ⇒ tài khoản admin bị SUSPENDED
❌ ĐỪNG tin SM restore được production — chưa từng đối chiếu payload ↔ runtime (C2A cố ý không đọc payload)
❌ ĐỪNG coi 73 session là 73 consumer đang hoạt động — chúng là rác của script login-rồi-không-logout
❌ ĐỪNG coi nuxt RestartCount tăng là do mission — nuxt tự thoát ExitCode=0 ~1–2h/lần, có từ trước
❌ ĐỪNG grep lỗi bằng regex lỏng ('401'/'403' khớp ID tài liệu Directus) — dùng word-boundary/ngữ cảnh HTTP
❌ ĐỪNG chạy code-backup-to-gdrive.sh thủ công (retention 56==REMOTE_KEEP ⇒ xoá artifact cũ)
DỪNG sau báo cáo. Không tự soạn hoặc chạy C2B.