@metasession.co/devaudit-cli 0.1.11 → 0.1.13
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 +13 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/sdlc/files/ci/post-deploy-prod.yml.template +86 -86
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.13",
|
|
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.13",
|
|
37
37
|
"commander": "^12.1.0",
|
|
38
38
|
"consola": "^3.2.3",
|
|
39
39
|
"env-paths": "^3.0.0",
|
|
@@ -6,16 +6,27 @@
|
|
|
6
6
|
# Production verification is READ-ONLY.
|
|
7
7
|
# No E2E tests, no database operations, no API mutations.
|
|
8
8
|
#
|
|
9
|
+
# Promotes EVERY in-scope release (each requirement with a pending release
|
|
10
|
+
# ticket), not just the first REQ found — a develop→main PR that bundles
|
|
11
|
+
# several requirements must advance all of them to the terminal status, else
|
|
12
|
+
# the requirements not picked first stay stuck at uat_approved with no
|
|
13
|
+
# production evidence. `workflow_dispatch` allows re-running / catching up a
|
|
14
|
+
# single release via the `release` input.
|
|
15
|
+
#
|
|
9
16
|
# In sdlc-v1.22.0+ the terminal release status is configurable via
|
|
10
17
|
# sdlc-config.json `production_review.terminal_status`:
|
|
11
18
|
# - "prod_review" (default, Option A) — stop at prod_review; human in the
|
|
12
|
-
# portal clicks "Approve Production" then "Mark as Released"
|
|
13
|
-
# explicit audit trail. Closes #138.
|
|
19
|
+
# portal clicks "Approve Production" then "Mark as Released".
|
|
14
20
|
# - "released" (Option B) — preserves v1.21.x auto-release behaviour.
|
|
15
21
|
|
|
16
22
|
name: Post-Deploy Production Evidence
|
|
17
23
|
|
|
18
24
|
on:
|
|
25
|
+
workflow_dispatch:
|
|
26
|
+
inputs:
|
|
27
|
+
release:
|
|
28
|
+
description: 'Optional REQ-XXX / version to promote (blank = all in-scope from pending release tickets).'
|
|
29
|
+
required: false
|
|
19
30
|
push:
|
|
20
31
|
branches: [main]
|
|
21
32
|
|
|
@@ -30,11 +41,12 @@ jobs:
|
|
|
30
41
|
PROJECT_SLUG: {{PROJECT_SLUG}}
|
|
31
42
|
GIT_SHA: ${{ github.sha }}
|
|
32
43
|
CI_RUN: ${{ github.run_id }}
|
|
44
|
+
RELEASE_INPUT: ${{ github.event.inputs.release }}
|
|
33
45
|
|
|
34
46
|
steps:
|
|
35
47
|
- uses: actions/checkout@v4
|
|
36
48
|
with:
|
|
37
|
-
fetch-depth: 0 # full history so
|
|
49
|
+
fetch-depth: 0 # full history so merged commits' REQ tags are readable
|
|
38
50
|
|
|
39
51
|
- name: Resolve DevAudit base URL and post-deploy terminal status
|
|
40
52
|
run: |
|
|
@@ -75,37 +87,31 @@ jobs:
|
|
|
75
87
|
echo "DEVAUDIT_BASE_URL=${BASE%/}" >> "$GITHUB_ENV"
|
|
76
88
|
echo "TERMINAL_STATUS=${TERMINAL_STATUS}" >> "$GITHUB_ENV"
|
|
77
89
|
|
|
78
|
-
- name: Resolve
|
|
79
|
-
id: release
|
|
90
|
+
- name: Resolve in-scope releases
|
|
80
91
|
run: |
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
# derive-release-version.sh → REQ-XXX).
|
|
84
|
-
# carries
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
# date release while the real REQ release stays uat_approved.
|
|
90
|
-
REQ=$(git log "${{ github.event.before }}..${{ github.sha }}" --format='%s%n%b' 2>/dev/null \
|
|
91
|
-
| grep -oiE '\[REQ-[0-9]+\]|Ref:[[:space:]]*REQ-[0-9]+' \
|
|
92
|
-
| grep -oiE 'REQ-[0-9]+' | head -1 | tr '[:lower:]' '[:upper:]' || true)
|
|
93
|
-
if [ -n "$REQ" ]; then
|
|
94
|
-
PREFIX="$REQ"
|
|
92
|
+
# The releases being PROMOTED are the requirements with a pending
|
|
93
|
+
# release ticket (the same set the dev/UAT pipeline versioned via
|
|
94
|
+
# derive-release-version.sh → REQ-XXX). A bundled develop→main PR
|
|
95
|
+
# carries several; promote ALL of them, not just the first. A manual
|
|
96
|
+
# dispatch can target one via the `release` input. Fall back to a
|
|
97
|
+
# bare date for date-versioned (ticketless) releases.
|
|
98
|
+
if [ -n "${RELEASE_INPUT}" ]; then
|
|
99
|
+
REQS="${RELEASE_INPUT}"
|
|
95
100
|
else
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
REQS=""
|
|
102
|
+
if [ -d compliance/pending-releases ]; then
|
|
103
|
+
for T in compliance/pending-releases/RELEASE-TICKET-REQ-*.md; do
|
|
104
|
+
[ -f "$T" ] || continue
|
|
105
|
+
REQS="${REQS} $(basename "$T" .md | sed 's/^RELEASE-TICKET-//')"
|
|
106
|
+
done
|
|
107
|
+
fi
|
|
108
|
+
REQS=$(echo ${REQS} | tr ' ' '\n' | sort -u | tr '\n' ' ' | sed 's/[[:space:]]*$//')
|
|
109
|
+
if [ -z "${REQS}" ]; then
|
|
110
|
+
REQS="v$(date +%Y.%m.%d)"
|
|
111
|
+
fi
|
|
104
112
|
fi
|
|
105
|
-
|
|
106
|
-
echo "
|
|
107
|
-
echo "release_id=${RELEASE_ID}" >> "$GITHUB_OUTPUT"
|
|
108
|
-
echo "Release version: ${VERSION}"
|
|
113
|
+
echo "In-scope releases to promote: ${REQS}"
|
|
114
|
+
echo "REQS=${REQS}" >> "$GITHUB_ENV"
|
|
109
115
|
|
|
110
116
|
- name: Wait for production deployment
|
|
111
117
|
run: |
|
|
@@ -142,63 +148,57 @@ jobs:
|
|
|
142
148
|
}
|
|
143
149
|
RESULTS_EOF
|
|
144
150
|
|
|
145
|
-
- name:
|
|
146
|
-
run: |
|
|
147
|
-
chmod +x scripts/upload-evidence.sh 2>/dev/null || true
|
|
148
|
-
VERSION="${{ steps.release.outputs.version }}"
|
|
149
|
-
FLAGS="--release ${VERSION} --create-release-if-missing --environment production --category test_report"
|
|
150
|
-
FLAGS="${FLAGS} --git-sha ${GIT_SHA} --ci-run-id ${CI_RUN} --branch main"
|
|
151
|
-
if [ -f prod-smoke-results.json ]; then
|
|
152
|
-
bash scripts/upload-evidence.sh \
|
|
153
|
-
"${PROJECT_SLUG}" "_compliance-docs" "test_report" prod-smoke-results.json \
|
|
154
|
-
${FLAGS} || echo "Warning: Failed to upload smoke results"
|
|
155
|
-
fi
|
|
156
|
-
|
|
157
|
-
- name: Upload release ticket to production
|
|
151
|
+
- name: Promote in-scope releases (evidence + status)
|
|
158
152
|
run: |
|
|
159
|
-
# Submit-for-production-review requires a release ticket (release_artifact)
|
|
160
|
-
# in the PRODUCTION environment — the dev/UAT pipeline only uploads it to
|
|
161
|
-
# uat. Carry the promoted release's ticket forward to production so the
|
|
162
|
-
# production release is self-contained and the prod-review gate passes.
|
|
163
153
|
chmod +x scripts/upload-evidence.sh 2>/dev/null || true
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
154
|
+
PROMOTED=0
|
|
155
|
+
for PREFIX in ${REQS}; do
|
|
156
|
+
echo "=== Promoting ${PREFIX} ==="
|
|
157
|
+
RESP=$(curl -s -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
|
|
158
|
+
"${BASE}/api/ci/releases/resolve?projectSlug=${PROJECT_SLUG}&versionPrefix=${PREFIX}")
|
|
159
|
+
VERSION=$(echo "$RESP" | jq -r '.latest.version // empty')
|
|
160
|
+
[ -z "$VERSION" ] && VERSION="${PREFIX}"
|
|
161
|
+
RELEASE_ID=$(echo "$RESP" | jq -r '.latest.id // empty')
|
|
162
|
+
# Production smoke evidence (whole-app health) attached to this release.
|
|
163
|
+
if [ -f prod-smoke-results.json ]; then
|
|
164
|
+
bash scripts/upload-evidence.sh \
|
|
165
|
+
"${PROJECT_SLUG}" "${VERSION}" test_report prod-smoke-results.json \
|
|
166
|
+
--release "${VERSION}" --create-release-if-missing --environment production \
|
|
167
|
+
--category test_report --git-sha "${GIT_SHA}" --ci-run-id "${CI_RUN}" --branch main \
|
|
168
|
+
|| echo "Warning: smoke upload failed for ${VERSION}"
|
|
169
|
+
fi
|
|
170
|
+
# Carry the release ticket into the production environment so the
|
|
171
|
+
# prod-review gate is self-contained.
|
|
172
|
+
TICKET=""
|
|
173
|
+
for DIR in compliance/pending-releases compliance/approved-releases; do
|
|
174
|
+
if [ -f "${DIR}/RELEASE-TICKET-${VERSION}.md" ]; then
|
|
175
|
+
TICKET="${DIR}/RELEASE-TICKET-${VERSION}.md"; break
|
|
176
|
+
fi
|
|
177
|
+
done
|
|
178
|
+
if [ -n "$TICKET" ]; then
|
|
179
|
+
bash scripts/upload-evidence.sh \
|
|
180
|
+
"${PROJECT_SLUG}" "${VERSION}" compliance_document "$TICKET" \
|
|
181
|
+
--release "${VERSION}" --create-release-if-missing --environment production \
|
|
182
|
+
--category release_artifact --git-sha "${GIT_SHA}" --ci-run-id "${CI_RUN}" --branch main \
|
|
183
|
+
|| echo "Warning: ticket upload failed for ${VERSION}"
|
|
184
|
+
else
|
|
185
|
+
echo "No RELEASE-TICKET-${VERSION}.md found — skipping ticket (date-versioned or archived)."
|
|
186
|
+
fi
|
|
187
|
+
# Advance status (idempotent — re-PATCHing an already-promoted release is a no-op).
|
|
188
|
+
if [ -n "$RELEASE_ID" ]; then
|
|
189
|
+
curl -s -o /dev/null -w " ${VERSION} status patch: HTTP %{http_code}\n" \
|
|
190
|
+
-X PATCH "${BASE}/api/ci/releases/${RELEASE_ID}" \
|
|
191
|
+
-H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
|
|
192
|
+
-H "Content-Type: application/json" \
|
|
193
|
+
-d "{\"status\":\"${TERMINAL_STATUS}\"}"
|
|
194
|
+
echo " ${VERSION} → ${TERMINAL_STATUS}"
|
|
195
|
+
PROMOTED=$((PROMOTED + 1))
|
|
196
|
+
else
|
|
197
|
+
echo "::warning::No release_id resolved for ${PREFIX} — skipping status patch"
|
|
172
198
|
fi
|
|
173
199
|
done
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
${FLAGS} || echo "Warning: Failed to upload release ticket to production"
|
|
179
|
-
else
|
|
180
|
-
echo "No RELEASE-TICKET-${VERSION}.md in pending-/approved-releases — skipping (date-versioned release or ticket archived)."
|
|
181
|
-
fi
|
|
182
|
-
|
|
183
|
-
- name: Advance release status (post-deploy)
|
|
184
|
-
run: |
|
|
185
|
-
RELEASE_ID="${{ steps.release.outputs.release_id }}"
|
|
186
|
-
if [ -z "$RELEASE_ID" ]; then
|
|
187
|
-
echo "::warning::No release_id resolved — skipping status patch"
|
|
188
|
-
exit 0
|
|
200
|
+
echo "Promoted ${PROMOTED} release(s) to ${TERMINAL_STATUS}."
|
|
201
|
+
if [ "${TERMINAL_STATUS}" = "prod_review" ]; then
|
|
202
|
+
echo "Next: a human in the portal clicks 'Approve Production' then 'Mark as Released' for each."
|
|
203
|
+
echo "Audit trail captures both events with reviewer identity per compliance/risk-register.md."
|
|
189
204
|
fi
|
|
190
|
-
curl -s -o /dev/null -w "Release status patch: HTTP %{http_code}\n" \
|
|
191
|
-
-X PATCH "${BASE}/api/ci/releases/${RELEASE_ID}" \
|
|
192
|
-
-H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
|
|
193
|
-
-H "Content-Type: application/json" \
|
|
194
|
-
-d "{\"status\":\"${TERMINAL_STATUS}\"}"
|
|
195
|
-
case "$TERMINAL_STATUS" in
|
|
196
|
-
prod_review)
|
|
197
|
-
echo "Release ${{ steps.release.outputs.version }} → prod_review."
|
|
198
|
-
echo "Next: a human in the portal clicks 'Approve Production' (→ prod_approved), then 'Mark as Released' (→ released)."
|
|
199
|
-
echo "Audit trail captures both events with reviewer identity per compliance/risk-register.md."
|
|
200
|
-
;;
|
|
201
|
-
released)
|
|
202
|
-
echo "Release ${{ steps.release.outputs.version }} → released (Option B: auto-release with no post-deploy human gate)."
|
|
203
|
-
;;
|
|
204
|
-
esac
|