@metasession.co/devaudit-cli 0.1.12 → 0.1.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 +72 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/sdlc/files/_common/5-deploy-main.md +9 -0
- package/sdlc/files/_common/implementing-an-sdlc-issue.md +12 -5
- package/sdlc/files/_common/scripts/close-out-release.sh +143 -0
- package/sdlc/files/ci/close-out-release.yml.template +96 -0
package/dist/index.js
CHANGED
|
@@ -54,7 +54,7 @@ function emitJsonResult(payload) {
|
|
|
54
54
|
|
|
55
55
|
// package.json
|
|
56
56
|
var package_default = {
|
|
57
|
-
version: "0.1.
|
|
57
|
+
version: "0.1.14"};
|
|
58
58
|
|
|
59
59
|
// src/lib/version.ts
|
|
60
60
|
var CLI_VERSION = package_default.version;
|
|
@@ -235,6 +235,57 @@ async function checkNodeVersion() {
|
|
|
235
235
|
const ok2 = major >= 22;
|
|
236
236
|
return { name: "node", ok: ok2, detail: `v${version} (require >=22)` };
|
|
237
237
|
}
|
|
238
|
+
async function checkReleaseCloseoutDrift() {
|
|
239
|
+
const name = "releases";
|
|
240
|
+
let cfg;
|
|
241
|
+
try {
|
|
242
|
+
cfg = JSON.parse(await promises.readFile("sdlc-config.json", "utf-8"));
|
|
243
|
+
} catch {
|
|
244
|
+
return { name, ok: true, detail: "skipped (not a consumer project)" };
|
|
245
|
+
}
|
|
246
|
+
let entries;
|
|
247
|
+
try {
|
|
248
|
+
entries = await promises.readdir("compliance/pending-releases");
|
|
249
|
+
} catch {
|
|
250
|
+
return { name, ok: true, detail: "no pending-releases/" };
|
|
251
|
+
}
|
|
252
|
+
const reqs = entries.filter((f) => /^RELEASE-TICKET-REQ-\d+\.md$/.test(f)).map((f) => f.replace(/^RELEASE-TICKET-/, "").replace(/\.md$/, ""));
|
|
253
|
+
if (reqs.length === 0) return { name, ok: true, detail: "no pending release tickets" };
|
|
254
|
+
const slug = cfg.devaudit?.project_slug ?? cfg.project_slug;
|
|
255
|
+
const base = (cfg.devaudit?.base_url ?? "").replace(/\/$/, "");
|
|
256
|
+
const apiKey = process.env["DEVAUDIT_API_KEY"];
|
|
257
|
+
if (!slug || !base || !apiKey) {
|
|
258
|
+
return {
|
|
259
|
+
name,
|
|
260
|
+
ok: true,
|
|
261
|
+
detail: `${reqs.length} pending ticket(s); portal drift check skipped (set DEVAUDIT_API_KEY + devaudit.base_url)`
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
const drifted = [];
|
|
265
|
+
for (const req of reqs) {
|
|
266
|
+
try {
|
|
267
|
+
const ctrl = new AbortController();
|
|
268
|
+
const timer = setTimeout(() => ctrl.abort(), 1e4);
|
|
269
|
+
const res = await fetch(
|
|
270
|
+
`${base}/api/ci/releases/resolve?projectSlug=${encodeURIComponent(slug)}&versionPrefix=${encodeURIComponent(req)}`,
|
|
271
|
+
{ headers: { Authorization: `Bearer ${apiKey}` }, signal: ctrl.signal }
|
|
272
|
+
);
|
|
273
|
+
clearTimeout(timer);
|
|
274
|
+
if (!res.ok) continue;
|
|
275
|
+
const body = await res.json();
|
|
276
|
+
if (body.latest?.status === "released") drifted.push(req);
|
|
277
|
+
} catch {
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (drifted.length > 0) {
|
|
281
|
+
return {
|
|
282
|
+
name,
|
|
283
|
+
ok: false,
|
|
284
|
+
detail: `released on the portal but still in pending-releases/: ${drifted.join(", ")} \u2014 run ./scripts/close-out-release.sh <REQ>`
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
return { name, ok: true, detail: `${reqs.length} pending ticket(s); none released on the portal` };
|
|
288
|
+
}
|
|
238
289
|
async function runDoctor(options = {}) {
|
|
239
290
|
const log = logger();
|
|
240
291
|
log.info("Running devaudit doctor \u2014 checking required tools...\n");
|
|
@@ -251,7 +302,13 @@ async function runDoctor(options = {}) {
|
|
|
251
302
|
if (!check.ok) allOk = false;
|
|
252
303
|
log.log(` ${marker} ${check.name.padEnd(8)} ${check.detail}`);
|
|
253
304
|
}
|
|
305
|
+
const closeout = await checkReleaseCloseoutDrift();
|
|
306
|
+
const closeoutMarker = closeout.ok ? "\u2713" : "\u26A0";
|
|
307
|
+
log.log(` ${closeoutMarker} ${closeout.name.padEnd(8)} ${closeout.detail}`);
|
|
254
308
|
log.log("");
|
|
309
|
+
if (!closeout.ok) {
|
|
310
|
+
log.warn("Release close-out drift detected \u2014 see above. (Does not affect the tool check.)");
|
|
311
|
+
}
|
|
255
312
|
const plugins = options.plugins ?? (await discoverPlugins()).loaded;
|
|
256
313
|
if (plugins.length > 0) {
|
|
257
314
|
const ctx = await buildPluginContext({ projectPath: resolve(process.cwd()) });
|
|
@@ -1741,7 +1798,8 @@ var CI_TEMPLATES = [
|
|
|
1741
1798
|
"compliance-validation.yml.template",
|
|
1742
1799
|
"check-release-approval.yml.template",
|
|
1743
1800
|
"post-deploy-prod.yml.template",
|
|
1744
|
-
"compliance-evidence.yml.template"
|
|
1801
|
+
"compliance-evidence.yml.template",
|
|
1802
|
+
"close-out-release.yml.template"
|
|
1745
1803
|
];
|
|
1746
1804
|
var OLD_WORKFLOWS_TO_REMOVE = ["test-on-pr.yml", "check-uat-approval.yml"];
|
|
1747
1805
|
function indentEnvBlock(env, indent) {
|
|
@@ -2383,8 +2441,18 @@ async function main(argv) {
|
|
|
2383
2441
|
...globals.yes !== void 0 ? { yes: Boolean(globals.yes) } : {}
|
|
2384
2442
|
});
|
|
2385
2443
|
});
|
|
2386
|
-
program.command("update
|
|
2387
|
-
|
|
2444
|
+
program.command("update [version] [paths...]").description(
|
|
2445
|
+
"Sync framework templates into existing consumer(s). Both args are optional: paths default to the current directory, and version is a cosmetic label (defaults to the running CLI version). So a bare `devaudit update` syncs the current project."
|
|
2446
|
+
).action(async (version, paths2) => {
|
|
2447
|
+
let resolvedVersion = version;
|
|
2448
|
+
let resolvedPaths = paths2 ?? [];
|
|
2449
|
+
const looksLikeVersion = (s) => /^v?\d+(\.\d+)/.test(s);
|
|
2450
|
+
if (resolvedVersion && resolvedPaths.length === 0 && !looksLikeVersion(resolvedVersion)) {
|
|
2451
|
+
resolvedPaths = [resolvedVersion];
|
|
2452
|
+
resolvedVersion = void 0;
|
|
2453
|
+
}
|
|
2454
|
+
if (resolvedPaths.length === 0) resolvedPaths = ["."];
|
|
2455
|
+
await runUpdate({ version: resolvedVersion ?? CLI_VERSION, paths: resolvedPaths });
|
|
2388
2456
|
});
|
|
2389
2457
|
program.command("push <project-slug> <requirement-id> <evidence-type> <file>").description("Upload evidence file(s) to DevAudit (port of scripts/upload-evidence.sh)").option("--release <version>", "release version (e.g. v1.0.0)").option("--create-release-if-missing", "auto-create the release as 'draft' if absent").option("--environment <env>", "uat | production").option("--category <cat>", "ci_pipeline | local_dev | planning | test_report | security_scan | release_artifact").option("--git-sha <sha>", "attached to metadata.gitSha").option("--ci-run-id <id>", "attached to metadata.ciRunId").option("--branch <name>", "attached to metadata.branch").option("--base-url <url>", "override portal URL (defaults to DEVAUDIT_BASE_URL env or production)").option("--api-key <key>", "override DEVAUDIT_API_KEY env var").action(
|
|
2390
2458
|
async (projectSlug, requirementId, evidenceType, file, opts, cmd) => {
|