@metasession.co/devaudit-cli 0.3.18 → 0.3.19
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/dist/index.js +35 -34
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/scripts/upload-evidence.sh +23 -19
- package/sdlc/files/_common/governance/incident-report.md.template +6 -1
- package/sdlc/files/_common/governance/nil-incident-report.md.template +5 -2
- package/sdlc/files/_common/scripts/check-release-pr-scope.sh +8 -1
- package/sdlc/files/_common/scripts/check-release-pr-scope.test.sh +58 -10
- package/sdlc/files/_common/scripts/check-self-hosted-runner.sh +103 -0
- package/sdlc/files/_common/scripts/check-self-hosted-runner.test.sh +74 -0
- package/sdlc/files/_common/scripts/record-uat-execution.sh +195 -0
- package/sdlc/files/_common/scripts/record-uat-execution.test.sh +144 -0
- package/sdlc/files/_common/scripts/render-test-executions.sh +146 -0
- package/sdlc/files/_common/scripts/{render-test-cycles.test.sh → render-test-executions.test.sh} +12 -18
- package/sdlc/files/_common/scripts/{report-test-cycle.sh → report-test-execution.sh} +66 -74
- package/sdlc/files/_common/scripts/report-test-execution.test.sh +177 -0
- package/sdlc/files/_common/scripts/submit-for-uat-review.sh +21 -0
- package/sdlc/files/_common/scripts/upload-evidence.sh +23 -19
- package/sdlc/files/_common/scripts/validate-commits.sh +6 -4
- package/sdlc/files/_common/scripts/validate-commits.test.sh +15 -0
- package/sdlc/files/_common/skills/e2e-test-engineer/SKILL.md +9 -7
- package/sdlc/files/_common/skills/e2e-test-engineer/references/e2e-regression-3-tier.yml +4 -1
- package/sdlc/files/_common/skills/sdlc-implementer/SKILL.md +16 -14
- package/sdlc/files/ci/ci.yml.template +54 -44
- package/sdlc/files/ci/compliance-evidence.yml.template +135 -46
- package/sdlc/files/ci/feature-e2e.yml.template +17 -17
- package/sdlc/files/ci/incident-export.yml.template +18 -4
- package/sdlc/files/ci/post-deploy-prod.yml.template +33 -30
- package/sdlc/files/ci/python/ci.yml.template +14 -14
- package/sdlc/files/ci/quality-gates-provenance.yml.template +3 -0
- package/sdlc/package.json +1 -1
- package/sdlc/src/blueprints/3-compile-evidence.raw.md +10 -10
- package/sdlc/src/blueprints/4-submit-for-review.raw.md +1 -1
- package/sdlc/src/blueprints/5-deploy-main.raw.md +1 -1
- package/sdlc/src/blueprints/implementing-an-sdlc-issue.raw.md +3 -3
- package/sdlc/files/_common/scripts/render-test-cycles.sh +0 -227
|
@@ -38,7 +38,10 @@ jobs:
|
|
|
38
38
|
if: >-
|
|
39
39
|
github.event_name == 'workflow_dispatch' ||
|
|
40
40
|
(github.event.deployment_status.state == 'success' &&
|
|
41
|
-
(github.event.deployment.environment == 'production' ||
|
|
41
|
+
(github.event.deployment.environment == 'production' ||
|
|
42
|
+
github.event.deployment.environment == 'prod' ||
|
|
43
|
+
endsWith(github.event.deployment.environment, '/ production') ||
|
|
44
|
+
endsWith(github.event.deployment.environment, '/production')))
|
|
42
45
|
runs-on: {{RUNNER}}
|
|
43
46
|
permissions:
|
|
44
47
|
contents: read
|
|
@@ -144,17 +147,17 @@ jobs:
|
|
|
144
147
|
echo "In-scope releases to promote: ${REQS}"
|
|
145
148
|
echo "REQS=${REQS}" >> "$GITHUB_ENV"
|
|
146
149
|
|
|
147
|
-
- name: Start production deployment
|
|
150
|
+
- name: Start production deployment executions
|
|
148
151
|
run: |
|
|
149
|
-
chmod +x scripts/report-test-
|
|
152
|
+
chmod +x scripts/report-test-execution.sh 2>/dev/null || true
|
|
150
153
|
for PREFIX in ${REQS}; do
|
|
151
154
|
RESP=$(curl -fsS -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
|
|
152
155
|
"${BASE}/api/ci/releases/resolve?projectSlug=${PROJECT_SLUG}&versionPrefix=${PREFIX}")
|
|
153
156
|
VERSION=$(echo "$RESP" | jq -r '.latest.version // empty')
|
|
154
157
|
[ -n "$VERSION" ] || VERSION="$PREFIX"
|
|
155
|
-
bash scripts/report-test-
|
|
158
|
+
bash scripts/report-test-execution.sh start \
|
|
156
159
|
--project-slug "$PROJECT_SLUG" --release "$VERSION" \
|
|
157
|
-
--sdlc-stage 5 --environment production --
|
|
160
|
+
--sdlc-stage 5 --environment production --suite-kind deployment \
|
|
158
161
|
--provider github_actions --external-run-id "$CI_RUN" \
|
|
159
162
|
--external-run-attempt "${{ github.run_attempt }}" --external-job-id "host-deployment" \
|
|
160
163
|
--idempotency-key "github:${{ github.repository }}:post-deploy-prod.deployment:${CI_RUN}:${{ github.run_attempt }}:5:${VERSION}" \
|
|
@@ -213,7 +216,7 @@ jobs:
|
|
|
213
216
|
fi
|
|
214
217
|
exit "$SCRIPT_EXIT"
|
|
215
218
|
|
|
216
|
-
- name: Complete production deployment
|
|
219
|
+
- name: Complete production deployment executions
|
|
217
220
|
if: always() && env.BASE != ''
|
|
218
221
|
run: |
|
|
219
222
|
HOST_VERIFICATION="${{ steps.host_deployment.outputs.verification || 'not_run' }}"
|
|
@@ -231,15 +234,15 @@ jobs:
|
|
|
231
234
|
OUTCOME=failed
|
|
232
235
|
CHECK_STATUS=failed
|
|
233
236
|
fi
|
|
234
|
-
chmod +x scripts/report-test-
|
|
237
|
+
chmod +x scripts/report-test-execution.sh scripts/report-release-check.sh 2>/dev/null || true
|
|
235
238
|
for PREFIX in ${REQS}; do
|
|
236
239
|
RESP=$(curl -fsS -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
|
|
237
240
|
"${BASE}/api/ci/releases/resolve?projectSlug=${PROJECT_SLUG}&versionPrefix=${PREFIX}")
|
|
238
241
|
VERSION=$(echo "$RESP" | jq -r '.latest.version // empty')
|
|
239
242
|
[ -n "$VERSION" ] || VERSION="$PREFIX"
|
|
240
|
-
bash scripts/report-test-
|
|
243
|
+
bash scripts/report-test-execution.sh complete \
|
|
241
244
|
--project-slug "$PROJECT_SLUG" --release "$VERSION" \
|
|
242
|
-
--sdlc-stage 5 --environment production --
|
|
245
|
+
--sdlc-stage 5 --environment production --suite-kind deployment \
|
|
243
246
|
--provider github_actions --external-run-id "$CI_RUN" \
|
|
244
247
|
--external-run-attempt "${{ github.run_attempt }}" --external-job-id "host-deployment" \
|
|
245
248
|
--idempotency-key "github:${{ github.repository }}:post-deploy-prod.deployment:${CI_RUN}:${{ github.run_attempt }}:5:${VERSION}" \
|
|
@@ -269,18 +272,18 @@ jobs:
|
|
|
269
272
|
exit 1
|
|
270
273
|
fi
|
|
271
274
|
|
|
272
|
-
- name: Start production smoke
|
|
275
|
+
- name: Start production smoke executions
|
|
273
276
|
if: steps.production_probe.outputs.verification == 'production_health_success' && steps.host_deployment.outputs.verification == 'success'
|
|
274
277
|
run: |
|
|
275
|
-
chmod +x scripts/report-test-
|
|
278
|
+
chmod +x scripts/report-test-execution.sh 2>/dev/null || true
|
|
276
279
|
for PREFIX in ${REQS}; do
|
|
277
280
|
RESP=$(curl -fsS -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
|
|
278
281
|
"${BASE}/api/ci/releases/resolve?projectSlug=${PROJECT_SLUG}&versionPrefix=${PREFIX}")
|
|
279
282
|
VERSION=$(echo "$RESP" | jq -r '.latest.version // empty')
|
|
280
283
|
[ -n "$VERSION" ] || VERSION="$PREFIX"
|
|
281
|
-
bash scripts/report-test-
|
|
284
|
+
bash scripts/report-test-execution.sh start \
|
|
282
285
|
--project-slug "$PROJECT_SLUG" --release "$VERSION" \
|
|
283
|
-
--sdlc-stage 5 --environment production --
|
|
286
|
+
--sdlc-stage 5 --environment production --suite-kind smoke \
|
|
284
287
|
--provider github_actions --external-run-id "$CI_RUN" \
|
|
285
288
|
--external-run-attempt "${{ github.run_attempt }}" --external-job-id "production-smoke" \
|
|
286
289
|
--idempotency-key "github:${{ github.repository }}:post-deploy-prod.smoke:${CI_RUN}:${{ github.run_attempt }}:5:${VERSION}" \
|
|
@@ -314,7 +317,7 @@ jobs:
|
|
|
314
317
|
}
|
|
315
318
|
RESULTS_EOF
|
|
316
319
|
|
|
317
|
-
- name: Complete production smoke
|
|
320
|
+
- name: Complete production smoke executions
|
|
318
321
|
if: always() && env.BASE != '' && steps.host_deployment.outcome == 'success'
|
|
319
322
|
run: |
|
|
320
323
|
case "${{ steps.production_smoke.outcome }}" in
|
|
@@ -323,15 +326,15 @@ jobs:
|
|
|
323
326
|
skipped) OUTCOME=skipped; CHECK_STATUS=skipped ;;
|
|
324
327
|
*) OUTCOME=failed; CHECK_STATUS=failed ;;
|
|
325
328
|
esac
|
|
326
|
-
chmod +x scripts/report-test-
|
|
329
|
+
chmod +x scripts/report-test-execution.sh scripts/report-release-check.sh 2>/dev/null || true
|
|
327
330
|
for PREFIX in ${REQS}; do
|
|
328
331
|
RESP=$(curl -fsS -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
|
|
329
332
|
"${BASE}/api/ci/releases/resolve?projectSlug=${PROJECT_SLUG}&versionPrefix=${PREFIX}")
|
|
330
333
|
VERSION=$(echo "$RESP" | jq -r '.latest.version // empty')
|
|
331
334
|
[ -n "$VERSION" ] || VERSION="$PREFIX"
|
|
332
|
-
bash scripts/report-test-
|
|
335
|
+
bash scripts/report-test-execution.sh complete \
|
|
333
336
|
--project-slug "$PROJECT_SLUG" --release "$VERSION" \
|
|
334
|
-
--sdlc-stage 5 --environment production --
|
|
337
|
+
--sdlc-stage 5 --environment production --suite-kind smoke \
|
|
335
338
|
--provider github_actions --external-run-id "$CI_RUN" \
|
|
336
339
|
--external-run-attempt "${{ github.run_attempt }}" --external-job-id "production-smoke" \
|
|
337
340
|
--idempotency-key "github:${{ github.repository }}:post-deploy-prod.smoke:${CI_RUN}:${{ github.run_attempt }}:5:${VERSION}" \
|
|
@@ -365,8 +368,8 @@ jobs:
|
|
|
365
368
|
# incident-export.yml fires on close → incident_report evidence
|
|
366
369
|
# lands on the portal → ISO29119.3.5.4 + SOC2.CC7.2 flip to COVERED.
|
|
367
370
|
#
|
|
368
|
-
#
|
|
369
|
-
# report traces back to the specific test
|
|
371
|
+
# testExecutionId (CI run ID) cross-references #209 so the incident
|
|
372
|
+
# report traces back to the specific test execution that detected
|
|
370
373
|
# the production failure.
|
|
371
374
|
#
|
|
372
375
|
# Ensure the incident label exists (idempotent).
|
|
@@ -385,7 +388,7 @@ jobs:
|
|
|
385
388
|
|
|
386
389
|
**Production URL:** ${PROD_URL}
|
|
387
390
|
**Git SHA:** ${GIT_SHA}
|
|
388
|
-
**
|
|
391
|
+
**testExecutionId:** ${CI_RUN}
|
|
389
392
|
**Workflow run:** ${WORKFLOW_URL}
|
|
390
393
|
**Date:** ${DATE}
|
|
391
394
|
|
|
@@ -429,7 +432,7 @@ jobs:
|
|
|
429
432
|
- name: Promote in-scope releases (evidence + status)
|
|
430
433
|
if: steps.production_smoke.outcome == 'success'
|
|
431
434
|
run: |
|
|
432
|
-
chmod +x scripts/upload-evidence.sh scripts/report-test-
|
|
435
|
+
chmod +x scripts/upload-evidence.sh scripts/report-test-execution.sh scripts/report-release-check.sh 2>/dev/null || true
|
|
433
436
|
PROMOTED=0
|
|
434
437
|
EVIDENCE_FAILURES=0
|
|
435
438
|
for PREFIX in ${REQS}; do
|
|
@@ -440,14 +443,14 @@ jobs:
|
|
|
440
443
|
[ -z "$VERSION" ] && VERSION="${PREFIX}"
|
|
441
444
|
RELEASE_ID=$(echo "$RESP" | jq -r '.latest.id // empty')
|
|
442
445
|
REQ_FAILURES=0
|
|
443
|
-
LINEAGE_FLAGS=(--test-
|
|
444
|
-
|
|
445
|
-
bash scripts/report-test-
|
|
446
|
+
LINEAGE_FLAGS=(--test-execution "${CI_RUN}")
|
|
447
|
+
EXECUTION_OUT="$(mktemp)"
|
|
448
|
+
bash scripts/report-test-execution.sh start \
|
|
446
449
|
--project-slug "${PROJECT_SLUG}" \
|
|
447
450
|
--release "${VERSION}" \
|
|
448
451
|
--sdlc-stage 5 \
|
|
449
452
|
--environment production \
|
|
450
|
-
--
|
|
453
|
+
--suite-kind smoke \
|
|
451
454
|
--provider github_actions \
|
|
452
455
|
--external-run-id "${CI_RUN}" \
|
|
453
456
|
--external-run-attempt "${{ github.run_attempt }}" \
|
|
@@ -457,11 +460,11 @@ jobs:
|
|
|
457
460
|
--branch main \
|
|
458
461
|
--workflow-name "Post-Deploy Production" \
|
|
459
462
|
--workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
|
|
460
|
-
--output-file "$
|
|
461
|
-
. "$
|
|
462
|
-
rm -f "$
|
|
463
|
-
if [ "${
|
|
464
|
-
LINEAGE_FLAGS+=(--evidence-scope
|
|
463
|
+
--output-file "$EXECUTION_OUT"
|
|
464
|
+
. "$EXECUTION_OUT"
|
|
465
|
+
rm -f "$EXECUTION_OUT"
|
|
466
|
+
if [ "${execution_supported:-false}" = "true" ] && [ -n "${execution_record_id:-}" ]; then
|
|
467
|
+
LINEAGE_FLAGS+=(--evidence-scope execution --test-execution-record-id "${execution_record_id}")
|
|
465
468
|
fi
|
|
466
469
|
# Production smoke evidence (whole-app health) attached to this release.
|
|
467
470
|
if [ -f prod-smoke-results.json ]; then
|
|
@@ -357,19 +357,19 @@ jobs:
|
|
|
357
357
|
- name: Generate and upload gate evidence
|
|
358
358
|
if: env.DEVAUDIT_BASE_URL != ''
|
|
359
359
|
run: |
|
|
360
|
-
chmod +x scripts/upload-evidence.sh scripts/report-test-
|
|
360
|
+
chmod +x scripts/upload-evidence.sh scripts/report-test-execution.sh 2>/dev/null || true
|
|
361
361
|
FLAGS="--git-sha ${{ github.sha }} --ci-run-id ${{ github.run_id }} --branch ${{ github.ref_name }}"
|
|
362
362
|
FLAGS="${FLAGS} --release ${{ needs.register-release.outputs.version }} --create-release-if-missing"
|
|
363
363
|
FLAGS="${FLAGS} --environment uat"
|
|
364
364
|
FLAGS="${FLAGS} --sdlc-stage 2"
|
|
365
|
-
PRIMARY_LINEAGE_FLAGS=(--test-
|
|
366
|
-
|
|
367
|
-
bash scripts/report-test-
|
|
365
|
+
PRIMARY_LINEAGE_FLAGS=(--test-execution "${{ github.run_id }}")
|
|
366
|
+
EXECUTION_OUT="$(mktemp)"
|
|
367
|
+
bash scripts/report-test-execution.sh start \
|
|
368
368
|
--project-slug {{PROJECT_SLUG}} \
|
|
369
369
|
--release "${{ needs.register-release.outputs.version }}" \
|
|
370
370
|
--sdlc-stage 2 \
|
|
371
371
|
--environment uat \
|
|
372
|
-
--
|
|
372
|
+
--suite-kind quality_gate \
|
|
373
373
|
--provider github_actions \
|
|
374
374
|
--external-run-id "${{ github.run_id }}" \
|
|
375
375
|
--external-run-attempt "${{ github.run_attempt }}" \
|
|
@@ -378,11 +378,11 @@ jobs:
|
|
|
378
378
|
--branch "${{ github.ref_name }}" \
|
|
379
379
|
--workflow-name "Quality Gates" \
|
|
380
380
|
--workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
|
|
381
|
-
--output-file "$
|
|
382
|
-
. "$
|
|
383
|
-
rm -f "$
|
|
384
|
-
if [ "${
|
|
385
|
-
PRIMARY_LINEAGE_FLAGS+=(--evidence-scope
|
|
381
|
+
--output-file "$EXECUTION_OUT"
|
|
382
|
+
. "$EXECUTION_OUT"
|
|
383
|
+
rm -f "$EXECUTION_OUT"
|
|
384
|
+
if [ "${execution_supported:-false}" = "true" ] && [ -n "${execution_record_id:-}" ]; then
|
|
385
|
+
PRIMARY_LINEAGE_FLAGS+=(--evidence-scope execution --test-execution-record-id "${execution_record_id}")
|
|
386
386
|
fi
|
|
387
387
|
|
|
388
388
|
UPLOAD_FAILURES=0
|
|
@@ -546,7 +546,7 @@ jobs:
|
|
|
546
546
|
exit 1
|
|
547
547
|
fi
|
|
548
548
|
|
|
549
|
-
- name: Complete primary quality-gate
|
|
549
|
+
- name: Complete primary quality-gate execution
|
|
550
550
|
if: always() && env.DEVAUDIT_BASE_URL != ''
|
|
551
551
|
run: |
|
|
552
552
|
case "${{ job.status }}" in
|
|
@@ -554,13 +554,13 @@ jobs:
|
|
|
554
554
|
cancelled) OUTCOME=cancelled ;;
|
|
555
555
|
*) OUTCOME=failed ;;
|
|
556
556
|
esac
|
|
557
|
-
chmod +x scripts/report-test-
|
|
558
|
-
bash scripts/report-test-
|
|
557
|
+
chmod +x scripts/report-test-execution.sh 2>/dev/null || true
|
|
558
|
+
bash scripts/report-test-execution.sh complete \
|
|
559
559
|
--project-slug {{PROJECT_SLUG}} \
|
|
560
560
|
--release "${{ needs.register-release.outputs.version }}" \
|
|
561
561
|
--sdlc-stage 2 \
|
|
562
562
|
--environment uat \
|
|
563
|
-
--
|
|
563
|
+
--suite-kind quality_gate \
|
|
564
564
|
--provider github_actions \
|
|
565
565
|
--external-run-id "${{ github.run_id }}" \
|
|
566
566
|
--external-run-attempt "${{ github.run_attempt }}" \
|
|
@@ -42,6 +42,9 @@ jobs:
|
|
|
42
42
|
PR_TITLE: ${{ github.event.pull_request.title }}
|
|
43
43
|
PR_BODY: ${{ github.event.pull_request.body }}
|
|
44
44
|
HEAD_REF: ${{ github.event.pull_request.head.ref }}
|
|
45
|
+
BASE_REF: ${{ github.event.pull_request.base.ref }}
|
|
46
|
+
INTEGRATION_BRANCH: {{INTEGRATION_BRANCH}}
|
|
47
|
+
RELEASE_BRANCH: {{RELEASE_BRANCH}}
|
|
45
48
|
run: |
|
|
46
49
|
chmod +x scripts/check-release-pr-scope.sh 2>/dev/null || true
|
|
47
50
|
bash scripts/check-release-pr-scope.sh
|
package/sdlc/package.json
CHANGED
|
@@ -82,7 +82,7 @@ A release is classified by version shape and release mode. **Most of this doc wa
|
|
|
82
82
|
|
|
83
83
|
### Housekeeping outcomes
|
|
84
84
|
|
|
85
|
-
Normal housekeeping skips the per-requirement evidence and approval path. Run the relevant gates, obtain terminal-green PR review, and merge to `develop`; the bare-date portal row is integration history. When a tracked release later absorbs the work, its bundled-change manifest preserves the source title, evidence ownership, stage, and
|
|
85
|
+
Normal housekeeping skips the per-requirement evidence and approval path. Run the relevant gates, obtain terminal-green PR review, and merge to `develop`; the bare-date portal row is integration history. When a tracked release later absorbs the work, its bundled-change manifest preserves the source title, evidence ownership, stage, and executions.
|
|
86
86
|
|
|
87
87
|
Use standalone housekeeping only when the change cannot reasonably wait for that tracked release. Follow `docs/release-playbooks/housekeeping-release.md`: add the validated `STANDALONE-HOUSEKEEPING-vYYYY.MM.DD.json` declaration, document why promotion is necessary, pass the required checks, and verify production. There is no automatic release-ticket or security-summary stub PR for either housekeeping outcome.
|
|
88
88
|
|
|
@@ -173,27 +173,27 @@ Rules:
|
|
|
173
173
|
- `environment_gap` and `precondition_gap` skips must be resolved before listing — if they appear here, the gate is not truly `SKIPPED` with operator approval.
|
|
174
174
|
- A skipped test never proves an acceptance criterion.
|
|
175
175
|
|
|
176
|
-
## Test
|
|
176
|
+
## Test Executions
|
|
177
177
|
|
|
178
|
-
Prefer the first-class release-journey /
|
|
178
|
+
Prefer the first-class release-journey / execution API when the portal exposes it. Generate the table from the API response rather than inferring executions from uploaded files:
|
|
179
179
|
|
|
180
180
|
```bash
|
|
181
181
|
# Example:
|
|
182
182
|
curl -s -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
|
|
183
183
|
"${DEVAUDIT_BASE_URL%/}/api/projects/<slug>/releases/REQ-XXX/journey" \
|
|
184
184
|
> /tmp/release-journey.json
|
|
185
|
-
bash scripts/render-test-
|
|
185
|
+
bash scripts/render-test-executions.sh /tmp/release-journey.json
|
|
186
186
|
```
|
|
187
187
|
|
|
188
|
-
The helper renders a first-class table when `.
|
|
188
|
+
The helper renders a first-class table when `.testExecutions[]` is present. It must not infer executions from legacy artifact grouping.
|
|
189
189
|
|
|
190
|
-
| Source Release | SDLC Stage |
|
|
190
|
+
| Source Release | SDLC Stage | Execution | Kind | Outcome | Workflow / Run | Related Evidence | Incident / Remediation | Date |
|
|
191
191
|
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
192
192
|
| REQ-XXX | 2 implement_test | #1 | quality_gate | passed | [Quality Gates](https://github.com/example/repo/actions/runs/123) (run 123, attempt 1) | quality-gates.json | None | 2026-07-16 11:03:00 |
|
|
193
193
|
| REQ-XXX | 2 implement_test | #2 | e2e | passed | [E2E Regression](https://github.com/example/repo/actions/runs/124) (run 124, attempt 2) | e2e-results.json, screenshots.zip | Incident #501 fixed in PR #507 | 2026-07-16 11:19:00 |
|
|
194
194
|
| REQ-089 | 4 uat_review | #1 | uat | passed | [UAT Review](https://devaudit.example/releases/REQ-089) | uat-checklist.md | None | 2026-07-16 12:02:00 |
|
|
195
195
|
|
|
196
|
-
**Final assessment:** [First-class
|
|
196
|
+
**Final assessment:** [First-class test execution records show all stage executions passed / N executions failed — see incidents]
|
|
197
197
|
|
|
198
198
|
## Bundled Release Context
|
|
199
199
|
|
|
@@ -338,12 +338,12 @@ status: "nil"
|
|
|
338
338
|
|
|
339
339
|
## Attestation
|
|
340
340
|
|
|
341
|
-
No incidents or defects were discovered during the test
|
|
341
|
+
No incidents or defects were discovered during the test execution for release `<version>`.
|
|
342
342
|
|
|
343
343
|
## Scope
|
|
344
344
|
|
|
345
345
|
- **Release:** <version>
|
|
346
|
-
- **Test
|
|
346
|
+
- **Test execution:** <description>
|
|
347
347
|
- **Test cases executed:** <count>
|
|
348
348
|
- **Test cases passed:** <count>
|
|
349
349
|
- **Test cases failed:** 0
|
|
@@ -352,7 +352,7 @@ No incidents or defects were discovered during the test cycle for release `<vers
|
|
|
352
352
|
|
|
353
353
|
## Framework attribution
|
|
354
354
|
|
|
355
|
-
- [x] `ISO29119.3.5.4` (Test incident report — nil report for this release
|
|
355
|
+
- [x] `ISO29119.3.5.4` (Test incident report — nil report for this release execution)
|
|
356
356
|
|
|
357
357
|
## Sign-off
|
|
358
358
|
|
|
@@ -179,7 +179,7 @@ CI runs automatically on this PR. The following gates must pass before merge:
|
|
|
179
179
|
- [ ] Implementation plan present and matches implementation (MEDIUM/HIGH risk)
|
|
180
180
|
- [ ] Release ticket created
|
|
181
181
|
- [ ] Test evidence saved
|
|
182
|
-
- [ ] Test execution summary includes Test
|
|
182
|
+
- [ ] Test execution summary includes Test Executions section (all CI runs for this release listed)
|
|
183
183
|
- [ ] Security evidence saved
|
|
184
184
|
- [ ] AI use documented
|
|
185
185
|
|
|
@@ -151,7 +151,7 @@ The backend stores both with reviewer identity, SHA, and timestamp. This satisfi
|
|
|
151
151
|
|
|
152
152
|
1. Wait for `post-deploy-prod.yml` to complete successfully **and** for its host-deployment check to confirm terminal success for the merged SHA.
|
|
153
153
|
2. Open the release in DevAudit: `https://[DEVAUDIT_BASE_URL]/projects/[PROJECT_SLUG]/releases/[releaseId]`.
|
|
154
|
-
3. Review the production deployment and smoke
|
|
154
|
+
3. Review the production deployment and smoke test execution records, their evidence, and any post-deploy actions logged in the release ticket. Do not approve while either execution or the host deployment remains queued/in progress.
|
|
155
155
|
4. Click **Approve Production** — status transitions to `prod_approved`.
|
|
156
156
|
5. Click **Mark as Released** — status transitions to `released`. This dispatches the automated close-out flow.
|
|
157
157
|
|
|
@@ -67,7 +67,7 @@ The [`sdlc-implementer`](#skills-inventory) skill is the **default way to implem
|
|
|
67
67
|
> Implement issue #N under the SDLC.
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
It **triages first** (Phase 0): it reads the issue + labels, classifies the change-type against the [change-workflows](https://github.com/metasession-dev/DevAudit-Installer/blob/main/docs/change-workflows.md) taxonomy, announces a **Workflow Decision** (which path, which gates, which approvals, what's skipped), and routes — only a tracked change continues into the full
|
|
70
|
+
It **triages first** (Phase 0): it reads the issue + labels, classifies the change-type against the [change-workflows](https://github.com/metasession-dev/DevAudit-Installer/blob/main/docs/change-workflows.md) taxonomy, announces a **Workflow Decision** (which path, which gates, which approvals, what's skipped), and routes — only a tracked change continues into the full execution; housekeeping / trivial / doc-only is announced and handed off to its lighter path. So pointing the skill at an issue no longer defaults to maximum ceremony — it decides the path at pickup.
|
|
71
71
|
|
|
72
72
|
For a tracked change it then runs Phases 1–4 unattended (with a plan-approval pause for HIGH/CRITICAL risk, or always-on via `--require-plan-approval`): classify risk, assign the next `REQ-XXX`, write the implementation plan, update `RTM.md`, implement, delegate all end-to-end / visual test work to [`e2e-test-engineer`](#skills-inventory), run the gates, compile evidence, open the PR, and submit for UAT review on the portal. It then **halts** at the UAT gate. After a reviewer approves on the portal:
|
|
73
73
|
|
|
@@ -77,9 +77,9 @@ For a tracked change it then runs Phases 1–4 unattended (with a plan-approval
|
|
|
77
77
|
|
|
78
78
|
It runs Phase 5: merge, monitor post-deploy, confirm production smoke evidence, advance the release. If changes are requested at UAT instead of approval, it addresses them and re-submits for UAT re-review. It **refuses** issues that decompose into multiple requirements (split them first).
|
|
79
79
|
|
|
80
|
-
**Where it routes (the Phase-0 decision):** the skill now makes this call at pickup rather than you discovering mid-PR that you over- (or under-) ceremonied. It still **drives each path to completion** — these are the paths it takes *instead of* the full tracked
|
|
80
|
+
**Where it routes (the Phase-0 decision):** the skill now makes this call at pickup rather than you discovering mid-PR that you over- (or under-) ceremonied. It still **drives each path to completion** — these are the paths it takes *instead of* the full tracked execution, not points where it abandons you:
|
|
81
81
|
|
|
82
|
-
- **Trivial / housekeeping changes** → the skill drives the lightweight escape hatch (above) to merge: branch → all gates locally → `chore:`/`docs:`/`ci:` PR → review → merge. No requirement, no tracked
|
|
82
|
+
- **Trivial / housekeeping changes** → the skill drives the lightweight escape hatch (above) to merge: branch → all gates locally → `chore:`/`docs:`/`ci:` PR → review → merge. No requirement, no tracked execution, but it guides every step. Docs, formatting, dependency bumps, CI tweaks (`docs:` / `chore:` / `ci:` …) don't need a requirement. (Note: `feat` / `fix` / `refactor` / `perf` commits **do** require a `[REQ-XXX]` / `Ref: REQ-XXX` and are rejected by commitlint + `validate-commits.sh` without one.)
|
|
83
83
|
- **Compliance-doc-only** → the skill drives a docs push against an **existing** `REQ-XXX` through to merge; no new requirement, no quality gates.
|
|
84
84
|
- **Stage-1 planning in isolation, or e2e test work alone** → run the manual walkthrough / invoke `e2e-test-engineer` directly.
|
|
85
85
|
- **Cross-issue refactors** spanning multiple `REQ-XXX` scopes → out of the one-issue contract; the skill refuses and asks you to split.
|
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# render-test-cycles.sh — Render release test cycles as markdown tables.
|
|
3
|
-
#
|
|
4
|
-
# Usage:
|
|
5
|
-
# bash scripts/render-test-cycles.sh path/to/release-journey.json
|
|
6
|
-
#
|
|
7
|
-
# Supported inputs:
|
|
8
|
-
# 1. First-class cycle payloads with `.cycles[]`
|
|
9
|
-
# 2. Legacy grouped-evidence payloads with one of:
|
|
10
|
-
# - `.legacyCycles[]`
|
|
11
|
-
# - `.testCycleGroups[]`
|
|
12
|
-
# - `.evidenceGroups[]`
|
|
13
|
-
#
|
|
14
|
-
# Output:
|
|
15
|
-
# Markdown suitable for inclusion under `## Test Cycles` in
|
|
16
|
-
# `compliance/evidence/REQ-XXX/test-execution-summary.md`.
|
|
17
|
-
|
|
18
|
-
set -euo pipefail
|
|
19
|
-
|
|
20
|
-
INPUT_JSON="${1:-}"
|
|
21
|
-
|
|
22
|
-
if [ -z "$INPUT_JSON" ] || [ ! -f "$INPUT_JSON" ]; then
|
|
23
|
-
echo "Usage: $0 <release-journey.json>" >&2
|
|
24
|
-
exit 2
|
|
25
|
-
fi
|
|
26
|
-
|
|
27
|
-
if ! command -v jq >/dev/null 2>&1; then
|
|
28
|
-
echo "Error: jq is required." >&2
|
|
29
|
-
exit 1
|
|
30
|
-
fi
|
|
31
|
-
|
|
32
|
-
stage_label() {
|
|
33
|
-
case "$1" in
|
|
34
|
-
1) printf '1 plan' ;;
|
|
35
|
-
2) printf '2 implement_test' ;;
|
|
36
|
-
3) printf '3 compile_evidence' ;;
|
|
37
|
-
4) printf '4 uat_review' ;;
|
|
38
|
-
5) printf '5 production' ;;
|
|
39
|
-
*) printf '%s unknown' "${1:-?}" ;;
|
|
40
|
-
esac
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
format_date() {
|
|
44
|
-
local value="$1"
|
|
45
|
-
if [ -z "$value" ] || [ "$value" = "null" ]; then
|
|
46
|
-
printf 'Unknown'
|
|
47
|
-
else
|
|
48
|
-
printf '%s' "$value" | sed -E 's/T/ /; s/Z$//; s/[.][0-9]+$//'
|
|
49
|
-
fi
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
render_first_class_cycles() {
|
|
53
|
-
echo "| Source Release | SDLC Stage | Cycle | Kind | Outcome | Workflow / Run | Related Evidence | Incident / Remediation | Date |"
|
|
54
|
-
echo "| --- | --- | --- | --- | --- | --- | --- | --- | --- |"
|
|
55
|
-
|
|
56
|
-
declare -A COUNTS=()
|
|
57
|
-
local rows
|
|
58
|
-
rows="$(
|
|
59
|
-
jq -r '
|
|
60
|
-
(.cycles // [])
|
|
61
|
-
| sort_by(.sourceRelease // "", .sdlcStage // 0, .startedAt // "", .completedAt // "", .cycleKind // "")
|
|
62
|
-
| .[]
|
|
63
|
-
| {
|
|
64
|
-
sourceRelease: (.sourceRelease // "Unknown"),
|
|
65
|
-
stageCode: ((.sdlcStage // 0) | tostring),
|
|
66
|
-
kind: (.cycleKind // "unknown"),
|
|
67
|
-
outcome: (.outcome // "unknown"),
|
|
68
|
-
workflow: (
|
|
69
|
-
if (.workflowUrl // "") != "" then
|
|
70
|
-
"[" + ((.workflowName // "Workflow")) + "](" + .workflowUrl + ")"
|
|
71
|
-
else
|
|
72
|
-
(.workflowName // "Manual")
|
|
73
|
-
end
|
|
74
|
-
),
|
|
75
|
-
runMeta: (
|
|
76
|
-
[
|
|
77
|
-
(if (.externalRunId // "") != "" then "run " + .externalRunId else empty end),
|
|
78
|
-
(if (.externalRunAttempt // null) != null then "attempt " + (.externalRunAttempt | tostring) else empty end)
|
|
79
|
-
]
|
|
80
|
-
| map(select(length > 0))
|
|
81
|
-
| join(", ")
|
|
82
|
-
),
|
|
83
|
-
evidence: (
|
|
84
|
-
(.relatedEvidence // [])
|
|
85
|
-
| map(.displayName // .fileName // .name // .evidenceType // empty)
|
|
86
|
-
| map(select(length > 0))
|
|
87
|
-
| join(", ")
|
|
88
|
-
),
|
|
89
|
-
incident: (
|
|
90
|
-
[
|
|
91
|
-
(.incidentReference // empty),
|
|
92
|
-
(.remediationReference // empty),
|
|
93
|
-
(.outcomeReason // empty)
|
|
94
|
-
]
|
|
95
|
-
| map(select(length > 0))
|
|
96
|
-
| join("; ")
|
|
97
|
-
),
|
|
98
|
-
date: (.completedAt // .startedAt // "")
|
|
99
|
-
}
|
|
100
|
-
| @base64
|
|
101
|
-
' "$INPUT_JSON"
|
|
102
|
-
)"
|
|
103
|
-
|
|
104
|
-
if [ -z "$rows" ]; then
|
|
105
|
-
echo "| Unknown | Unknown | None | unknown | unknown | No cycle records returned | None | None | Unknown |"
|
|
106
|
-
echo
|
|
107
|
-
echo "**Final assessment:** No first-class cycle records were returned by the portal."
|
|
108
|
-
return 0
|
|
109
|
-
fi
|
|
110
|
-
|
|
111
|
-
while IFS= read -r row_b64; do
|
|
112
|
-
[ -n "$row_b64" ] || continue
|
|
113
|
-
local source_release stage_code kind outcome workflow run_meta evidence incident date
|
|
114
|
-
source_release="$(printf '%s' "$row_b64" | base64 -d | jq -r '.sourceRelease')"
|
|
115
|
-
stage_code="$(printf '%s' "$row_b64" | base64 -d | jq -r '.stageCode')"
|
|
116
|
-
kind="$(printf '%s' "$row_b64" | base64 -d | jq -r '.kind')"
|
|
117
|
-
outcome="$(printf '%s' "$row_b64" | base64 -d | jq -r '.outcome')"
|
|
118
|
-
workflow="$(printf '%s' "$row_b64" | base64 -d | jq -r '.workflow')"
|
|
119
|
-
run_meta="$(printf '%s' "$row_b64" | base64 -d | jq -r '.runMeta')"
|
|
120
|
-
evidence="$(printf '%s' "$row_b64" | base64 -d | jq -r '.evidence')"
|
|
121
|
-
incident="$(printf '%s' "$row_b64" | base64 -d | jq -r '.incident')"
|
|
122
|
-
date="$(printf '%s' "$row_b64" | base64 -d | jq -r '.date')"
|
|
123
|
-
[ -n "$source_release" ] || continue
|
|
124
|
-
local group_key cycle_ordinal workflow_cell evidence_cell incident_cell
|
|
125
|
-
group_key="${source_release}|${stage_code}"
|
|
126
|
-
COUNTS["$group_key"]=$(( ${COUNTS["$group_key"]:-0} + 1 ))
|
|
127
|
-
cycle_ordinal="#${COUNTS[$group_key]}"
|
|
128
|
-
workflow_cell="$workflow"
|
|
129
|
-
if [ -n "$run_meta" ]; then
|
|
130
|
-
workflow_cell="${workflow_cell} (${run_meta})"
|
|
131
|
-
fi
|
|
132
|
-
evidence_cell="${evidence:-None}"
|
|
133
|
-
incident_cell="${incident:-None}"
|
|
134
|
-
printf '| %s | %s | %s | %s | %s | %s | %s | %s | %s |\n' \
|
|
135
|
-
"$source_release" \
|
|
136
|
-
"$(stage_label "$stage_code")" \
|
|
137
|
-
"$cycle_ordinal" \
|
|
138
|
-
"$kind" \
|
|
139
|
-
"$outcome" \
|
|
140
|
-
"$workflow_cell" \
|
|
141
|
-
"$evidence_cell" \
|
|
142
|
-
"$incident_cell" \
|
|
143
|
-
"$(format_date "$date")"
|
|
144
|
-
done <<<"$rows"
|
|
145
|
-
|
|
146
|
-
echo
|
|
147
|
-
echo "**Final assessment:** Stage-scoped cycle numbering is authoritative from first-class portal cycle records."
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
render_legacy_cycles() {
|
|
151
|
-
echo "> Legacy portal fallback — first-class cycle records unavailable; grouped by uploaded evidence \`testCycleId\`."
|
|
152
|
-
echo
|
|
153
|
-
echo "| Source Release | SDLC Stage | Cycle | Kind | Outcome | Workflow / Run | Related Evidence | Incident / Remediation | Date |"
|
|
154
|
-
echo "| --- | --- | --- | --- | --- | --- | --- | --- | --- |"
|
|
155
|
-
|
|
156
|
-
local rows
|
|
157
|
-
rows="$(
|
|
158
|
-
jq -r '
|
|
159
|
-
(.legacyCycles // .testCycleGroups // .evidenceGroups // [])
|
|
160
|
-
| .[]
|
|
161
|
-
| {
|
|
162
|
-
sourceRelease: (.sourceRelease // "Legacy grouped evidence"),
|
|
163
|
-
stageLabel: (.sdlcStageLabel // "legacy grouping"),
|
|
164
|
-
cycleId: (.testCycleId // .cycleId // "unknown"),
|
|
165
|
-
kind: (.cycleKind // "legacy"),
|
|
166
|
-
outcome: (.outcome // "unknown"),
|
|
167
|
-
workflow: (
|
|
168
|
-
if (.workflowUrl // "") != "" then
|
|
169
|
-
"[" + ((.workflowName // "Workflow")) + "](" + .workflowUrl + ")"
|
|
170
|
-
else
|
|
171
|
-
(.workflowName // "Legacy grouping")
|
|
172
|
-
end
|
|
173
|
-
),
|
|
174
|
-
evidence: (
|
|
175
|
-
(.relatedEvidence // .evidence // [])
|
|
176
|
-
| map(.displayName // .fileName // .name // .evidenceType // .path // empty)
|
|
177
|
-
| map(select(length > 0))
|
|
178
|
-
| join(", ")
|
|
179
|
-
),
|
|
180
|
-
incident: (.incidentReference // .notes // "Legacy fallback"),
|
|
181
|
-
date: (.date // .createdAt // "")
|
|
182
|
-
}
|
|
183
|
-
| @base64
|
|
184
|
-
' "$INPUT_JSON"
|
|
185
|
-
)"
|
|
186
|
-
|
|
187
|
-
if [ -z "$rows" ]; then
|
|
188
|
-
echo "| Legacy grouped evidence | legacy grouping | unknown | legacy | unknown | Legacy grouping | None | Legacy fallback | Unknown |"
|
|
189
|
-
echo
|
|
190
|
-
echo "**Final assessment:** Legacy fallback used, but no grouped evidence records were returned."
|
|
191
|
-
return 0
|
|
192
|
-
fi
|
|
193
|
-
|
|
194
|
-
while IFS= read -r row_b64; do
|
|
195
|
-
[ -n "$row_b64" ] || continue
|
|
196
|
-
local source_release stage_label_value cycle_id kind outcome workflow evidence incident date
|
|
197
|
-
source_release="$(printf '%s' "$row_b64" | base64 -d | jq -r '.sourceRelease')"
|
|
198
|
-
stage_label_value="$(printf '%s' "$row_b64" | base64 -d | jq -r '.stageLabel')"
|
|
199
|
-
cycle_id="$(printf '%s' "$row_b64" | base64 -d | jq -r '.cycleId')"
|
|
200
|
-
kind="$(printf '%s' "$row_b64" | base64 -d | jq -r '.kind')"
|
|
201
|
-
outcome="$(printf '%s' "$row_b64" | base64 -d | jq -r '.outcome')"
|
|
202
|
-
workflow="$(printf '%s' "$row_b64" | base64 -d | jq -r '.workflow')"
|
|
203
|
-
evidence="$(printf '%s' "$row_b64" | base64 -d | jq -r '.evidence')"
|
|
204
|
-
incident="$(printf '%s' "$row_b64" | base64 -d | jq -r '.incident')"
|
|
205
|
-
date="$(printf '%s' "$row_b64" | base64 -d | jq -r '.date')"
|
|
206
|
-
[ -n "$cycle_id" ] || continue
|
|
207
|
-
printf '| %s | %s | %s | %s | %s | %s | %s | %s | %s |\n' \
|
|
208
|
-
"$source_release" \
|
|
209
|
-
"$stage_label_value" \
|
|
210
|
-
"$cycle_id" \
|
|
211
|
-
"$kind" \
|
|
212
|
-
"$outcome" \
|
|
213
|
-
"$workflow" \
|
|
214
|
-
"${evidence:-None}" \
|
|
215
|
-
"${incident:-Legacy fallback}" \
|
|
216
|
-
"$(format_date "$date")"
|
|
217
|
-
done <<<"$rows"
|
|
218
|
-
|
|
219
|
-
echo
|
|
220
|
-
echo "**Final assessment:** Legacy grouping was used because the portal did not expose first-class cycle records."
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
if jq -e '((.cycles // []) | length) > 0' "$INPUT_JSON" >/dev/null 2>&1; then
|
|
224
|
-
render_first_class_cycles
|
|
225
|
-
else
|
|
226
|
-
render_legacy_cycles
|
|
227
|
-
fi
|