@metasession.co/devaudit-cli 0.1.13 → 0.1.15

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metasession.co/devaudit-cli",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "DevAudit CLI — installs, syncs, and operates the Metasession SDLC across consumer projects.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -33,7 +33,7 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "@clack/prompts": "^0.8.2",
36
- "@metasession.co/devaudit-plugin-sdk": "^0.1.13",
36
+ "@metasession.co/devaudit-plugin-sdk": "^0.1.15",
37
37
  "commander": "^12.1.0",
38
38
  "consola": "^3.2.3",
39
39
  "env-paths": "^3.0.0",
package/sdlc/SKILLS.md CHANGED
@@ -96,22 +96,17 @@ node scripts/validate-adapter.cjs sdlc/files/_common/skills/<name>/SKILL.md
96
96
  | Skill | Location | Triggers (paraphrased) | Additional emissions |
97
97
  | ------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
98
98
  | `e2e-test-engineer` | `_common/skills/` | "add e2e tests", "bootstrap an e2e suite", "update the test pack", "are any tests obsolete", "run e2e tests and file issues" | `e2e/helpers/evidence.ts` (node-stack consumers) |
99
+ | `sdlc-implementer` | `_common/skills/` | "implement issue #N under the SDLC", "run the SDLC for issue #N", "automate REQ-XXX from issue to release", "resume REQ-XXX" | — (orchestrator; invokes `e2e-test-engineer`) |
99
100
 
