universal-dev-standards 5.3.2 → 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/agent-communication-protocol.ai.yaml +32 -166
- package/bundled/ai/standards/agent-dispatch.ai.yaml +32 -58
- package/bundled/ai/standards/audit-trail.ai.yaml +113 -0
- package/bundled/ai/standards/branch-completion.ai.yaml +34 -70
- package/bundled/ai/standards/change-batching-standards.ai.yaml +31 -180
- 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/execution-history.ai.yaml +30 -288
- 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/pipeline-integration-standards.ai.yaml +28 -169
- 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/ai/standards/workflow-enforcement.ai.yaml +34 -240
- package/bundled/ai/standards/workflow-state-protocol.ai.yaml +31 -107
- 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 +474 -12
- 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,521 @@
|
|
|
1
|
+
# 容器安全標準
|
|
2
|
+
|
|
3
|
+
> **版本**:v1.0.0 | **更新日期**:2026-05-04 | **分類**:security
|
|
4
|
+
>
|
|
5
|
+
> AI 最佳化格式:`ai/standards/container-security.ai.yaml`
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 概覽
|
|
10
|
+
|
|
11
|
+
本標準涵蓋容器與 Kubernetes 環境的完整安全要求,適用於所有使用 Docker 或 K8s 部署的服務,尤其針對 **AI Agent 生產環境**(VibeOps)提供特化規則。
|
|
12
|
+
|
|
13
|
+
### 六大安全域
|
|
14
|
+
|
|
15
|
+
| 域 | 說明 |
|
|
16
|
+
|----|------|
|
|
17
|
+
| [映像強化](#1-映像強化-image-hardening) | distroless/alpine base、non-root USER、multi-stage build |
|
|
18
|
+
| [Registry 安全](#2-registry-安全-registry-security) | 私有 Registry、Cosign/Notary 簽章、immutable tag、Trivy |
|
|
19
|
+
| [Runtime 安全](#3-runtime-安全-runtime-security) | read-only rootfs、drop ALL capabilities、seccompProfile |
|
|
20
|
+
| [Secrets 管理](#4-secrets-管理-secrets-management) | 禁止 ENV 傳 secret、K8s Secrets、Vault |
|
|
21
|
+
| [網路策略](#5-網路策略-network-policy) | K8s NetworkPolicy default-deny、AI Agent 出站白名單 |
|
|
22
|
+
| [供應鏈安全](#6-供應鏈安全-supply-chain) | SBOM、digest pin、Sigstore keyless、lockfile 驗證 |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 1. 映像強化(Image Hardening)
|
|
27
|
+
|
|
28
|
+
### 1.1 Base Image 選擇
|
|
29
|
+
|
|
30
|
+
**優先使用**(依安全性排序):
|
|
31
|
+
|
|
32
|
+
| Base Image | 適用場景 | 大小 |
|
|
33
|
+
|------------|---------|------|
|
|
34
|
+
| `gcr.io/distroless/static-debian12` | 靜態二進位(Go) | ~2 MB |
|
|
35
|
+
| `gcr.io/distroless/base-debian12` | 動態連結二進位 | ~20 MB |
|
|
36
|
+
| `gcr.io/distroless/nodejs20-debian12` | Node.js 應用 | ~120 MB |
|
|
37
|
+
| `alpine:3.19` | 需要 shell 的建置場景 | ~7 MB |
|
|
38
|
+
|
|
39
|
+
**禁止**:
|
|
40
|
+
- `ubuntu:latest`、`debian:latest`(浮動 tag + 龐大 attack surface)
|
|
41
|
+
- 以 `latest` tag 指定任何 base image
|
|
42
|
+
- 在 final stage 使用含完整套件管理器的映像
|
|
43
|
+
|
|
44
|
+
### 1.2 Dockerfile 最佳實踐
|
|
45
|
+
|
|
46
|
+
```dockerfile
|
|
47
|
+
# ── 建置階段 ──────────────────────────────────────
|
|
48
|
+
FROM node:20-alpine AS builder
|
|
49
|
+
WORKDIR /app
|
|
50
|
+
COPY package-lock.json package.json ./
|
|
51
|
+
RUN npm ci --only=production # 只安裝 production 依賴
|
|
52
|
+
|
|
53
|
+
COPY src/ ./src/
|
|
54
|
+
RUN npm run build
|
|
55
|
+
|
|
56
|
+
# ── 最終階段(distroless)────────────────────────
|
|
57
|
+
FROM gcr.io/distroless/nodejs20-debian12@sha256:<digest>
|
|
58
|
+
WORKDIR /app
|
|
59
|
+
|
|
60
|
+
# 只複製必要檔案
|
|
61
|
+
COPY --from=builder /app/dist ./dist
|
|
62
|
+
COPY --from=builder /app/node_modules ./node_modules
|
|
63
|
+
|
|
64
|
+
# 強制 non-root(UID 1000)
|
|
65
|
+
USER 1000
|
|
66
|
+
|
|
67
|
+
EXPOSE 3000
|
|
68
|
+
CMD ["dist/index.js"]
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**規則摘要**:
|
|
72
|
+
|
|
73
|
+
- `multi-stage build`:建置工具不進入 final image
|
|
74
|
+
- `USER 1000`:final stage 必須設定非 root 使用者
|
|
75
|
+
- `RUN` 禁止在 final stage 執行套件安裝
|
|
76
|
+
- `COPY` 只複製特定檔案;禁止 `COPY . .` 於 final stage
|
|
77
|
+
- base image 固定 digest(`@sha256:<digest>`),非 tag
|
|
78
|
+
|
|
79
|
+
### 1.3 Kubernetes SecurityContext
|
|
80
|
+
|
|
81
|
+
```yaml
|
|
82
|
+
# Pod 層級
|
|
83
|
+
spec:
|
|
84
|
+
securityContext:
|
|
85
|
+
runAsNonRoot: true
|
|
86
|
+
runAsUser: 1000
|
|
87
|
+
fsGroup: 1000
|
|
88
|
+
seccompProfile:
|
|
89
|
+
type: RuntimeDefault
|
|
90
|
+
|
|
91
|
+
containers:
|
|
92
|
+
- name: ai-agent
|
|
93
|
+
securityContext:
|
|
94
|
+
allowPrivilegeEscalation: false
|
|
95
|
+
readOnlyRootFilesystem: true
|
|
96
|
+
capabilities:
|
|
97
|
+
drop: ["ALL"]
|
|
98
|
+
add: [] # 只在有明確需求時加入,並文件化理由
|
|
99
|
+
# AppArmor(Kubernetes annotation)
|
|
100
|
+
# annotations:
|
|
101
|
+
# container.apparmor.security.beta.kubernetes.io/ai-agent: runtime/default
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 2. Registry 安全(Registry Security)
|
|
107
|
+
|
|
108
|
+
### 2.1 私有 Registry 要求
|
|
109
|
+
|
|
110
|
+
- **生產環境禁止**使用 Docker Hub 公開映像(未驗證來源)
|
|
111
|
+
- 必須使用私有 Registry:GHCR、ECR、GCR、Harbor 等
|
|
112
|
+
- Registry 存取使用 Service Account + RBAC(不用個人帳號密碼)
|
|
113
|
+
|
|
114
|
+
### 2.2 Tag 策略
|
|
115
|
+
|
|
116
|
+
| 環境 | 要求 |
|
|
117
|
+
|------|------|
|
|
118
|
+
| 開發 | `<branch>-<git-sha>` |
|
|
119
|
+
| Staging | `<semver>-rc.<N>` |
|
|
120
|
+
| 生產 | `<semver>`(e.g., `v1.2.3`)+ digest pin |
|
|
121
|
+
|
|
122
|
+
**禁止**:生產 Deployment 使用 `latest` tag。
|
|
123
|
+
|
|
124
|
+
### 2.3 映像簽章(Cosign)
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# 建置後簽章
|
|
128
|
+
IMAGE_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' myimage)
|
|
129
|
+
cosign sign "${IMAGE_DIGEST}"
|
|
130
|
+
|
|
131
|
+
# 驗證(在 CI 或 Admission Controller)
|
|
132
|
+
cosign verify \
|
|
133
|
+
--certificate-identity-regexp="https://github.com/org/repo/.*" \
|
|
134
|
+
--certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
|
|
135
|
+
"${IMAGE_DIGEST}"
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 2.4 Trivy 弱點掃描 Gate
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# CI 強制 gate:critical 或 high CVE → 阻擋推送
|
|
142
|
+
trivy image \
|
|
143
|
+
--exit-code 1 \
|
|
144
|
+
--severity CRITICAL,HIGH \
|
|
145
|
+
--ignore-unfixed \
|
|
146
|
+
myimage:v1.2.3
|
|
147
|
+
|
|
148
|
+
# 周期性掃描(已部署映像)
|
|
149
|
+
trivy image --format json --output trivy-report.json myimage@sha256:<digest>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**SLA**:
|
|
153
|
+
|
|
154
|
+
| 嚴重度 | 允許推送 | 修補期限 |
|
|
155
|
+
|--------|---------|---------|
|
|
156
|
+
| Critical | 否 | 立即修補 |
|
|
157
|
+
| High | 否 | 24 小時內 |
|
|
158
|
+
| Medium | 是 | 7 天內 |
|
|
159
|
+
| Low | 是 | 下次維護窗口 |
|
|
160
|
+
|
|
161
|
+
> **Trial / Community Edition 強制啟用**:避免 supply chain compromise,所有版本均強制 Trivy gate。
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## 3. Runtime 安全(Runtime Security)
|
|
166
|
+
|
|
167
|
+
### 3.1 禁止項目
|
|
168
|
+
|
|
169
|
+
```yaml
|
|
170
|
+
# 以下設定禁止用於生產環境
|
|
171
|
+
securityContext:
|
|
172
|
+
privileged: true # 禁止
|
|
173
|
+
spec:
|
|
174
|
+
hostNetwork: true # 禁止(除非有書面需求核准)
|
|
175
|
+
hostPID: true # 禁止
|
|
176
|
+
hostIPC: true # 禁止
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 3.2 Seccomp Profile
|
|
180
|
+
|
|
181
|
+
```yaml
|
|
182
|
+
# Pod 層級啟用 RuntimeDefault
|
|
183
|
+
spec:
|
|
184
|
+
securityContext:
|
|
185
|
+
seccompProfile:
|
|
186
|
+
type: RuntimeDefault # 封鎖 300+ 危險 syscall
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
若服務需要自訂 syscall 清單,使用 `Localhost` profile 並維護 seccomp JSON 文件。
|
|
190
|
+
|
|
191
|
+
### 3.3 Writable Volume 策略
|
|
192
|
+
|
|
193
|
+
| 用途 | 允許掛載類型 |
|
|
194
|
+
|------|------------|
|
|
195
|
+
| 應用程式資料 | PersistentVolumeClaim |
|
|
196
|
+
| 暫存檔案 | `emptyDir`(限 /tmp) |
|
|
197
|
+
| Audit Log | hostPath(append-only partition)|
|
|
198
|
+
| Secret | K8s Secret volume mount |
|
|
199
|
+
|
|
200
|
+
**禁止**:將 `emptyDir` 用作 audit log 存放位置(重啟後資料消失)。
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 4. Secrets 管理(Secrets Management)
|
|
205
|
+
|
|
206
|
+
### 4.1 禁止模式
|
|
207
|
+
|
|
208
|
+
```dockerfile
|
|
209
|
+
# ❌ 禁止:Secret 硬編碼在映像中
|
|
210
|
+
ENV API_KEY=sk-abc123
|
|
211
|
+
|
|
212
|
+
# ❌ 禁止:Secret 在 build ARG(會殘留 layer)
|
|
213
|
+
ARG DATABASE_PASSWORD
|
|
214
|
+
RUN configure --password=$DATABASE_PASSWORD
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
```yaml
|
|
218
|
+
# ❌ 禁止:Secret 以明文存 ConfigMap
|
|
219
|
+
apiVersion: v1
|
|
220
|
+
kind: ConfigMap
|
|
221
|
+
data:
|
|
222
|
+
api_key: "sk-real-key" # 禁止
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### 4.2 允許模式
|
|
226
|
+
|
|
227
|
+
**Staging:K8s Secret + Volume Mount**
|
|
228
|
+
|
|
229
|
+
```yaml
|
|
230
|
+
# K8s Secret(base64 encoded)
|
|
231
|
+
apiVersion: v1
|
|
232
|
+
kind: Secret
|
|
233
|
+
metadata:
|
|
234
|
+
name: ai-agent-secrets
|
|
235
|
+
type: Opaque
|
|
236
|
+
data:
|
|
237
|
+
anthropic-api-key: <base64-encoded-value>
|
|
238
|
+
---
|
|
239
|
+
# Pod 掛載
|
|
240
|
+
spec:
|
|
241
|
+
containers:
|
|
242
|
+
- name: ai-agent
|
|
243
|
+
volumeMounts:
|
|
244
|
+
- name: secrets
|
|
245
|
+
mountPath: /run/secrets
|
|
246
|
+
readOnly: true
|
|
247
|
+
volumes:
|
|
248
|
+
- name: secrets
|
|
249
|
+
secret:
|
|
250
|
+
secretName: ai-agent-secrets
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**生產:Vault Agent Injector(推薦)**
|
|
254
|
+
|
|
255
|
+
```yaml
|
|
256
|
+
# 使用 Vault annotation 自動注入 secret
|
|
257
|
+
spec:
|
|
258
|
+
template:
|
|
259
|
+
metadata:
|
|
260
|
+
annotations:
|
|
261
|
+
vault.hashicorp.com/agent-inject: "true"
|
|
262
|
+
vault.hashicorp.com/role: "ai-agent"
|
|
263
|
+
vault.hashicorp.com/agent-inject-secret-api-key: "secret/ai-agent/anthropic"
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### 4.3 AI Agent 特殊規則
|
|
267
|
+
|
|
268
|
+
- LLM API 金鑰(Anthropic、OpenAI)**必須**透過 mounted secret volume 注入,不得使用 ENV
|
|
269
|
+
- Guardian OPA policy 檔案**不是** secret,使用 ConfigMap 即可
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## 5. 網路策略(Network Policy)
|
|
274
|
+
|
|
275
|
+
### 5.1 Default Deny 基準策略
|
|
276
|
+
|
|
277
|
+
```yaml
|
|
278
|
+
# 每個 namespace 必須先套用 default-deny
|
|
279
|
+
apiVersion: networking.k8s.io/v1
|
|
280
|
+
kind: NetworkPolicy
|
|
281
|
+
metadata:
|
|
282
|
+
name: default-deny-all
|
|
283
|
+
namespace: vibeops
|
|
284
|
+
spec:
|
|
285
|
+
podSelector: {} # 套用到所有 Pod
|
|
286
|
+
policyTypes:
|
|
287
|
+
- Ingress
|
|
288
|
+
- Egress
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### 5.2 AI Agent 出站白名單
|
|
292
|
+
|
|
293
|
+
```yaml
|
|
294
|
+
apiVersion: networking.k8s.io/v1
|
|
295
|
+
kind: NetworkPolicy
|
|
296
|
+
metadata:
|
|
297
|
+
name: ai-agent-egress-allowlist
|
|
298
|
+
namespace: vibeops
|
|
299
|
+
spec:
|
|
300
|
+
podSelector:
|
|
301
|
+
matchLabels:
|
|
302
|
+
app: ai-agent
|
|
303
|
+
policyTypes:
|
|
304
|
+
- Egress
|
|
305
|
+
egress:
|
|
306
|
+
# DNS(必須)
|
|
307
|
+
- ports:
|
|
308
|
+
- protocol: UDP
|
|
309
|
+
port: 53
|
|
310
|
+
- protocol: TCP
|
|
311
|
+
port: 53
|
|
312
|
+
# Anthropic API
|
|
313
|
+
- to:
|
|
314
|
+
- ipBlock:
|
|
315
|
+
cidr: 0.0.0.0/0 # 實際部署時替換為 Anthropic IP range
|
|
316
|
+
ports:
|
|
317
|
+
- protocol: TCP
|
|
318
|
+
port: 443
|
|
319
|
+
# kube-dns / CoreDNS
|
|
320
|
+
- to:
|
|
321
|
+
- namespaceSelector:
|
|
322
|
+
matchLabels:
|
|
323
|
+
kubernetes.io/metadata.name: kube-system
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**允許出站端點清單**:
|
|
327
|
+
|
|
328
|
+
| 端點 | 協定 | 埠 | 用途 |
|
|
329
|
+
|------|------|-----|------|
|
|
330
|
+
| `api.anthropic.com` | HTTPS | 443 | Claude LLM API |
|
|
331
|
+
| `api.openai.com` | HTTPS | 443 | OpenAI LLM API |
|
|
332
|
+
| `bedrock.*.amazonaws.com` | HTTPS | 443 | AWS Bedrock |
|
|
333
|
+
| CoreDNS | UDP/TCP | 53 | DNS 解析 |
|
|
334
|
+
|
|
335
|
+
### 5.3 Guardian OPA Sidecar 部署
|
|
336
|
+
|
|
337
|
+
```yaml
|
|
338
|
+
# Guardian 作為 sidecar container(同 Pod)
|
|
339
|
+
spec:
|
|
340
|
+
containers:
|
|
341
|
+
- name: ai-agent
|
|
342
|
+
image: vibeops/ai-agent:v1.2.3@sha256:<digest>
|
|
343
|
+
# ...
|
|
344
|
+
- name: guardian-opa
|
|
345
|
+
image: openpolicyagent/opa:latest-rootless@sha256:<digest>
|
|
346
|
+
args:
|
|
347
|
+
- run
|
|
348
|
+
- --server
|
|
349
|
+
- --addr=localhost:8181
|
|
350
|
+
- /policies
|
|
351
|
+
volumeMounts:
|
|
352
|
+
- name: opa-policies
|
|
353
|
+
mountPath: /policies
|
|
354
|
+
readOnly: true
|
|
355
|
+
volumes:
|
|
356
|
+
- name: opa-policies
|
|
357
|
+
configMap:
|
|
358
|
+
name: guardian-opa-policies
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## 6. 供應鏈安全(Supply Chain)
|
|
364
|
+
|
|
365
|
+
### 6.1 SBOM 生成
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
# 使用 Syft 生成 CycloneDX 格式 SBOM
|
|
369
|
+
syft myimage:v1.2.3 -o cyclonedx-json > sbom-v1.2.3.json
|
|
370
|
+
|
|
371
|
+
# 使用 Trivy 生成 SPDX 格式 SBOM
|
|
372
|
+
trivy image --format spdx-json --output sbom.spdx.json myimage:v1.2.3
|
|
373
|
+
|
|
374
|
+
# 附加到 OCI Registry(Cosign)
|
|
375
|
+
cosign attach sbom --sbom sbom-v1.2.3.json myimage@sha256:<digest>
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### 6.2 Digest Pinning
|
|
379
|
+
|
|
380
|
+
```dockerfile
|
|
381
|
+
# ✅ 正確:使用 digest 固定
|
|
382
|
+
FROM gcr.io/distroless/nodejs20-debian12@sha256:abc123...
|
|
383
|
+
|
|
384
|
+
# ❌ 錯誤:浮動 tag
|
|
385
|
+
FROM gcr.io/distroless/nodejs20-debian12:latest
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
```yaml
|
|
389
|
+
# ✅ 正確:K8s Deployment 使用 digest
|
|
390
|
+
spec:
|
|
391
|
+
containers:
|
|
392
|
+
- image: myregistry.io/ai-agent:v1.2.3@sha256:def456...
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### 6.3 Sigstore Keyless Signing(GitHub Actions)
|
|
396
|
+
|
|
397
|
+
```yaml
|
|
398
|
+
# .github/workflows/build-push.yml
|
|
399
|
+
- name: Sign container image
|
|
400
|
+
uses: sigstore/cosign-installer@v3
|
|
401
|
+
- name: Sign
|
|
402
|
+
run: |
|
|
403
|
+
cosign sign --yes \
|
|
404
|
+
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
|
|
405
|
+
env:
|
|
406
|
+
COSIGN_EXPERIMENTAL: "true" # Keyless (OIDC)
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### 6.4 各語言 Lockfile 驗證
|
|
410
|
+
|
|
411
|
+
**Node.js**:
|
|
412
|
+
```bash
|
|
413
|
+
# 使用 npm ci(嚴格 lockfile)
|
|
414
|
+
npm ci --only=production
|
|
415
|
+
|
|
416
|
+
# 不允許
|
|
417
|
+
npm install # 可能更新 lockfile
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**Python**:
|
|
421
|
+
```bash
|
|
422
|
+
# 使用 hash 驗證
|
|
423
|
+
pip install --require-hashes -r requirements.txt
|
|
424
|
+
|
|
425
|
+
# 生成(使用 pip-tools)
|
|
426
|
+
pip-compile --generate-hashes requirements.in -o requirements.txt
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
**Go**:
|
|
430
|
+
```bash
|
|
431
|
+
# 驗證 go.sum 完整性
|
|
432
|
+
go mod verify
|
|
433
|
+
|
|
434
|
+
# 下載並驗證
|
|
435
|
+
GONOSUMCHECK="" GOFLAGS="-mod=mod" go mod download
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
## AI Agent 特殊考量
|
|
441
|
+
|
|
442
|
+
本節補充 AI Agent(VibeOps)相關的容器安全特化要求:
|
|
443
|
+
|
|
444
|
+
### 強制要求
|
|
445
|
+
|
|
446
|
+
| 項目 | 要求 | 說明 |
|
|
447
|
+
|------|------|------|
|
|
448
|
+
| Container UID | 1000(非 root) | LLM 呼叫流程不得以 root 執行 |
|
|
449
|
+
| 出站白名單 | api.anthropic.com / api.openai.com / bedrock.*.amazonaws.com | NetworkPolicy 明確允許 |
|
|
450
|
+
| Guardian OPA Sidecar | 同 Pod 或同 namespace | 才能實施 Veto 決策 |
|
|
451
|
+
| Audit Log Volume | append-only partition | 禁止 emptyDir;重啟後不可消失 |
|
|
452
|
+
| LLM API Key 注入 | Mounted secret volume | 禁止 ENV 注入 |
|
|
453
|
+
| Trivy Gate | 強制(含 Trial/Community) | 避免 supply chain compromise |
|
|
454
|
+
|
|
455
|
+
### Audit Log Volume 配置
|
|
456
|
+
|
|
457
|
+
```yaml
|
|
458
|
+
# ✅ 正確:hostPath 指向 append-only partition
|
|
459
|
+
volumes:
|
|
460
|
+
- name: audit-log
|
|
461
|
+
hostPath:
|
|
462
|
+
path: /var/log/vibeops/audit # 需事先 chattr +a
|
|
463
|
+
type: DirectoryOrCreate
|
|
464
|
+
|
|
465
|
+
# ❌ 錯誤:emptyDir(重啟消失)
|
|
466
|
+
volumes:
|
|
467
|
+
- name: audit-log
|
|
468
|
+
emptyDir: {}
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
在宿主機設定 append-only:
|
|
472
|
+
```bash
|
|
473
|
+
# 設定目錄為 append-only(需 root)
|
|
474
|
+
chattr +a /var/log/vibeops/audit
|
|
475
|
+
lsattr /var/log/vibeops/audit # 驗證 a 屬性
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
## 合規對映表
|
|
481
|
+
|
|
482
|
+
| 標準 | 章節 | 對映到本標準 |
|
|
483
|
+
|------|------|------------|
|
|
484
|
+
| ISO/IEC 27001:2022 | A.8.9 Configuration Management | Image Hardening、Runtime Security |
|
|
485
|
+
| ISO/IEC 27001:2022 | A.8.12 Data Leakage Prevention | Secrets Management |
|
|
486
|
+
| ISO/IEC 27001:2022 | A.8.20 Networks Security | Network Policy |
|
|
487
|
+
| ISO/IEC 27001:2022 | A.8.22 Web Filtering | Network Policy 出站白名單 |
|
|
488
|
+
| ISO/IEC 27001:2022 | A.8.8 Technical Vulnerabilities | Registry Security(Trivy)|
|
|
489
|
+
| ISO/IEC 27001:2022 | A.8.24 Use of Cryptography | Secrets Management |
|
|
490
|
+
| NIST SP 800-190 | §4.1 Image Vulnerabilities | Image Hardening |
|
|
491
|
+
| NIST SP 800-190 | §4.2 Image Configuration Defects | Registry Security |
|
|
492
|
+
| NIST SP 800-190 | §4.3 Container Runtime Vulnerabilities | Runtime Security |
|
|
493
|
+
| NIST SP 800-190 | §4.4 Image and Registry Vulnerabilities | Supply Chain |
|
|
494
|
+
| NIST SP 800-190 | §4.5 Host OS Vulnerabilities | Supply Chain |
|
|
495
|
+
| CIS Docker Benchmark v1.6 | §4 Container Images | Image Hardening |
|
|
496
|
+
| CIS Docker Benchmark v1.6 | §5 Container Runtime | Runtime Security |
|
|
497
|
+
| CIS Kubernetes Benchmark v1.8 | §5.3 Network Policies | Network Policy |
|
|
498
|
+
| SLSA Framework | Level 2+ provenance | Supply Chain |
|
|
499
|
+
|
|
500
|
+
---
|
|
501
|
+
|
|
502
|
+
## 快速檢查清單
|
|
503
|
+
|
|
504
|
+
```
|
|
505
|
+
□ Base image 固定 digest(不用 tag)
|
|
506
|
+
□ Multi-stage build;只 COPY 產物到 final stage
|
|
507
|
+
□ Final stage:USER 1000(non-root)
|
|
508
|
+
□ securityContext:runAsNonRoot、readOnlyRootFilesystem、allowPrivilegeEscalation:false
|
|
509
|
+
□ capabilities.drop: [ALL]
|
|
510
|
+
□ seccompProfile:RuntimeDefault
|
|
511
|
+
□ Trivy scan:0 critical、0 high,才可推送
|
|
512
|
+
□ Image 已簽章(Cosign / Notary v2)
|
|
513
|
+
□ SBOM 已生成(CycloneDX 或 SPDX)
|
|
514
|
+
□ Dockerfile 無 ENV secret、無 build-arg secret
|
|
515
|
+
□ K8s Secret 或 Vault 注入 secret(非 ENV)
|
|
516
|
+
□ NetworkPolicy:default-deny + 明確 allow
|
|
517
|
+
□ AI Agent egress:allowlist(Anthropic、OpenAI、Bedrock)
|
|
518
|
+
□ Guardian OPA Sidecar:同 Pod 或同 namespace
|
|
519
|
+
□ Audit log volume:append-only partition(非 emptyDir)
|
|
520
|
+
□ Lockfile 固定(npm ci / pip --require-hashes / go mod verify)
|
|
521
|
+
```
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Cost Budget Test Standards
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
AI agent systems that call LLM APIs can accumulate costs rapidly if a pipeline runs in a runaway loop, encounters an unexpected token explosion, or has misconfigured budget thresholds. Cost budget tests verify that the zone classifier, threshold constants, and pipeline budget guards behave correctly at every boundary.
|
|
6
|
+
|
|
7
|
+
## Zone Classification
|
|
8
|
+
|
|
9
|
+
Most AI agent token budget systems divide usage ratios into zones. The boundaries between zones are the highest-risk points for off-by-one errors.
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
// Vitest boundary tests using TOKEN_BUDGET constants (not magic numbers)
|
|
13
|
+
import { classifyTokenZone, TOKEN_BUDGET } from "../types/index.js"
|
|
14
|
+
import { describe, it, expect } from "vitest"
|
|
15
|
+
|
|
16
|
+
describe("TokenBudgetZone classification boundaries", () => {
|
|
17
|
+
it.each([
|
|
18
|
+
[0.0, "safe", "zero usage"],
|
|
19
|
+
[TOKEN_BUDGET.WARNING_THRESHOLD - 0.01, "safe", "just below WARNING"],
|
|
20
|
+
[TOKEN_BUDGET.WARNING_THRESHOLD, "warning", "exactly at WARNING"],
|
|
21
|
+
[TOKEN_BUDGET.DANGER_THRESHOLD - 0.01, "warning", "just below DANGER"],
|
|
22
|
+
[TOKEN_BUDGET.DANGER_THRESHOLD, "danger", "exactly at DANGER"],
|
|
23
|
+
[TOKEN_BUDGET.BLOCKING_THRESHOLD - 0.01,"danger", "just below BLOCKING"],
|
|
24
|
+
[TOKEN_BUDGET.BLOCKING_THRESHOLD, "blocking", "exactly at BLOCKING"],
|
|
25
|
+
[1.0, "blocking", "fully exhausted"],
|
|
26
|
+
])("ratio=%f → %s (%s)", (ratio, expected) => {
|
|
27
|
+
expect(classifyTokenZone(ratio)).toBe(expected)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it("returns 'blocking' for ratio > 1.0 (over-budget)", () => {
|
|
31
|
+
expect(classifyTokenZone(1.5)).toBe("blocking")
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Pipeline Budget Config Tests
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import type { PipelineBudgetConfig } from "../types/index.js"
|
|
40
|
+
|
|
41
|
+
describe("PipelineBudgetConfig semantics", () => {
|
|
42
|
+
it("warningThreshold defaults should be 0-1 range", () => {
|
|
43
|
+
const config: PipelineBudgetConfig = {
|
|
44
|
+
maxCostPerRun: 1.0,
|
|
45
|
+
maxCostPerDay: 10.0,
|
|
46
|
+
warningThreshold: 0.8,
|
|
47
|
+
autoDowngrade: true,
|
|
48
|
+
}
|
|
49
|
+
expect(config.warningThreshold).toBeGreaterThan(0)
|
|
50
|
+
expect(config.warningThreshold).toBeLessThan(1)
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## What to Test
|
|
56
|
+
|
|
57
|
+
| Test Category | Why |
|
|
58
|
+
|---------------|-----|
|
|
59
|
+
| Exact boundary values (WARNING/DANGER/BLOCKING) | Off-by-one errors hide here |
|
|
60
|
+
| Below each boundary | Confirm zone below is correct |
|
|
61
|
+
| Zero usage ratio | Clean state |
|
|
62
|
+
| Ratio > 1.0 | Over-budget should still block |
|
|
63
|
+
| All TOKEN_BUDGET constants referenced | Mutation survival prevention |
|
|
64
|
+
|
|
65
|
+
## Related Standards
|
|
66
|
+
|
|
67
|
+
- [Mutation Testing Standards](mutation-testing.md) — constants without test coverage survive mutations
|
|
68
|
+
- [Testing Standards](testing.md) — overall test pyramid
|
|
69
|
+
- [LLM Output Validation](llm-output-validation.md) — output-layer budget constraints
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Data Migration Testing
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Database schema migrations are high-risk operations: they transform persistent data in ways that cannot be easily undone without a tested rollback path. A comprehensive migration test suite validates three axes — correctness (up applies cleanly), safety (down restores state), and robustness (applying twice is harmless).
|
|
6
|
+
|
|
7
|
+
## Requirements Summary
|
|
8
|
+
|
|
9
|
+
| ID | Rule | Rationale |
|
|
10
|
+
|----|------|-----------|
|
|
11
|
+
| REQ-DMT-001 | Every migration must have an up test | Unverified migrations corrupt production schema |
|
|
12
|
+
| REQ-DMT-002 | Every migration with a down function must have a rollback test | Untested rollbacks fail during incidents |
|
|
13
|
+
| REQ-DMT-003 | Applying the same migration twice must not fail | CI retries can trigger double-apply |
|
|
14
|
+
| REQ-DMT-004 | Migrations that alter data must include a data preservation test | Schema correctness ≠ data correctness |
|
|
15
|
+
| REQ-DMT-005 | Each test must use an isolated database | Shared state causes non-deterministic failures |
|
|
16
|
+
|
|
17
|
+
## Test Structure
|
|
18
|
+
|
|
19
|
+
### Isolation
|
|
20
|
+
|
|
21
|
+
Every migration test runs against an isolated database — either in-memory (SQLite `:memory:`) or a fresh Docker container (PostgreSQL). Never run migration tests against a shared development or staging database.
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// Good: isolated in-memory database per test file
|
|
25
|
+
const db = new Database(':memory:')
|
|
26
|
+
await applyBaseline(db)
|
|
27
|
+
|
|
28
|
+
// Bad: tests share a dev database
|
|
29
|
+
const db = openDatabase(process.env.DATABASE_URL)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Up Test
|
|
33
|
+
|
|
34
|
+
Apply the migration to a baseline schema. Assert the expected post-state.
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
it('adds email column to users table', async () => {
|
|
38
|
+
await migrate.up(db)
|
|
39
|
+
const columns = db.prepare("PRAGMA table_info(users)").all()
|
|
40
|
+
expect(columns.map(c => c.name)).toContain('email')
|
|
41
|
+
})
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Down Test (Rollback)
|
|
45
|
+
|
|
46
|
+
Apply up, then down. Assert the schema returns to its pre-migration state.
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
it('rollback removes email column', async () => {
|
|
50
|
+
await migrate.up(db)
|
|
51
|
+
await migrate.down(db)
|
|
52
|
+
const columns = db.prepare("PRAGMA table_info(users)").all()
|
|
53
|
+
expect(columns.map(c => c.name)).not.toContain('email')
|
|
54
|
+
})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Idempotency Test
|
|
58
|
+
|
|
59
|
+
Apply the migration twice. The second apply must not throw.
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
it('applying migration twice is safe', async () => {
|
|
63
|
+
await migrate.up(db)
|
|
64
|
+
await expect(migrate.up(db)).resolves.not.toThrow()
|
|
65
|
+
})
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Data Preservation Test
|
|
69
|
+
|
|
70
|
+
Seed rows before the migration. Assert data integrity after.
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
it('preserves existing user rows', async () => {
|
|
74
|
+
db.prepare("INSERT INTO users (id, name) VALUES (1, 'Alice')").run()
|
|
75
|
+
await migrate.up(db)
|
|
76
|
+
const user = db.prepare("SELECT * FROM users WHERE id = 1").get()
|
|
77
|
+
expect(user.name).toBe('Alice')
|
|
78
|
+
})
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Tooling
|
|
82
|
+
|
|
83
|
+
### SQLite / Drizzle ORM
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import Database from 'better-sqlite3'
|
|
87
|
+
import { drizzle } from 'drizzle-orm/better-sqlite3'
|
|
88
|
+
import { migrate } from 'drizzle-orm/better-sqlite3/migrator'
|
|
89
|
+
|
|
90
|
+
const sqlite = new Database(':memory:')
|
|
91
|
+
const db = drizzle(sqlite)
|
|
92
|
+
await migrate(db, { migrationsFolder: './drizzle' })
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### PostgreSQL
|
|
96
|
+
|
|
97
|
+
Use `testcontainers` to spin up a fresh PostgreSQL container per test suite. The container is destroyed after the suite, guaranteeing isolation.
|
|
98
|
+
|
|
99
|
+
## Anti-Patterns
|
|
100
|
+
|
|
101
|
+
- **Testing against a shared database** — causes cross-test pollution, non-repeatable builds
|
|
102
|
+
- **Skipping down migration tests** — rollbacks fail during production incidents
|
|
103
|
+
- **Writing migration tests after the fact without seeding data** — misses data preservation bugs entirely
|
|
104
|
+
- **Committing a migration without a corresponding test** — the migration is untested until production
|
|
105
|
+
|
|
106
|
+
## See Also
|
|
107
|
+
|
|
108
|
+
- `database-standards.ai.yaml` — schema design principles
|
|
109
|
+
- `testing.ai.yaml` — general test structure and pyramid
|
|
110
|
+
- `verification-evidence.ai.yaml` — audit evidence requirements
|