@metasession.co/devaudit-cli 0.3.13 → 0.3.14
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 +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/sdlc/files/_common/scripts/generate-bundled-changes.sh +13 -4
- package/sdlc/files/_common/scripts/generate-bundled-changes.test.sh +5 -0
- package/sdlc/files/_common/scripts/report-release-check.sh +86 -0
- package/sdlc/files/_common/scripts/report-release-check.test.sh +97 -0
- package/sdlc/files/ci/ci.yml.template +49 -12
- package/sdlc/files/ci/compliance-evidence.yml.template +32 -6
- package/sdlc/files/ci/post-deploy-prod.yml.template +149 -21
- package/sdlc/package.json +1 -1
|
@@ -117,19 +117,47 @@ jobs:
|
|
|
117
117
|
echo "In-scope releases to promote: ${REQS}"
|
|
118
118
|
echo "REQS=${REQS}" >> "$GITHUB_ENV"
|
|
119
119
|
|
|
120
|
+
- name: Start production deployment cycles
|
|
121
|
+
run: |
|
|
122
|
+
chmod +x scripts/report-test-cycle.sh 2>/dev/null || true
|
|
123
|
+
for PREFIX in ${REQS}; do
|
|
124
|
+
RESP=$(curl -fsS -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
|
|
125
|
+
"${BASE}/api/ci/releases/resolve?projectSlug=${PROJECT_SLUG}&versionPrefix=${PREFIX}")
|
|
126
|
+
VERSION=$(echo "$RESP" | jq -r '.latest.version // empty')
|
|
127
|
+
[ -n "$VERSION" ] || VERSION="$PREFIX"
|
|
128
|
+
bash scripts/report-test-cycle.sh start \
|
|
129
|
+
--project-slug "$PROJECT_SLUG" --release "$VERSION" \
|
|
130
|
+
--sdlc-stage 5 --environment production --cycle-kind deployment \
|
|
131
|
+
--provider github_actions --external-run-id "$CI_RUN" \
|
|
132
|
+
--external-run-attempt "${{ github.run_attempt }}" --external-job-id "host-deployment" \
|
|
133
|
+
--idempotency-key "github:${{ github.repository }}:post-deploy-prod.deployment:${CI_RUN}:${{ github.run_attempt }}:5:${VERSION}" \
|
|
134
|
+
--commit-sha "$GIT_SHA" --branch main \
|
|
135
|
+
--workflow-name "Post-Deploy Production" \
|
|
136
|
+
--workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
|
137
|
+
done
|
|
138
|
+
|
|
120
139
|
- name: Wait for production deployment
|
|
140
|
+
id: wait_deployment
|
|
121
141
|
run: |
|
|
142
|
+
DEPLOY_READY=false
|
|
122
143
|
for i in $(seq 1 30); do
|
|
123
144
|
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "${PROD_URL}/" || echo "000")
|
|
124
145
|
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 400 ]; then
|
|
125
146
|
echo "Production is up (HTTP ${HTTP_CODE})"
|
|
147
|
+
DEPLOY_READY=true
|
|
126
148
|
break
|
|
127
149
|
fi
|
|
128
150
|
echo "Attempt ${i}/30: HTTP ${HTTP_CODE} — waiting 10s..."
|
|
129
151
|
sleep 10
|
|
130
152
|
done
|
|
153
|
+
if [ "$DEPLOY_READY" != "true" ]; then
|
|
154
|
+
echo "::error::Production did not become ready within the deployment window"
|
|
155
|
+
exit 1
|
|
156
|
+
fi
|
|
131
157
|
|
|
132
158
|
- name: Confirm terminal host deployment success
|
|
159
|
+
id: host_deployment
|
|
160
|
+
if: steps.wait_deployment.outcome == 'success'
|
|
133
161
|
env:
|
|
134
162
|
GH_TOKEN: ${{ github.token }}
|
|
135
163
|
run: |
|
|
@@ -140,7 +168,68 @@ jobs:
|
|
|
140
168
|
--max-attempts=30 \
|
|
141
169
|
--poll-seconds=10
|
|
142
170
|
|
|
171
|
+
- name: Complete production deployment cycles
|
|
172
|
+
if: always() && env.BASE != ''
|
|
173
|
+
run: |
|
|
174
|
+
if [ "${{ steps.wait_deployment.outcome }}" = "success" ] && [ "${{ steps.host_deployment.outcome }}" = "success" ]; then
|
|
175
|
+
OUTCOME=passed
|
|
176
|
+
CHECK_STATUS=successful
|
|
177
|
+
elif [ "${{ steps.wait_deployment.outcome }}" = "cancelled" ] || [ "${{ steps.host_deployment.outcome }}" = "cancelled" ]; then
|
|
178
|
+
OUTCOME=cancelled
|
|
179
|
+
CHECK_STATUS=cancelled
|
|
180
|
+
else
|
|
181
|
+
OUTCOME=failed
|
|
182
|
+
CHECK_STATUS=failed
|
|
183
|
+
fi
|
|
184
|
+
chmod +x scripts/report-test-cycle.sh scripts/report-release-check.sh 2>/dev/null || true
|
|
185
|
+
for PREFIX in ${REQS}; do
|
|
186
|
+
RESP=$(curl -fsS -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
|
|
187
|
+
"${BASE}/api/ci/releases/resolve?projectSlug=${PROJECT_SLUG}&versionPrefix=${PREFIX}")
|
|
188
|
+
VERSION=$(echo "$RESP" | jq -r '.latest.version // empty')
|
|
189
|
+
[ -n "$VERSION" ] || VERSION="$PREFIX"
|
|
190
|
+
bash scripts/report-test-cycle.sh complete \
|
|
191
|
+
--project-slug "$PROJECT_SLUG" --release "$VERSION" \
|
|
192
|
+
--sdlc-stage 5 --environment production --cycle-kind deployment \
|
|
193
|
+
--provider github_actions --external-run-id "$CI_RUN" \
|
|
194
|
+
--external-run-attempt "${{ github.run_attempt }}" --external-job-id "host-deployment" \
|
|
195
|
+
--idempotency-key "github:${{ github.repository }}:post-deploy-prod.deployment:${CI_RUN}:${{ github.run_attempt }}:5:${VERSION}" \
|
|
196
|
+
--commit-sha "$GIT_SHA" --branch main \
|
|
197
|
+
--workflow-name "Post-Deploy Production" \
|
|
198
|
+
--workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
|
|
199
|
+
--outcome "$OUTCOME" --outcome-reason "host deployment: ${{ steps.host_deployment.outcome }}"
|
|
200
|
+
bash scripts/report-release-check.sh \
|
|
201
|
+
--project-slug "$PROJECT_SLUG" --release "$VERSION" \
|
|
202
|
+
--check-key "production-deployment:${CI_RUN}:${{ github.run_attempt }}" \
|
|
203
|
+
--label "Production Deployment" --provider github_actions --status "$CHECK_STATUS" \
|
|
204
|
+
--external-run-id "$CI_RUN" \
|
|
205
|
+
--external-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
|
|
206
|
+
--commit-sha "$GIT_SHA" --branch main \
|
|
207
|
+
--details-json '{"waitOutcome":"${{ steps.wait_deployment.outcome }}","hostOutcome":"${{ steps.host_deployment.outcome }}"}'
|
|
208
|
+
done
|
|
209
|
+
|
|
210
|
+
- name: Start production smoke cycles
|
|
211
|
+
if: steps.wait_deployment.outcome == 'success' && steps.host_deployment.outcome == 'success'
|
|
212
|
+
run: |
|
|
213
|
+
chmod +x scripts/report-test-cycle.sh 2>/dev/null || true
|
|
214
|
+
for PREFIX in ${REQS}; do
|
|
215
|
+
RESP=$(curl -fsS -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
|
|
216
|
+
"${BASE}/api/ci/releases/resolve?projectSlug=${PROJECT_SLUG}&versionPrefix=${PREFIX}")
|
|
217
|
+
VERSION=$(echo "$RESP" | jq -r '.latest.version // empty')
|
|
218
|
+
[ -n "$VERSION" ] || VERSION="$PREFIX"
|
|
219
|
+
bash scripts/report-test-cycle.sh start \
|
|
220
|
+
--project-slug "$PROJECT_SLUG" --release "$VERSION" \
|
|
221
|
+
--sdlc-stage 5 --environment production --cycle-kind smoke \
|
|
222
|
+
--provider github_actions --external-run-id "$CI_RUN" \
|
|
223
|
+
--external-run-attempt "${{ github.run_attempt }}" --external-job-id "production-smoke" \
|
|
224
|
+
--idempotency-key "github:${{ github.repository }}:post-deploy-prod.smoke:${CI_RUN}:${{ github.run_attempt }}:5:${VERSION}" \
|
|
225
|
+
--commit-sha "$GIT_SHA" --branch main \
|
|
226
|
+
--workflow-name "Post-Deploy Production" \
|
|
227
|
+
--workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
|
228
|
+
done
|
|
229
|
+
|
|
143
230
|
- name: Production smoke tests (read-only)
|
|
231
|
+
id: production_smoke
|
|
232
|
+
if: steps.wait_deployment.outcome == 'success' && steps.host_deployment.outcome == 'success'
|
|
144
233
|
run: |
|
|
145
234
|
echo "=== Production Smoke Tests ==="
|
|
146
235
|
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "${PROD_URL}/")
|
|
@@ -163,8 +252,43 @@ jobs:
|
|
|
163
252
|
}
|
|
164
253
|
RESULTS_EOF
|
|
165
254
|
|
|
255
|
+
- name: Complete production smoke cycles
|
|
256
|
+
if: always() && env.BASE != '' && steps.host_deployment.outcome == 'success'
|
|
257
|
+
run: |
|
|
258
|
+
case "${{ steps.production_smoke.outcome }}" in
|
|
259
|
+
success) OUTCOME=passed; CHECK_STATUS=successful ;;
|
|
260
|
+
cancelled) OUTCOME=cancelled; CHECK_STATUS=cancelled ;;
|
|
261
|
+
skipped) OUTCOME=skipped; CHECK_STATUS=skipped ;;
|
|
262
|
+
*) OUTCOME=failed; CHECK_STATUS=failed ;;
|
|
263
|
+
esac
|
|
264
|
+
chmod +x scripts/report-test-cycle.sh scripts/report-release-check.sh 2>/dev/null || true
|
|
265
|
+
for PREFIX in ${REQS}; do
|
|
266
|
+
RESP=$(curl -fsS -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
|
|
267
|
+
"${BASE}/api/ci/releases/resolve?projectSlug=${PROJECT_SLUG}&versionPrefix=${PREFIX}")
|
|
268
|
+
VERSION=$(echo "$RESP" | jq -r '.latest.version // empty')
|
|
269
|
+
[ -n "$VERSION" ] || VERSION="$PREFIX"
|
|
270
|
+
bash scripts/report-test-cycle.sh complete \
|
|
271
|
+
--project-slug "$PROJECT_SLUG" --release "$VERSION" \
|
|
272
|
+
--sdlc-stage 5 --environment production --cycle-kind smoke \
|
|
273
|
+
--provider github_actions --external-run-id "$CI_RUN" \
|
|
274
|
+
--external-run-attempt "${{ github.run_attempt }}" --external-job-id "production-smoke" \
|
|
275
|
+
--idempotency-key "github:${{ github.repository }}:post-deploy-prod.smoke:${CI_RUN}:${{ github.run_attempt }}:5:${VERSION}" \
|
|
276
|
+
--commit-sha "$GIT_SHA" --branch main \
|
|
277
|
+
--workflow-name "Post-Deploy Production" \
|
|
278
|
+
--workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
|
|
279
|
+
--outcome "$OUTCOME" --outcome-reason "production smoke: ${{ steps.production_smoke.outcome }}"
|
|
280
|
+
bash scripts/report-release-check.sh \
|
|
281
|
+
--project-slug "$PROJECT_SLUG" --release "$VERSION" \
|
|
282
|
+
--check-key "production-smoke:${CI_RUN}:${{ github.run_attempt }}" \
|
|
283
|
+
--label "Production Smoke" --provider github_actions --status "$CHECK_STATUS" \
|
|
284
|
+
--external-run-id "$CI_RUN" \
|
|
285
|
+
--external-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
|
|
286
|
+
--commit-sha "$GIT_SHA" --branch main \
|
|
287
|
+
--details-json '{"executionSource":"steps.production_smoke.outcome"}'
|
|
288
|
+
done
|
|
289
|
+
|
|
166
290
|
- name: File incident on smoke failure
|
|
167
|
-
if: failure
|
|
291
|
+
if: steps.production_smoke.outcome == 'failure'
|
|
168
292
|
env:
|
|
169
293
|
# GitHub issue/label mutations use the workflow token. DevAudit
|
|
170
294
|
# user tokens are portal PATs, not guaranteed GitHub PATs (#305).
|
|
@@ -241,9 +365,11 @@ jobs:
|
|
|
241
365
|
fi
|
|
242
366
|
|
|
243
367
|
- name: Promote in-scope releases (evidence + status)
|
|
368
|
+
if: steps.production_smoke.outcome == 'success'
|
|
244
369
|
run: |
|
|
245
|
-
chmod +x scripts/upload-evidence.sh scripts/report-test-cycle.sh 2>/dev/null || true
|
|
370
|
+
chmod +x scripts/upload-evidence.sh scripts/report-test-cycle.sh scripts/report-release-check.sh 2>/dev/null || true
|
|
246
371
|
PROMOTED=0
|
|
372
|
+
EVIDENCE_FAILURES=0
|
|
247
373
|
for PREFIX in ${REQS}; do
|
|
248
374
|
echo "=== Promoting ${PREFIX} ==="
|
|
249
375
|
RESP=$(curl -s -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
|
|
@@ -263,6 +389,7 @@ jobs:
|
|
|
263
389
|
--provider github_actions \
|
|
264
390
|
--external-run-id "${CI_RUN}" \
|
|
265
391
|
--external-run-attempt "${{ github.run_attempt }}" \
|
|
392
|
+
--external-job-id "production-smoke" \
|
|
266
393
|
--idempotency-key "github:${{ github.repository }}:post-deploy-prod.smoke:${CI_RUN}:${{ github.run_attempt }}:5:${VERSION}" \
|
|
267
394
|
--commit-sha "${GIT_SHA}" \
|
|
268
395
|
--branch main \
|
|
@@ -296,31 +423,28 @@ jobs:
|
|
|
296
423
|
"${PROJECT_SLUG}" "${VERSION}" release_ticket "$TICKET" \
|
|
297
424
|
--release "${VERSION}" --create-release-if-missing --environment production \
|
|
298
425
|
--category release_artifact --sdlc-stage 5 --git-sha "${GIT_SHA}" --ci-run-id "${CI_RUN}" --branch main \
|
|
299
|
-
|| echo "Warning: ticket upload failed for ${VERSION}"
|
|
426
|
+
|| { echo "Warning: ticket upload failed for ${VERSION}"; REQ_FAILURES=$((REQ_FAILURES + 1)); }
|
|
300
427
|
else
|
|
301
428
|
echo "No RELEASE-TICKET-${VERSION}.md found — skipping ticket (date-versioned or archived)."
|
|
302
429
|
fi
|
|
303
430
|
if [ "$REQ_FAILURES" -gt 0 ]; then
|
|
304
|
-
|
|
431
|
+
EVIDENCE_STATUS=failed
|
|
432
|
+
EVIDENCE_FAILURES=$((EVIDENCE_FAILURES + 1))
|
|
305
433
|
else
|
|
306
|
-
|
|
434
|
+
EVIDENCE_STATUS=successful
|
|
435
|
+
fi
|
|
436
|
+
bash scripts/report-release-check.sh \
|
|
437
|
+
--project-slug "$PROJECT_SLUG" --release "$VERSION" \
|
|
438
|
+
--check-key "production-evidence:${CI_RUN}:${{ github.run_attempt }}" \
|
|
439
|
+
--label "Production Evidence Completeness" --provider devaudit_installer \
|
|
440
|
+
--status "$EVIDENCE_STATUS" --external-run-id "$CI_RUN" \
|
|
441
|
+
--external-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
|
|
442
|
+
--commit-sha "$GIT_SHA" --branch main \
|
|
443
|
+
--details-json "{\"uploadFailures\":${REQ_FAILURES}}"
|
|
444
|
+
if [ "$REQ_FAILURES" -gt 0 ]; then
|
|
445
|
+
echo "::error::Skipping status promotion for ${VERSION}: production evidence is incomplete"
|
|
446
|
+
continue
|
|
307
447
|
fi
|
|
308
|
-
bash scripts/report-test-cycle.sh complete \
|
|
309
|
-
--project-slug "${PROJECT_SLUG}" \
|
|
310
|
-
--release "${VERSION}" \
|
|
311
|
-
--sdlc-stage 5 \
|
|
312
|
-
--environment production \
|
|
313
|
-
--cycle-kind smoke \
|
|
314
|
-
--provider github_actions \
|
|
315
|
-
--external-run-id "${CI_RUN}" \
|
|
316
|
-
--external-run-attempt "${{ github.run_attempt }}" \
|
|
317
|
-
--idempotency-key "github:${{ github.repository }}:post-deploy-prod.smoke:${CI_RUN}:${{ github.run_attempt }}:5:${VERSION}" \
|
|
318
|
-
--commit-sha "${GIT_SHA}" \
|
|
319
|
-
--branch main \
|
|
320
|
-
--workflow-name "Post-Deploy Production" \
|
|
321
|
-
--workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
|
|
322
|
-
--started-at "${cycle_started_at:-}" \
|
|
323
|
-
--outcome "${REQ_OUTCOME}"
|
|
324
448
|
# Advance status (idempotent — re-PATCHing an already-promoted release is a no-op).
|
|
325
449
|
if [ -n "$RELEASE_ID" ]; then
|
|
326
450
|
curl -s -o /dev/null -w " ${VERSION} status patch: HTTP %{http_code}\n" \
|
|
@@ -334,6 +458,10 @@ jobs:
|
|
|
334
458
|
echo "::warning::No release_id resolved for ${PREFIX} — skipping status patch"
|
|
335
459
|
fi
|
|
336
460
|
done
|
|
461
|
+
if [ "$EVIDENCE_FAILURES" -gt 0 ]; then
|
|
462
|
+
echo "::error::${EVIDENCE_FAILURES} release(s) have incomplete production evidence"
|
|
463
|
+
exit 1
|
|
464
|
+
fi
|
|
337
465
|
echo "Promoted ${PROMOTED} release(s) to ${TERMINAL_STATUS}."
|
|
338
466
|
if [ "${TERMINAL_STATUS}" = "prod_review" ]; then
|
|
339
467
|
echo "Next: a human in the portal clicks 'Approve Production' then 'Mark as Released' for each."
|
package/sdlc/package.json
CHANGED