100
- ## Skills on the roadmap
101
-
102
- | Candidate skill | Likely trigger surface | Supports SDLC stage |
103
- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------- |
104
- | `sdlc-implementer` | "implement issue #N under the SDLC", "run the SDLC for issue #N", "automate REQ-XXX from issue to release", "do the SDLC for [issue]" | All stages (1–5) |
105
-
106
- `sdlc-implementer` is an **orchestration skill** — it drives Claude Code's native tools (`gh`, shell, `devaudit` CLI, portal API) through the full 5-stage flow against a single GitHub issue, pausing only at the UAT-review gate (and at the plan checkpoint for HIGH/CRITICAL risk). It replaces an earlier roadmap of five atomic skills (`risk-classifier`, `commit-message-author`, `compliance-evidence-author`, `sast-triager`, `release-ticket-author`) that were deprioritised — Claude Code's innate capabilities already cover what those atomic skills wrapped; the value-add is end-to-end orchestration with framework-compliant pauses, not five discoverable helpers a human still has to compose.
107
-
108
- **Current status.** SKILL.md + 3 references files are authored at [`sdlc/files/_common/skills/sdlc-implementer/`](./files/_common/skills/sdlc-implementer/) on `main` (Phase B, PR #31). Validator passes. Phase C — smoke against `wawagardenbar-app` — is the last step before this row moves to "Skills currently shipped" above.
101
+ `sdlc-implementer` is the **default entry point for a tracked change** — an **orchestration skill** that drives Claude Code's native tools (`gh`, shell, `devaudit` CLI, portal API) through the full 5-stage flow against a single GitHub issue, pausing only at the UAT-review gate (and at the plan checkpoint for HIGH/CRITICAL risk). It is synced into every consumer (`.claude/skills/sdlc-implementer/`) by `devaudit update`. It replaces an earlier roadmap of five atomic skills (`risk-classifier`, `commit-message-author`, `compliance-evidence-author`, `sast-triager`, `release-ticket-author`) that were deprioritised — Claude Code's innate capabilities already cover what those atomic skills wrapped; the value-add is end-to-end orchestration with framework-compliant pauses, not five discoverable helpers a human still has to compose.
109
102
 
110
103
  **Sub-skill invocation requirement.** During its Phase 2 (Implement & test), the orchestrator **MUST** invoke `e2e-test-engineer` for any end-to-end or visual-regression test work — both scenario derivation from the implementation plan and execution of the resulting suite. The orchestrator does NOT author e2e tests directly. (Unit tests stay with the orchestrator until a unit-test counterpart skill ships.) The invocation pattern is documented in [docs/adding-a-skill.md §Orchestrator skills](../docs/adding-a-skill.md#orchestrator-skills-calling-other-skills); this is a hard contract — the orchestrator's SKILL.md fails review if it inlines `e2e-test-engineer`'s procedure.
111
104
 
112
- Tracking: [`metasession-dev/DevAudit-Installer#29`](https://github.com/metasession-dev/DevAudit-Installer/issues/29) (umbrella).
105
+ `sdlc-implementer` is **not** used for trivial / housekeeping changes (docs, formatting, dependency bumps, CI tweaks) — those skip the requirement and the ceremony. See [the change-type matrix](../docs/change-workflows.md) and the [trivial-change walkthrough](./files/_common/implementing-an-sdlc-issue.md#trivial-change-walkthrough).
106
+
107
+ ## Skills on the roadmap
113
108
 
114
- Other speculative skills land when a real driver appears (a project's day-to-day work surfaces the same pain repeatedly and the orchestrator's internals demonstrably need it as a separable component).
109
+ No concrete candidates are queued. A `unit-test-engineer` counterpart to `e2e-test-engineer` is the most likely next skill, but it lands only when day-to-day work repeatedly surfaces the pain and the orchestrator demonstrably needs it as a separable component. Tracking: [`metasession-dev/DevAudit-Installer#29`](https://github.com/metasession-dev/DevAudit-Installer/issues/29).
115
110
 
116
111
  ## When to make a skill vs. when to keep something in a stage doc
117
112
 
@@ -151,6 +151,15 @@ If the smoke results look wrong or a manual verification fails, click **Reject**
151
151
 
152
152
  ### Step 6: Finalize Compliance (Tracked Requirements Only)
153
153
 
154
+ > **Automated path (preferred).** Run the synced helper instead of doing this by hand — it flips the ticket Status → `RELEASED` (+ backlinks the release PR and records the sign-off), flips the matching `RTM.md` row, and `git mv`s the ticket to `approved-releases/`, then stages the changes for you to commit:
155
+ >
156
+ > ```bash
157
+ > ./scripts/close-out-release.sh REQ-XXX --release-pr <release-PR-#>
158
+ > git add -A && git commit -m "docs(compliance): close out REQ-XXX release ticket (RELEASED)" && git push origin develop
159
+ > ```
160
+ >
161
+ > It is **idempotent** (a no-op if already closed out) and, when `DEVAUDIT_API_KEY` + `DEVAUDIT_BASE_URL` are set, **refuses** unless the portal reports the release as `released` (so you can't flip the local tree ahead of the Production approval). The `close-out-release.yml` workflow runs the same script automatically when the portal marks a release released (and is `workflow_dispatch`-able for catch-up). The manual steps below are the fallback / reference for what the script does.
162
+
154
163
  ```bash
155
164
  mv compliance/pending-releases/RELEASE-TICKET-REQ-XXX.md compliance/approved-releases/
156
165
  ```
@@ -36,23 +36,43 @@ For typo fixes, formatting changes, dependency bumps, and other zero-risk chores
36
36
 
37
37
  If you're not sure whether your change is trivial, treat it as non-trivial (cheaper than discovering mid-PR that an auditor needs evidence).
38
38
 
39
- ## Automated mode (`sdlc-implementer` — pending Phase C smoke)
39
+ ### Trivial-change walkthrough
40
40
 
41
- The [`sdlc-implementer`](#skills-inventory) skill has been authored (SKILL.md + 3 references on `main`, validator-clean) but hasn't yet been smoke-tested against `wawagardenbar-app`. Once Phase C completes, this entire walkthrough collapses to:
41
+ A worked end-to-end example for a zero-risk change (a typo, a dependency bump, a README tweak, a CI-config nudge). No requirement, no plan, no evidence pack — but the gates still run and a human still reviews the PR. `sdlc-implementer` is **not** used here.
42
+
43
+ 1. **Branch off `develop`.** `git checkout develop && git pull && git checkout -b docs/fix-readme-typo` (or `chore/…`, `ci/…`). A GitHub issue is welcome but not required for a true triviality.
44
+ 2. **Make the change, keep it single-purpose.** If it touches `app/` or `lib/` runtime behaviour, it is **not** trivial — stop and run the full SDLC (Stage 1 onward). The commit-type rule below is the backstop.
45
+ 3. **Commit with a housekeeping type.** `docs:` / `chore:` / `ci:` / `build:` / `test:` / `revert:` are **exempt** from the `[REQ-XXX]` rule — e.g. `git commit -m "docs: fix typo in README"`. A `feat` / `fix` / `refactor` / `perf` subject without a `[REQ-XXX]` or `Ref: REQ-XXX` is **rejected** by commitlint and `validate-commits.sh` — if that fires, you picked the wrong type and the change isn't trivial.
46
+ 4. **Run the gates locally — not optional.** `npx tsc --noEmit`, lint, and the test suite must pass before you push. Trivial ≠ unverified.
47
+ 5. **Push and open a PR.** CI runs the same quality gates. `compliance-validation.yml` finds no `REQ-XXX` and **skips** artifact validation; no release ticket, no RTM row, no evidence pack is required.
48
+ 6. **Merge once CI is green** and a reviewer approves the PR. There's **no** portal release record to approve, no UAT/Production gate, and no close-out — a housekeeping push produces at most a bare-date release (`vYYYY.MM.DD`), which carries no approval gate. (Contrast the tracked-change flow below, which produces a `REQ-XXX` release that goes through four-eyes.)
49
+
50
+ If at any step it stops feeling trivial — it changes behaviour, touches auth/payments/data, or an auditor would ask about it — switch to a tracked change and run `sdlc-implementer`. When unsure, it's not trivial.
51
+
52
+ ## Default mode: the `sdlc-implementer` skill
53
+
54
+ The [`sdlc-implementer`](#skills-inventory) skill is the **default way to implement a tracked change** — it is shipped and synced into this repo at `.claude/skills/sdlc-implementer/`. Give it one GitHub issue and the whole walkthrough below collapses to:
42
55
 
43
56
  ```text
44
57
  > Implement issue #N under the SDLC.
45
58
  ```
46
59
 
47
- The skill runs phases 1–4 unattended (with a plan-approval pause for HIGH/CRITICAL risk) and surfaces a UAT review waiting for you on the portal. Approve it on the portal, then:
60
+ It 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:
48
61
 
49
62
  ```text
50
63
  > Resume REQ-XXX.
51
64
  ```
52
65
 
53
- The skill completes phase 5: merge, monitor post-deploy, capture production smoke evidence, mark the release Released. If changes are requested at UAT instead of approval, the skill addresses them and re-submits for UAT re-review.
66
+ 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).
54
67
 
55
- The manual walkthrough below remains the source of truth for what the skill is doing (and the fallback for cases where the skill can't be used). Until the skill ships, follow the walkthrough manually — the sample prompts at the end of this doc are the per-stage stopgap.
68
+ **When it is NOT used:**
69
+
70
+ - **Trivial / housekeeping changes** — see the escape hatch above. Docs, formatting, dependency bumps, CI tweaks (`docs:` / `chore:` / `ci:` …) don't need a requirement and don't go through the skill. (Note: `feat` / `fix` / `refactor` / `perf` commits **do** require a `[REQ-XXX]` / `Ref: REQ-XXX` and are rejected by commitlint + `validate-commits.sh` without one.)
71
+ - **Stage-1 planning in isolation, or e2e test work alone** — run the manual walkthrough / invoke `e2e-test-engineer` directly.
72
+ - **Cross-issue refactors** spanning multiple `REQ-XXX` scopes — out of the one-issue contract.
73
+ - **When the orchestration can't apply** (unusual repo state, partial work mid-stream) — fall back to the manual walkthrough below.
74
+
75
+ The manual walkthrough below is the **operational reference** for exactly what the skill does at each stage — and the fallback when the skill isn't the right fit. (For an audience-level walkthrough with sample AI prompts, see the portal's [`implementing-an-sdlc-issue.md`](https://github.com/metasession-dev/devaudit/blob/main/docs/implementing-an-sdlc-issue.md).)
56
76
 
57
77
  ---
58
78
 
@@ -74,7 +94,7 @@ Assign yourself, move the issue to **In Progress** in the project board.
74
94
 
75
95
  Goal: a written, reviewable plan before any code lands.
76
96
 
77
- Steps (manual; the [`sdlc-implementer`](#skills-inventory) orchestration skill will run this phase automatically once Phase C smoke completes):
97
+ Steps (the [`sdlc-implementer`](#skills-inventory) skill runs this phase automatically the steps below are what it does, and the manual fallback):
78
98
 
79
99
  1. **Classify risk** per [`Test_Policy.md`](https://github.com/metasession-dev/DevAudit-Installer/blob/main/sdlc/files/_common/Test_Policy.md) — LOW, MEDIUM, HIGH, or CRITICAL.
80
100
  2. **Pick or assign a REQ-XXX ID.** Inspect `compliance/RTM.md` for existing entries; if this is genuinely new, take the next available number.
@@ -100,7 +120,7 @@ Goal: code, tests, all gates green locally before pushing.
100
120
  - MEDIUM: unit + integration; e2e for any UI-facing change.
101
121
  - HIGH: unit + integration + e2e for every user-visible path + at least one negative/abuse test.
102
122
  - CRITICAL: HIGH plus targeted security tests (authz bypass attempts, input fuzzing where applicable).
103
- - **For any e2e or visual-regression work in this step, invoke the `e2e-test-engineer` skill** — it derives scenarios from the acceptance criteria + diff, reconciles with the existing pack, retires obsolete tests, runs the suite, and files defects for failures. Don't author e2e tests by hand when the skill is shipped. (Once `sdlc-implementer` Phase C smoke completes, it enforces this delegation automatically.)
123
+ - **For any e2e or visual-regression work in this step, invoke the `e2e-test-engineer` skill** — it derives scenarios from the acceptance criteria + diff, reconciles with the existing pack, retires obsolete tests, runs the suite, and files defects for failures. Don't author e2e tests by hand. (`sdlc-implementer` enforces this delegation automatically in Phase 2.)
104
124
  3. **Implement the change.** Reference the implementation plan; deviations from the plan must be noted in the plan itself (it's the source of truth, not a one-shot artefact).
105
125
  4. **Run all gates locally** before pushing:
106
126
  ```bash
@@ -358,16 +378,11 @@ The Metasession SDLC framework includes a set of [Claude Code Skills](https://gi
358
378
  | Skill | Stage | Scope |
359
379
  | ------------------------------------------------------------------------------------------------------------------------------------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
360
380
  | [`e2e-test-engineer`](https://github.com/metasession-dev/DevAudit-Installer/blob/main/sdlc/files/_common/skills/e2e-test-engineer/SKILL.md) | 2 | Bootstrap or maintain e2e + visual regression suites. Derives scenarios from issue/PR diff, reconciles with existing pack, retires obsolete tests (after confirmation), runs the suite, files defects for failures. Framework-agnostic (Playwright, Cypress, WDIO, Selenium, …). |
381
+ | [`sdlc-implementer`](https://github.com/metasession-dev/DevAudit-Installer/blob/main/sdlc/files/_common/skills/sdlc-implementer/SKILL.md) | 1–5 | One-command orchestration (the **default** for a tracked change): `"implement issue #N under the SDLC"` runs Phase 1 (classify risk, write plan, update RTM) → Phase 2 (branch, tests, implement, gates) → Phase 3 (evidence + portal upload) → Phase 4 (PR + request UAT review), halting at the UAT gate. `"resume REQ-XXX"` runs Phase 5 (merge, post-deploy, mark Released), or the change-request loop. **MUST** invoke `e2e-test-engineer` for e2e/visual work; never authors e2e directly. Enforces six compliance constraints (never skip UAT, no self-approval for HIGH/CRITICAL, mandatory plan checkpoint for HIGH/CRITICAL, change-request → UAT re-review, AI disclosure per commit, all portal mutations audit-logged). **Not** used for trivial/housekeeping changes. |
361
382
 
362
- ### Planned
363
-
364
- One orchestration skill replaces an earlier roadmap of five atomic skills. The atomic ones (`risk-classifier`, `commit-message-author`, `compliance-evidence-author`, `sast-triager`, `release-ticket-author`) were deprioritised: Claude Code's innate capabilities already cover what each wrapped; the actual value-add is end-to-end orchestration with framework-compliant pauses, not five discoverable helpers a human still has to compose.
365
-
366
- | Skill (planned name) | Stage | Scope it will cover |
367
- | -------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
368
- | `sdlc-implementer` | All 5 stages | One-command orchestration: `"implement issue #N under the SDLC"` triggers Phase 1 (classify risk, write plan, update RTM) → Phase 2 (branch, tests, implement, gates) → Phase 3 (evidence capture + portal upload) → Phase 4 (PR open, request UAT review). Halts at Phase 4 with a UAT review waiting for the human on the portal. Resumed by `"resume REQ-XXX"`: if UAT approved → Phase 5 (merge, monitor post-deploy, capture prod smoke evidence, mark Released); if changes requested → re-runs Phase 2 + 3, re-submits for UAT re-review. **MUST invoke** [`e2e-test-engineer`](https://github.com/metasession-dev/DevAudit-Installer/blob/main/sdlc/files/_common/skills/e2e-test-engineer/SKILL.md) for end-to-end and visual-regression test work in Phase 2 — the orchestrator never authors e2e tests directly. Unit-test work stays with the orchestrator until a counterpart unit-test skill ships. Enforces six architectural compliance constraints: never skip UAT gate, never act as UAT approver for HIGH/CRITICAL, plan checkpoint mandatory for HIGH/CRITICAL, change-request loop triggers UAT re-review, AI disclosure on every commit, all portal mutations through audit-logged APIs. Tracked at [`metasession-dev/DevAudit-Installer#29`](https://github.com/metasession-dev/DevAudit-Installer/issues/29). |
383
+ ### Roadmap
369
384
 
370
- After Phase C smoke completes against `wawagardenbar-app`, the skill will appear in every onboarded consumer's `~/.config/devaudit/skills/` on the next `devaudit update`, become discoverable to Claude Code by name (`Skill(name: "sdlc-implementer", …)`), and get a row moved from **Planned** to **Integrated today** above.
385
+ No concrete candidates are queued. The orchestration above replaced an earlier roadmap of five atomic skills (`risk-classifier`, `commit-message-author`, `compliance-evidence-author`, `sast-triager`, `release-ticket-author`) Claude Code's innate capabilities already cover what each wrapped; the value-add is the end-to-end orchestration, not five composable helpers. A `unit-test-engineer` counterpart to `e2e-test-engineer` is the most likely next skill, when day-to-day work surfaces the need. Tracking: [`metasession-dev/DevAudit-Installer#29`](https://github.com/metasession-dev/DevAudit-Installer/issues/29).
371
386
 
372
387
  ### Why skills (vs. just prompts)
373
388
 
@@ -0,0 +1,143 @@
1
+ #!/usr/bin/env bash
2
+ # close-out-release.sh — Reconcile the local compliance tree after a release
3
+ # is marked `released` on the DevAudit portal.
4
+ #
5
+ # For one requirement it: flips the release ticket Status -> RELEASED (backlinks
6
+ # the release PR + records the sign-off), flips the matching compliance/RTM.md
7
+ # row -> RELEASED, and moves the ticket from compliance/pending-releases/ to
8
+ # compliance/approved-releases/. It stages the changes but does NOT commit — the
9
+ # caller (the close-out workflow, or a human) commits/opens the PR.
10
+ #
11
+ # Usage:
12
+ # ./scripts/close-out-release.sh <REQ-ID> [--release-pr <url-or-number>]
13
+ #
14
+ # Example:
15
+ # ./scripts/close-out-release.sh REQ-046 --release-pr 138
16
+ #
17
+ # Optional environment (portal safety check — recommended in CI):
18
+ # DEVAUDIT_API_KEY + DEVAUDIT_BASE_URL — when both are set, the script
19
+ # confirms the portal reports the release as `released` before flipping
20
+ # anything, refusing otherwise (prevents local "RELEASED" while the portal
21
+ # is still at prod_review). When unset, it warns and proceeds (manual mode).
22
+ #
23
+ # Idempotent: if the ticket is already in approved-releases/ with Status
24
+ # RELEASED (and the RTM row already RELEASED), it exits 0 as a no-op.
25
+
26
+ set -euo pipefail
27
+
28
+ REQ_ID="${1:-}"
29
+ RELEASE_PR=""
30
+ shift || true
31
+ while [ $# -gt 0 ]; do
32
+ case "$1" in
33
+ --release-pr) RELEASE_PR="${2:-}"; shift 2 ;;
34
+ *) echo "Unknown option: $1" >&2; exit 2 ;;
35
+ esac
36
+ done
37
+
38
+ if ! printf '%s' "$REQ_ID" | grep -qE '^REQ-[0-9]{3,}$'; then
39
+ echo "Usage: $0 <REQ-ID> [--release-pr <url-or-number>] (REQ-ID like REQ-046)" >&2
40
+ exit 2
41
+ fi
42
+
43
+ PENDING="compliance/pending-releases/RELEASE-TICKET-${REQ_ID}.md"
44
+ APPROVED_DIR="compliance/approved-releases"
45
+ APPROVED="${APPROVED_DIR}/RELEASE-TICKET-${REQ_ID}.md"
46
+ RTM="compliance/RTM.md"
47
+ TODAY="$(date +%Y-%m-%d)"
48
+
49
+ # ── Optional portal safety check ─────────────────────────────────────────────
50
+ if [ -n "${DEVAUDIT_API_KEY:-}" ] && [ -n "${DEVAUDIT_BASE_URL:-}" ]; then
51
+ BASE="${DEVAUDIT_BASE_URL%/}"
52
+ SLUG="$(jq -r '.devaudit.project_slug // .project_slug // empty' sdlc-config.json 2>/dev/null || true)"
53
+ STATUS="$(curl -s -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
54
+ "${BASE}/api/ci/releases/resolve?projectSlug=${SLUG}&versionPrefix=${REQ_ID}" 2>/dev/null \
55
+ | jq -r '.latest.status // empty' 2>/dev/null || true)"
56
+ if [ -n "$STATUS" ] && [ "$STATUS" != "released" ]; then
57
+ echo "::error::Portal reports ${REQ_ID} as '${STATUS}', not 'released'. Refusing to close out." >&2
58
+ exit 1
59
+ fi
60
+ [ "$STATUS" = "released" ] && echo "Portal confirms ${REQ_ID} is released."
61
+ else
62
+ echo "::warning::DEVAUDIT_API_KEY/DEVAUDIT_BASE_URL not set — skipping portal status check (manual mode)."
63
+ fi
64
+
65
+ # ── Idempotency ──────────────────────────────────────────────────────────────
66
+ if [ ! -f "$PENDING" ] && [ -f "$APPROVED" ]; then
67
+ if grep -qE '^\*\*Status:\*\*[[:space:]]*RELEASED' "$APPROVED"; then
68
+ echo "${REQ_ID} already closed out (ticket in approved-releases/, Status RELEASED) — no-op."
69
+ exit 0
70
+ fi
71
+ fi
72
+ if [ ! -f "$PENDING" ] && [ ! -f "$APPROVED" ]; then
73
+ echo "::error::No RELEASE-TICKET-${REQ_ID}.md in pending-releases/ or approved-releases/." >&2
74
+ exit 1
75
+ fi
76
+
77
+ # ── Move ticket pending -> approved (if still pending) ───────────────────────
78
+ mkdir -p "$APPROVED_DIR"
79
+ if [ -f "$PENDING" ]; then
80
+ git mv "$PENDING" "$APPROVED" 2>/dev/null || mv "$PENDING" "$APPROVED"
81
+ echo "Moved ticket -> ${APPROVED}"
82
+ fi
83
+
84
+ # ── Flip ticket Status + backlink + sign-off (edit AFTER the move, then stage —
85
+ # avoids leaving content edits unstaged behind a rename) ────────────────────
86
+ TMP="$(mktemp)"
87
+ SIGN_OFF="**Sign-off (dual-actor):** UAT approved + Production approved on the DevAudit portal (\`released\`); post-deploy production smoke evidence captured. Closed out ${TODAY}."
88
+ PR_LINE=""
89
+ if [ -n "$RELEASE_PR" ]; then
90
+ case "$RELEASE_PR" in
91
+ http*) PR_LINE="**Release PR:** ${RELEASE_PR}" ;;
92
+ *) PR_LINE="**Release PR:** #${RELEASE_PR}" ;;
93
+ esac
94
+ fi
95
+ awk -v signoff="$SIGN_OFF" -v prline="$PR_LINE" '
96
+ BEGIN { status_done=0; signoff_added=0 }
97
+ # Flip the first Status line.
98
+ /^\*\*Status:\*\*/ && status_done==0 { print "**Status:** RELEASED"; status_done=1; next }
99
+ # Replace a placeholder Release PR line if present and a PR was supplied.
100
+ /^\*\*Release PR:\*\*/ && prline!="" { print prline; next }
101
+ { print }
102
+ # After the DevAudit Release line, append the sign-off (once) if not already present.
103
+ /^\*\*DevAudit Release:\*\*/ && signoff_added==0 {
104
+ print signoff; signoff_added=1
105
+ }
106
+ ' "$APPROVED" > "$TMP"
107
+ # Only add a Release PR line if there was no existing one to replace.
108
+ if [ -n "$PR_LINE" ] && ! grep -qE '^\*\*Release PR:\*\*' "$TMP"; then
109
+ awk -v prline="$PR_LINE" '
110
+ /^\*\*DevAudit Release:\*\*/ { print prline }
111
+ { print }
112
+ ' "$TMP" > "${TMP}.2" && mv "${TMP}.2" "$TMP"
113
+ fi
114
+ mv "$TMP" "$APPROVED"
115
+ git add "$APPROVED" 2>/dev/null || true
116
+ echo "Ticket Status -> RELEASED."
117
+
118
+ # ── Flip the RTM row -> RELEASED (preserve any parenthetical note) ───────────
119
+ if [ -f "$RTM" ] && grep -qE "^\| ${REQ_ID} " "$RTM"; then
120
+ awk -v req="$REQ_ID" '
121
+ BEGIN { FS="|"; OFS="|"; statuscol=0 }
122
+ # Locate the "Status" column from the first header row that has one.
123
+ statuscol==0 {
124
+ for (i=1; i<=NF; i++) { c=$i; gsub(/^[[:space:]]+|[[:space:]]+$/, "", c); if (c=="Status") statuscol=i }
125
+ }
126
+ $0 ~ ("^\\| " req " ") && statuscol>0 {
127
+ cell=$statuscol
128
+ note=""
129
+ if (match(cell, /\(/)) note=substr(cell, RSTART) # preserve any " (requirement note)"
130
+ gsub(/^[[:space:]]+|[[:space:]]+$/, "", note)
131
+ $statuscol = (note != "" ? " RELEASED " note " " : " RELEASED ")
132
+ print; next
133
+ }
134
+ { print }
135
+ ' "$RTM" > "$TMP" && mv "$TMP" "$RTM"
136
+ git add "$RTM" 2>/dev/null || true
137
+ echo "RTM row ${REQ_ID} -> RELEASED."
138
+ else
139
+ echo "::warning::No RTM row for ${REQ_ID} in ${RTM} — skipped RTM flip."
140
+ rm -f "$TMP"
141
+ fi
142
+
143
+ echo "Close-out staged for ${REQ_ID}. Commit + open a PR to develop to land it."
@@ -0,0 +1,96 @@
1
+ # Release close-out — reconcile the local compliance tree after a release is
2
+ # marked `released` on the DevAudit portal.
3
+ #
4
+ # Generated by `devaudit install` / `devaudit update` from sdlc-config.json.
5
+ # Do not edit manually — re-run the CLI (`devaudit update`) to regenerate.
6
+ #
7
+ # Triggers:
8
+ # - repository_dispatch (type: release-closed) — sent by the DevAudit portal
9
+ # when it advances a release to `released`. client_payload: { release,
10
+ # release_pr }.
11
+ # - workflow_dispatch — manual catch-up for an already-released requirement.
12
+ #
13
+ # It runs scripts/close-out-release.sh for the requirement (flip ticket +
14
+ # RTM, move ticket to approved-releases/), then opens a PR to develop. The
15
+ # script is idempotent, so a no-op produces no PR.
16
+
17
+ name: Release Close-out
18
+
19
+ on:
20
+ workflow_dispatch:
21
+ inputs:
22
+ release:
23
+ description: 'REQ-XXX to close out (e.g. REQ-046)'
24
+ required: true
25
+ release_pr:
26
+ description: 'Release PR number or URL to backlink (optional)'
27
+ required: false
28
+ repository_dispatch:
29
+ types: [release-closed]
30
+
31
+ permissions:
32
+ contents: write
33
+ pull-requests: write
34
+
35
+ jobs:
36
+ close-out:
37
+ name: Close out release
38
+ runs-on: {{RUNNER}}
39
+ env:
40
+ GH_TOKEN: ${{ github.token }}
41
+ DEVAUDIT_API_KEY: ${{ secrets.DEVAUDIT_API_KEY }}
42
+ steps:
43
+ - uses: actions/checkout@v4
44
+ with:
45
+ ref: develop
46
+ fetch-depth: 0
47
+
48
+ - name: Resolve inputs
49
+ id: in
50
+ run: |
51
+ REQ="${{ github.event.inputs.release }}${{ github.event.client_payload.release }}"
52
+ PR="${{ github.event.inputs.release_pr }}${{ github.event.client_payload.release_pr }}"
53
+ if ! printf '%s' "$REQ" | grep -qE '^REQ-[0-9]{3,}$'; then
54
+ echo "::error::No valid REQ-XXX supplied (inputs.release / client_payload.release)."
55
+ exit 1
56
+ fi
57
+ echo "req=${REQ}" >> "$GITHUB_OUTPUT"
58
+ echo "pr=${PR}" >> "$GITHUB_OUTPUT"
59
+ # Portal base URL for the safety check (read from sdlc-config.json).
60
+ BASE=$(jq -r '.devaudit.base_url // empty' sdlc-config.json 2>/dev/null || true)
61
+ echo "DEVAUDIT_BASE_URL=${BASE%/}" >> "$GITHUB_ENV"
62
+
63
+ - name: Run close-out
64
+ id: closeout
65
+ run: |
66
+ chmod +x scripts/close-out-release.sh 2>/dev/null || true
67
+ ARGS="${{ steps.in.outputs.req }}"
68
+ [ -n "${{ steps.in.outputs.pr }}" ] && ARGS="${ARGS} --release-pr ${{ steps.in.outputs.pr }}"
69
+ bash scripts/close-out-release.sh ${ARGS}
70
+ if [ -n "$(git status --porcelain)" ]; then
71
+ echo "changed=true" >> "$GITHUB_OUTPUT"
72
+ else
73
+ echo "changed=false" >> "$GITHUB_OUTPUT"
74
+ echo "Nothing to close out (idempotent no-op) — no PR opened."
75
+ fi
76
+
77
+ - name: Open close-out PR
78
+ if: steps.closeout.outputs.changed == 'true'
79
+ run: |
80
+ REQ="${{ steps.in.outputs.req }}"
81
+ BRANCH="chore/close-out-${REQ}"
82
+ git config user.name "devaudit-bot"
83
+ git config user.email "devaudit-bot@users.noreply.github.com"
84
+ git checkout -b "$BRANCH"
85
+ git add -A
86
+ git commit -m "docs(compliance): close out ${REQ} release ticket (RELEASED)
87
+
88
+ Automated reconciliation after the DevAudit portal marked ${REQ} released.
89
+ Ticket Status -> RELEASED + moved to approved-releases/; RTM row -> RELEASED.
90
+
91
+ Ref: ${REQ}"
92
+ git push -u origin "$BRANCH" --force-with-lease
93
+ gh pr create --base develop --head "$BRANCH" \
94
+ --title "docs(compliance): close out ${REQ} release ticket (RELEASED)" \
95
+ --body "Automated close-out — the DevAudit portal marked **${REQ}** \`released\`. This moves the ticket to \`approved-releases/\`, flips its Status and the RTM row to \`RELEASED\`. Review + merge to develop, then promote to main." \
96
+ || echo "::warning::PR may already exist for ${BRANCH}."