@metasession.co/devaudit-cli 0.3.17 → 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 +36 -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-host-deployment.sh +58 -8
- package/sdlc/files/_common/scripts/check-host-deployment.test.sh +35 -3
- package/sdlc/files/_common/scripts/check-release-pr-scope.sh +8 -1
- package/sdlc/files/_common/scripts/check-release-pr-scope.test.sh +61 -12
- 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/derive-release-version.sh +7 -9
- package/sdlc/files/_common/scripts/derive-release-version.test.sh +18 -18
- package/sdlc/files/_common/scripts/generate-bundled-changes.sh +24 -3
- package/sdlc/files/_common/scripts/generate-bundled-changes.test.sh +9 -5
- package/sdlc/files/_common/scripts/reconcile-railway-deployment.sh +37 -0
- package/sdlc/files/_common/scripts/reconcile-railway-deployment.test.sh +30 -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 +62 -10
- package/sdlc/files/_common/skills/sdlc-implementer/SKILL.md +19 -16
- package/sdlc/files/ci/ci.yml.template +86 -46
- package/sdlc/files/ci/compliance-evidence.yml.template +173 -49
- 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 +92 -48
- package/sdlc/files/ci/python/ci.yml.template +14 -14
- package/sdlc/files/ci/quality-gates-provenance.yml.template +3 -0
- package/sdlc/files/ci/reconcile-deployment.yml.template +59 -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
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sdlc-implementer
|
|
3
|
-
description: Take a GitHub issue end-to-end through the Metasession SDLC. Opens with a Workflow Triage step (Phase 0) that classifies the change and routes it — tracked work continues into the full
|
|
3
|
+
description: Take a GitHub issue end-to-end through the Metasession SDLC. Opens with a Workflow Triage step (Phase 0) that classifies the change and routes it — tracked work continues into the full execution; housekeeping/trivial/doc-only is driven to merge down a lightweight path (same step-by-step guidance, no tracked ceremony). Use when the user wants to implement a single GitHub issue as a complete SDLC execution — Phase 1 (classify risk, write implementation plan, update RTM) through Phase 4 (open PR, request UAT review on the portal), then halt; and Phase 5 (merge, post-deploy smoke evidence, mark Released, or change-request loop) on resume. Trigger phrases — "implement issue #N", "fix issue #N", "do issue #N", "implement #N", "implement issue #N under the SDLC", "run the SDLC for issue #N", "automate REQ-XXX from issue to release", "do the SDLC stages for [issue]". Resume phrase — "resume REQ-XXX". MUST delegate end-to-end and visual-regression test work to the e2e-test-engineer skill in Phase 2; never authors e2e tests directly. Do NOT use for partial work — for stage-1 planning only, run the manual walkthrough; for test work alone, invoke e2e-test-engineer directly.
|
|
4
4
|
tags: [sdlc, orchestration, compliance, automation]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# SDLC implementer
|
|
8
8
|
|
|
9
|
-
Take a single GitHub issue end-to-end through the Metasession SDLC. The skill **triages first** (Phase 0): it classifies the change, announces the path it will take, and routes — only a **tracked** change continues into the full
|
|
9
|
+
Take a single GitHub issue end-to-end through the Metasession SDLC. The skill **triages first** (Phase 0): it classifies the change, announces the path it will take, and routes — only a **tracked** change continues into the full execution, while housekeeping, trivial, and compliance-doc-only work is driven down its lighter path **to completion** (the skill still guides every step to merge; it just skips the tracked ceremony). For a tracked change, one command runs Phase 1 through Phase 4 unattended (with a plan-approval pause for HIGH/CRITICAL risk); the human enters the loop at the UAT review gate on the portal. On resume, the skill runs Phase 5 — merge, post-deploy smoke evidence, mark the release Released, or address change-requests and re-submit for UAT re-review.
|
|
10
10
|
|
|
11
11
|
This skill is a single entry point that **routes**, not one that always runs heavy. The change-type taxonomy it routes against is the canonical table in [`change-workflows.md`](https://github.com/metasession-dev/DevAudit-Installer/blob/main/docs/change-workflows.md) (six change-types → commit-type → requirement? → path).
|
|
12
12
|
|
|
@@ -105,7 +105,7 @@ This gate is distinct from Phase 2 step 4's "any deviation from the plan must be
|
|
|
105
105
|
|
|
106
106
|
## Requirements gap flow (devaudit-installer#212)
|
|
107
107
|
|
|
108
|
-
A **requirements gap** is "the ACs themselves were wrong, incomplete, or missing" — discovered by the skill or sub-skills mid-
|
|
108
|
+
A **requirements gap** is "the ACs themselves were wrong, incomplete, or missing" — discovered by the skill or sub-skills mid-execution, not by a user request. This is distinct from:
|
|
109
109
|
|
|
110
110
|
- **Scope expansion** (user asks for something beyond the ACs → scope-expansion halt gate above)
|
|
111
111
|
- **Defect** (implementation doesn't match the ACs → incident filing)
|
|
@@ -146,7 +146,7 @@ Amendment steps:
|
|
|
146
146
|
8. If Phase 3+: re-compile affected evidence
|
|
147
147
|
9. Continue from current phase
|
|
148
148
|
|
|
149
|
-
**(c) File a follow-up REQ** — ship the current REQ as-is, file a separate issue for the requirements gap. Appropriate when the gap is a genuine new behaviour that deserves its own
|
|
149
|
+
**(c) File a follow-up REQ** — ship the current REQ as-is, file a separate issue for the requirements gap. Appropriate when the gap is a genuine new behaviour that deserves its own execution. Continue with the current REQ unchanged.
|
|
150
150
|
|
|
151
151
|
### Distinction from scope-expansion halt gate
|
|
152
152
|
|
|
@@ -324,7 +324,7 @@ _Workflow tweak (CI artifact upload, gate timeout bump, etc.)_
|
|
|
324
324
|
|
|
325
325
|
### Lightweight path (housekeeping / trivial / compliance-doc-only)
|
|
326
326
|
|
|
327
|
-
Reached from Phase 0 for non-tracked change-types. The skill drives this end-to-end; the only difference from the tracked
|
|
327
|
+
Reached from Phase 0 for non-tracked change-types. The skill drives this end-to-end; the only difference from the tracked execution is the absence of _ceremony_, not the absence of _guidance_. It pauses only where a human is genuinely required (PR review, merge).
|
|
328
328
|
|
|
329
329
|
**CI trigger shape — read once before step 7.** DevAudit-Installer-generated `ci.yml.template` runs `Quality Gates` on PRs to the integration branch and on pushes to the integration branch. Older consumers may still have post-merge-only CI (`push: branches: [<integration>]`, no `pull_request:` trigger) until they re-run `devaudit update`. The skill must adapt step 7's wording to whichever shape the project uses; never poll a PR for checks that won't arrive on that consumer yet.
|
|
330
330
|
|
|
@@ -342,7 +342,7 @@ Reached from Phase 0 for non-tracked change-types. The skill drives this end-to-
|
|
|
342
342
|
|
|
343
343
|
Either way, never bypass a gate (no `--no-verify`, no `--admin` merge of a red required check); the only difference is **where** you wait for the gate to fire — before merge vs. after merge.
|
|
344
344
|
8. **Guide review -> merge.** A human still reviews the PR. Merge only after all required checks are terminal green on the current PR head SHA; queued, running, stale, cancelled, unexpectedly skipped, or failed checks are not green. There is no portal release approval, UAT four-eyes, Production gate, or standalone close-out on the normal lightweight path.
|
|
345
|
-
9. **Record the correct release meaning.** A housekeeping push produces at most a bare-date release (`vYYYY.MM.DD`) that is integration/history, not an active approval by default. It waits on `$INTEGRATION_BRANCH` until
|
|
345
|
+
9. **Record the correct release meaning.** A housekeeping push produces at most a bare-date release (`vYYYY.MM.DD`) that is integration/history, not an active approval by default. It waits on `$INTEGRATION_BRANCH` until a later tracked release explicitly absorbs it through the required bundled-changes markdown/JSON manifest and portal lineage. Never infer that an unrelated hotfix or mandatory back-merge belongs to the only pending REQ. A submitted REQ bundle is frozen approval scope; changing it returns that REQ to evidence compilation and UAT resubmission. A doc-only push attaches documents to the existing `REQ-XXX` release.
|
|
346
346
|
10. **Standalone exception.** Only when housekeeping cannot reasonably wait for the next tracked release may the skill prepare a standalone promotion. It must state `Standalone housekeeping promotion` and why in the release PR, add `compliance/standalone-housekeeping/STANDALONE-HOUSEKEEPING-vYYYY.MM.DD.json` with `schemaVersion: 1`, the exact derived bare-date version, `releaseMode: standalone_housekeeping`, and a specific reason. It must obtain terminal-green CI and PR review. The installed release-scope check validates the declaration before merge; post-deploy uploads it as release-ticket evidence and changes the portal row to standalone housekeeping. Use portal approval only if project policy explicitly opts in. If the installed workflow cannot implement that policy, halt and keep the change on the normal integration path.
|
|
347
347
|
|
|
348
348
|
### Phase 1 — Plan (SDLC stage 1)
|
|
@@ -499,9 +499,10 @@ Reached only on the **tracked** route from Phase 0 (the issue is already fetched
|
|
|
499
499
|
|
|
500
500
|
5. **Generate nil incident report if no incidents were closed (devaudit-installer#210 §8a).** After the test pack re-run passes, check whether any `incident`-labelled issues were closed during this REQ's lifecycle (`gh issue list --label incident --state closed --search "REQ-XXX" --json number`). If none were closed and the test pack re-run passes:
|
|
501
501
|
- Create `compliance/governance/nil-incident-report-<version>.md` from the `nil-incident-report.md.template` template.
|
|
502
|
+
- Set frontmatter `incident_kind: "no_incidents_attestation"`, `source_release: "<version>"`, and `semantic_id: "NIL-<version>"`. The `source_release` must be the REQ or standalone housekeeping release that actually owns the attestation.
|
|
502
503
|
- Fill in the scope section (test cases executed/passed/failed, defects filed, incidents reported).
|
|
503
504
|
- Leave the sign-off section with REPLACE markers — the operator fills it in.
|
|
504
|
-
- The nil report uploads as `incident_report` evidence via `compliance-evidence.yml`'s `upload_incident_report` function, flipping `ISO29119.3.5.4` to COVERED for clean releases.
|
|
505
|
+
- The nil report uploads as source-owned `incident_report` evidence via `compliance-evidence.yml`'s `upload_incident_report` function, flipping `ISO29119.3.5.4` to COVERED for clean releases. Historical nil reports are not re-uploaded to later REQs unless an explicit bundle manifest references the source release; even then ownership remains on the source release.
|
|
505
506
|
- If incidents WERE closed, skip nil report generation — the populated incident report(s) from `incident-export.yml` serve as the evidence.
|
|
506
507
|
|
|
507
508
|
5b. **Validate test-execution-summary.md gate states (devaudit-installer#240).** Before uploading evidence, verify that `compliance/evidence/REQ-XXX/test-execution-summary.md` does not contain invalid gate states. Run:
|
|
@@ -512,22 +513,22 @@ Reached only on the **tracked** route from Phase 0 (the issue is already fetched
|
|
|
512
513
|
|
|
513
514
|
If the validator fails, fix the summary before proceeding. E2E gate results must be one of: `PASS`, `FAIL`, `NOT_NEEDED` (with reason), or `SKIPPED` (with operator-approved rationale). The word "deferred" must never appear in `test-execution-summary.md` — not as a gate state, not in prose, not in final assessment. "Deferred to CI" and "Playwright browsers not installed locally" are environment issues, not gate states. The CI validator (`validate-test-summary.sh`) will reject any summary containing "deferred" or "browsers not installed" on PRs to main.
|
|
514
515
|
|
|
515
|
-
|
|
516
|
+
5b.1. **Render the Test Executions table from the portal's execution read model when available (devaudit-installer#394).** Do not hand-build execution rows from uploaded artefacts if the portal exposes first-class test execution records. Query the release-journey / execution API, save the JSON, and render the markdown table with:
|
|
516
517
|
|
|
517
518
|
```bash
|
|
518
|
-
bash scripts/render-test-
|
|
519
|
+
bash scripts/render-test-executions.sh /tmp/release-journey.json
|
|
519
520
|
```
|
|
520
521
|
|
|
521
522
|
First-class rows must preserve:
|
|
522
523
|
- source release
|
|
523
524
|
- SDLC stage
|
|
524
|
-
-
|
|
525
|
-
-
|
|
525
|
+
- execution ordinal within that source release + stage
|
|
526
|
+
- execution kind / outcome
|
|
526
527
|
- workflow or run link
|
|
527
528
|
- related evidence
|
|
528
529
|
- incident or remediation reference
|
|
529
530
|
|
|
530
|
-
If the portal does not
|
|
531
|
+
If the portal does not expose first-class test executions, do not infer executions from uploaded artefact groups. Record the gap in the summary and keep the release unresolved until the execution read model is available.
|
|
531
532
|
|
|
532
533
|
5c. **Run the Phase 3 completion guard before any PR/release-review step (devaudit-installer#341).** The tracked-release evidence pack is incomplete until the required Git artefacts exist. Before proceeding past Phase 3, verify:
|
|
533
534
|
|
|
@@ -634,7 +635,7 @@ Reached only on the **tracked** route from Phase 0 (the issue is already fetched
|
|
|
634
635
|
**Solo-operator teams.** On a one-person team, the literal "reviewer ≠ submitter" check is structurally unsatisfiable. The supported interpretation is _actor type, not human identity_ — AI tooling (the skill-trigger) and the human operator (the portal-approver) are distinct actors. Document this on the release ticket under `## Sign-off (dual-actor)` with the explicit interpretation, and ensure the human operator has independently reviewed the diff before clicking _Approve Production_ in the portal. Without this attestation the four-eyes claim is performative.
|
|
635
636
|
|
|
636
637
|
3. **Apply labels** — `awaiting-uat-review`, `risk:<class>`.
|
|
637
|
-
4. **Comment on the issue**: "Implementation complete. PR #M opened. Evidence on portal: <link>. UAT review requested. Resume with `resume REQ-XXX` once UAT approval is granted on the portal."
|
|
638
|
+
4. **Comment on the issue**: "Implementation complete. PR #M opened. Evidence on portal: <link>. UAT review requested. Reviewer action — perform UAT, record it with `scripts/record-uat-execution.sh`, then approve or request changes on the portal. Resume with `resume REQ-XXX` once UAT approval is granted on the portal."
|
|
638
639
|
5. **Inspect PR blockers before handoff (devaudit-installer#304).** Run `gh pr view <N> --json mergeStateStatus,reviewDecision,statusCheckRollup,url` and categorize the state:
|
|
639
640
|
- `reviewDecision` not approved → human approval blocker; hand off to the reviewer.
|
|
640
641
|
- Release Approval Gate failing while portal state is not `uat_approved` → portal approval blocker; hand off to portal UAT reviewer.
|
|
@@ -658,7 +659,8 @@ Reached only on the **tracked** route from Phase 0 (the issue is already fetched
|
|
|
658
659
|
The watcher persists retry state in `.sdlc-pr-watch.json`, polls `gh pr view` + `gh pr checks`, re-runs likely flaky workflows automatically, and re-runs the Release Approval Gate when the portal is already approved but GitHub has not converged yet. For a release PR (`$INTEGRATION_BRANCH -> $RELEASE_BRANCH`), it must not call the PR green until the full required release check set has reached terminal success: `Quality Gates`, `Release Scope Integrity`, `Compliance Validation`, `DevAudit Release Approval`, and `E2E Regression Suite`. Use `--once` when you only need a single classification pass.
|
|
659
660
|
|
|
660
661
|
6. **Hard stop only after blocker classification.** Phase 4 ends here. Do not proceed to merge; the human's next action is reviewing on the portal or clearing the categorized blocker above.
|
|
661
|
-
7. **
|
|
662
|
+
7. **Require a separate UAT execution record.** `scripts/submit-for-uat-review.sh` is a queue transition only. The reviewer must run `scripts/record-uat-execution.sh --project-slug <slug> --release REQ-XXX --outcome passed|failed --executor "<identity>" --tested-sha <sha> --checklist-ref "<ref>" --evidence-ref "<ref>"` after performing UAT and before portal approval. A `failed` execution must include `--remediation-ref <issue-or-pr>` and returns to the change-request loop. The skill must not create a passing UAT execution on behalf of the reviewer.
|
|
663
|
+
8. **Update SDLC status sticky** before halting: `bash scripts/update-sdlc-status.sh "$ISSUE_NUM" "Phase 4 — truthful release PR #<N> prepared against $RELEASE_BRANCH; blockers classified" "Operator action — review PR #<N>, perform UAT, record Stage 4 UAT execution, then approve or request changes on the portal; sdlc-implementer halts until you ping resume REQ-XXX"`. This is a critical handoff — the sticky must reflect that the agent has stopped + the operator is on the hook.
|
|
662
664
|
|
|
663
665
|
**When an external gate hangs or fails for unrelated reasons.** A required gate may fail for reasons outside the change's scope — flaky infra, an unrelated regression test that hangs at hour-plus runtime with no log activity, a known-failing suite. When this happens:
|
|
664
666
|
|
|
@@ -693,8 +695,9 @@ Invoked separately by the user after UAT activity on the portal. Trigger: "resum
|
|
|
693
695
|
- **Enumerate all in-scope REQs** from `compliance/pending-releases/RELEASE-TICKET-REQ-*.md` and check each one's portal state before merging. If ANY are `uat_changes_requested`: halt — "REQ-YYY has changes requested on the portal. Cannot merge bundled PR until all in-scope REQs are approved." If ANY are still `uat_review`: halt — "REQ-YYY is still pending UAT review." If ALL are `uat_approved` (or `prod_review`/`prod_approved`/`released`): proceed with merge.
|
|
694
696
|
- `gh pr merge <M> --merge` (merge commit; `--squash` and `--rebase` are blocked by branch protection on SDLC repos and would break the audit trail).
|
|
695
697
|
- **Before watching `post-deploy-prod.yml`**, verify the workflow exists and has triggered: `gh run list --workflow post-deploy-prod.yml --limit 1 --json status,conclusion`. If no run appears within 5 minutes of the merge, halt — "post-deploy-prod.yml did not trigger after merge. Check workflow configuration, secrets, and deployment platform. Operator action — run `gh workflow run post-deploy-prod.yml` manually, then ping `resume REQ-XXX`."
|
|
698
|
+
- **Gate topology:** when a host waits for CI before deploy, only pre-deploy eligibility belongs to the main-push suite. Post-deploy evidence and full regression trigger from a successful production `deployment_status`, not that same push. If the provider skipped the SHA due to CI gating, redeploy that exact SHA before running post-deploy verification.
|
|
696
699
|
- Watch `post-deploy-prod.yml` via `gh run watch` — block until the workflow reaches a terminal state. Wrap in a timeout (30 minutes default, configurable via `sdlc-config.json:post_deploy.timeout_minutes`). If the timeout fires: halt — "post-deploy-prod.yml has not reached a terminal state in N minutes. The deployment may be stuck. Operator action — check hosting platform logs, decide whether to wait or rollback, then ping `resume REQ-XXX`."
|
|
697
|
-
- Treat `post-deploy-prod.yml` success as necessary but not sufficient. The workflow must also confirm the hosting platform's GitHub deployment status for the merged SHA reached terminal `success`. If the
|
|
700
|
+
- Treat `post-deploy-prod.yml` success as necessary but not sufficient. The workflow must also confirm the hosting platform's GitHub deployment status for the merged SHA reached terminal `success`. If it reports `deployment_status_timeout`, `deployment_status_missing`, or terminal failure, remain blocked and preserve the deployment ID, SHA, environment, final observed state, target URL, elapsed time, and independent health-probe result. A successful health probe is corroboration only, never deployment-status proof. Halt — "The host deployment for <sha> is not terminal-successful after merge. Do not approve Production or mark Released. Operator action — inspect provider logs, fix forward or rollback, then rerun post-deploy verification once the production state is understood."
|
|
698
701
|
- Verify production smoke evidence uploaded (`--environment production`) at `https://devaudit.metasession.co/projects/<slug>/releases/<version>`.
|
|
699
702
|
- **Read `production_review.terminal_status` from `sdlc-config.json`** (default: `prod_review`). Branch:
|
|
700
703
|
- If `released` (Option B): PATCH directly to `released` — `PATCH /releases/<version>` with `{"status": "released"}`.
|
|
@@ -705,7 +708,7 @@ Invoked separately by the user after UAT activity on the portal. Trigger: "resum
|
|
|
705
708
|
These steps are mandatory — "PR merged" or "release marked Released" is not complete until the automated close-out PR has merged or a documented fallback reconciliation is complete. Without it, CI can keep uploading evidence against a completed REQ and pollute the audit trail.
|
|
706
709
|
- **Update SDLC status sticky** to the terminal state: `bash scripts/update-sdlc-status.sh "$ISSUE_NUM" "Phase 5 complete — release marked Released; production smoke evidence uploaded; automated close-out reconciled RTM and release ticket" "Done — close issue + retire feature branch (sdlc-implementer halts)"`.
|
|
707
710
|
- Close the issue only after close-out reconciliation completes.
|
|
708
|
-
- If production smoke fails: do NOT mark as Released. **Delegate incident filing to `governance-doc-author` (devaudit-installer#210 §6c)** — invoke `Skill(name: "governance-doc-author", args: "Production smoke failure for REQ-XXX. File an incident issue with the `incident` label + `### Framework attribution` section (ISO29119.3.5.4 + SOC2.CC7.2), severity `blocker`. Include the production URL, git SHA,
|
|
711
|
+
- If production smoke fails: do NOT mark as Released. **Delegate incident filing to `governance-doc-author` (devaudit-installer#210 §6c)** — invoke `Skill(name: "governance-doc-author", args: "Production smoke failure for REQ-XXX. File an incident issue with the `incident` label + `### Framework attribution` section (ISO29119.3.5.4 + SOC2.CC7.2), severity `blocker`. Include the production URL, git SHA, testExecutionId (CI run ID), and smoke results in the issue body.")`. Page the on-call per the project's incident playbook, follow the rollback plan from the implementation plan. If the rollback also fails: update the sticky to "Phase 5 CRITICAL — production smoke failed AND rollback failed. Production is in a broken state. Operator action — page on-call immediately, engage hosting platform support, declare incident per the project's incident playbook. This is beyond the skill's scope." Do NOT attempt further automated remediation. **Update the sticky** to reflect the incident state: `… "Phase 5 BLOCKED — production smoke failed; INCIDENT issue #N filed" "Operator action — read INCIDENT #N + execute rollback per plan"`.
|
|
709
712
|
|
|
710
713
|
- **Changes requested** → run change-request loop:
|
|
711
714
|
- Fetch change-request comments from the PR (`gh pr view <M> --comments`) and from the portal release page.
|
|
@@ -57,7 +57,18 @@ jobs:
|
|
|
57
57
|
# tag each captured screenshot as feature vs regression.
|
|
58
58
|
fetch-depth: 0
|
|
59
59
|
|
|
60
|
-
- name:
|
|
60
|
+
- name: Validate self-hosted runner prerequisites
|
|
61
|
+
env:
|
|
62
|
+
DEVAUDIT_RUNNER_ENVIRONMENT: ${{ runner.environment }}
|
|
63
|
+
run: |
|
|
64
|
+
if [ -f scripts/check-self-hosted-runner.sh ]; then
|
|
65
|
+
chmod +x scripts/check-self-hosted-runner.sh
|
|
66
|
+
bash scripts/check-self-hosted-runner.sh
|
|
67
|
+
else
|
|
68
|
+
echo "::warning::scripts/check-self-hosted-runner.sh missing; run devaudit update to sync runner preflight."
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
- name: Start authoritative quality-gate execution
|
|
61
72
|
if: github.event_name != 'pull_request' && github.ref_name == '{{INTEGRATION_BRANCH}}' && needs.register-release.outputs.version != 'skip'
|
|
62
73
|
run: |
|
|
63
74
|
BASE=""
|
|
@@ -65,13 +76,13 @@ jobs:
|
|
|
65
76
|
BASE=$(jq -r '.devaudit.base_url // empty' sdlc-config.json 2>/dev/null || true)
|
|
66
77
|
fi
|
|
67
78
|
[ -n "$BASE" ] || BASE="$DEVAUDIT_BASE_URL_VAR"
|
|
68
|
-
[ -n "$BASE" ] || { echo "::warning::No DevAudit URL;
|
|
79
|
+
[ -n "$BASE" ] || { echo "::warning::No DevAudit URL; test execution lifecycle disabled"; exit 0; }
|
|
69
80
|
echo "DEVAUDIT_BASE_URL=${BASE%/}" >> "$GITHUB_ENV"
|
|
70
|
-
chmod +x scripts/report-test-
|
|
71
|
-
bash scripts/report-test-
|
|
81
|
+
chmod +x scripts/report-test-execution.sh scripts/report-release-check.sh 2>/dev/null || true
|
|
82
|
+
bash scripts/report-test-execution.sh start \
|
|
72
83
|
--project-slug {{PROJECT_SLUG}} \
|
|
73
84
|
--release "${{ needs.register-release.outputs.version }}" \
|
|
74
|
-
--sdlc-stage 2 --environment ci --
|
|
85
|
+
--sdlc-stage 2 --environment ci --suite-kind quality_gate \
|
|
75
86
|
--provider github_actions --external-run-id "${{ github.run_id }}" \
|
|
76
87
|
--external-run-attempt "${{ github.run_attempt }}" \
|
|
77
88
|
--external-job-id "quality-gates" \
|
|
@@ -323,11 +334,11 @@ jobs:
|
|
|
323
334
|
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
|
324
335
|
echo "Release version: ${VERSION}"
|
|
325
336
|
|
|
326
|
-
- name: Ensure release exists for gate-
|
|
337
|
+
- name: Ensure release exists for gate-execution lineage
|
|
327
338
|
if: env.DEVAUDIT_BASE_URL != '' && steps.version.outputs.version != 'skip'
|
|
328
339
|
run: |
|
|
329
|
-
# First-class
|
|
330
|
-
# stage-2
|
|
340
|
+
# First-class test execution APIs need an exact release row before the
|
|
341
|
+
# stage-2 execution can start. This keeps failed gate runs visible even
|
|
331
342
|
# when later evidence generation fails.
|
|
332
343
|
chmod +x scripts/upload-evidence.sh 2>/dev/null || true
|
|
333
344
|
bash scripts/upload-evidence.sh \
|
|
@@ -501,17 +512,17 @@ jobs:
|
|
|
501
512
|
- name: Generate and upload gate evidence
|
|
502
513
|
if: env.DEVAUDIT_BASE_URL != ''
|
|
503
514
|
run: |
|
|
504
|
-
chmod +x scripts/upload-evidence.sh scripts/report-test-
|
|
515
|
+
chmod +x scripts/upload-evidence.sh scripts/report-test-execution.sh 2>/dev/null || true
|
|
505
516
|
FLAGS="--git-sha ${{ github.sha }} --ci-run-id ${{ github.run_id }} --branch ${{ github.ref_name }}"
|
|
506
517
|
FLAGS="${FLAGS} --release ${{ needs.register-release.outputs.version }} --create-release-if-missing"
|
|
507
518
|
FLAGS="${FLAGS} --environment uat"
|
|
508
519
|
FLAGS="${FLAGS} --sdlc-stage 2"
|
|
509
|
-
PRIMARY_LINEAGE_FLAGS=(--test-
|
|
510
|
-
|
|
511
|
-
bash scripts/report-test-
|
|
520
|
+
PRIMARY_LINEAGE_FLAGS=(--test-execution "${{ github.run_id }}")
|
|
521
|
+
EXECUTION_OUT="$(mktemp)"
|
|
522
|
+
bash scripts/report-test-execution.sh start \
|
|
512
523
|
--project-slug {{PROJECT_SLUG}} \
|
|
513
524
|
--release "${{ needs.register-release.outputs.version }}" \
|
|
514
|
-
--sdlc-stage 2 --environment ci --
|
|
525
|
+
--sdlc-stage 2 --environment ci --suite-kind quality_gate \
|
|
515
526
|
--provider github_actions --external-run-id "${{ github.run_id }}" \
|
|
516
527
|
--external-run-attempt "${{ github.run_attempt }}" \
|
|
517
528
|
--external-job-id "quality-gates" \
|
|
@@ -519,11 +530,11 @@ jobs:
|
|
|
519
530
|
--commit-sha "${{ github.sha }}" --branch "${{ github.ref_name }}" \
|
|
520
531
|
--workflow-name "Quality Gates" \
|
|
521
532
|
--workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
|
|
522
|
-
--output-file "$
|
|
523
|
-
. "$
|
|
524
|
-
rm -f "$
|
|
525
|
-
if [ "${
|
|
526
|
-
PRIMARY_LINEAGE_FLAGS+=(--evidence-scope
|
|
533
|
+
--output-file "$EXECUTION_OUT"
|
|
534
|
+
. "$EXECUTION_OUT"
|
|
535
|
+
rm -f "$EXECUTION_OUT"
|
|
536
|
+
if [ "${execution_supported:-false}" = "true" ] && [ -n "${execution_record_id:-}" ]; then
|
|
537
|
+
PRIMARY_LINEAGE_FLAGS+=(--evidence-scope execution --test-execution-record-id "${execution_record_id}")
|
|
527
538
|
fi
|
|
528
539
|
|
|
529
540
|
# Track failures across all uploads so we can fail the job at the
|
|
@@ -646,20 +657,51 @@ jobs:
|
|
|
646
657
|
--environment uat --sdlc-stage 2
|
|
647
658
|
fi
|
|
648
659
|
|
|
649
|
-
#
|
|
650
|
-
#
|
|
651
|
-
# release
|
|
652
|
-
#
|
|
653
|
-
#
|
|
654
|
-
#
|
|
655
|
-
#
|
|
656
|
-
#
|
|
657
|
-
#
|
|
658
|
-
#
|
|
659
|
-
#
|
|
660
|
-
#
|
|
660
|
+
# Per-REQ E2E JSON attachment only.
|
|
661
|
+
# Gate outcomes above are intentionally uploaded only to the single
|
|
662
|
+
# commit-derived release in FLAGS. A generic integration Quality
|
|
663
|
+
# Gates run is run-level evidence; pending release tickets alone do
|
|
664
|
+
# not make that gate current approval evidence for every REQ. Bundle
|
|
665
|
+
# membership must be represented through an explicit bundle manifest
|
|
666
|
+
# and portal lineage, not by fanning out gate-outcomes.json rows
|
|
667
|
+
# (DevAudit-Installer#438).
|
|
668
|
+
#
|
|
669
|
+
# E2E JSON is different: it may be attached to a REQ only when the
|
|
670
|
+
# report itself contains an executed test tagged for that REQ. A smoke
|
|
671
|
+
# run must never overwrite or obscure a prior targeted feature
|
|
672
|
+
# execution merely because a pending ticket exists
|
|
673
|
+
# (DevAudit-Installer#435).
|
|
674
|
+
has_req_tagged_e2e_result() {
|
|
675
|
+
python3 - "$1" "$2" <<'PY'
|
|
676
|
+
import json, re, sys
|
|
677
|
+
|
|
678
|
+
req_id, filename = sys.argv[1:]
|
|
679
|
+
def values(value):
|
|
680
|
+
if isinstance(value, str): return [value]
|
|
681
|
+
if isinstance(value, dict): return [str(value.get('type', '')), str(value.get('description', ''))]
|
|
682
|
+
return []
|
|
683
|
+
def tagged(node, ancestry):
|
|
684
|
+
text = [*ancestry, str(node.get('title', ''))]
|
|
685
|
+
for field in ('annotations', 'tags'):
|
|
686
|
+
for value in node.get(field, []): text.extend(values(value))
|
|
687
|
+
return any(req_id in value for value in text)
|
|
688
|
+
def executed(test):
|
|
689
|
+
return any(result.get('status') not in {'skipped', 'interrupted'} for result in test.get('results', []))
|
|
690
|
+
def contains(node, ancestry):
|
|
691
|
+
title = str(node.get('title', ''))
|
|
692
|
+
path = [*ancestry, title] if title else ancestry
|
|
693
|
+
for spec in node.get('specs', []):
|
|
694
|
+
if tagged(spec, path) and any(executed(test) for test in spec.get('tests', [])): return True
|
|
695
|
+
for test in node.get('tests', []):
|
|
696
|
+
if tagged(test, path) and executed(test): return True
|
|
697
|
+
return any(contains(suite, path) for suite in node.get('suites', []))
|
|
698
|
+
with open(filename, encoding='utf-8') as handle:
|
|
699
|
+
report = json.load(handle)
|
|
700
|
+
raise SystemExit(0 if re.fullmatch(r'REQ-[A-Z0-9-]+', req_id) and contains(report, []) else 1)
|
|
701
|
+
PY
|
|
702
|
+
}
|
|
661
703
|
COMMIT_REQ="${{ needs.register-release.outputs.version }}"
|
|
662
|
-
|
|
704
|
+
E2E_REQS=()
|
|
663
705
|
if [ -d compliance/pending-releases ]; then
|
|
664
706
|
for TICKET in compliance/pending-releases/RELEASE-TICKET-REQ-*.md; do
|
|
665
707
|
[ -f "$TICKET" ] || continue
|
|
@@ -673,25 +715,23 @@ jobs:
|
|
|
673
715
|
if [ "$REQ_ID" = "$COMMIT_REQ" ]; then
|
|
674
716
|
continue
|
|
675
717
|
fi
|
|
676
|
-
|
|
718
|
+
E2E_REQS+=("$REQ_ID")
|
|
677
719
|
done
|
|
678
720
|
fi
|
|
679
|
-
if [ "${#
|
|
680
|
-
echo "
|
|
681
|
-
|
|
721
|
+
if [ "${#E2E_REQS[@]}" -gt 0 ]; then
|
|
722
|
+
echo "Checking tagged E2E JSON attachment candidates: ${E2E_REQS[*]}"
|
|
723
|
+
echo "::notice::Not fanning out gate-outcomes.json to pending REQs; gate evidence remains on ${COMMIT_REQ} unless represented through explicit release lineage."
|
|
724
|
+
for REQ_ID in "${E2E_REQS[@]}"; do
|
|
682
725
|
FANOUT_FLAGS="--git-sha ${{ github.sha }} --ci-run-id ${{ github.run_id }} --branch ${{ github.ref_name }}"
|
|
683
726
|
FANOUT_FLAGS="${FANOUT_FLAGS} --release ${REQ_ID} --create-release-if-missing"
|
|
684
727
|
FANOUT_FLAGS="${FANOUT_FLAGS} --environment uat --sdlc-stage 2"
|
|
685
|
-
FANOUT_FLAGS="${FANOUT_FLAGS} --test-
|
|
686
|
-
if [ -f ci-evidence/
|
|
687
|
-
upload "gate-outcomes.json -> ${REQ_ID}" \
|
|
688
|
-
{{PROJECT_SLUG}} "${REQ_ID}" gate_outcome ci-evidence/gate-outcomes.json \
|
|
689
|
-
--category ci_pipeline ${FANOUT_FLAGS}
|
|
690
|
-
fi
|
|
691
|
-
if [ -f ci-evidence/e2e-results.json ]; then
|
|
728
|
+
FANOUT_FLAGS="${FANOUT_FLAGS} --test-execution ${{ github.run_id }}"
|
|
729
|
+
if [ -f ci-evidence/e2e-results.json ] && has_req_tagged_e2e_result "$REQ_ID" ci-evidence/e2e-results.json; then
|
|
692
730
|
upload "e2e-results.json -> ${REQ_ID}" \
|
|
693
731
|
{{PROJECT_SLUG}} "${REQ_ID}" e2e_result ci-evidence/e2e-results.json \
|
|
694
732
|
--category e2e_result ${FANOUT_FLAGS}
|
|
733
|
+
elif [ -f ci-evidence/e2e-results.json ]; then
|
|
734
|
+
echo "::notice::Not attaching generic E2E JSON to ${REQ_ID}: this CI tier executed no tagged ${REQ_ID} test. Run-level evidence remains on _compliance-docs."
|
|
695
735
|
fi
|
|
696
736
|
done
|
|
697
737
|
fi
|
|
@@ -945,7 +985,7 @@ jobs:
|
|
|
945
985
|
exit 1
|
|
946
986
|
fi
|
|
947
987
|
|
|
948
|
-
- name: Complete primary quality-gate
|
|
988
|
+
- name: Complete primary quality-gate execution
|
|
949
989
|
if: always() && env.DEVAUDIT_BASE_URL != ''
|
|
950
990
|
run: |
|
|
951
991
|
case "${{ needs.quality-gates.result }}" in
|
|
@@ -953,13 +993,13 @@ jobs:
|
|
|
953
993
|
cancelled) OUTCOME=cancelled ;;
|
|
954
994
|
*) OUTCOME=failed ;;
|
|
955
995
|
esac
|
|
956
|
-
chmod +x scripts/report-test-
|
|
957
|
-
bash scripts/report-test-
|
|
996
|
+
chmod +x scripts/report-test-execution.sh scripts/report-release-check.sh 2>/dev/null || true
|
|
997
|
+
bash scripts/report-test-execution.sh complete \
|
|
958
998
|
--project-slug {{PROJECT_SLUG}} \
|
|
959
999
|
--release "${{ needs.register-release.outputs.version }}" \
|
|
960
1000
|
--sdlc-stage 2 \
|
|
961
1001
|
--environment ci \
|
|
962
|
-
--
|
|
1002
|
+
--suite-kind quality_gate \
|
|
963
1003
|
--provider github_actions \
|
|
964
1004
|
--external-run-id "${{ github.run_id }}" \
|
|
965
1005
|
--external-run-attempt "${{ github.run_attempt }}" \
|