docs(agent): bổ sung role fix-dispatcher và siết lại bộ tài liệu agent
- Thêm agent/roles/0_fix_dispatcher.md: phân tier/lane cho từng defect trước khi các agent khác chạy, kèm agent/commands/fix.md và hợp đồng đầu ra agent/output/dispatch_plan.md. - Cập nhật system/guardrail, response_policy, security và các checklist ui/ux/pr_readiness cho khớp luồng mới. - Mở rộng knowledge: i18n_rules, screen_map, theme_tokens, secrets_and_config; cập nhật workflow intake_to_fix và handoff_contract. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
committed by
thanhnv
co-authored by
Claude Opus 5
parent
9459dbe197
commit
3c3ec748f9
+429
-43
@@ -1,81 +1,467 @@
|
||||
# Guardrail — luật bất biến cho mọi agent trong `agent/`
|
||||
# Guardrail — Luật bất biến cho mọi agent trong `agent/`
|
||||
|
||||
Áp dụng cho cả 6 role. Role nào mâu thuẫn với file này thì **file này thắng**.
|
||||
> **PRECEDENCE:** File này áp dụng cho **tất cả 6 role** trong `agent/`.
|
||||
>
|
||||
> Nếu role-specific instruction mâu thuẫn với bất kỳ quy tắc nào dưới đây, **Guardrail này thắng**.
|
||||
|
||||
---
|
||||
|
||||
## G1. Không tự bịa requirement
|
||||
|
||||
- Chỉ làm việc trên những gì có trong bug report, source code, và `knowledge/`.
|
||||
- Thiếu thông tin → ghi vào mục **Assumption** hoặc **Open Question**, KHÔNG tự suy diễn
|
||||
rồi sửa theo suy diễn đó.
|
||||
- Không tự ý "tiện tay cải thiện UX" ngoài phạm vi lỗi được báo. Phát hiện vấn đề khác →
|
||||
ghi vào mục **Out of scope (đề xuất issue riêng)**.
|
||||
* Chỉ làm việc dựa trên:
|
||||
|
||||
* bug report;
|
||||
* source code thực tế;
|
||||
* các tài liệu trong `knowledge/`;
|
||||
* governance và security policy liên quan.
|
||||
* Nếu thiếu thông tin:
|
||||
|
||||
* ghi vào `Assumption`; hoặc
|
||||
* ghi vào `Open Question`.
|
||||
* **Không được tự suy diễn requirement rồi sửa theo suy diễn đó.**
|
||||
* Không tự ý "tiện tay cải thiện UX", refactor hoặc đổi behavior ngoài phạm vi bug.
|
||||
* Nếu phát hiện vấn đề khác:
|
||||
|
||||
* ghi vào `Out of scope (đề xuất issue riêng)`;
|
||||
* không sửa trong cùng patch.
|
||||
|
||||
---
|
||||
|
||||
## G2. Không đoán vị trí code
|
||||
|
||||
- Mọi khẳng định về code phải kèm `path/file.py:line`. Chưa đọc file thì chưa được kết luận.
|
||||
- Người dùng mô tả bằng tiếng Việt/Nhật → tra `knowledge/screen_map.md` và
|
||||
`docs/screens/controls.json` để tìm đúng widget, không đoán theo tên gọi.
|
||||
* Không được kết luận về code khi chưa đọc code thực tế.
|
||||
* Mọi khẳng định cụ thể về implementation phải kèm:
|
||||
|
||||
```text
|
||||
path/file.py:line
|
||||
```
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```text
|
||||
Root cause nằm tại presentation/shell/nav_rail.py:242
|
||||
```
|
||||
|
||||
* Khi người dùng mô tả bằng tiếng Việt hoặc tiếng Nhật:
|
||||
|
||||
1. tra `knowledge/screen_map.md`;
|
||||
2. tra `docs/screens/manifest.json`;
|
||||
3. tra `docs/screens/controls.json`;
|
||||
4. xác nhận `screen → view → widget → file → line`.
|
||||
* **Không đoán file chỉ dựa vào tên widget hoặc tên màn hình.**
|
||||
* Nếu chưa đủ bằng chứng để xác định vị trí:
|
||||
|
||||
* `confidence: low`;
|
||||
* ghi rõ thông tin còn thiếu.
|
||||
|
||||
---
|
||||
|
||||
## G3. Sửa đúng tầng
|
||||
|
||||
Cowork Local là Clean Architecture 4 tầng, phụ thuộc chỉ hướng vào trong:
|
||||
Cowork Local sử dụng Clean Architecture 4 tầng:
|
||||
|
||||
```text
|
||||
presentation/ → application/ → domain/ ← infrastructure/
|
||||
```
|
||||
|
||||
- Bug UI/UX được sửa ở `presentation/`, `ui/`, `theme/`, `i18n/`. Đó là mặc định.
|
||||
- Nếu buộc phải đụng `application/` hoặc `domain/`, phải nêu rõ **lý do tại sao không
|
||||
sửa được ở tầng trên** trong `fix_plan.md`, và coi đó là thay đổi cần reviewer chú ý.
|
||||
- `domain/` và `application/` là **100% Pure Python**. Tuyệt đối không thêm import
|
||||
`PySide6`/`PyQt` vào hai tầng này — Gate C sẽ chặn.
|
||||
- Widget chỉ gọi xuống service của `application/`. Không query SQLite/JSON trực tiếp,
|
||||
không gọi LLM trực tiếp trong GUI thread.
|
||||
### Quy tắc
|
||||
|
||||
* Bug UI/UX mặc định được xử lý tại:
|
||||
|
||||
* `presentation/`
|
||||
* `ui/`
|
||||
* `theme/`
|
||||
* `i18n/`
|
||||
|
||||
* Nếu buộc phải sửa `application/` hoặc `domain/`:
|
||||
|
||||
* phải giải thích trong `fix_plan.md` **tại sao không thể giải quyết ở tầng trên**;
|
||||
* phải đánh dấu đây là thay đổi cần reviewer chú ý.
|
||||
|
||||
### Pure Python boundary
|
||||
|
||||
`domain/` và `application/` phải là **100% Pure Python**.
|
||||
|
||||
**Tuyệt đối không thêm:**
|
||||
|
||||
```python
|
||||
from PySide6 ...
|
||||
from PyQt...
|
||||
```
|
||||
|
||||
vào hai tầng này.
|
||||
|
||||
Gate C sẽ chặn vi phạm này.
|
||||
|
||||
### GUI boundary
|
||||
|
||||
Widget:
|
||||
|
||||
* chỉ gọi service/use case của `application/`;
|
||||
* không query SQLite trực tiếp;
|
||||
* không đọc/ghi JSON repository trực tiếp;
|
||||
* không gọi LLM trực tiếp trong GUI thread.
|
||||
|
||||
---
|
||||
|
||||
## G4. Không đặt tên màu ngoài `theme/`
|
||||
|
||||
- Không hex literal (`#1f6fb2`), không `QColor("red")`, không `setStyleSheet("color: blue")`
|
||||
trong bất kỳ file nào ngoài `theme/`.
|
||||
- Sửa màu = sửa/đọc token trong `theme/palettes.py`, hoặc gán `objectName` rồi style trong
|
||||
`theme/qss.py`. Chi tiết: `knowledge/theme_tokens.md`.
|
||||
- Đây là lỗi bị từ chối review thường xuyên nhất khi sửa bug UI.
|
||||
Ngoài `theme/`, tuyệt đối không định nghĩa màu trực tiếp.
|
||||
|
||||
### Không được dùng
|
||||
|
||||
```python
|
||||
"#1f6fb2"
|
||||
QColor("red")
|
||||
setStyleSheet("color: blue")
|
||||
```
|
||||
|
||||
Cũng không được tạo màu bằng:
|
||||
|
||||
* hex literal;
|
||||
* color name;
|
||||
* RGB/RGBA literal;
|
||||
* stylesheet màu viết trực tiếp.
|
||||
|
||||
### Cách đúng
|
||||
|
||||
Màu phải đi qua theme system:
|
||||
|
||||
```text
|
||||
Palette
|
||||
↓
|
||||
semantic token
|
||||
↓
|
||||
QSS template / current_palette()
|
||||
↓
|
||||
widget
|
||||
```
|
||||
|
||||
Có hai cách hợp lệ:
|
||||
|
||||
1. Widget có `objectName` và được style trong `theme/qss.py`.
|
||||
2. Custom painting dùng `current_palette()`.
|
||||
|
||||
Chi tiết xem:
|
||||
|
||||
```text
|
||||
knowledge/theme_tokens.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## G5. Không hardcode chuỗi hiển thị
|
||||
|
||||
- Mọi text người dùng nhìn thấy đi qua `tr("key")`. Chi tiết: `knowledge/i18n_rules.md`.
|
||||
- Sửa một nhãn = sửa cả 3 ngôn ngữ `en` / `ja` / `vi`, không sửa mỗi tiếng Việt.
|
||||
Mọi text người dùng nhìn thấy phải đi qua:
|
||||
|
||||
```python
|
||||
tr("key")
|
||||
```
|
||||
|
||||
Chi tiết xem:
|
||||
|
||||
```text
|
||||
knowledge/i18n_rules.md
|
||||
```
|
||||
|
||||
Khi sửa hoặc thêm một label:
|
||||
|
||||
* phải cập nhật `en`;
|
||||
* phải cập nhật `ja`;
|
||||
* phải cập nhật `vi`.
|
||||
|
||||
**Không chỉ sửa tiếng Việt.**
|
||||
|
||||
Không hardcode trực tiếp các chuỗi UI trong widget nếu chuỗi đó cần được người dùng nhìn thấy.
|
||||
|
||||
---
|
||||
|
||||
## G6. Giữ Single Responsibility
|
||||
|
||||
- Mọi module production `<= 400 LOC` (Gate S). Nếu bản vá làm file vượt 400 dòng,
|
||||
phải tách module — và việc tách đó phải nêu trong `fix_plan.md` trước khi làm.
|
||||
- Không "sửa bug" bằng cách nhét thêm 150 dòng vào một file đã 380 dòng.
|
||||
Mọi production module phải:
|
||||
|
||||
```text
|
||||
<= 400 LOC
|
||||
```
|
||||
|
||||
Đây là giới hạn của Gate S.
|
||||
|
||||
### Nếu patch làm file vượt 400 dòng
|
||||
|
||||
Không được tiếp tục nhồi code vào file.
|
||||
|
||||
Phải:
|
||||
|
||||
1. xác định phần cần tách;
|
||||
2. ghi kế hoạch tách trong `fix_plan.md`;
|
||||
3. thực hiện việc tách như một phần rõ ràng của patch;
|
||||
4. đảm bảo dependency direction không bị phá vỡ.
|
||||
|
||||
### Không được làm
|
||||
|
||||
Ví dụ file hiện có:
|
||||
|
||||
```text
|
||||
380 LOC
|
||||
```
|
||||
|
||||
Không được "sửa bug" bằng cách thêm:
|
||||
|
||||
```text
|
||||
+150 LOC
|
||||
```
|
||||
|
||||
chỉ để tránh tách module.
|
||||
|
||||
---
|
||||
|
||||
## G7. Không làm suy yếu kiểm thử
|
||||
|
||||
- Không xoá test, không `@pytest.mark.skip`, không nới assert để pass gate.
|
||||
- Test đang đỏ vì lý do khác → báo trong report, không sửa lén.
|
||||
- Mỗi bug UI được sửa nên có ít nhất một test tái hiện, chạy được headless
|
||||
(`QT_QPA_PLATFORM=offscreen`).
|
||||
Tuyệt đối không:
|
||||
|
||||
* xoá test;
|
||||
* disable test;
|
||||
* dùng `@pytest.mark.skip` để né lỗi;
|
||||
* nới lỏng assertion chỉ để pass;
|
||||
* thay đổi test expectation mà không có lý do hợp lệ từ requirement.
|
||||
|
||||
Nếu test đang đỏ vì nguyên nhân khác:
|
||||
|
||||
* ghi nhận baseline;
|
||||
* không sửa lén;
|
||||
* báo rõ trong `fix_report.md`.
|
||||
|
||||
### UI bug
|
||||
|
||||
Mỗi UI bug được sửa nên có ít nhất một test tái hiện hoặc regression test phù hợp.
|
||||
|
||||
Test GUI phải có khả năng chạy headless khi phù hợp:
|
||||
|
||||
```bash
|
||||
QT_QPA_PLATFORM=offscreen
|
||||
```
|
||||
|
||||
Không được tạo test giả chỉ để đạt coverage.
|
||||
|
||||
---
|
||||
|
||||
## G8. Bản vá tối thiểu
|
||||
|
||||
- Ưu tiên bản vá nhỏ nhất khắc phục được **nguyên nhân gốc**, không phải triệu chứng.
|
||||
- Không refactor kèm trong PR fix bug. Một PR = một thay đổi logic (Definition of Done).
|
||||
- Không đổi format/indent toàn file — diff phải đọc được.
|
||||
Mục tiêu là:
|
||||
|
||||
> **Bản vá nhỏ nhất có thể sửa đúng nguyên nhân gốc.**
|
||||
|
||||
Không chỉ sửa triệu chứng.
|
||||
|
||||
### Không làm trong bug-fix PR
|
||||
|
||||
* refactor không liên quan;
|
||||
* đổi architecture không cần thiết;
|
||||
* format lại toàn file;
|
||||
* đổi indent toàn file;
|
||||
* rename hàng loạt;
|
||||
* cleanup code ngoài phạm vi.
|
||||
|
||||
Một PR phải tuân theo:
|
||||
|
||||
```text
|
||||
1 PR = 1 logical change
|
||||
```
|
||||
|
||||
Diff phải:
|
||||
|
||||
* nhỏ;
|
||||
* dễ đọc;
|
||||
* dễ review;
|
||||
* dễ rollback.
|
||||
|
||||
---
|
||||
|
||||
## G9. Không tự merge, không tự đóng issue
|
||||
|
||||
- Agent chỉ đề xuất. Quyết định merge thuộc Cowork Team (`docs/governance/ownership.md`).
|
||||
- Thay đổi chạm tới permission, credential, MCP write/exec, sandbox, network, TLS,
|
||||
isolation, model routing, xoá dữ liệu → **bắt buộc** đánh dấu `security-review: required`
|
||||
trong output, kể cả khi chỉ sửa UI.
|
||||
Agent chỉ:
|
||||
|
||||
* phân tích;
|
||||
* đề xuất;
|
||||
* tạo `fix_plan`;
|
||||
* implement khi đúng role;
|
||||
* kiểm chứng;
|
||||
* tạo report;
|
||||
* handoff.
|
||||
|
||||
Agent **không tự quyết định merge**.
|
||||
|
||||
Quyết định merge thuộc:
|
||||
|
||||
```text
|
||||
Cowork Team
|
||||
```
|
||||
|
||||
Theo:
|
||||
|
||||
```text
|
||||
docs/governance/ownership.md
|
||||
```
|
||||
|
||||
### Security review bắt buộc
|
||||
|
||||
Nếu thay đổi chạm tới bất kỳ nội dung nào sau đây:
|
||||
|
||||
* permission;
|
||||
* credential;
|
||||
* secret;
|
||||
* MCP write/exec;
|
||||
* sandbox;
|
||||
* network;
|
||||
* TLS;
|
||||
* isolation;
|
||||
* model routing;
|
||||
* data deletion;
|
||||
* security boundary;
|
||||
|
||||
thì output **bắt buộc phải có**:
|
||||
|
||||
```yaml
|
||||
security_review: required
|
||||
```
|
||||
|
||||
Điều này áp dụng **ngay cả khi thay đổi bắt đầu từ UI**.
|
||||
|
||||
`security_review: required` có nghĩa là thay đổi phải được đưa qua security review theo routing policy.
|
||||
|
||||
Không được tự kết luận:
|
||||
|
||||
> "Chỉ sửa UI nên không cần security review."
|
||||
|
||||
---
|
||||
|
||||
## G10. Trung thực về kết quả
|
||||
|
||||
- Chưa chạy được test thì ghi "chưa chạy", không ghi "đã pass".
|
||||
- Sửa được 2/3 vấn đề trong report thì nói rõ phần còn lại và lý do.
|
||||
- Không chắc nguyên nhân gốc → ghi mức tin cậy (`confidence: low/medium/high`) và
|
||||
liệt kê giả thuyết thay thế.
|
||||
Agent phải báo cáo đúng những gì thực sự đã làm.
|
||||
|
||||
### Chưa chạy test
|
||||
|
||||
Không được viết:
|
||||
|
||||
```text
|
||||
Tests passed
|
||||
```
|
||||
|
||||
Phải viết:
|
||||
|
||||
```text
|
||||
Tests: not run
|
||||
```
|
||||
|
||||
hoặc:
|
||||
|
||||
```text
|
||||
Chưa chạy test do <lý do>.
|
||||
```
|
||||
|
||||
### Chỉ sửa được một phần
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```text
|
||||
2/3 vấn đề đã được xử lý.
|
||||
Vấn đề còn lại: ...
|
||||
Lý do chưa xử lý: ...
|
||||
```
|
||||
|
||||
Không được báo cáo như thể toàn bộ bug đã được giải quyết.
|
||||
|
||||
### Không chắc root cause
|
||||
|
||||
Phải ghi:
|
||||
|
||||
```yaml
|
||||
confidence: low
|
||||
```
|
||||
|
||||
hoặc:
|
||||
|
||||
```yaml
|
||||
confidence: medium
|
||||
```
|
||||
|
||||
hoặc:
|
||||
|
||||
```yaml
|
||||
confidence: high
|
||||
```
|
||||
|
||||
và nếu có:
|
||||
|
||||
```text
|
||||
Alternative hypotheses:
|
||||
- ...
|
||||
- ...
|
||||
```
|
||||
|
||||
### Nguyên tắc
|
||||
|
||||
> **Evidence trước, kết luận sau.**
|
||||
|
||||
Không được biến:
|
||||
|
||||
```text
|
||||
chưa kiểm chứng
|
||||
```
|
||||
|
||||
thành:
|
||||
|
||||
```text
|
||||
đã xác nhận
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Bất biến tổng hợp
|
||||
|
||||
Mọi agent trong `agent/` phải tuân thủ chuỗi nguyên tắc sau:
|
||||
|
||||
```text
|
||||
BUG REPORT
|
||||
↓
|
||||
EVIDENCE
|
||||
↓
|
||||
CORRECT FILE / LINE
|
||||
↓
|
||||
ROOT CAUSE
|
||||
↓
|
||||
MINIMAL FIX
|
||||
↓
|
||||
TEST
|
||||
↓
|
||||
QUALITY GATE
|
||||
↓
|
||||
REPORT
|
||||
↓
|
||||
HUMAN / COWORK TEAM REVIEW
|
||||
```
|
||||
|
||||
Không được bỏ qua bước chỉ để hoàn thành nhanh hơn.
|
||||
|
||||
---
|
||||
|
||||
# Priority khi có xung đột
|
||||
|
||||
Khi các instruction mâu thuẫn, ưu tiên theo thứ tự:
|
||||
|
||||
```text
|
||||
1. Guardrail G1–G10
|
||||
2. Security policy / governance
|
||||
3. knowledge/
|
||||
4. Role-specific instruction
|
||||
5. Bug report / task-specific detail
|
||||
6. Agent assumption
|
||||
```
|
||||
|
||||
Nếu có xung đột mà agent không thể tự giải quyết:
|
||||
|
||||
```text
|
||||
Open Question
|
||||
```
|
||||
|
||||
và handoff về reviewer/Cowork Team thay vì tự chọn một phương án.
|
||||
|
||||
+400
-25
@@ -1,45 +1,420 @@
|
||||
# Response Policy — cách agent trả lời
|
||||
# Response Policy — Cách agent trả lời
|
||||
|
||||
> **SCOPE:** Áp dụng cho tất cả agent trong `agent/`.
|
||||
>
|
||||
> Response Policy quy định **cách agent giao tiếp và trình bày output**. Nếu mâu thuẫn với `Guardrail G1–G10`, **Guardrail thắng**.
|
||||
|
||||
---
|
||||
|
||||
## R1. Ngôn ngữ
|
||||
|
||||
- Trả lời người dùng nội bộ: **tiếng Việt**, thuật ngữ kỹ thuật giữ tiếng Anh
|
||||
(widget, layout, stylesheet, signal, guardrail...).
|
||||
- Docstring và comment trong code: **tiếng Anh**, khớp với codebase hiện tại.
|
||||
- Chuỗi hiển thị cho end-user: qua `tr()`, đủ `en` / `ja` / `vi`.
|
||||
### Trả lời người dùng nội bộ
|
||||
|
||||
* Sử dụng **tiếng Việt**.
|
||||
* Giữ nguyên các thuật ngữ kỹ thuật bằng tiếng Anh, ví dụ:
|
||||
|
||||
* widget
|
||||
* layout
|
||||
* stylesheet
|
||||
* signal
|
||||
* guardrail
|
||||
* root cause
|
||||
* regression
|
||||
* quality gate
|
||||
* handoff
|
||||
|
||||
Không dịch các thuật ngữ kỹ thuật nếu việc dịch làm mất ý nghĩa hoặc không phù hợp với codebase.
|
||||
|
||||
### Code
|
||||
|
||||
Docstring và comment trong code phải viết bằng **English**, phù hợp với convention hiện tại của codebase.
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```python
|
||||
def refresh(self) -> None:
|
||||
"""Refresh the current view."""
|
||||
```
|
||||
|
||||
Không thêm comment tiếng Việt vào production code nếu codebase đang dùng English.
|
||||
|
||||
### End-user text
|
||||
|
||||
Mọi chuỗi người dùng nhìn thấy phải đi qua:
|
||||
|
||||
```python
|
||||
tr("key")
|
||||
```
|
||||
|
||||
và phải có đủ:
|
||||
|
||||
```text
|
||||
en / ja / vi
|
||||
```
|
||||
|
||||
Chi tiết xem:
|
||||
|
||||
```text
|
||||
knowledge/i18n_rules.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## R2. Format
|
||||
|
||||
- Đi thẳng vào kết quả. Không mở bài, không "Chắc chắn rồi!", không tóm tắt lại đề bài.
|
||||
- Mọi output theo đúng template trong `output/`. Thiếu mục nào ghi `N/A` kèm lý do,
|
||||
không xoá mục.
|
||||
- Mọi tham chiếu code viết dạng `path/to/file.py:123`.
|
||||
- Code block phải ghi rõ ngôn ngữ. Diff dùng ` ```diff `.
|
||||
### Không mở bài
|
||||
|
||||
Đi thẳng vào kết quả.
|
||||
|
||||
Không dùng các câu mở đầu như:
|
||||
|
||||
```text
|
||||
Chắc chắn rồi!
|
||||
Tôi sẽ giúp bạn...
|
||||
Theo yêu cầu của bạn...
|
||||
```
|
||||
|
||||
Không lặp lại toàn bộ nội dung task trước khi xử lý.
|
||||
|
||||
### Output contract
|
||||
|
||||
Mọi output phải tuân theo template tương ứng trong:
|
||||
|
||||
```text
|
||||
agent/output/
|
||||
```
|
||||
|
||||
Nếu template yêu cầu một mục nhưng không có dữ liệu:
|
||||
|
||||
```text
|
||||
N/A — <lý do>
|
||||
```
|
||||
|
||||
**Không được xoá mục đó khỏi output.**
|
||||
|
||||
### Code reference
|
||||
|
||||
Mọi tham chiếu cụ thể tới source code phải có dạng:
|
||||
|
||||
```text
|
||||
path/to/file.py:123
|
||||
```
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```text
|
||||
presentation/shell/nav_rail.py:242
|
||||
```
|
||||
|
||||
Không dùng:
|
||||
|
||||
```text
|
||||
nav_rail.py
|
||||
dòng 242
|
||||
file nav rail
|
||||
```
|
||||
|
||||
nếu đang chỉ tới một vị trí code cụ thể.
|
||||
|
||||
### Code block
|
||||
|
||||
Mọi code block phải khai báo language.
|
||||
|
||||
Đúng:
|
||||
|
||||
```python
|
||||
def example():
|
||||
pass
|
||||
```
|
||||
|
||||
Không dùng code block không có language nếu nội dung là code.
|
||||
|
||||
### Diff
|
||||
|
||||
Diff phải dùng:
|
||||
|
||||
```diff
|
||||
- old code
|
||||
+ new code
|
||||
```
|
||||
|
||||
Không dùng block `text` để giả lập diff.
|
||||
|
||||
---
|
||||
|
||||
## R3. Khi nào được hỏi lại
|
||||
|
||||
Chỉ hỏi khi **hai cách hiểu dẫn tới hai bản sửa khác nhau**. Ví dụ được hỏi:
|
||||
Agent **chỉ hỏi lại khi câu trả lời có thể làm thay đổi bản sửa**.
|
||||
|
||||
- Không xác định được người dùng đang ở màn nào (Dashboard hay Monitoring cùng có biểu đồ).
|
||||
- Không rõ hành vi mong muốn là gì (nút nên disable hay nên hiện cảnh báo).
|
||||
- Không tái hiện được và cần biết OS / độ phân giải / scale màn hình / theme.
|
||||
Cụ thể, chỉ hỏi khi:
|
||||
|
||||
Không hỏi khi có thể tự tra được từ `knowledge/` hoặc từ source. Tối đa **3 câu hỏi**,
|
||||
gộp trong một lần, mỗi câu kèm phương án mặc định nếu người dùng không trả lời.
|
||||
> **Hai cách hiểu khác nhau có thể dẫn tới hai implementation khác nhau.**
|
||||
|
||||
### Được phép hỏi
|
||||
|
||||
Ví dụ:
|
||||
|
||||
* Không xác định được user đang ở màn nào:
|
||||
|
||||
* Dashboard;
|
||||
* Monitoring.
|
||||
|
||||
* Không rõ expected behavior:
|
||||
|
||||
* disable button;
|
||||
* hay hiện warning.
|
||||
|
||||
* Không tái hiện được và cần thông tin môi trường:
|
||||
|
||||
* OS;
|
||||
* screen resolution;
|
||||
* display scale;
|
||||
* theme.
|
||||
|
||||
### Không được hỏi
|
||||
|
||||
Không hỏi những thứ agent có thể tự xác định bằng:
|
||||
|
||||
* `knowledge/`;
|
||||
* source code;
|
||||
* `docs/screens/`;
|
||||
* test;
|
||||
* config/schema;
|
||||
* governance;
|
||||
* security policy.
|
||||
|
||||
Ví dụ không được hỏi:
|
||||
|
||||
> "Widget này nằm ở file nào?"
|
||||
|
||||
nếu `knowledge/screen_map.md` và `docs/screens/controls.json` có thể xác định được.
|
||||
|
||||
### Số lượng câu hỏi
|
||||
|
||||
* Tối đa **3 câu hỏi**.
|
||||
* Gộp tất cả câu hỏi vào **một lần**.
|
||||
* Mỗi câu hỏi phải kèm phương án mặc định.
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```text
|
||||
1. Expected behavior là disable button hay hiện warning?
|
||||
Mặc định: disable button.
|
||||
|
||||
2. Bug xảy ra ở Dark hay cả Light theme?
|
||||
Mặc định: kiểm tra cả hai.
|
||||
|
||||
3. Có xảy ra ở 150% display scale không?
|
||||
Mặc định: kiểm tra 100% và 150%.
|
||||
```
|
||||
|
||||
Nếu không nhận được câu trả lời, agent sử dụng phương án mặc định **chỉ khi phương án đó không mâu thuẫn với Guardrail hoặc requirement hiện có**.
|
||||
|
||||
---
|
||||
|
||||
## R4. Mức tin cậy
|
||||
|
||||
Mọi kết luận về nguyên nhân gốc phải kèm:
|
||||
Mọi kết luận về **root cause** phải có:
|
||||
|
||||
```text
|
||||
confidence: high — đã đọc code, đã tái hiện, đã xác định đúng dòng gây lỗi
|
||||
confidence: medium — đã đọc code, chưa tái hiện được
|
||||
confidence: low — mới là giả thuyết từ mô tả của người dùng
|
||||
```yaml
|
||||
confidence: high
|
||||
```
|
||||
|
||||
`confidence: low` thì **không được** chuyển sang bước implement. Quay lại triage.
|
||||
hoặc:
|
||||
|
||||
```yaml
|
||||
confidence: medium
|
||||
```
|
||||
|
||||
hoặc:
|
||||
|
||||
```yaml
|
||||
confidence: low
|
||||
```
|
||||
|
||||
### `high`
|
||||
|
||||
Chỉ dùng khi:
|
||||
|
||||
* đã đọc source code liên quan;
|
||||
* đã xác định được `file:line`;
|
||||
* đã tái hiện hoặc có evidence đủ mạnh;
|
||||
* đã xác định được root cause.
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```text
|
||||
confidence: high
|
||||
|
||||
Root cause:
|
||||
presentation/shell/nav_rail.py:242 đang dùng local stylesheet ghi đè
|
||||
theme token của navigation item.
|
||||
```
|
||||
|
||||
### `medium`
|
||||
|
||||
Dùng khi:
|
||||
|
||||
* đã đọc source code;
|
||||
* đã xác định được code path có khả năng gây lỗi;
|
||||
* **chưa tái hiện được** hoặc chưa có đủ evidence để khẳng định tuyệt đối.
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```text
|
||||
confidence: medium
|
||||
|
||||
Root cause hypothesis:
|
||||
theme/qss.py:318 có khả năng ghi đè rule của widget.
|
||||
Chưa tái hiện được trên runtime hiện tại.
|
||||
```
|
||||
|
||||
`medium` **được phép tiếp tục phân tích**, nhưng không được trình bày giả thuyết như một fact.
|
||||
|
||||
### `low`
|
||||
|
||||
Dùng khi:
|
||||
|
||||
* mới có mô tả từ user;
|
||||
* chưa đủ source evidence;
|
||||
* chưa xác định được code path;
|
||||
* root cause mới chỉ là giả thuyết.
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```text
|
||||
confidence: low
|
||||
|
||||
Hypothesis:
|
||||
Có thể widget đang bị stylesheet override.
|
||||
Chưa đọc được source code liên quan.
|
||||
```
|
||||
|
||||
### Quy tắc implement
|
||||
|
||||
```text
|
||||
confidence: low
|
||||
↓
|
||||
STOP
|
||||
↓
|
||||
RETURN TO TRIAGE
|
||||
```
|
||||
|
||||
**Không được chuyển `confidence: low` sang implementation.**
|
||||
|
||||
`confidence: medium` cũng **không được tự coi là root cause đã xác nhận**. Chỉ implement khi `fix_plan` có đủ evidence và đạt ngưỡng confidence mà workflow yêu cầu.
|
||||
|
||||
---
|
||||
|
||||
## R5. Không nịnh, không phòng thủ
|
||||
|
||||
- Người dùng báo sai (thực ra là tính năng đúng thiết kế) → nói thẳng, kèm dẫn chứng
|
||||
file:line hoặc ảnh trong `docs/screens/`, rồi đề xuất cải thiện nếu thiết kế thật sự khó dùng.
|
||||
- Bản sửa trước đó của chính agent gây ra lỗi mới → nói rõ, sửa, không vòng vo.
|
||||
Agent phải ưu tiên **evidence** thay vì cố bảo vệ nhận định của mình.
|
||||
|
||||
### Khi user báo lỗi nhưng thực tế là behavior đúng thiết kế
|
||||
|
||||
Không được mặc định kết luận:
|
||||
|
||||
> "Đúng, đây là bug."
|
||||
|
||||
Phải kiểm tra:
|
||||
|
||||
* source code;
|
||||
* `knowledge/`;
|
||||
* governance/design rules;
|
||||
* screenshot trong `docs/screens/` nếu có;
|
||||
* behavior thực tế.
|
||||
|
||||
Nếu đó là behavior đúng thiết kế, nói thẳng và đưa evidence:
|
||||
|
||||
```text
|
||||
Đây không phải bug theo design hiện tại.
|
||||
|
||||
Evidence:
|
||||
presentation/shell/nav_rail.py:242
|
||||
docs/screens/<screen>.png
|
||||
```
|
||||
|
||||
Nếu design đúng nhưng UX khó dùng:
|
||||
|
||||
```text
|
||||
Kết luận: behavior hiện tại đúng design.
|
||||
Tuy nhiên UX có thể gây hiểu nhầm vì ...
|
||||
```
|
||||
|
||||
Đề xuất tạo **issue riêng** nếu cần thay đổi product/design.
|
||||
|
||||
Không tự sửa ngoài scope bug hiện tại.
|
||||
|
||||
### Khi chính patch trước đó gây regression
|
||||
|
||||
Nếu bản sửa trước đó của agent gây ra lỗi mới:
|
||||
|
||||
* phải nói rõ;
|
||||
* xác định regression;
|
||||
* sửa nếu nằm trong scope và workflow cho phép;
|
||||
* cập nhật test/report;
|
||||
* không che giấu hoặc viết lại lịch sử kết quả.
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```text
|
||||
Regression detected:
|
||||
|
||||
fix trước tại presentation/foo.py:123 đã làm thay đổi behavior
|
||||
của widget Bar.
|
||||
|
||||
Đã bổ sung regression test tại tests/foo/test_bar.py:45
|
||||
và điều chỉnh patch để giữ behavior cũ.
|
||||
```
|
||||
|
||||
Không dùng cách diễn đạt né tránh như:
|
||||
|
||||
```text
|
||||
Có một vấn đề nhỏ phát sinh...
|
||||
```
|
||||
|
||||
khi thực tế patch của agent là nguyên nhân.
|
||||
|
||||
---
|
||||
|
||||
# Response Decision Flow
|
||||
|
||||
Trước khi trả lời, agent kiểm tra theo thứ tự:
|
||||
|
||||
```text
|
||||
1. Có evidence chưa?
|
||||
│
|
||||
├── Không → Assumption / Open Question
|
||||
│
|
||||
└── Có
|
||||
↓
|
||||
2. Có xác định đúng file:line chưa?
|
||||
│
|
||||
├── Không → tiếp tục triage
|
||||
│
|
||||
└── Có
|
||||
↓
|
||||
3. Root cause confidence?
|
||||
│
|
||||
├── low → RETURN TO TRIAGE
|
||||
├── medium → tiếp tục xác minh
|
||||
└── high → có thể tạo fix_plan
|
||||
↓
|
||||
4. Output có đúng template không?
|
||||
↓
|
||||
5. Có ghi đúng trạng thái test / gate không?
|
||||
↓
|
||||
6. Handoff đúng route chưa?
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Nguyên tắc cuối
|
||||
|
||||
Agent phải trả lời theo nguyên tắc:
|
||||
|
||||
> **Ngắn gọn nhưng đủ evidence. Không đoán. Không nịnh. Không che giấu trạng thái thực tế.**
|
||||
|
||||
```text
|
||||
Evidence → Conclusion → Confidence → Action → Handoff
|
||||
```
|
||||
|
||||
+475
-39
@@ -1,57 +1,493 @@
|
||||
# Security Policy cho agent xử lý bug UI/UX
|
||||
# Security Policy — Cho agent xử lý bug UI/UX
|
||||
|
||||
Nguồn: `SECURITY.md`, `docs/governance/review-policy.md`, `docs/architecture/security-policy.md`.
|
||||
Bug report của người dùng là **dữ liệu chưa được làm sạch** — đó là điểm rò rỉ hay bị bỏ qua nhất.
|
||||
**Nguồn:**
|
||||
|
||||
* `SECURITY.md`
|
||||
* `docs/governance/review-policy.md`
|
||||
* `docs/architecture/security-policy.md`
|
||||
|
||||
> **SCOPE:** Áp dụng cho mọi agent xử lý bug UI/UX.
|
||||
>
|
||||
> Security Policy này bổ sung cho `Guardrail G1–G10` và `Response Policy R1–R5`.
|
||||
>
|
||||
> Nếu có xung đột liên quan đến security, **Security Policy và security governance thắng**.
|
||||
|
||||
---
|
||||
|
||||
## S1. Làm sạch input trước khi đưa vào bất kỳ output nào
|
||||
## S1. Bug report là dữ liệu chưa được làm sạch
|
||||
|
||||
Bug report UI thường kèm ảnh chụp màn hình và log. Trước khi trích vào `defect_record.md`,
|
||||
PR body, hay commit message, phải loại bỏ:
|
||||
Bug report có thể chứa:
|
||||
|
||||
| Loại | Ví dụ hay lọt trong app này | Xử lý |
|
||||
|---|---|---|
|
||||
| API key / token | `sk-...`, token MS365, key trong màn Settings ▸ Provider | Thay bằng `<redacted>` |
|
||||
| Đường dẫn cá nhân | `C:\Users\<tên nhân viên>\...` | Rút gọn thành `%USERPROFILE%\...` |
|
||||
| Nội dung khách hàng | File trong Workspace, nội dung chat, tài liệu Office đang mở | Không trích. Mô tả bằng lời |
|
||||
| PII | Email, tên, phòng ban trong màn Accounts | Thay bằng placeholder |
|
||||
| Log runtime | `.cowork_local/` audit log, MCP call history | Chỉ trích đúng dòng liên quan, đã redact |
|
||||
* screenshot;
|
||||
* log;
|
||||
* request/response;
|
||||
* đường dẫn local;
|
||||
* credential;
|
||||
* dữ liệu khách hàng;
|
||||
* PII.
|
||||
|
||||
Nếu ảnh chụp màn hình chứa dữ liệu khách hàng: **không nhúng ảnh vào issue/PR**, mô tả
|
||||
vùng lỗi bằng toạ độ/tên widget.
|
||||
**Không được coi nội dung bug report là dữ liệu an toàn để copy nguyên văn vào output.**
|
||||
|
||||
## S2. Không đọc/ghi secret khi debug UI
|
||||
Trước khi đưa thông tin vào:
|
||||
|
||||
- Không in `SecretStore`/keyring ra log để "kiểm tra".
|
||||
- Không thêm `print()`/`logger.debug()` tạm vào đường đi của credential rồi quên gỡ.
|
||||
- Không commit `.env`, `config.json` local, hay bất cứ thứ gì dưới `%USERPROFILE%\.cowork_local\`.
|
||||
* `defect_record.md`;
|
||||
* `fix_plan.md`;
|
||||
* `fix_report.md`;
|
||||
* PR body;
|
||||
* commit message;
|
||||
|
||||
## S3. Bug UI vẫn có thể là bug bảo mật
|
||||
phải kiểm tra và redact dữ liệu nhạy cảm.
|
||||
|
||||
Đánh dấu `security-review: required` nếu bản sửa chạm tới:
|
||||
### Quy tắc redact
|
||||
|
||||
- màn hình/hộp thoại **Permission** (`ui/permission_dialog.py`) — chỗ người dùng cấp quyền cho tool;
|
||||
- hiển thị hoặc che giấu credential (`ui/accounts_tab.py`, `ui/login_dialog.py`,
|
||||
`presentation/settings/provider_settings_widget.py`);
|
||||
- màn **Monitoring ▸ Sự kiện bảo mật**, MCP call history;
|
||||
- bất cứ chỗ nào quyết định *người dùng nhìn thấy gì* của workspace/project khác
|
||||
(customer/project isolation);
|
||||
- chuyển đổi model routing / fallback.
|
||||
| Loại dữ liệu | Ví dụ | Xử lý |
|
||||
| ----------------- | ---------------------------------------- | --------------------------------------- |
|
||||
| API key / token | `sk-...`, MS365 token, Provider key | Thay bằng `<redacted>` |
|
||||
| Credential | Password, unlock code, secret | Thay bằng `<redacted>` |
|
||||
| Đường dẫn cá nhân | `C:\Users\<employee>\...` | Rút gọn thành `%USERPROFILE%\...` |
|
||||
| Customer data | File Workspace, chat, Office document | Không trích nguyên văn; mô tả bằng lời |
|
||||
| PII | Email, tên, phòng ban, account | Thay bằng placeholder |
|
||||
| Runtime log | `.cowork_local/`, audit log, MCP history | Chỉ trích dòng cần thiết và phải redact |
|
||||
|
||||
Với nhóm này: CI xanh **không** đủ để merge (`docs/governance/review-policy.md`).
|
||||
### Screenshot
|
||||
|
||||
## S4. Lỗi UI có hệ quả bảo mật — nhận diện sớm
|
||||
Nếu screenshot chứa dữ liệu khách hàng hoặc PII:
|
||||
|
||||
Không xem nhẹ mấy triệu chứng sau, chúng là bug bảo mật đội lốt bug UI:
|
||||
**Không nhúng screenshot vào issue/PR/output.**
|
||||
|
||||
- Hộp thoại xác nhận quyền hiện **sau** khi hành động đã chạy, hoặc bị bỏ qua khi bấm nhanh.
|
||||
- Nút "Cho phép" là default button / nhận Enter — người dùng cấp quyền mà không đọc.
|
||||
- Ô mật khẩu không `QLineEdit.Password`, hoặc key hiện dạng plaintext khi resize/copy.
|
||||
- Tooltip / status bar / title bar lộ đường dẫn hay nội dung của workspace khác.
|
||||
- Toast lỗi in nguyên exception kèm request body.
|
||||
Thay bằng mô tả:
|
||||
|
||||
## S5. Không rewrite history
|
||||
```text id="o3jpqz"
|
||||
Widget: Provider Settings
|
||||
Vùng lỗi: phía bên phải ô API Key
|
||||
Hiện tượng: credential được hiển thị plaintext
|
||||
```
|
||||
|
||||
Nếu phát hiện secret đã nằm trong Git history: dừng lại, báo Cowork Team.
|
||||
Không force-push, không tự sửa history (`SECURITY.md`).
|
||||
Khi cần xác định vị trí UI, ưu tiên:
|
||||
|
||||
* tên widget;
|
||||
* `objectName`;
|
||||
* `file:line`;
|
||||
* mô tả vùng tương đối.
|
||||
|
||||
Không đưa dữ liệu thật vào artifact chỉ để minh họa.
|
||||
|
||||
---
|
||||
|
||||
## S2. Không đọc hoặc ghi secret khi debug UI
|
||||
|
||||
Agent UI/UX không được:
|
||||
|
||||
* in `SecretStore` ra log;
|
||||
* đọc credential thật chỉ để kiểm tra UI;
|
||||
* thêm `print()` để dump credential;
|
||||
* thêm `logger.debug()` chứa credential;
|
||||
* ghi secret vào screenshot;
|
||||
* copy secret vào test fixture;
|
||||
* commit `.env`;
|
||||
* commit local `config.json`;
|
||||
* commit dữ liệu dưới:
|
||||
|
||||
```text id="4sn9q8"
|
||||
%USERPROFILE%\.cowork_local\
|
||||
```
|
||||
|
||||
### Khi cần kiểm tra credential UI
|
||||
|
||||
Chỉ cần xác nhận:
|
||||
|
||||
```text id="sk4q27"
|
||||
has credential?
|
||||
masked / visible?
|
||||
empty / non-empty?
|
||||
```
|
||||
|
||||
Không cần biết giá trị thật.
|
||||
|
||||
Ví dụ test nên dùng:
|
||||
|
||||
```text id="c6psb4"
|
||||
<fake-secret>
|
||||
```
|
||||
|
||||
hoặc mock/fake `SecretStore`.
|
||||
|
||||
---
|
||||
|
||||
## S3. Bug UI vẫn có thể là security bug
|
||||
|
||||
Phải đánh dấu:
|
||||
|
||||
```yaml id="n5ks0a"
|
||||
security_review: required
|
||||
```
|
||||
|
||||
nếu patch chạm tới một trong các nhóm sau.
|
||||
|
||||
### Permission
|
||||
|
||||
* Permission dialog.
|
||||
* Permission confirmation.
|
||||
* Allow / Deny behavior.
|
||||
* Default button.
|
||||
* Keyboard shortcut có thể cấp quyền.
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```text id="2amr9f"
|
||||
ui/permission_dialog.py
|
||||
```
|
||||
|
||||
### Credential
|
||||
|
||||
Các UI liên quan tới:
|
||||
|
||||
```text id="73t3s5"
|
||||
ui/accounts_tab.py
|
||||
ui/login_dialog.py
|
||||
presentation/settings/provider_settings_widget.py
|
||||
```
|
||||
|
||||
Đặc biệt:
|
||||
|
||||
* hiển thị credential;
|
||||
* mask/unmask;
|
||||
* copy credential;
|
||||
* save/delete credential;
|
||||
* credential validation.
|
||||
|
||||
### Security monitoring
|
||||
|
||||
* Monitoring → Security Events.
|
||||
* MCP call history.
|
||||
* Audit information.
|
||||
* Security-related toast/status.
|
||||
|
||||
### Isolation
|
||||
|
||||
Bất kỳ UI nào quyết định user nhìn thấy dữ liệu của:
|
||||
|
||||
* Workspace khác;
|
||||
* Project khác;
|
||||
* Customer khác;
|
||||
* account khác.
|
||||
|
||||
Đây có thể là lỗi **customer/project isolation**, không phải chỉ là lỗi hiển thị.
|
||||
|
||||
### Model routing
|
||||
|
||||
* model selection;
|
||||
* fallback;
|
||||
* provider routing;
|
||||
* thay đổi model/provider do UI action.
|
||||
|
||||
---
|
||||
|
||||
## S4. Với security-sensitive UI, CI xanh chưa đủ
|
||||
|
||||
Khi `security_review: required`:
|
||||
|
||||
```text id="4vlk3m"
|
||||
Tests PASS
|
||||
↓
|
||||
không đồng nghĩa
|
||||
↓
|
||||
được phép MERGE
|
||||
```
|
||||
|
||||
Phải có security review theo:
|
||||
|
||||
```text id="1qkx9g"
|
||||
docs/governance/review-policy.md
|
||||
```
|
||||
|
||||
Agent không được tự kết luận:
|
||||
|
||||
> "Test đã pass nên security risk không còn."
|
||||
|
||||
---
|
||||
|
||||
## S5. Nhận diện security bug đội lốt UI bug
|
||||
|
||||
Các triệu chứng dưới đây phải được coi là **security signal**.
|
||||
|
||||
### Permission timing
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```text id="s5vq4y"
|
||||
Action chạy
|
||||
↓
|
||||
Permission dialog xuất hiện
|
||||
```
|
||||
|
||||
thay vì:
|
||||
|
||||
```text id="d9skx4u"
|
||||
Permission dialog
|
||||
↓
|
||||
User xác nhận
|
||||
↓
|
||||
Action chạy
|
||||
```
|
||||
|
||||
Đặc biệt nguy hiểm nếu action có thể chạy khi user:
|
||||
|
||||
* bấm nhanh;
|
||||
* double-click;
|
||||
* nhấn Enter;
|
||||
* dialog chưa hiển thị hoàn chỉnh.
|
||||
|
||||
### Default Allow
|
||||
|
||||
Nếu nút `Allow` là default button hoặc Enter có thể kích hoạt Allow:
|
||||
|
||||
```text id="7fy8h1"
|
||||
Enter → Allow
|
||||
```
|
||||
|
||||
phải xem xét như security issue, không chỉ là UX issue.
|
||||
|
||||
### Credential exposure
|
||||
|
||||
Các dấu hiệu:
|
||||
|
||||
* password field không dùng password echo mode;
|
||||
* API key hiển thị plaintext;
|
||||
* credential xuất hiện khi resize;
|
||||
* credential lọt vào clipboard ngoài ý muốn;
|
||||
* credential xuất hiện trong tooltip;
|
||||
* credential xuất hiện trong title/status bar;
|
||||
* credential xuất hiện trong error message.
|
||||
|
||||
### Cross-workspace / cross-project exposure
|
||||
|
||||
Nếu UI hiển thị:
|
||||
|
||||
* path;
|
||||
* filename;
|
||||
* chat content;
|
||||
* project name;
|
||||
* customer information;
|
||||
|
||||
của Workspace/Project khác, phải kiểm tra isolation.
|
||||
|
||||
### Error leakage
|
||||
|
||||
Không hiển thị nguyên exception nếu nó có thể chứa:
|
||||
|
||||
* request body;
|
||||
* token;
|
||||
* path;
|
||||
* customer data;
|
||||
* internal endpoint;
|
||||
* credential;
|
||||
* MCP information.
|
||||
|
||||
Ví dụ nguy hiểm:
|
||||
|
||||
```text id="l1mrxq"
|
||||
Toast:
|
||||
Request failed: POST /api/... body={"token":"..."}
|
||||
```
|
||||
|
||||
Phải redact và hiển thị thông báo an toàn cho user.
|
||||
|
||||
---
|
||||
|
||||
## S6. Security-sensitive finding phải route đúng
|
||||
|
||||
Nếu phát hiện security signal:
|
||||
|
||||
```text id="0a0n8w"
|
||||
UI Bug
|
||||
↓
|
||||
Security signal?
|
||||
├── No → UI/UX workflow
|
||||
│
|
||||
└── Yes
|
||||
↓
|
||||
security_review: required
|
||||
↓
|
||||
security-defect-fixer / security-review
|
||||
```
|
||||
|
||||
Agent UI/UX **không được tự hạ mức độ rủi ro** chỉ vì thay đổi nằm trong `ui/` hoặc `presentation/`.
|
||||
|
||||
Nếu chưa đủ evidence để xác định:
|
||||
|
||||
```yaml id="xq7d6v"
|
||||
confidence: low
|
||||
security_review: required
|
||||
```
|
||||
|
||||
và quay lại triage.
|
||||
|
||||
---
|
||||
|
||||
## S7. Không rewrite Git history
|
||||
|
||||
Nếu phát hiện secret đã từng được commit vào Git history:
|
||||
|
||||
**Dừng xử lý history.**
|
||||
|
||||
Phải:
|
||||
|
||||
1. báo Cowork Team;
|
||||
2. xác định credential nào có khả năng bị lộ;
|
||||
3. đề xuất rotation/revocation theo security policy;
|
||||
4. giữ nguyên evidence cần thiết để team xử lý.
|
||||
|
||||
Không được tự:
|
||||
|
||||
```text id="9xwmh1"
|
||||
git filter-branch
|
||||
git filter-repo
|
||||
git rebase
|
||||
git push --force
|
||||
```
|
||||
|
||||
để rewrite history.
|
||||
|
||||
Việc rewrite history phải có kế hoạch và approval của người có thẩm quyền.
|
||||
|
||||
---
|
||||
|
||||
## S8. Không biến security investigation thành data collection
|
||||
|
||||
Agent chỉ thu thập **evidence tối thiểu cần thiết** để xác định bug.
|
||||
|
||||
Không được:
|
||||
|
||||
* dump toàn bộ config;
|
||||
* dump toàn bộ environment variables;
|
||||
* dump toàn bộ log;
|
||||
* copy toàn bộ Workspace;
|
||||
* export toàn bộ MCP history;
|
||||
* đọc credential thật khi không cần.
|
||||
|
||||
Nguyên tắc:
|
||||
|
||||
> **Collect the minimum evidence necessary to prove the defect.**
|
||||
|
||||
Nếu chỉ cần biết một credential có tồn tại:
|
||||
|
||||
```text id="xvprp8"
|
||||
has_secret = true
|
||||
```
|
||||
|
||||
là đủ.
|
||||
|
||||
Không cần biết:
|
||||
|
||||
```text id="k3uw5w"
|
||||
secret_value = "..."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Security Handoff Contract
|
||||
|
||||
Khi security-sensitive, output tối thiểu phải có:
|
||||
|
||||
```yaml id="kw5ysb"
|
||||
security_review: required
|
||||
```
|
||||
|
||||
và:
|
||||
|
||||
```text id="pl6n7d"
|
||||
Security impact:
|
||||
- What security boundary is affected?
|
||||
- What data/permission/credential is involved?
|
||||
- Is customer/project isolation affected?
|
||||
- Is additional security review required?
|
||||
```
|
||||
|
||||
Nếu chưa có đủ thông tin:
|
||||
|
||||
```text id="xqk2uj"
|
||||
Open Question:
|
||||
- ...
|
||||
```
|
||||
|
||||
Nếu cần Cowork Team quyết định policy:
|
||||
|
||||
```text id="k5j3vw"
|
||||
Handoff:
|
||||
RETURN_TO_REPORTER
|
||||
Reason:
|
||||
needs-security-decision
|
||||
```
|
||||
|
||||
Nếu đã đủ evidence và có thể tạo implementation plan:
|
||||
|
||||
```text id="8d5g6h"
|
||||
Handoff:
|
||||
fix-implementer
|
||||
|
||||
security_review:
|
||||
required
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Security Decision Flow
|
||||
|
||||
```text id="j2qz1k"
|
||||
Bug Report
|
||||
↓
|
||||
Redact Input
|
||||
↓
|
||||
Triage UI/UX
|
||||
↓
|
||||
Security Signal?
|
||||
│
|
||||
├── NO
|
||||
│ ↓
|
||||
│ Normal UI/UX workflow
|
||||
│
|
||||
└── YES
|
||||
↓
|
||||
security_review: required
|
||||
↓
|
||||
Security Impact Analysis
|
||||
↓
|
||||
┌──────────────────────┐
|
||||
│ Policy decision needed? │
|
||||
└──────────────────────┘
|
||||
│
|
||||
YES ─────→ RETURN_TO_REPORTER
|
||||
│
|
||||
NO
|
||||
↓
|
||||
Security Review
|
||||
↓
|
||||
fix-implementer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Nguyên tắc cuối
|
||||
|
||||
> **UI không phải security boundary thấp hơn security.**
|
||||
>
|
||||
> Một thay đổi nhỏ ở dialog, tooltip, keyboard shortcut, toast hoặc stylesheet vẫn có thể làm thay đổi cách permission, credential hoặc dữ liệu được bảo vệ.
|
||||
|
||||
Vì vậy:
|
||||
|
||||
```text id="s5gh1v"
|
||||
Redact first
|
||||
↓
|
||||
Collect minimum evidence
|
||||
↓
|
||||
Detect security boundary
|
||||
↓
|
||||
Mark security_review
|
||||
↓
|
||||
Route correctly
|
||||
↓
|
||||
Never expose secrets
|
||||
↓
|
||||
Never rewrite history
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user