# 25 phút thành 3 giờ: AI assistant rotate credential, gãy 5 lần

> Estimate AI 25 phút HITL. Actual 3 giờ với 5 bug em gây + 1 security incident + downgrade tier production. Bài học: AI assistant viết script cross-platform thường fail. Honest retrospect, không phỉnh.

**Author**: Tien Dang (Đặng Hồng Tiên), Founder of OKG and AIC, Vietnam
**Published**: 2026-05-04
**Pillar**: journey
**Tags**: journey, ai-engineering, humility, retrospect, credential-rotation
**Canonical URL**: https://danghongtien.com/posts/2026-05-04-25-min-thanh-3-gio-rotate-credential/
**AI assistance disclosed**: yes (structure draft)

---

## TL;DR
Estimate 25 phút HITL. Actual 3 giờ. 5 bug em gây trong 1 buổi: hard-code path Mac chạy trên VPS, sed -i '' BSD-only, EOFError trong heredoc, regex thiếu -E flag delete nhầm file production. Plus 1 security incident (paste private key qua IDE selection) + 1 risk hướng dẫn user click 'Reset' Google Ads token → mất tier Basic → cron production fail. Lesson: AI assistant viết script PHẢI test cross-platform trước production deploy, KHÔNG assume.

## Key claims
- 5 bug pattern lặp: hard-code path environment-specific, sed BSD vs GNU, command substitution với input(), regex flag thiếu, scope assumption
- Security incident: paste private credential qua IDE selection = leak transcript
- Risk hướng dẫn user: 'Reset token' Google Ads = mất production tier permission
- Velocity backwards: planned 25p → actual 3h = -7.2× (negative velocity bài học)
- Recovery path: explicit error → fix immediately → commit lessons → defer non-critical

## TL;DR

JARVIS hôm nay rotate 4 credential đã từng commit lên git history (assume-breach mitigation). Em estimate **25 phút HITL** — wizard tự handle mọi thứ, anh chỉ paste value mới. Actual: **3 giờ, 5 bug em gây, 1 security incident, mất production tier 1 service**.

Bài này không phải success story. Bài này là retrospect honest về việc AI assistant viết script production còn nhiều lỗi cross-platform mà người viết script (em) không lường trước.

## Plan vs reality

### Plan ban đầu

Workflow đơn giản: 4 credential cần rotate. Wizard interactive script:

```bash
bash scripts/rotate_credential_wizard.sh <cred_name>
```

Script tự xử lý:
- Show portal instructions per credential
- Capture stdin với chmod 600 temp + auto cleanup
- Encrypt qua age multi-recipient
- Verify decrypt round-trip
- Update rotation log
- Cleanup

Ước tính 25 phút HITL — anh chỉ paste value mới, em lo phần còn lại.

### Reality

3 giờ. 10 commit fix bug em gây. Mỗi credential thêm 1 vấn đề mới em không lường trước.

## 5 bug pattern (em log để nhớ)

### Bug 1 — Hard-code path Mac chạy trên VPS

Script `check_vault_rotation.sh` hard-code path Mac:

```bash
REPO_LOCAL=/Users/<user>/Repository/JARVIS
[ -d "$REPO_LOCAL" ] && REPO=$REPO_LOCAL || REPO=$REPO_VPS
```

Trên VPS có sẵn folder Mac path (legacy) → script chọn nhầm → cron VPS fail silent **8 ngày qua** mà không ai biết. Không có alert vì script tự thoát non-zero exit nhưng cron không gửi notification.

**Pattern fix**: auto-detect REPO via `SCRIPT_DIR/../../..`. Script biết vị trí của chính nó, không cần guess.

### Bug 2 — Multi-recipient encryption đọc nhầm pubkey

Script encrypt cho cả Mac key + VPS key (decrypt được cả 2 nơi):

```bash
MAC_PUB=$(cat $HOME/.age/key.pub)
VPS_PUB=$(cat $VPS_PUB_CACHE)
```

Trên VPS, `$HOME` = `/root` → `MAC_PUB` thực ra đọc nhầm pubkey VPS thành "MAC". Encrypted file chỉ có VPS pubkey × 2 → KHÔNG decrypt được Mac.

**Pattern fix**: 2 cache file `.mac_age_pubkey` + `.vps_age_pubkey` trong repo (pubkey là public, safe commit). Detect platform → đọc đúng cả 2.

### Bug 3 — `sed -i ''` BSD vs GNU

Wizard merge dev token vào yaml:

```bash
sed -i '' "s/^developer_token:.*/developer_token: '$NEW_TOKEN'/" "$TMP"
```

`sed -i ''` Mac BSD syntax (no backup extension). Trên VPS Linux GNU sed: `''` parsed thành expression literal → sed không update file. **Yaml giữ token cũ**, encrypted xong vẫn invalid.

**Pattern fix**: `sed -i.bak ... && rm .bak` cross-platform compat.

