Người review: Grill QA
Ngày: 2026/07/19
Mức đánh giá: ❌ C: Không đạt — Rủi ro hệ thống nghiêm trọng, cần thiết kế lại từ đầu
Kế hoạch chia làm 2 repo + symlink + 2 cron git-sync độc lập chứa ít nhất 12 lỗ hổng kỹ thuật, trong đó 4 lỗi critical có thể dẫn đến mất dữ liệu runtime, lộ credentials, hoặc hệ thống không boot được. Phương án này không nên triển khai ở dạng hiện tại.
| File tracked trong CEO repo | Rủi ro |
|---|---|
scripts/auth_refresh.py |
Có thể chứa token/refresh token Google |
scripts/notebooklm_auth_watchdog.sh |
Script auth, dễ lộ credential |
scripts/rotate_gs_proxy.py |
Proxy credential |
brand-monitoring/brands/fulbright/keywords.yaml |
Keywords nghiệp vụ (rủi ro IP) |
.gitignore hiện tại KHÔNG đủ mạnh:
- Chỉ git restore --staged .env trong script auto-sync — nhưng nếu developer add thủ công git add .env và push, secret đã leak.
- Không có pre-commit hook chặn credential.
- Hậu quả: Một lần push lộ credential = Google OAuth token bị thu hồi, toàn bộ hệ thống notebooklm, gmail pipeline chết.
Trong kế hoạch hiện tại, cả 2 repo đều public (GitHub). Nếu config.yaml (chứa API keys, provider config) nằm ở system repo và vô tình bị push, hậu quả còn nghiêm trọng hơn vì attacker có luôn config để giả mạo Hermes.
state.db của mỗi profile (grill-qa: 30MB, it-ai: 38MB) chứa toàn bộ lịch sử hội thoại.git-auto-sync.sh hiện tại dùng git add -A rồi mới git restore --staged 'profiles/*/state.db' — đây là anti-pattern: git add -A trước rồi unstage sau rất dễ miss nếu đường dẫn thay đổi.Kịch bản 1: Một trong 2 repo bị git pull --rebase conflict. Symlink trỏ vào file đã bị conflict (.git/MERGE_HEAD hoặc file có conflict markers). Hermes đọc skill → đọc file lỗi → crash.
Kịch bản 2: Symlink dangling. Nếu ceo-ai-os repo được clone lại ở đường dẫn khác (CI/CD, server mới), symlink từ ~/.hermes/skills/ → /opt/ai-os/products/ceo/skills/ sẽ chết. Hermes mất toàn bộ skills = không hoạt động.
# Dòng 23: Pull với --rebase — conflict sẽ crash script
if ! git pull --rebase origin main >/dev/null 2>&1; then
true # Silent fail — KHÔNG xử lý conflict, KHÔNG log
fi
git pull --rebase khi có conflict sẽ để repo ở trạng thái rebase dở dang.git stash push -u stash cả untracked files — nếu có file lớn (state.db, model cache) sẽ treo hoặc tạo stash khổng lồ.git add -A add tất cả, kể cả file nhạy cảm — rất nguy hiểm.Tình huống: Cả 2 cron chạy đồng thời (hoặc lệch pha):
config.yaml thay đổi → pushskills/research-pipeline/SKILL.md thay đổi → push| File | Thuộc CEO? | Thuộc System? | Vấn đề |
|---|---|---|---|
cron_kanban_watcher.py |
✅ (scripts/) | ✅ (~/.hermes/scripts/) | Duplicate — tồn tại ở cả 2 nơi |
git-auto-sync.sh |
❌ | ✅ | Hiện ở CEO repo? |
SOUL.md |
✅ | ✅ (symlink) | Symlink chéo giữa 2 repo |
| Các skills CEO-specific | ✅ | ✅ (external_dirs) | Config.yaml dùng external_dirs trỏ vào CEO repo |
Phát hiện: Config.yaml của Hermes đã dùng skills.external_dirs trỏ thẳng vào /opt/ai-os/products/ceo/skills/. Điều này nghĩa là kế hoạch symlink là dư thừa — Hermes đã đọc được skills từ CEO repo qua external_dirs rồi. Symlink chỉ tạo thêm lớp phức tạp.
/root/.hermes/profiles/bd-mkt/skills → /opt/ai-os/products/ceo/profiles/str-mkt/skills ☠️
str-mkt đã được rename thành bd-mkt nhưng symlink vẫn trỏ vào đường dẫn cũ. Thư mục str-mkt/skills không tồn tại. Kết quả: profile bd-mkt không tìm thấy skills của nó. Nếu triển khai kế hoạch 2 repo + symlink, loại lỗi này sẽ nhân lên gấp bội.
Khi git-sync tự động push một thay đổi hỏng (ví dụ: config.yaml sai syntax), cả 2 repo đều đã bị overwrite. Không có pre-push validation, không có canary, không có backup.
Hiện tại Hermes cron jobs reference script bằng tên (vd: cron_kanban_watcher.py). Hermes dùng cơ chế path resolution để tìm script. Nếu cùng một script name tồn tại ở cả 2 repo, Hermes sẽ load script nào? Nếu không deterministic, cùng một cron job có thể chạy code khác nhau giữa các lần.
sequenceDiagram
participant C1 as Cron System Sync
participant C2 as Cron CEO Sync
participant R1 as System Repo
participant R2 as CEO Repo
C1->>R1: git pull --rebase
C2->>R2: git pull --rebase
C1->>R1: git add -A
C2->>R2: git add -A
C1->>R1: git commit + push
C2->>R2: git commit + push
Note over C1,C2: ✗ No cross-lock - possible<br/>interleaving corruption
Nếu 2 cron chạy overlapping, và có file symlink chéo (SOUL.md từ CEO repo được symlink vào Hermes runtime), thay đổi ở một repo có thể ảnh hưởng đến working tree của repo kia.
Script hiện tại silent fail mọi lỗi (|| true). Nếu sync không hoạt động trong 1 tuần, không ai biết. Git history sẽ mất tracking.
git add -A — dùng git add theo từng đường dẫn cụ thểdetect-secrets hoặc trufflehog)bd-mkt/skills → str-mkt/skills NGAYgit stash push -u — dùng git worktree hoặc --autostash an toàn hơnThay vì 2 repo + symlink, tôi đề xuất phương án an toàn hơn:
Phương án A: Monorepo + Package-based (Khuyến nghị)
- Giữ 1 repo duy nhất cho CEO AI OS
- Dùng git submodules hoặc subtree cho ~/.hermes/ config
- Hoặc dùng GitHub Actions / CI pipeline để deploy config từ repo vào runtime
Phương án B: Git-sync 1 chiều + backup
- CEO repo là source of truth
- Hermes runtime chỉ pull (không push)
- Dùng rsync hoặc deploy script để copy config vào ~/.hermes/
- Không có git trong runtime — tránh conflict
Phương án C: Nếu nhất định phải 2 repo
- System repo phải là private (chứa API keys)
- Dùng git submodule để CEO repo tham chiếu system repo (control version)
- Pre-push hook bắt buộc validate config YAML
- Mỗi lần sync phải tạo git tag để rollback
Ngoài phản biện kế hoạch, trong quá trình review tôi phát hiện thêm:
str-mkt/skills). Profile này không load được skills.cron_kanban_watcher.py duplicate ở cả ~/.hermes/scripts/ và ceo/scripts/ với cùng checksum — nhưng quyền khác nhau (755 vs 644). Khi cron chạy, Hermes sẽ load file theo đường dẫn nào? Không rõ.skills.external_dirs trỏ vào /opt/ai-os/products/ceo/skills/. Kế hoạch symlink skills là dư thừa — nếu muốn Hermes đọc skills từ CEO repo, external_dirs đã làm việc đó.~/.hermes/scripts/ không được version control: 17 scripts runtime đang ở ~/.hermes/scripts/ không có trong git. Nếu mất server, mất toàn bộ.| # | Rủi ro | Loại | Severity | Xác suất | Impact |
|---|---|---|---|---|---|
| 1 | Lộ credential qua git | Security | Critical | Cao | Mất quyền truy cập Google, toàn bộ pipeline |
| 2 | Symlink chết | Runtime | Critical | Trung bình | Hermes không boot được |
| 3 | Conflict git-sync kép | Integrity | Critical | Thấp | Mất dữ liệu git, không recover được |
| 4 | Silent fail sync | Ops | High | Cao | Mất tracking, không biết sync hỏng |
| 5 | Stale symlink profile | Runtime | High | Đã xảy ra | Profile không load skills |
| 6 | Path resolution ambiguity | Runtime | Medium | Cao | Cron chạy script sai |
| 7 | external_dirs trùng với symlink | Design | Medium | Chắc chắn | Overengineered, khó debug |
Đánh giá tổng thể: ❌ C — Không đạt
Kế hoạch hiện tại có quá nhiều lỗ hổng nghiêm trọng: - 🚫 Lộ credentials là khi nào chứ không phải có hay không - 🚫 Symlink không giải quyết được vấn đề — Hermes đã có external_dirs - 🚫 2 cron sync độc lập tạo race condition không kiểm soát - 🚫 Không có rollback, monitoring, validation
Khuyến nghị: Dẹp bỏ kế hoạch symlink + 2 repo. Giữ monorepo CEO làm source of truth. Dùng CI/CD để deploy config vào Hermes runtime. Nếu muốn split, làm private submodule chứ không public.
Lưu ý cho CEO: Trước khi nghĩ đến tái cấu trúc, fix ngay stale symlink bd-mkt/skills và thêm pre-commit hook chặn credential — 2 lỗi đang active trên hệ thống hiện tại.