universal-dev-standards 5.4.0 → 5.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled/ai/standards/adversarial-test.ai.yaml +277 -0
- package/bundled/ai/standards/audit-trail.ai.yaml +113 -0
- package/bundled/ai/standards/chaos-injection-tests.ai.yaml +91 -0
- package/bundled/ai/standards/container-image-standards.ai.yaml +88 -0
- package/bundled/ai/standards/container-security.ai.yaml +331 -0
- package/bundled/ai/standards/cost-budget-test.ai.yaml +96 -0
- package/bundled/ai/standards/data-contract.ai.yaml +110 -0
- package/bundled/ai/standards/data-migration-testing.ai.yaml +96 -0
- package/bundled/ai/standards/data-pipeline.ai.yaml +113 -0
- package/bundled/ai/standards/disaster-recovery-drill.ai.yaml +89 -0
- package/bundled/ai/standards/flaky-test-management.ai.yaml +89 -0
- package/bundled/ai/standards/flow-based-testing.ai.yaml +240 -0
- package/bundled/ai/standards/iac-design-principles.ai.yaml +83 -0
- package/bundled/ai/standards/incident-response.ai.yaml +107 -0
- package/bundled/ai/standards/license-compliance.ai.yaml +106 -0
- package/bundled/ai/standards/llm-output-validation.ai.yaml +269 -0
- package/bundled/ai/standards/mock-boundary.ai.yaml +250 -0
- package/bundled/ai/standards/mutation-testing.ai.yaml +192 -0
- package/bundled/ai/standards/pii-classification.ai.yaml +109 -0
- package/bundled/ai/standards/policy-as-code-testing.ai.yaml +227 -0
- package/bundled/ai/standards/prd-standards.ai.yaml +88 -0
- package/bundled/ai/standards/product-metrics-standards.ai.yaml +111 -0
- package/bundled/ai/standards/prompt-regression.ai.yaml +94 -0
- package/bundled/ai/standards/property-based-testing.ai.yaml +105 -0
- package/bundled/ai/standards/release-quality-manifest.ai.yaml +135 -0
- package/bundled/ai/standards/replay-test.ai.yaml +111 -0
- package/bundled/ai/standards/runbook.ai.yaml +104 -0
- package/bundled/ai/standards/sast-advanced.ai.yaml +135 -0
- package/bundled/ai/standards/schema-evolution.ai.yaml +111 -0
- package/bundled/ai/standards/secret-management-standards.ai.yaml +105 -0
- package/bundled/ai/standards/secure-op.ai.yaml +365 -0
- package/bundled/ai/standards/security-testing.ai.yaml +171 -0
- package/bundled/ai/standards/server-ops-security.ai.yaml +274 -0
- package/bundled/ai/standards/slo-sli.ai.yaml +97 -0
- package/bundled/ai/standards/smoke-test.ai.yaml +87 -0
- package/bundled/ai/standards/supply-chain-attestation.ai.yaml +109 -0
- package/bundled/ai/standards/test-completeness-dimensions.ai.yaml +52 -5
- package/bundled/ai/standards/user-story-mapping.ai.yaml +108 -0
- package/bundled/core/adversarial-test.md +212 -0
- package/bundled/core/chaos-injection-tests.md +116 -0
- package/bundled/core/container-security.md +521 -0
- package/bundled/core/cost-budget-test.md +69 -0
- package/bundled/core/data-migration-testing.md +110 -0
- package/bundled/core/disaster-recovery-drill.md +73 -0
- package/bundled/core/flaky-test-management.md +73 -0
- package/bundled/core/flow-based-testing.md +142 -0
- package/bundled/core/llm-output-validation.md +178 -0
- package/bundled/core/mock-boundary.md +100 -0
- package/bundled/core/mutation-testing.md +97 -0
- package/bundled/core/policy-as-code-testing.md +188 -0
- package/bundled/core/prompt-regression.md +72 -0
- package/bundled/core/property-based-testing.md +73 -0
- package/bundled/core/release-quality-manifest.md +147 -0
- package/bundled/core/replay-test.md +86 -0
- package/bundled/core/sast-advanced.md +300 -0
- package/bundled/core/secure-op.md +314 -0
- package/bundled/core/security-testing.md +87 -0
- package/bundled/core/server-ops-security.md +493 -0
- package/bundled/core/smoke-test.md +65 -0
- package/bundled/core/supply-chain-attestation.md +117 -0
- package/bundled/locales/zh-CN/CHANGELOG.md +3 -3
- package/bundled/locales/zh-CN/README.md +1 -1
- package/bundled/locales/zh-CN/skills/ai-instruction-standards/SKILL.md +5 -5
- package/bundled/locales/zh-TW/CHANGELOG.md +3 -3
- package/bundled/locales/zh-TW/README.md +1 -1
- package/bundled/locales/zh-TW/skills/ai-instruction-standards/SKILL.md +183 -79
- package/bundled/skills/README.md +4 -3
- package/bundled/skills/SKILL_NAMING.md +94 -0
- package/bundled/skills/ai-instruction-standards/SKILL.md +181 -88
- package/bundled/skills/atdd-assistant/SKILL.md +8 -0
- package/bundled/skills/bdd-assistant/SKILL.md +7 -0
- package/bundled/skills/checkin-assistant/SKILL.md +8 -0
- package/bundled/skills/code-review-assistant/SKILL.md +7 -0
- package/bundled/skills/journey-test-assistant/SKILL.md +203 -0
- package/bundled/skills/orchestrate/SKILL.md +167 -0
- package/bundled/skills/plan/SKILL.md +234 -0
- package/bundled/skills/pr-automation-assistant/SKILL.md +8 -0
- package/bundled/skills/push/SKILL.md +49 -2
- package/bundled/skills/{process-automation → skill-builder}/SKILL.md +1 -1
- package/bundled/skills/{forward-derivation → spec-derivation}/SKILL.md +1 -1
- package/bundled/skills/spec-driven-dev/SKILL.md +7 -0
- package/bundled/skills/sweep/SKILL.md +145 -0
- package/bundled/skills/tdd-assistant/SKILL.md +7 -0
- package/package.json +1 -1
- package/src/commands/flow.js +8 -0
- package/src/commands/start.js +14 -0
- package/src/commands/sweep.js +8 -0
- package/src/commands/workflow.js +8 -0
- package/standards-registry.json +426 -4
- package/bundled/locales/zh-CN/skills/ac-coverage-assistant/SKILL.md +0 -190
- package/bundled/locales/zh-CN/skills/forward-derivation/SKILL.md +0 -71
- package/bundled/locales/zh-CN/skills/forward-derivation/guide.md +0 -130
- package/bundled/locales/zh-CN/skills/methodology-system/SKILL.md +0 -88
- package/bundled/locales/zh-CN/skills/methodology-system/create-methodology.md +0 -350
- package/bundled/locales/zh-CN/skills/methodology-system/guide.md +0 -131
- package/bundled/locales/zh-CN/skills/methodology-system/runtime.md +0 -279
- package/bundled/locales/zh-CN/skills/process-automation/SKILL.md +0 -143
- package/bundled/locales/zh-TW/skills/ac-coverage-assistant/SKILL.md +0 -195
- package/bundled/locales/zh-TW/skills/deploy-assistant/SKILL.md +0 -178
- package/bundled/locales/zh-TW/skills/forward-derivation/SKILL.md +0 -69
- package/bundled/locales/zh-TW/skills/forward-derivation/guide.md +0 -415
- package/bundled/locales/zh-TW/skills/methodology-system/SKILL.md +0 -86
- package/bundled/locales/zh-TW/skills/methodology-system/create-methodology.md +0 -350
- package/bundled/locales/zh-TW/skills/methodology-system/guide.md +0 -131
- package/bundled/locales/zh-TW/skills/methodology-system/runtime.md +0 -279
- package/bundled/locales/zh-TW/skills/process-automation/SKILL.md +0 -144
- /package/bundled/skills/{ac-coverage-assistant → ac-coverage}/SKILL.md +0 -0
- /package/bundled/skills/{methodology-system → dev-methodology}/SKILL.md +0 -0
- /package/bundled/skills/{methodology-system → dev-methodology}/create-methodology.md +0 -0
- /package/bundled/skills/{methodology-system → dev-methodology}/guide.md +0 -0
- /package/bundled/skills/{methodology-system → dev-methodology}/integrated-flow.md +0 -0
- /package/bundled/skills/{methodology-system → dev-methodology}/prerequisite-check.md +0 -0
- /package/bundled/skills/{methodology-system → dev-methodology}/runtime.md +0 -0
- /package/bundled/skills/{forward-derivation → spec-derivation}/guide.md +0 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# Policy as Code 測試標準
|
|
2
|
+
|
|
3
|
+
> 標準 ID:`policy-as-code-testing`
|
|
4
|
+
> 版本:v1.0.0
|
|
5
|
+
> 最後更新:2026-05-05
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 為什麼需要測試 Policy as Code?
|
|
10
|
+
|
|
11
|
+
OPA(Open Policy Agent)的 Rego policy 控制 AI Agent 能否執行生產環境操作。**未測試的 policy = 靜默的安全漏洞。**
|
|
12
|
+
|
|
13
|
+
Policy as Code 的特殊風險:
|
|
14
|
+
1. **邊界條件難以推理**:`reversible: false` + `target_env: "prod"` 組合是否觸發?
|
|
15
|
+
2. **型別錯誤只在執行時爆發**:`array.concat()` 用在 set 型別 → 靜默失效
|
|
16
|
+
3. **Fail-Open 風險**:評估失敗若回傳 `allow: true`,攻擊者可觸發未定義路徑
|
|
17
|
+
4. **Policy 改動回歸**:新增一條 rule 可能意外放行原本被擋的案例
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 一、OPA 測試框架
|
|
22
|
+
|
|
23
|
+
### 測試規則格式
|
|
24
|
+
|
|
25
|
+
```rego
|
|
26
|
+
# 檔案命名:<policy_module>_test.rego
|
|
27
|
+
# Package:<policy_package>_test
|
|
28
|
+
package vibeops.guardian.forbidden_patterns_test
|
|
29
|
+
|
|
30
|
+
import future.keywords.if
|
|
31
|
+
|
|
32
|
+
# 正向測試:規則應觸發(assert rule fires)
|
|
33
|
+
test_drop_database_is_forbidden if {
|
|
34
|
+
data.vibeops.guardian.forbidden_patterns.has_forbidden_pattern with input as {
|
|
35
|
+
"plan": [{"command_type": "sql", "command": "DROP DATABASE prod_main", "reversible": false}]
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# 負向測試:規則不應觸發(assert rule does NOT fire)
|
|
40
|
+
test_safe_select_is_not_forbidden if {
|
|
41
|
+
not data.vibeops.guardian.forbidden_patterns.has_forbidden_pattern with input as {
|
|
42
|
+
"plan": [{"command_type": "sql", "command": "SELECT * FROM users LIMIT 10", "reversible": true}]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 執行方式
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# OPA 已安裝時
|
|
51
|
+
opa test src/guardian/policies/ -v
|
|
52
|
+
|
|
53
|
+
# 透過 Docker(不需安裝 OPA)
|
|
54
|
+
docker run --rm \
|
|
55
|
+
-v "$(pwd)/src/guardian/policies:/policies:ro" \
|
|
56
|
+
openpolicyagent/opa:latest-static \
|
|
57
|
+
test /policies -v
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 二、每個 Policy Module 的最低測試要求
|
|
63
|
+
|
|
64
|
+
| 類型 | 最少案例 | 說明 |
|
|
65
|
+
|------|---------|------|
|
|
66
|
+
| ALLOW cases | 2 | 應該通過的正常操作 |
|
|
67
|
+
| DENY cases | 3 | 應該被攔截的危險操作 |
|
|
68
|
+
| Boundary cases | 1 | 邊界條件(如 reversible=true vs. false)|
|
|
69
|
+
| Integration(main policy)| 2 | 整合 main.rego 的允許 + 拒絕路徑 |
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 三、Policy Module 設計原則
|
|
74
|
+
|
|
75
|
+
### 3.1 Fail-Closed 預設
|
|
76
|
+
|
|
77
|
+
```rego
|
|
78
|
+
# main.rego 必須包含以下預設
|
|
79
|
+
default allow = false
|
|
80
|
+
|
|
81
|
+
allow if {
|
|
82
|
+
not data.vibeops.guardian.forbidden_patterns.has_forbidden_pattern
|
|
83
|
+
not data.vibeops.guardian.env_policy.prod_violation
|
|
84
|
+
not data.vibeops.guardian.logic_constraints.has_logic_violation
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
任何 `undefined` 評估結果都應回傳 DENY,不能回傳 ALLOW。
|
|
89
|
+
|
|
90
|
+
### 3.2 使用 Set(不要 array.concat)
|
|
91
|
+
|
|
92
|
+
OPA ≥ 0.40 的型別系統嚴格區分 array 和 set。`violations` partial rule 是 set 型別,**不可用 `array.concat()`**。
|
|
93
|
+
|
|
94
|
+
```rego
|
|
95
|
+
# ✅ 正確:partial set rule 集合 violations
|
|
96
|
+
deny_reasons[r] if { r := data.vibeops.guardian.forbidden_patterns.violations[_] }
|
|
97
|
+
deny_reasons[r] if { r := data.vibeops.guardian.env_policy.violations[_] }
|
|
98
|
+
deny_reasons[r] if { r := data.vibeops.guardian.logic_constraints.violations[_] }
|
|
99
|
+
|
|
100
|
+
# ❌ 錯誤:array.concat 用在 set 上 → rego_type_error
|
|
101
|
+
# deny_reasons := array.concat(violations1, violations2)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 3.3 禁止解析自由文字欄位
|
|
105
|
+
|
|
106
|
+
Policy 決策**不得依賴** `intent`、`description`、`annotation` 等使用者可控文字欄位。
|
|
107
|
+
|
|
108
|
+
```rego
|
|
109
|
+
# ❌ 危險:解析 intent 欄位 → Prompt Injection 攻擊面(OWASP LLM01)
|
|
110
|
+
allow if { contains(input.intent, "EMERGENCY") }
|
|
111
|
+
|
|
112
|
+
# ✅ 安全:只使用結構化欄位
|
|
113
|
+
allow if {
|
|
114
|
+
input.target_env != "prod"
|
|
115
|
+
every step in input.plan { step.reversible == true }
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### 3.4 一個 Module 管一個關注點
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
policies/
|
|
123
|
+
forbidden_patterns.rego ← 禁止指令模式
|
|
124
|
+
forbidden_patterns_test.rego
|
|
125
|
+
env_policy.rego ← 環境特定規則(prod 保護)
|
|
126
|
+
env_policy_test.rego
|
|
127
|
+
logic_constraints.rego ← 邏輯一致性(stop+start 用 restart)
|
|
128
|
+
logic_constraints_test.rego
|
|
129
|
+
risk_gate.rego ← 風險分數閾值
|
|
130
|
+
risk_gate_test.rego
|
|
131
|
+
main.rego ← 整合所有 module,Fail-Closed
|
|
132
|
+
main_test.rego ← 整合測試
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## 四、CI 整合
|
|
138
|
+
|
|
139
|
+
### GitHub Actions 步驟
|
|
140
|
+
|
|
141
|
+
```yaml
|
|
142
|
+
- name: Test OPA Rego Policies
|
|
143
|
+
run: |
|
|
144
|
+
docker run --rm \
|
|
145
|
+
-v "${{ github.workspace }}/src/guardian/policies:/policies:ro" \
|
|
146
|
+
openpolicyagent/opa:latest-static \
|
|
147
|
+
test /policies -v
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### npm script
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"test:policy": "docker run --rm -v \"$(pwd)/src/guardian/policies:/policies:ro\" openpolicyagent/opa:latest-static test /policies -v"
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 五、品質閘門
|
|
161
|
+
|
|
162
|
+
| 閘門 | 閾值 | 強制程度 |
|
|
163
|
+
|------|------|---------|
|
|
164
|
+
| OPA 測試通過率(CI) | 100%(所有 test_ rule 通過)| Block merge |
|
|
165
|
+
| Root policy Fail-Closed | `default allow = false` 存在 | Block merge |
|
|
166
|
+
| 每個 policy module 有 _test.rego | 每個 .rego 有對應測試 | Advisory |
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 六、反模式(Anti-patterns)
|
|
171
|
+
|
|
172
|
+
| 反模式 | 問題 | 正確做法 |
|
|
173
|
+
|--------|------|---------|
|
|
174
|
+
| `array.concat()` 用在 violations(set 型)| OPA 型別錯誤 | 改用 partial set rule |
|
|
175
|
+
| Root policy 缺少 `default allow = false` | Fail-Open 漏洞 | 加入 default |
|
|
176
|
+
| Intent 欄位參與安全決策 | Prompt Injection 攻擊面 | 只用結構化欄位 |
|
|
177
|
+
| 只測試 DENY(無 ALLOW 測試)| 無法偵測過度限制 | 加入 ALLOW 案例 |
|
|
178
|
+
| _test.rego 只在本機跑,不在 CI | policy 改動無安全網 | CI 加 `opa test` step |
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 參考標準
|
|
183
|
+
|
|
184
|
+
- [OPA Testing Guide](https://www.openpolicyagent.org/docs/latest/policy-testing/)
|
|
185
|
+
- NIST SP 800-204C — Attribute-based Access Control
|
|
186
|
+
- [UDS `secure-op.ai.yaml`](./secure-op.md) — AI Agent 安全操作六大支柱
|
|
187
|
+
- [UDS `adversarial-test.ai.yaml`](./adversarial-test.md) — 對抗性測試(OWASP LLM01)
|
|
188
|
+
- [UDS `container-security.ai.yaml`](./container-security.md) — 容器安全(OPA Sidecar 部署)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Prompt Regression Standards
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
AI agent prompts are code. Unintended changes silently degrade agent behaviour without triggering type errors or unit test failures. Prompt regression tests use golden SHA-256 checksums to detect any modification, forcing developers to explicitly acknowledge and document prompt changes.
|
|
6
|
+
|
|
7
|
+
## Why Checksums
|
|
8
|
+
|
|
9
|
+
- Diffs alone don't block CI — checksums do
|
|
10
|
+
- Prompts are large markdown files; minor edits (whitespace, punctuation) can shift model behaviour
|
|
11
|
+
- Checksum update + comment creates an audit trail of why each prompt changed
|
|
12
|
+
|
|
13
|
+
## Implementation
|
|
14
|
+
|
|
15
|
+
### 1. Compute Initial Checksums
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
for f in agents/*/prompt.md; do
|
|
19
|
+
echo -n "$f: "
|
|
20
|
+
sha256sum "$f" | cut -d' ' -f1
|
|
21
|
+
done
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### 2. Golden Checksum Test (Vitest)
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
28
|
+
import { createHash } from "crypto"
|
|
29
|
+
import { readFileSync } from "fs"
|
|
30
|
+
import { join } from "path"
|
|
31
|
+
import { describe, it, expect } from "vitest"
|
|
32
|
+
|
|
33
|
+
// Update these values ONLY when prompt changes are intentional.
|
|
34
|
+
// Add a comment on the same line explaining WHY the prompt changed.
|
|
35
|
+
const GOLDEN_CHECKSUMS: Record<string, string> = {
|
|
36
|
+
architect: "98017d39b0e48cda88b796687d21e0f884c810805e534453a23b7ad935e4a5ef",
|
|
37
|
+
builder: "5c2acda3e48dae771c61f55d3a5b0d5ac7383870054ef71e757714e367c50031",
|
|
38
|
+
// ... all agents
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
describe("Agent prompt regression (XSPEC-162)", () => {
|
|
42
|
+
for (const [agent, expected] of Object.entries(GOLDEN_CHECKSUMS)) {
|
|
43
|
+
it(`agents/${agent}/prompt.md checksum matches golden`, () => {
|
|
44
|
+
const filePath = join(__dirname, "..", "..", "agents", agent, "prompt.md")
|
|
45
|
+
const content = readFileSync(filePath)
|
|
46
|
+
const actual = createHash("sha256").update(content).digest("hex")
|
|
47
|
+
expect(actual, `Prompt for '${agent}' changed unexpectedly. If intentional, update GOLDEN_CHECKSUMS with a comment.`).toBe(expected)
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 3. CI Integration
|
|
54
|
+
|
|
55
|
+
The checksum test runs as part of the standard `npm run test:coverage` gate (already enforced via XSPEC-156). No additional CI step needed.
|
|
56
|
+
|
|
57
|
+
### 4. Updating Checksums
|
|
58
|
+
|
|
59
|
+
When a prompt change is intentional:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
// BEFORE:
|
|
63
|
+
architect: "98017d39...", // updated 2026-05-05: added Guardian policy XSPEC-160 reference
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The comment is mandatory. PRs that update checksums without explanatory comments should be rejected in code review.
|
|
67
|
+
|
|
68
|
+
## Related Standards
|
|
69
|
+
|
|
70
|
+
- [LLM Output Validation](llm-output-validation.md) — schema-level validation
|
|
71
|
+
- [Adversarial Test](adversarial-test.md) — red-team corpus
|
|
72
|
+
- [Testing Standards](testing.md) — overall testing pyramid
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Property-Based Testing Standards
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Example-based tests only verify the cases a developer thought to write. Property-based testing inverts this: you define an invariant ("the score is always between 0 and 100") and the framework generates hundreds of inputs to try to falsify it. When it finds a failing input, it shrinks it to the minimal counterexample.
|
|
6
|
+
|
|
7
|
+
## When to Use
|
|
8
|
+
|
|
9
|
+
| Use Property Tests | Use Example Tests |
|
|
10
|
+
|-------------------|------------------|
|
|
11
|
+
| Pure math functions | Complex business logic |
|
|
12
|
+
| Parsers / serializers | Integration paths |
|
|
13
|
+
| Score clamping / rounding | UI behaviour |
|
|
14
|
+
| Hash / encoding | Database operations |
|
|
15
|
+
| Security validators | External API calls |
|
|
16
|
+
|
|
17
|
+
## Tool: fast-check (TypeScript)
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install --save-dev fast-check
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import fc from "fast-check"
|
|
25
|
+
import { describe, it, expect } from "vitest"
|
|
26
|
+
import { classifyTokenZone, TOKEN_BUDGET } from "../types/index.js"
|
|
27
|
+
|
|
28
|
+
describe("classifyTokenZone property: result is always a valid zone", () => {
|
|
29
|
+
it("for any ratio in [0, 2], returns a valid TokenBudgetZone", () => {
|
|
30
|
+
fc.assert(
|
|
31
|
+
fc.property(
|
|
32
|
+
fc.float({ min: 0, max: 2, noNaN: true }),
|
|
33
|
+
(ratio) => {
|
|
34
|
+
const zone = classifyTokenZone(ratio)
|
|
35
|
+
return ["safe", "warning", "danger", "blocking"].includes(zone)
|
|
36
|
+
}
|
|
37
|
+
),
|
|
38
|
+
{ numRuns: 1000 }
|
|
39
|
+
)
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Guardian scoreReviewable Properties
|
|
45
|
+
|
|
46
|
+
Key invariants to test:
|
|
47
|
+
|
|
48
|
+
| Property | Description |
|
|
49
|
+
|----------|-------------|
|
|
50
|
+
| **Range clamping** | `score` is always `[0, 100]` |
|
|
51
|
+
| **Determinism** | Same input always produces same score |
|
|
52
|
+
| **Monotonicity** | prod > staging > dev for same operation |
|
|
53
|
+
| **Non-negativity** | `breakdown` values are all >= 0 |
|
|
54
|
+
|
|
55
|
+
## Counterexample Shrinking
|
|
56
|
+
|
|
57
|
+
When fast-check finds a failing case, it automatically shrinks:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
Original failure: { target_env: "prod", command: "rm -rf /tmp/xyz123...", ... }
|
|
61
|
+
Shrunk to: { target_env: "prod", command: "rm", ... }
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Save the seed from the error message to reproduce:
|
|
65
|
+
```typescript
|
|
66
|
+
fc.assert(property, { seed: 1234567890 })
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Related Standards
|
|
70
|
+
|
|
71
|
+
- [Mutation Testing Standards](mutation-testing.md) — complement to PBT
|
|
72
|
+
- [Testing Standards](testing-standards.md) — overall test pyramid
|
|
73
|
+
- [Adversarial Test Standards](adversarial-test.md) — security-focused fuzzing
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Release Quality Manifest
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
A Release Quality Manifest (RQM) is a machine-readable document generated automatically by CI for every release. It aggregates the results of all quality gates into a single artifact that serves as the authoritative evidence of release readiness — both for internal go/no-go automation and for customer audits.
|
|
6
|
+
|
|
7
|
+
## Why a Manifest?
|
|
8
|
+
|
|
9
|
+
Without a manifest, quality evidence is scattered across CI logs, coverage HTML reports, SARIF files, and container scan summaries. When a customer asks "how was this release tested?", the answer is either "trust us" or a 45-minute manual aggregation exercise.
|
|
10
|
+
|
|
11
|
+
A Release Quality Manifest makes quality evidence:
|
|
12
|
+
- **Aggregated**: one file, all gates
|
|
13
|
+
- **Machine-readable**: downstream tooling can parse and enforce
|
|
14
|
+
- **Timestamped and commit-pinned**: tied to a specific release artifact
|
|
15
|
+
- **Customer-shareable**: ready to attach to a release package
|
|
16
|
+
|
|
17
|
+
## Schema
|
|
18
|
+
|
|
19
|
+
```yaml
|
|
20
|
+
release: vibeops-commercial-1.2.0
|
|
21
|
+
generated_at: "2026-05-05T04:00:00Z"
|
|
22
|
+
commit: "abc1234"
|
|
23
|
+
gates:
|
|
24
|
+
unit_coverage:
|
|
25
|
+
actual: "73%"
|
|
26
|
+
target: "80%"
|
|
27
|
+
status: warn # within 10pp of target → warn, not fail
|
|
28
|
+
mutation_score:
|
|
29
|
+
actual: "62%"
|
|
30
|
+
target: "60%"
|
|
31
|
+
status: pass
|
|
32
|
+
sca_critical_cve:
|
|
33
|
+
actual: 0
|
|
34
|
+
target: 0
|
|
35
|
+
status: pass
|
|
36
|
+
sca_high_cve:
|
|
37
|
+
actual: 0
|
|
38
|
+
target: 0
|
|
39
|
+
status: pass
|
|
40
|
+
sast_high:
|
|
41
|
+
actual: 0
|
|
42
|
+
target: 0
|
|
43
|
+
status: pass
|
|
44
|
+
e2e_pass_rate:
|
|
45
|
+
actual: "96%"
|
|
46
|
+
target: "95%"
|
|
47
|
+
status: pass
|
|
48
|
+
container_cve_critical:
|
|
49
|
+
actual: 0
|
|
50
|
+
target: 0
|
|
51
|
+
status: pass
|
|
52
|
+
image_signed:
|
|
53
|
+
actual: true
|
|
54
|
+
target: true
|
|
55
|
+
status: pass
|
|
56
|
+
sbom_present:
|
|
57
|
+
actual: true
|
|
58
|
+
target: true
|
|
59
|
+
status: pass
|
|
60
|
+
overall: WARN # worst gate status (2 warns, no fails)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Status Semantics
|
|
64
|
+
|
|
65
|
+
| Status | Meaning | Action |
|
|
66
|
+
|--------|---------|--------|
|
|
67
|
+
| `pass` | Meets or exceeds target | None required |
|
|
68
|
+
| `warn` | Within acceptable deviation (see per-gate policy) | Document reason; no release block |
|
|
69
|
+
| `fail` | Below hard minimum | **Blocks release** |
|
|
70
|
+
|
|
71
|
+
### Per-Gate Hard Minimums (Examples)
|
|
72
|
+
|
|
73
|
+
| Gate | Warn Band | Fail Threshold |
|
|
74
|
+
|------|-----------|----------------|
|
|
75
|
+
| unit_coverage | target - 10pp to target | below target - 10pp |
|
|
76
|
+
| mutation_score | target - 5pp to target | below target - 5pp |
|
|
77
|
+
| sca_critical_cve | — | any critical CVE = fail |
|
|
78
|
+
| container_cve_critical | — | any critical CVE = fail |
|
|
79
|
+
| e2e_pass_rate | target - 3pp to target | below target - 3pp |
|
|
80
|
+
|
|
81
|
+
## Automated Generation
|
|
82
|
+
|
|
83
|
+
Generate the manifest in CI after all gate jobs complete:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
#!/usr/bin/env bash
|
|
87
|
+
# scripts/generate-quality-manifest.sh
|
|
88
|
+
set -euo pipefail
|
|
89
|
+
|
|
90
|
+
COVERAGE=$(node -e "
|
|
91
|
+
const r = JSON.parse(require('fs').readFileSync('coverage/coverage-summary.json'));
|
|
92
|
+
console.log(r.total.lines.pct.toFixed(1) + '%')
|
|
93
|
+
")
|
|
94
|
+
|
|
95
|
+
MUTATION=$(node -e "
|
|
96
|
+
const r = JSON.parse(require('fs').readFileSync('reports/mutation/mutation-testing-report.json'));
|
|
97
|
+
console.log(r.metrics.mutationScore.toFixed(1) + '%')
|
|
98
|
+
")
|
|
99
|
+
|
|
100
|
+
CRITICAL_CVE=$(jq '[.Results[]?.Vulnerabilities[]? | select(.Severity == "CRITICAL")] | length' trivy-report.json)
|
|
101
|
+
|
|
102
|
+
cat > quality-manifest.yaml <<YAML
|
|
103
|
+
release: ${RELEASE_TAG}
|
|
104
|
+
generated_at: "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
105
|
+
commit: "${GITHUB_SHA:-$(git rev-parse HEAD)}"
|
|
106
|
+
gates:
|
|
107
|
+
unit_coverage:
|
|
108
|
+
actual: "${COVERAGE}"
|
|
109
|
+
target: "80%"
|
|
110
|
+
status: $([ $(echo "$COVERAGE" | tr -d '%') -ge 80 ] && echo pass || echo warn)
|
|
111
|
+
sca_critical_cve:
|
|
112
|
+
actual: ${CRITICAL_CVE}
|
|
113
|
+
target: 0
|
|
114
|
+
status: $([ "$CRITICAL_CVE" -eq 0 ] && echo pass || echo fail)
|
|
115
|
+
overall: $(grep -q "fail" quality-manifest.yaml && echo FAIL || grep -q "warn" quality-manifest.yaml && echo WARN || echo PASS)
|
|
116
|
+
YAML
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Customer-Facing Summary
|
|
120
|
+
|
|
121
|
+
Generate a Markdown table alongside the YAML for inclusion in release notes:
|
|
122
|
+
|
|
123
|
+
```markdown
|
|
124
|
+
## Release Quality Gates — vibeops-commercial-1.2.0
|
|
125
|
+
|
|
126
|
+
| Gate | Actual | Target | Status |
|
|
127
|
+
|------|--------|--------|--------|
|
|
128
|
+
| Unit Test Coverage | 73% | 80% | ⚠️ WARN |
|
|
129
|
+
| Mutation Score | 62% | 60% | ✅ PASS |
|
|
130
|
+
| Critical CVEs | 0 | 0 | ✅ PASS |
|
|
131
|
+
...
|
|
132
|
+
| **Overall** | | | ⚠️ WARN |
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Anti-Patterns
|
|
136
|
+
|
|
137
|
+
- **Manually authoring the manifest** — defeats the purpose; must be generated from tool outputs
|
|
138
|
+
- **Using warn for critical security gates** — `sca_critical_cve` and `container_cve_critical` are binary
|
|
139
|
+
- **Generating the manifest before all gates have run** — values must reflect actual results, not estimates
|
|
140
|
+
- **Not attaching the manifest to the release artifact** — a manifest in git history is not accessible to customers
|
|
141
|
+
|
|
142
|
+
## See Also
|
|
143
|
+
|
|
144
|
+
- `verification-evidence.ai.yaml` — audit evidence principles
|
|
145
|
+
- `supply-chain-attestation.ai.yaml` — SBOM and provenance
|
|
146
|
+
- `testing.ai.yaml` — overall test strategy
|
|
147
|
+
- `deployment-standards.ai.yaml` — release gate integration
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Replay Test Standards
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
AI agent systems interact with users through complex multi-step pipelines. When a customer reports unexpected behaviour, reproducing the exact failure is often difficult — the model output may be non-deterministic, the environment may have changed, or the exact inputs may be unclear. Golden fixture replay solves this by serialising the exact inputs and expected outputs at time of discovery, enabling deterministic regression tests.
|
|
6
|
+
|
|
7
|
+
## Fixture Format
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"meta": {
|
|
12
|
+
"recorded": "2026-05-05",
|
|
13
|
+
"source": "customer-report | ci-regression | red-team | incident",
|
|
14
|
+
"description": "Human-readable description of what this tests"
|
|
15
|
+
},
|
|
16
|
+
"input": { /* exact component input */ },
|
|
17
|
+
"expected": { /* expected output fields to assert */ }
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Fixture Naming
|
|
22
|
+
|
|
23
|
+
`<component>-<outcome>-<description>.json`
|
|
24
|
+
|
|
25
|
+
| Good | Bad |
|
|
26
|
+
|------|-----|
|
|
27
|
+
| `guardian-deny-prod-drop-table.json` | `test1.json` |
|
|
28
|
+
| `guardian-allow-dev-npm-test.json` | `fixture.json` |
|
|
29
|
+
| `guardian-hitl-prod-irreversible.json` | `scenario_3.json` |
|
|
30
|
+
|
|
31
|
+
## Replay Test Implementation (Vitest)
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
35
|
+
import { readdirSync, readFileSync } from "fs"
|
|
36
|
+
import { join } from "path"
|
|
37
|
+
import { describe, it, expect } from "vitest"
|
|
38
|
+
import { scoreReviewable } from "../scoring/risk-engine.js"
|
|
39
|
+
|
|
40
|
+
const FIXTURES_DIR = join(__dirname, "..", "__fixtures__")
|
|
41
|
+
|
|
42
|
+
interface ReplayFixture {
|
|
43
|
+
meta: { recorded: string; source: string; description: string }
|
|
44
|
+
input: Parameters<typeof scoreReviewable>[0]
|
|
45
|
+
expected: { decision: string }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function deriveDecision(score: number): string {
|
|
49
|
+
if (score >= 76) return "DENY"
|
|
50
|
+
if (score >= 51) return "REQUIRE_HITL"
|
|
51
|
+
return "ALLOW"
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
describe("Guardian replay fixtures", () => {
|
|
55
|
+
const fixtures = readdirSync(FIXTURES_DIR)
|
|
56
|
+
.filter(f => f.endsWith(".json"))
|
|
57
|
+
.map(f => ({
|
|
58
|
+
name: f,
|
|
59
|
+
fixture: JSON.parse(readFileSync(join(FIXTURES_DIR, f), "utf-8")) as ReplayFixture,
|
|
60
|
+
}))
|
|
61
|
+
|
|
62
|
+
for (const { name, fixture } of fixtures) {
|
|
63
|
+
it(`[${fixture.meta.source}] ${fixture.meta.description}`, () => {
|
|
64
|
+
const result = scoreReviewable(fixture.input)
|
|
65
|
+
const decision = deriveDecision(result.score)
|
|
66
|
+
expect(decision).toBe(fixture.expected.decision)
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Bug Regression Workflow
|
|
73
|
+
|
|
74
|
+
1. Customer reports unexpected Guardian verdict
|
|
75
|
+
2. Capture the exact `Reviewable` input (from audit logs)
|
|
76
|
+
3. Create fixture file: `guardian-<outcome>-<description>.json`
|
|
77
|
+
4. Reproduce failure locally (test should fail)
|
|
78
|
+
5. Fix the bug
|
|
79
|
+
6. Confirm test passes
|
|
80
|
+
7. The fixture now permanently prevents regression
|
|
81
|
+
|
|
82
|
+
## Related Standards
|
|
83
|
+
|
|
84
|
+
- [Adversarial Test Standards](adversarial-test.md) — red-team corpus
|
|
85
|
+
- [Verification Evidence Standards](verification-evidence.md) — AC traceability
|
|
86
|
+
- [Testing Standards](testing.md) — overall test pyramid
|