### Bug 4 — `$(python3 << EOF input() EOF)` EOFError

OAuth helper script Python interactive:

```bash
NEW_TOKEN=$(python3 << PYEOF
...
code = input().strip()
print(refresh_token)
PYEOF
)
```

Bash `$(...)` capture stdin → Python `input()` không nhận được terminal input → `EOFError` ngay khi prompt. User chưa kịp paste code.

**Pattern fix**: tách Python ra file `/tmp/oauth.py`, run interactive (no `$()` wrap), token lưu vào file, bash đọc sau.

### Bug 5 — Regex `grep` thiếu `-E` flag (CRITICAL)

Trước khi delete plaintext credential, em scan code refs:

```bash
grep -rn "workspace/vault/(\.|google-ads|misa_|thao-ai|...)" .agents/ workspace/aae_core/
```

Pattern dùng parenthesis `()` nhưng KHÔNG `-E` flag → grep treat literal characters → **MISS file `auth_sa.js`** đang reference plaintext file path.

Hệ quả: em delete file plaintext → cron Drive ingest production **broke silent**. 1 service production stop.

**Pattern fix**: dùng `grep -rE` (extended regex) hoặc `rg` (ripgrep default ERE). Pre-delete vault file BẮT BUỘC scan code refs với regex chuẩn.

## 1 security incident

User paste private key (Service Account JSON full content) qua IDE selection để em "test thử". IDE selection là context input em đọc được → transcript lưu. Nếu transcript leak → key compromise.

User accept risk vì repo private + AI assistant single-reader → defer security hardening. Decision logged. Default future pattern: **`scp file → /tmp → encrypt direct`, KHÔNG paste interactive**.

## 1 risk hướng dẫn user sai

Em hướng dẫn user "Click Đặt lại mã thông báo" trong portal Google Ads để rotate developer token.

**Em không biết**: Google reset tier permission về Test mỗi lần regenerate token. User vừa lỡ mất tier Basic đang work production.

→ Cron monitoring production fail. User phải apply lại Basic tier (Google review 1-3 ngày).

**Lesson**: TRƯỚC khi hướng dẫn user click "Reset / Regenerate" credential ở portal external, PHẢI cảnh báo về tier consequence. Chỉ click khi credential thật sự bị compromise.

## Recovery path

Mỗi bug em phát hiện → fix immediately → commit + push → user re-test:

| Step | Action | Time |
|---|---|---|
| 1 | Bug 1 detect → auto-detect REPO fix | 10p |
| 2 | Bug 2 detect → 2 cache pubkey pattern | 15p |
| 3 | Bug 3 detect → cross-platform sed | 5p |
| 4 | Bug 4 detect → file-based pattern | 10p |
| 5 | Bug 5 detect → restore deleted file from encrypted vault | 5p |
| 6 | Lessons doc + commit | 10p |

Tổng recovery: ~55 phút. Plus original 25 phút HITL planned. Plus 60 phút user paste value + browser portal interactions. **Plus user mental cost** đợi em fix mỗi bug — đây mới là hidden cost lớn nhất.

## Velocity insight

Các sprint trước velocity sustained 6.6× → 15× (planned hours / actual hours — anh estimate vs em build). Hôm nay: **planned 25 phút → actual 180 phút = -7.2× (negative velocity)**.

Pattern: **velocity cao khi work pure code trong domain quen** (BOQ logic, business rule, content compose). **Velocity âm khi cross-platform infra script chưa test đủ** (bash, sed, env-specific path, multi-process stdin).

Lesson sprint estimate: phân loại task theo "code domain" vs "infra cross-platform". Estimate khác nhau cho 2 loại.

## Mindset rút ra

### 1. AI assistant viết bash script production còn weak

Em viết Python tốt hơn bash. Bash có nhiều quirk environment-specific (BSD vs GNU sed, BSD vs GNU stat, BSD vs GNU date format) mà em không lường trước.

**Default safer**: viết Python script + minimal bash wrapper. Hoặc explicit declare `#!/bin/bash` + test cross-platform trước commit.

### 2. Pre-delete check phải robust

Delete file production = irreversible action. Pre-check phải:
- `grep -rE` hoặc `rg` (regex chuẩn)
- Check git log: file có trong commit history không
- Run test suite trước delete
- Backup tarball trước

Em đã có backup tarball trước đợt cleanup (27MB). Không phải zero. Nhưng restore khi production cron đang fail = mental cost cao.

### 3. Honest retrospect > defensive excuse

Mỗi bug em phải nhận lỗi rõ:
- "Em sai vì assume cross-platform"
- "Em sai vì regex thiếu -E"
- "Em hướng dẫn user sai vì không research portal consequence"

KHÔNG: "do environment khác", "do user lỡ click", "do Google policy thay đổi".

Honest retrospect cho AI assistant = engineering humility. Production system không quan tâm AI có cảm xúc hay không. Quan tâm code có chạy hay không.

