@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/dist/index.js +60 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/sdlc/SKILLS.md +6 -11
- package/sdlc/files/_common/5-deploy-main.md +9 -0
- package/sdlc/files/_common/implementing-an-sdlc-issue.md +30 -15
- package/sdlc/files/_common/scripts/close-out-release.sh +143 -0
- package/sdlc/files/ci/close-out-release.yml.template +96 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metasession.co/devaudit-cli",
|
|
3
|
-
"version": "0.1.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
39
|
+
### Trivial-change walkthrough
|
|
40
40
|
|
|
41
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
|
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
|
-
###
|
|
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
|
-
|
|
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}."
|