@metasession.co/devaudit-cli 0.3.11 → 0.3.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 +94 -6
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/scripts/upload-evidence.sh +55 -1
- package/sdlc/ai-rules/SDLC_RULES.md +27 -7
- package/sdlc/files/_common/0-project-setup.md +13 -7
- package/sdlc/files/_common/Periodic_Security_Review_Schedule.md +5 -5
- package/sdlc/files/_common/README_TEMPLATE.md +8 -8
- package/sdlc/files/_common/Test_Architecture.md +15 -15
- package/sdlc/files/_common/Test_Plan_TEMPLATE.md +13 -13
- package/sdlc/files/_common/Test_Policy.md +2 -2
- package/sdlc/files/_common/Test_Strategy.md +10 -10
- package/sdlc/files/_common/governance/ai-disclosure.md.template +3 -3
- package/sdlc/files/_common/governance/dpia.md.template +3 -3
- package/sdlc/files/_common/governance/incident-report.md.template +3 -3
- package/sdlc/files/_common/governance/nil-incident-report.md.template +1 -1
- package/sdlc/files/_common/governance/periodic-review.md.template +3 -3
- package/sdlc/files/_common/governance/risk-register.md.template +1 -1
- package/sdlc/files/_common/governance/ropa.md.template +2 -2
- package/sdlc/files/_common/joining-an-existing-project.md +4 -4
- package/sdlc/files/_common/scripts/check-host-deployment.sh +107 -0
- package/sdlc/files/_common/scripts/check-host-deployment.test.sh +119 -0
- package/sdlc/files/_common/scripts/check-release-pr-scope.sh +95 -0
- package/sdlc/files/_common/scripts/check-release-pr-scope.test.sh +137 -0
- package/sdlc/files/_common/scripts/close-out-release.sh +175 -54
- package/sdlc/files/_common/scripts/close-out-release.test.sh +90 -0
- package/sdlc/files/_common/scripts/extract-release-metadata.sh +65 -0
- package/sdlc/files/_common/scripts/extract-release-metadata.test.sh +38 -0
- package/sdlc/files/_common/scripts/generate-bundled-changes.sh +307 -58
- package/sdlc/files/_common/scripts/generate-bundled-changes.test.sh +128 -78
- package/sdlc/files/_common/scripts/generate-housekeeping-release-ticket.sh +18 -9
- package/sdlc/files/_common/scripts/generate-housekeeping-release-ticket.test.sh +66 -0
- package/sdlc/files/_common/scripts/generate-security-summary.sh +14 -5
- package/sdlc/files/_common/scripts/generate-security-summary.test.sh +57 -0
- package/sdlc/files/_common/scripts/prepare-release-pr.sh +44 -4
- package/sdlc/files/_common/scripts/render-test-cycles.sh +227 -0
- package/sdlc/files/_common/scripts/render-test-cycles.test.sh +107 -0
- package/sdlc/files/_common/scripts/report-test-cycle.sh +344 -0
- package/sdlc/files/_common/scripts/submit-bundle-manifest.sh +100 -0
- package/sdlc/files/_common/scripts/submit-bundle-manifest.test.sh +138 -0
- package/sdlc/files/_common/scripts/upload-evidence.sh +55 -1
- package/sdlc/files/_common/scripts/upload-evidence.test.sh +119 -0
- package/sdlc/files/_common/scripts/validate-compliance-artifacts.sh +169 -2
- package/sdlc/files/_common/scripts/validate-compliance-artifacts.test.sh +169 -0
- package/sdlc/files/_common/scripts/validate-test-summary.test.sh +4 -4
- package/sdlc/files/_common/skills/adr-author/SKILL.md +2 -2
- package/sdlc/files/_common/skills/e2e-test-engineer/SKILL.md +2 -2
- package/sdlc/files/_common/skills/e2e-test-engineer/references/bootstrap.md +5 -5
- package/sdlc/files/_common/skills/governance-doc-author/references/incident-classification.md +1 -1
- package/sdlc/files/_common/skills/requirements-aligner/SKILL.md +4 -4
- package/sdlc/files/_common/skills/sdlc-implementer/SKILL.md +57 -3
- package/sdlc/files/_common/skills/sdlc-implementer/references/change-request-loop.md +1 -1
- package/sdlc/files/_common/skills/sdlc-implementer/references/compliance-constraints.md +7 -14
- package/sdlc/files/ci/check-release-approval.yml.template +18 -28
- package/sdlc/files/ci/ci.yml.template +95 -35
- package/sdlc/files/ci/close-out-release.yml.template +7 -4
- package/sdlc/files/ci/compliance-evidence.yml.template +234 -49
- package/sdlc/files/ci/feature-e2e.yml.template +84 -1
- package/sdlc/files/ci/post-deploy-prod.yml.template +59 -4
- package/sdlc/files/ci/python/ci.yml.template +60 -12
- package/sdlc/files/ci/quality-gates-provenance.yml.template +123 -28
- package/sdlc/package.json +1 -1
- package/sdlc/src/bin/devaudit-sdlc.js +44 -2
- package/sdlc/src/blueprints/1-plan-requirement.raw.md +6 -1
- package/sdlc/src/blueprints/2-implement-and-test.raw.md +1 -1
- package/sdlc/src/blueprints/3-compile-evidence.raw.md +102 -20
- package/sdlc/src/blueprints/4-submit-for-review.raw.md +3 -3
- package/sdlc/src/blueprints/5-deploy-main.raw.md +2 -2
package/dist/index.js
CHANGED
|
@@ -56,7 +56,7 @@ function emitJsonResult(payload) {
|
|
|
56
56
|
|
|
57
57
|
// package.json
|
|
58
58
|
var package_default = {
|
|
59
|
-
version: "0.3.
|
|
59
|
+
version: "0.3.13"};
|
|
60
60
|
|
|
61
61
|
// src/lib/version.ts
|
|
62
62
|
var CLI_VERSION = package_default.version;
|
|
@@ -595,6 +595,23 @@ async function runStatus(options) {
|
|
|
595
595
|
log.warn(`${missingFiles.length} framework file(s) missing. Re-sync with \`devaudit update <version> <path>\` to refresh.`);
|
|
596
596
|
}
|
|
597
597
|
}
|
|
598
|
+
|
|
599
|
+
// src/lib/release-lineage-contract.ts
|
|
600
|
+
function renderEvidenceLineageFields(input, capabilities) {
|
|
601
|
+
if (input.testCycleRecordId && input.evidenceScope !== "cycle") {
|
|
602
|
+
throw new Error("testCycleRecordId requires cycle evidenceScope");
|
|
603
|
+
}
|
|
604
|
+
if (!capabilities.supportsFirstClassCycleApi) {
|
|
605
|
+
return input.testCycleId ? { testCycleId: input.testCycleId } : {};
|
|
606
|
+
}
|
|
607
|
+
return {
|
|
608
|
+
...input.evidenceScope ? { evidenceScope: input.evidenceScope } : {},
|
|
609
|
+
...input.testCycleRecordId ? { testCycleRecordId: input.testCycleRecordId } : {},
|
|
610
|
+
...input.testCycleId ? { testCycleId: input.testCycleId } : {}
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// src/lib/ci-upload.ts
|
|
598
615
|
var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
|
|
599
616
|
var DEFAULT_MAX_ATTEMPTS = 5;
|
|
600
617
|
var DEFAULT_UPLOAD_MAX_TIME_SECONDS = 120;
|
|
@@ -685,12 +702,24 @@ async function createUploadSource(file) {
|
|
|
685
702
|
}
|
|
686
703
|
}
|
|
687
704
|
function buildUploadForm(file, source, opts) {
|
|
705
|
+
const metadata = {
|
|
706
|
+
...opts.metadata ?? {},
|
|
707
|
+
...opts.commitTimestamp ? { commitTimestamp: opts.commitTimestamp } : {}
|
|
708
|
+
};
|
|
709
|
+
const lineageFields = renderEvidenceLineageFields(
|
|
710
|
+
{
|
|
711
|
+
evidenceScope: opts.evidenceScope,
|
|
712
|
+
testCycleRecordId: opts.testCycleRecordId,
|
|
713
|
+
testCycleId: opts.testCycleId
|
|
714
|
+
},
|
|
715
|
+
opts.lineageCapabilities ?? { supportsFirstClassCycleApi: true }
|
|
716
|
+
);
|
|
688
717
|
const form = new FormData();
|
|
689
718
|
form.set("file", source.blob, basename(file));
|
|
690
719
|
form.set("projectSlug", opts.projectSlug);
|
|
691
720
|
form.set("requirementId", opts.requirementId);
|
|
692
721
|
form.set("evidenceType", opts.evidenceType);
|
|
693
|
-
form.set("metadata", JSON.stringify(
|
|
722
|
+
form.set("metadata", JSON.stringify(metadata));
|
|
694
723
|
if (opts.releaseVersion) form.set("releaseVersion", opts.releaseVersion);
|
|
695
724
|
if (opts.createReleaseIfMissing) form.set("createReleaseIfMissing", "true");
|
|
696
725
|
if (opts.environment) form.set("environment", opts.environment);
|
|
@@ -701,7 +730,11 @@ function buildUploadForm(file, source, opts) {
|
|
|
701
730
|
if (opts.changeType) form.set("changeType", opts.changeType);
|
|
702
731
|
if (opts.gateStatus) form.set("gateStatus", opts.gateStatus);
|
|
703
732
|
if (opts.sdlcStage) form.set("sdlcStage", opts.sdlcStage);
|
|
704
|
-
if (
|
|
733
|
+
if (lineageFields.testCycleId) form.set("testCycleId", lineageFields.testCycleId);
|
|
734
|
+
if (lineageFields.evidenceScope) form.set("evidenceScope", lineageFields.evidenceScope);
|
|
735
|
+
if (lineageFields.testCycleRecordId) form.set("testCycleRecordId", lineageFields.testCycleRecordId);
|
|
736
|
+
if (opts.sentinelContent) form.set("sentinelContent", opts.sentinelContent);
|
|
737
|
+
if (opts.commitTimestamp) form.set("commitTimestamp", opts.commitTimestamp);
|
|
705
738
|
return form;
|
|
706
739
|
}
|
|
707
740
|
function uploadFailureMessage(err, timeoutSeconds) {
|
|
@@ -786,7 +819,18 @@ async function uploadPresigned(file, source, opts) {
|
|
|
786
819
|
const maxAttemptsPresigned = DEFAULT_PRESIGNED_MAX_ATTEMPTS;
|
|
787
820
|
const timeoutSeconds = uploadMaxTimeSeconds();
|
|
788
821
|
const presignedTimeoutSeconds = DEFAULT_PRESIGNED_UPLOAD_MAX_TIME_SECONDS;
|
|
789
|
-
const metadata =
|
|
822
|
+
const metadata = {
|
|
823
|
+
...opts.metadata ?? {},
|
|
824
|
+
...opts.commitTimestamp ? { commitTimestamp: opts.commitTimestamp } : {}
|
|
825
|
+
};
|
|
826
|
+
const lineageFields = renderEvidenceLineageFields(
|
|
827
|
+
{
|
|
828
|
+
evidenceScope: opts.evidenceScope,
|
|
829
|
+
testCycleRecordId: opts.testCycleRecordId,
|
|
830
|
+
testCycleId: opts.testCycleId
|
|
831
|
+
},
|
|
832
|
+
opts.lineageCapabilities ?? { supportsFirstClassCycleApi: true }
|
|
833
|
+
);
|
|
790
834
|
let uploadUrl = "";
|
|
791
835
|
let evidenceId = "";
|
|
792
836
|
let attempt = 1;
|
|
@@ -817,8 +861,13 @@ async function uploadPresigned(file, source, opts) {
|
|
|
817
861
|
...opts.evidenceCategory ? { evidenceCategory: opts.evidenceCategory } : {},
|
|
818
862
|
...opts.releaseTitle ? { releaseTitle: opts.releaseTitle } : {},
|
|
819
863
|
...opts.releaseSummary ? { releaseSummary: opts.releaseSummary } : {},
|
|
864
|
+
...opts.changeType ? { changeType: opts.changeType } : {},
|
|
820
865
|
...opts.sdlcStage ? { sdlcStage: opts.sdlcStage } : {},
|
|
821
|
-
...
|
|
866
|
+
...lineageFields.testCycleId ? { testCycleId: lineageFields.testCycleId } : {},
|
|
867
|
+
...lineageFields.evidenceScope ? { evidenceScope: lineageFields.evidenceScope } : {},
|
|
868
|
+
...lineageFields.testCycleRecordId ? { testCycleRecordId: lineageFields.testCycleRecordId } : {},
|
|
869
|
+
...opts.sentinelContent ? { sentinelContent: opts.sentinelContent } : {},
|
|
870
|
+
...opts.commitTimestamp ? { commitTimestamp: opts.commitTimestamp } : {}
|
|
822
871
|
}),
|
|
823
872
|
signal: controller.signal
|
|
824
873
|
});
|
|
@@ -964,6 +1013,7 @@ async function uploadEvidence(opts) {
|
|
|
964
1013
|
|
|
965
1014
|
// src/commands/push.ts
|
|
966
1015
|
var DEFAULT_BASE_URL3 = "https://devaudit.metasession.co";
|
|
1016
|
+
var TRACKED_CHANGE_TYPES = /* @__PURE__ */ new Set(["feat", "fix", "refactor", "perf", "compliance", "revert"]);
|
|
967
1017
|
function buildMetadata(options) {
|
|
968
1018
|
const metadata = {};
|
|
969
1019
|
if (options.gitSha) metadata["gitSha"] = options.gitSha;
|
|
@@ -975,6 +1025,28 @@ function buildMetadata(options) {
|
|
|
975
1025
|
}
|
|
976
1026
|
return metadata;
|
|
977
1027
|
}
|
|
1028
|
+
async function resolveSentinelContext(options) {
|
|
1029
|
+
if (!options.changeType || !TRACKED_CHANGE_TYPES.has(options.changeType)) {
|
|
1030
|
+
return {};
|
|
1031
|
+
}
|
|
1032
|
+
const sentinelPath = join(process.cwd(), ".sdlc-implementer-invoked");
|
|
1033
|
+
let sentinelContent;
|
|
1034
|
+
try {
|
|
1035
|
+
const raw = await promises.readFile(sentinelPath, "utf8");
|
|
1036
|
+
if (raw.trim()) sentinelContent = raw;
|
|
1037
|
+
} catch {
|
|
1038
|
+
sentinelContent = void 0;
|
|
1039
|
+
}
|
|
1040
|
+
let commitTimestamp;
|
|
1041
|
+
try {
|
|
1042
|
+
const target = options.gitSha?.trim() ? options.gitSha.trim() : "HEAD";
|
|
1043
|
+
const { stdout } = await execa("git", ["show", "-s", "--format=%cI", target], { reject: false });
|
|
1044
|
+
if (stdout.trim()) commitTimestamp = stdout.trim();
|
|
1045
|
+
} catch {
|
|
1046
|
+
commitTimestamp = void 0;
|
|
1047
|
+
}
|
|
1048
|
+
return { sentinelContent, commitTimestamp };
|
|
1049
|
+
}
|
|
978
1050
|
function validateOptions(options) {
|
|
979
1051
|
if (options.environment && !options.release) {
|
|
980
1052
|
return "--environment requires --release (evidence without a release is orphaned)";
|
|
@@ -985,6 +1057,12 @@ function validateOptions(options) {
|
|
|
985
1057
|
for (const kv of options.metaKeys ?? []) {
|
|
986
1058
|
if (!kv.includes("=")) return `--meta-key requires key=value (got: ${kv})`;
|
|
987
1059
|
}
|
|
1060
|
+
if (options.evidenceScope !== void 0 && !["release", "stage", "cycle", "approval"].includes(options.evidenceScope)) {
|
|
1061
|
+
return "--evidence-scope must be one of: release, stage, cycle, approval";
|
|
1062
|
+
}
|
|
1063
|
+
if (options.testCycleRecordId && options.evidenceScope !== "cycle") {
|
|
1064
|
+
return "--test-cycle-record-id requires --evidence-scope cycle";
|
|
1065
|
+
}
|
|
988
1066
|
return null;
|
|
989
1067
|
}
|
|
990
1068
|
async function runDryRun(options, baseUrl) {
|
|
@@ -1045,6 +1123,8 @@ async function runPush(options) {
|
|
|
1045
1123
|
await runHook(plugins, "beforePush", ctx);
|
|
1046
1124
|
}
|
|
1047
1125
|
const metadata = buildMetadata(options);
|
|
1126
|
+
const { sentinelContent, commitTimestamp } = await resolveSentinelContext(options);
|
|
1127
|
+
if (commitTimestamp) metadata["commitTimestamp"] = commitTimestamp;
|
|
1048
1128
|
const results = await uploadEvidence({
|
|
1049
1129
|
projectSlug: options.projectSlug,
|
|
1050
1130
|
requirementId: options.requirementId,
|
|
@@ -1063,6 +1143,10 @@ async function runPush(options) {
|
|
|
1063
1143
|
...options.gateStatus !== void 0 ? { gateStatus: options.gateStatus } : {},
|
|
1064
1144
|
...options.sdlcStage !== void 0 ? { sdlcStage: options.sdlcStage } : {},
|
|
1065
1145
|
...options.testCycleId !== void 0 ? { testCycleId: options.testCycleId } : {},
|
|
1146
|
+
...options.evidenceScope !== void 0 ? { evidenceScope: options.evidenceScope } : {},
|
|
1147
|
+
...options.testCycleRecordId !== void 0 ? { testCycleRecordId: options.testCycleRecordId } : {},
|
|
1148
|
+
...sentinelContent !== void 0 ? { sentinelContent } : {},
|
|
1149
|
+
...commitTimestamp !== void 0 ? { commitTimestamp } : {},
|
|
1066
1150
|
metadata
|
|
1067
1151
|
});
|
|
1068
1152
|
let okCount = 0;
|
|
@@ -2447,6 +2531,8 @@ async function syncCiTemplates(ctx) {
|
|
|
2447
2531
|
const tokens = {
|
|
2448
2532
|
PROJECT_SLUG: cfg.project_slug,
|
|
2449
2533
|
PRODUCTION_URL_SECRET: cfg.production_url_secret,
|
|
2534
|
+
INTEGRATION_BRANCH: cfg.integration_branch ?? "develop",
|
|
2535
|
+
RELEASE_BRANCH: cfg.release_branch ?? "main",
|
|
2450
2536
|
NODE_VERSION: String(cfg.node_version ?? ""),
|
|
2451
2537
|
PYTHON_VERSION: String(cfg.python_version ?? ""),
|
|
2452
2538
|
WORKING_DIRECTORY: workingDirectory || ".",
|
|
@@ -3388,7 +3474,7 @@ async function main(argv) {
|
|
|
3388
3474
|
...globals.dryRun !== void 0 ? { dryRun: Boolean(globals.dryRun) } : {}
|
|
3389
3475
|
});
|
|
3390
3476
|
});
|
|
3391
|
-
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>", "git branch \u2014 sent as releaseBranch + metadata.branch").option("--release-title <text>", "human title for the release row (releaseTitle; portal no-clobbers)").option("--release-summary <text>", "reviewer-facing short description (releaseSummary; portal no-clobbers)").option("--change-type <type>", "conventional-commit prefix for the release row (changeType)").option("--gate-status <status>", "passed | failed | skipped (gateStatus)").option("--sdlc-stage <stage>", "SDLC stage 1-5 (sdlcStage)").option("--test-cycle <id>", "test cycle identifier (typically the CI run ID)").option(
|
|
3477
|
+
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>", "git branch \u2014 sent as releaseBranch + metadata.branch").option("--release-title <text>", "human title for the release row (releaseTitle; portal no-clobbers)").option("--release-summary <text>", "reviewer-facing short description (releaseSummary; portal no-clobbers)").option("--change-type <type>", "conventional-commit prefix for the release row (changeType)").option("--gate-status <status>", "passed | failed | skipped (gateStatus)").option("--sdlc-stage <stage>", "SDLC stage 1-5 (sdlcStage)").option("--test-cycle <id>", "test cycle identifier (typically the CI run ID)").option("--evidence-scope <scope>", "release | stage | cycle | approval (evidenceScope)").option("--test-cycle-record-id <id>", "first-class portal cycle UUID (requires --evidence-scope cycle)").option(
|
|
3392
3478
|
"--meta-key <pair>",
|
|
3393
3479
|
"repeatable key=value merged into the metadata JSON",
|
|
3394
3480
|
(val, acc) => [...acc, val],
|
|
@@ -3414,6 +3500,8 @@ async function main(argv) {
|
|
|
3414
3500
|
...opts.gateStatus !== void 0 ? { gateStatus: opts.gateStatus } : {},
|
|
3415
3501
|
...opts.sdlcStage !== void 0 ? { sdlcStage: opts.sdlcStage } : {},
|
|
3416
3502
|
...opts.testCycle !== void 0 ? { testCycleId: opts.testCycle } : {},
|
|
3503
|
+
...opts.evidenceScope !== void 0 ? { evidenceScope: opts.evidenceScope } : {},
|
|
3504
|
+
...opts.testCycleRecordId !== void 0 ? { testCycleRecordId: opts.testCycleRecordId } : {},
|
|
3417
3505
|
...opts.metaKey !== void 0 && opts.metaKey.length > 0 ? { metaKeys: opts.metaKey } : {},
|
|
3418
3506
|
...opts.baseUrl !== void 0 ? { baseUrl: opts.baseUrl } : {},
|
|
3419
3507
|
...opts.apiKey !== void 0 ? { apiKey: opts.apiKey } : {},
|