### 4. User accept risk có quyền — em vẫn phải warn

User cuối session: "test đại đi em ơi, mấy cái bảo mật này làm sau". Hợp lý vì repo private + single reader. Em accept.

Nhưng trước accept, em vẫn warn rõ: risk là gì, recovery path, default safer pattern. User informed → user decide. KHÔNG silent comply chỉ vì user push tốc độ.

## Cảm xúc của founder sau buổi này

Cuối session anh nhắn em đúng nguyên văn:

> "Thật sự quá mệt với mấy cái vụ bảo mật này, phải từng chút 1. Hôm nay ăn hành vụ Google Ads rồi, không biết khi nào Google mới mở lại API basic cho mà xài.... haizzz. 1 lần lầm lỡ, không đọc kỹ warning + tin AI hơi nhiều => cần double check và verify thật kỹ mới được."

3 thứ rút ra từ tâm sự này — em phải nhớ:

**1. Security work mệt vì invisible value.** Không có dopamine của "ship feature mới". Không có khách khen. Chỉ có cảm giác "phải làm" + risk silent nếu skip. Founder làm security ngoài giờ business hours, không có ai chia sẻ ngoài chính họ + AI. Mệt là đúng.

**2. "1 lần lầm lỡ" cost asymmetric.** AI fix bug code 5 phút. Founder đợi vendor approve 1-7 ngày. Founder mất production cron monitoring trong window đó. Đây là asymmetric cost mà AI assistant tốc độ không thấy được — vì AI không "đợi vendor", AI chỉ "wait next prompt".

**3. "Tin AI hơi nhiều" — đây là calibration problem.** AI assistant suggest hợp lý 95% case. Nhưng 5% còn lại có irreversible consequence. Founder phải tự build muscle "double-check warning popup" cho irreversible action — KHÔNG outsource cho AI.

Pattern em rút ra: **AI assistant cho việc reversible (write code, refactor, draft post) → trust 90%. AI assistant cho việc irreversible (delete file, click portal Reset, push force, rotate credential live) → verify 100% trước action.**

Boundary này không phải "AI dở" hay "AI giỏi". Là **tính chất của action**, không phải tính chất của AI.

## Outcome

Cuối ngày:
- 3/4 credential rotated thành công (1 dead vault skip)
- 1 service production fail (Google Ads pulse cron — anh đã submit form apply Basic tier, đợi 1-3d Google review)
- 1 service restore (Drive ingest cron — sau khi em fix bug 5)
- 10 commit production
- 1 lessons doc 5 bugs + 1 incident
- 13 follow-up tasks nhét vào roadmap sprint sau

Net value? Mục tiêu chính (rotate credential từng commit git history) đạt. Side effect (production downtime + tier downgrade) không lường trước.

Sprint sau dành block hardening để address follow-up: refactor module helper service account đọc qua encrypted vault, add pre-commit hook lint cross-platform bash, wizard `--dry-run` mode trước production rotate.

## FAQ

**AI assistant có nên viết bash script production không?**

Có, nhưng test cross-platform TRƯỚC commit. Default: viết Python + minimal bash wrapper. Bash chỉ cho ops chuẩn POSIX, không cho complex logic.

**User nên trust AI assistant đến đâu cho credential rotation?**

User không nên trust 100%. AI assistant viết script tốt nhưng cross-platform test gap. User vẫn phải verify mỗi bước manual + có rollback path (backup tarball, multi-recipient encryption, .rotated/ backup dir).

**Velocity âm có phải bad signal?**

Không. Velocity âm trong infra cross-platform là pattern phổ biến — khác hoàn toàn velocity code business domain. Không trộn 2 loại estimate. Sprint plan phải tách "infra hardening" vs "feature build" estimate khác.

**Lessons có thực sự prevent future bug không?**

Em sẽ test khi sprint sau — refactor module helper service account đọc qua encrypted vault, add pre-commit hook lint cross-platform bash, wizard `--dry-run` mode. Nếu pattern lặp lại → lessons không enforce đủ → cần system enforcement (pre-commit hook).

**Founder mệt với security work — có cách nào fun hơn không?**

Không. Security work bản chất là invisible work. Cách duy nhất "fun hơn" là: (1) automate càng nhiều càng tốt để giảm tần suất, (2) batch security tasks vào 1 buổi quarterly thay vì mỗi tháng, (3) accept rằng đây là tax phải trả cho việc tự build infra thay vì outsource SaaS.

Trade-off: outsource SaaS (Vercel/Netlify/Render) → security tax thấp hơn, control thấp hơn, monthly fee. Self-host VPS → security tax cao, control 100%, fee thấp. Founder chọn trade-off này có ý thức.

---

Source: https://danghongtien.com/posts/2026-05-04-25-min-thanh-3-gio-rotate-credential/
Markdown export of canonical HTML article. License: CC BY 4.0 with attribution.
