@h9-foundry/agentforge-cli 0.9.0 → 0.11.0
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/.tsbuildinfo +1 -1
- package/dist/bin.js +1 -1
- package/dist/bin.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +539 -19
- package/dist/index.js.map +1 -1
- package/dist/internal/builtin-agents.d.ts.map +1 -1
- package/dist/internal/builtin-agents.js +1794 -72
- package/dist/internal/builtin-agents.js.map +1 -1
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { buildAuditBundle, createAuditEntry, renderAuditBundleMarkdown } from "@
|
|
|
6
6
|
import { createWorkflowState, findWorkspaceRoot } from "@h9-foundry/agentforge-context-engine";
|
|
7
7
|
import { createPolicyEngine, loadPolicyDocument, resolvePolicy } from "@h9-foundry/agentforge-policy-engine";
|
|
8
8
|
import { runWorkflow } from "@h9-foundry/agentforge-runtime";
|
|
9
|
-
import { agentforgeConfigSchema, auditBundleSchema, benchmarkArtifactSchema, designArtifactSchema, designRequestSchema, evalArtifactSchema, evalFixtureCorpusSchema, implementationRequestSchema, incidentRequestSchema, maintenanceRequestSchema, planningArtifactSchema, planningRequestSchema, qaRequestSchema, releaseRequestSchema, schemaFixtures, securityRequestSchema, workflowDefinitionSchema } from "@h9-foundry/agentforge-schemas";
|
|
9
|
+
import { agentforgeConfigSchema, auditBundleSchema, benchmarkArtifactSchema, designArtifactSchema, designRequestSchema, deploymentRequestSchema, evalArtifactSchema, evalFixtureCorpusSchema, implementationRequestSchema, incidentRequestSchema, maintenanceRequestSchema, pipelineRequestSchema, planningArtifactSchema, planningRequestSchema, promotionRequestSchema, qaRequestSchema, releaseRequestSchema, schemaFixtures, securityRequestSchema, workflowDefinitionSchema } from "@h9-foundry/agentforge-schemas";
|
|
10
10
|
import { createBuiltinAdapters } from "./internal/builtin-adapters.js";
|
|
11
11
|
import { createBuiltinAgentRegistry } from "./internal/builtin-agents.js";
|
|
12
12
|
import { LocalPluginRegistry } from "./internal/local-plugin-registry.js";
|
|
@@ -239,7 +239,7 @@ description: Validate a bounded release-readiness request while keeping trusted
|
|
|
239
239
|
trigger: manual
|
|
240
240
|
catalog:
|
|
241
241
|
domain: release
|
|
242
|
-
supportLevel:
|
|
242
|
+
supportLevel: official
|
|
243
243
|
maturity: mvp
|
|
244
244
|
trustScope: official-core-only
|
|
245
245
|
nodes:
|
|
@@ -259,6 +259,84 @@ nodes:
|
|
|
259
259
|
kind: report
|
|
260
260
|
outputs_to: reports.final
|
|
261
261
|
`;
|
|
262
|
+
const pipelineWorkflowTemplate = `version: 1
|
|
263
|
+
name: pipeline-evidence-review
|
|
264
|
+
description: Review bounded local pipeline evidence through the shared CI model without assuming a release target.
|
|
265
|
+
trigger: manual
|
|
266
|
+
catalog:
|
|
267
|
+
domain: release
|
|
268
|
+
supportLevel: official
|
|
269
|
+
maturity: mvp
|
|
270
|
+
trustScope: official-core-only
|
|
271
|
+
nodes:
|
|
272
|
+
- id: intake
|
|
273
|
+
kind: deterministic
|
|
274
|
+
agent: pipeline-intake
|
|
275
|
+
outputs_to: agentResults.intake
|
|
276
|
+
- id: evidence
|
|
277
|
+
kind: deterministic
|
|
278
|
+
agent: pipeline-evidence-normalizer
|
|
279
|
+
outputs_to: agentResults.evidence
|
|
280
|
+
- id: pipeline
|
|
281
|
+
kind: reasoning
|
|
282
|
+
agent: pipeline-analyst
|
|
283
|
+
outputs_to: agentResults.pipeline
|
|
284
|
+
- id: report
|
|
285
|
+
kind: report
|
|
286
|
+
outputs_to: reports.final
|
|
287
|
+
`;
|
|
288
|
+
const deploymentGateWorkflowTemplate = `version: 1
|
|
289
|
+
name: deployment-gate-review
|
|
290
|
+
description: Review a bounded deployment candidate using shared CI evidence and referenced lifecycle artifacts.
|
|
291
|
+
trigger: manual
|
|
292
|
+
catalog:
|
|
293
|
+
domain: release
|
|
294
|
+
supportLevel: official
|
|
295
|
+
maturity: mvp
|
|
296
|
+
trustScope: official-core-only
|
|
297
|
+
nodes:
|
|
298
|
+
- id: intake
|
|
299
|
+
kind: deterministic
|
|
300
|
+
agent: deployment-gate-intake
|
|
301
|
+
outputs_to: agentResults.intake
|
|
302
|
+
- id: evidence
|
|
303
|
+
kind: deterministic
|
|
304
|
+
agent: deployment-gate-evidence-normalizer
|
|
305
|
+
outputs_to: agentResults.evidence
|
|
306
|
+
- id: deployment
|
|
307
|
+
kind: reasoning
|
|
308
|
+
agent: deployment-gate-analyst
|
|
309
|
+
outputs_to: agentResults.deployment
|
|
310
|
+
- id: report
|
|
311
|
+
kind: report
|
|
312
|
+
outputs_to: reports.final
|
|
313
|
+
`;
|
|
314
|
+
const promotionApprovalWorkflowTemplate = `version: 1
|
|
315
|
+
name: promotion-approval
|
|
316
|
+
description: Review promotion approval readiness using bounded CI evidence plus ready release and deployment gate artifacts.
|
|
317
|
+
trigger: manual
|
|
318
|
+
catalog:
|
|
319
|
+
domain: release
|
|
320
|
+
supportLevel: official
|
|
321
|
+
maturity: mvp
|
|
322
|
+
trustScope: official-core-only
|
|
323
|
+
nodes:
|
|
324
|
+
- id: intake
|
|
325
|
+
kind: deterministic
|
|
326
|
+
agent: promotion-approval-intake
|
|
327
|
+
outputs_to: agentResults.intake
|
|
328
|
+
- id: evidence
|
|
329
|
+
kind: deterministic
|
|
330
|
+
agent: promotion-approval-evidence-normalizer
|
|
331
|
+
outputs_to: agentResults.evidence
|
|
332
|
+
- id: promotion
|
|
333
|
+
kind: reasoning
|
|
334
|
+
agent: promotion-approval-analyst
|
|
335
|
+
outputs_to: agentResults.promotion
|
|
336
|
+
- id: report
|
|
337
|
+
kind: report
|
|
338
|
+
outputs_to: reports.final
|
|
339
|
+
`;
|
|
262
340
|
const incidentWorkflowTemplate = `version: 1
|
|
263
341
|
name: incident-handoff
|
|
264
342
|
description: Validate staged incident evidence while keeping the default path local, read-only, and explicit.
|
|
@@ -328,24 +406,90 @@ function runGit(root, args) {
|
|
|
328
406
|
return "";
|
|
329
407
|
}
|
|
330
408
|
}
|
|
331
|
-
function
|
|
409
|
+
function inferScmPlatform(host) {
|
|
410
|
+
const normalizedHost = host.toLowerCase();
|
|
411
|
+
if (normalizedHost.includes("github")) {
|
|
412
|
+
return "github";
|
|
413
|
+
}
|
|
414
|
+
if (normalizedHost.includes("gitlab")) {
|
|
415
|
+
return "gitlab";
|
|
416
|
+
}
|
|
417
|
+
return "generic";
|
|
418
|
+
}
|
|
419
|
+
function parseScmRepositoryUrl(value) {
|
|
332
420
|
const trimmed = value.trim();
|
|
333
|
-
const sshMatch = trimmed.match(/^git@([^:]+):(
|
|
421
|
+
const sshMatch = trimmed.match(/^git@([^:]+):(.+?)(?:\.git)?$/i);
|
|
334
422
|
if (sshMatch) {
|
|
423
|
+
const host = sshMatch[1].toLowerCase();
|
|
424
|
+
const pathSegments = sshMatch[2].split("/").filter(Boolean);
|
|
425
|
+
if (pathSegments.length < 2) {
|
|
426
|
+
return undefined;
|
|
427
|
+
}
|
|
428
|
+
const repo = pathSegments[pathSegments.length - 1] ?? "";
|
|
429
|
+
const namespace = pathSegments.slice(0, -1).join("/");
|
|
430
|
+
const platform = inferScmPlatform(host);
|
|
431
|
+
if (platform === "github") {
|
|
432
|
+
return {
|
|
433
|
+
platform,
|
|
434
|
+
host,
|
|
435
|
+
owner: namespace,
|
|
436
|
+
repo
|
|
437
|
+
};
|
|
438
|
+
}
|
|
335
439
|
return {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
440
|
+
platform,
|
|
441
|
+
host,
|
|
442
|
+
namespace,
|
|
443
|
+
repo
|
|
339
444
|
};
|
|
340
445
|
}
|
|
341
|
-
const httpsMatch = trimmed.match(/^https?:\/\/([^/]+)\/(
|
|
446
|
+
const httpsMatch = trimmed.match(/^https?:\/\/([^/]+)\/(.+?)(?:\.git)?(?:\/)?$/i);
|
|
342
447
|
if (!httpsMatch) {
|
|
343
448
|
return undefined;
|
|
344
449
|
}
|
|
450
|
+
const host = httpsMatch[1].toLowerCase();
|
|
451
|
+
const pathSegments = httpsMatch[2].split("/").filter(Boolean);
|
|
452
|
+
if (pathSegments.length < 2) {
|
|
453
|
+
return undefined;
|
|
454
|
+
}
|
|
455
|
+
const repo = pathSegments[pathSegments.length - 1] ?? "";
|
|
456
|
+
const namespace = pathSegments.slice(0, -1).join("/");
|
|
457
|
+
const platform = inferScmPlatform(host);
|
|
458
|
+
if (platform === "github") {
|
|
459
|
+
return {
|
|
460
|
+
platform,
|
|
461
|
+
host,
|
|
462
|
+
owner: namespace,
|
|
463
|
+
repo
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
return {
|
|
467
|
+
platform,
|
|
468
|
+
host,
|
|
469
|
+
namespace,
|
|
470
|
+
repo
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
function parseGitHubRepositoryUrl(value) {
|
|
474
|
+
const parsed = parseScmRepositoryUrl(value);
|
|
475
|
+
if (!parsed || parsed.platform !== "github") {
|
|
476
|
+
return undefined;
|
|
477
|
+
}
|
|
478
|
+
return {
|
|
479
|
+
host: parsed.host,
|
|
480
|
+
owner: parsed.owner,
|
|
481
|
+
repo: parsed.repo
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
function parseGitLabRepositoryUrl(value) {
|
|
485
|
+
const parsed = parseScmRepositoryUrl(value);
|
|
486
|
+
if (!parsed || parsed.platform !== "gitlab") {
|
|
487
|
+
return undefined;
|
|
488
|
+
}
|
|
345
489
|
return {
|
|
346
|
-
host:
|
|
347
|
-
|
|
348
|
-
repo:
|
|
490
|
+
host: parsed.host,
|
|
491
|
+
namespace: parsed.namespace,
|
|
492
|
+
repo: parsed.repo
|
|
349
493
|
};
|
|
350
494
|
}
|
|
351
495
|
function inferGitHubRepoContext(root) {
|
|
@@ -371,6 +515,60 @@ function inferGitHubRepoContext(root) {
|
|
|
371
515
|
const remoteUrl = runGit(root, ["config", "--get", "remote.origin.url"]);
|
|
372
516
|
return remoteUrl ? parseGitHubRepositoryUrl(remoteUrl) : undefined;
|
|
373
517
|
}
|
|
518
|
+
function inferGitLabRepoContext(root) {
|
|
519
|
+
const packageJsonPath = join(root, "package.json");
|
|
520
|
+
if (existsSync(packageJsonPath)) {
|
|
521
|
+
const parsed = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
522
|
+
if (isRecord(parsed)) {
|
|
523
|
+
const repository = parsed.repository;
|
|
524
|
+
if (typeof repository === "string") {
|
|
525
|
+
const context = parseGitLabRepositoryUrl(repository);
|
|
526
|
+
if (context) {
|
|
527
|
+
return context;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
if (isRecord(repository) && typeof repository.url === "string") {
|
|
531
|
+
const context = parseGitLabRepositoryUrl(repository.url);
|
|
532
|
+
if (context) {
|
|
533
|
+
return context;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
const remoteUrl = runGit(root, ["config", "--get", "remote.origin.url"]);
|
|
539
|
+
return remoteUrl ? parseGitLabRepositoryUrl(remoteUrl) : undefined;
|
|
540
|
+
}
|
|
541
|
+
function inferScmRepoContext(root) {
|
|
542
|
+
const gitHubContext = inferGitHubRepoContext(root);
|
|
543
|
+
if (gitHubContext) {
|
|
544
|
+
return { platform: "github", ...gitHubContext };
|
|
545
|
+
}
|
|
546
|
+
const gitLabContext = inferGitLabRepoContext(root);
|
|
547
|
+
if (gitLabContext) {
|
|
548
|
+
return { platform: "gitlab", ...gitLabContext };
|
|
549
|
+
}
|
|
550
|
+
const packageJsonPath = join(root, "package.json");
|
|
551
|
+
if (existsSync(packageJsonPath)) {
|
|
552
|
+
const parsed = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
553
|
+
if (isRecord(parsed)) {
|
|
554
|
+
const repository = parsed.repository;
|
|
555
|
+
if (typeof repository === "string") {
|
|
556
|
+
const context = parseScmRepositoryUrl(repository);
|
|
557
|
+
if (context) {
|
|
558
|
+
return context;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
if (isRecord(repository) && typeof repository.url === "string") {
|
|
562
|
+
const context = parseScmRepositoryUrl(repository.url);
|
|
563
|
+
if (context) {
|
|
564
|
+
return context;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
const remoteUrl = runGit(root, ["config", "--get", "remote.origin.url"]);
|
|
570
|
+
return remoteUrl ? parseScmRepositoryUrl(remoteUrl) : undefined;
|
|
571
|
+
}
|
|
374
572
|
function normalizeGitHubReference(rawValue, repoContext) {
|
|
375
573
|
const raw = rawValue.trim();
|
|
376
574
|
if (!raw) {
|
|
@@ -426,6 +624,86 @@ function normalizeGitHubReferences(rawValues, repoContext) {
|
|
|
426
624
|
}
|
|
427
625
|
return normalized;
|
|
428
626
|
}
|
|
627
|
+
function normalizeGitLabReference(rawValue, repoContext) {
|
|
628
|
+
const raw = rawValue.trim();
|
|
629
|
+
if (!raw) {
|
|
630
|
+
return undefined;
|
|
631
|
+
}
|
|
632
|
+
const fromParts = (context, kind, number) => ({
|
|
633
|
+
platform: "gitlab",
|
|
634
|
+
host: context.host,
|
|
635
|
+
namespace: context.namespace,
|
|
636
|
+
repo: context.repo,
|
|
637
|
+
kind,
|
|
638
|
+
identifier: `${number}`,
|
|
639
|
+
number,
|
|
640
|
+
canonical: kind === "issue"
|
|
641
|
+
? `${context.host}/${context.namespace}/${context.repo}#${number}`
|
|
642
|
+
: `${context.host}/${context.namespace}/${context.repo}!${number}`,
|
|
643
|
+
url: kind === "issue"
|
|
644
|
+
? `https://${context.host}/${context.namespace}/${context.repo}/-/issues/${number}`
|
|
645
|
+
: `https://${context.host}/${context.namespace}/${context.repo}/-/merge_requests/${number}`,
|
|
646
|
+
source: raw
|
|
647
|
+
});
|
|
648
|
+
const urlMatch = raw.match(/^https?:\/\/([^/]+)\/(.+?)\/-\/(issues|merge_requests)\/(\d+)(?:\/)?$/i);
|
|
649
|
+
if (urlMatch) {
|
|
650
|
+
const pathSegments = urlMatch[2].split("/").filter(Boolean);
|
|
651
|
+
if (pathSegments.length < 2) {
|
|
652
|
+
return undefined;
|
|
653
|
+
}
|
|
654
|
+
const repo = pathSegments[pathSegments.length - 1] ?? "";
|
|
655
|
+
const namespace = pathSegments.slice(0, -1).join("/");
|
|
656
|
+
return fromParts({ host: urlMatch[1].toLowerCase(), namespace, repo }, urlMatch[3].toLowerCase() === "merge_requests" ? "merge_request" : "issue", Number.parseInt(urlMatch[4], 10));
|
|
657
|
+
}
|
|
658
|
+
const shortIssueMatch = raw.match(/^#(\d+)$/);
|
|
659
|
+
if (shortIssueMatch && repoContext) {
|
|
660
|
+
return fromParts(repoContext, "issue", Number.parseInt(shortIssueMatch[1], 10));
|
|
661
|
+
}
|
|
662
|
+
const shortMergeRequestMatch = raw.match(/^!(\d+)$/);
|
|
663
|
+
if (shortMergeRequestMatch && repoContext) {
|
|
664
|
+
return fromParts(repoContext, "merge_request", Number.parseInt(shortMergeRequestMatch[1], 10));
|
|
665
|
+
}
|
|
666
|
+
return undefined;
|
|
667
|
+
}
|
|
668
|
+
function normalizeScmReference(rawValue, repoContext) {
|
|
669
|
+
const raw = rawValue.trim();
|
|
670
|
+
if (!raw) {
|
|
671
|
+
return undefined;
|
|
672
|
+
}
|
|
673
|
+
const gitHubRef = normalizeGitHubReference(raw, repoContext?.platform === "github"
|
|
674
|
+
? { host: repoContext.host, owner: repoContext.owner, repo: repoContext.repo }
|
|
675
|
+
: undefined);
|
|
676
|
+
if (gitHubRef) {
|
|
677
|
+
return {
|
|
678
|
+
platform: "github",
|
|
679
|
+
host: gitHubRef.host,
|
|
680
|
+
namespace: gitHubRef.owner,
|
|
681
|
+
repo: gitHubRef.repo,
|
|
682
|
+
kind: gitHubRef.kind,
|
|
683
|
+
identifier: `${gitHubRef.number}`,
|
|
684
|
+
number: gitHubRef.number,
|
|
685
|
+
canonical: `${gitHubRef.host}/${gitHubRef.owner}/${gitHubRef.repo}${gitHubRef.kind === "issue" ? `#${gitHubRef.number}` : `/pull/${gitHubRef.number}`}`,
|
|
686
|
+
url: gitHubRef.url,
|
|
687
|
+
source: gitHubRef.source
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
return normalizeGitLabReference(raw, repoContext?.platform === "gitlab"
|
|
691
|
+
? { host: repoContext.host, namespace: repoContext.namespace, repo: repoContext.repo }
|
|
692
|
+
: undefined);
|
|
693
|
+
}
|
|
694
|
+
function normalizeScmReferences(rawValues, repoContext) {
|
|
695
|
+
const seen = new Set();
|
|
696
|
+
const normalized = [];
|
|
697
|
+
for (const rawValue of rawValues) {
|
|
698
|
+
const scmRef = normalizeScmReference(rawValue, repoContext);
|
|
699
|
+
if (!scmRef || seen.has(scmRef.canonical)) {
|
|
700
|
+
continue;
|
|
701
|
+
}
|
|
702
|
+
seen.add(scmRef.canonical);
|
|
703
|
+
normalized.push(scmRef);
|
|
704
|
+
}
|
|
705
|
+
return normalized;
|
|
706
|
+
}
|
|
429
707
|
export function mapWorkflowRunStatusToGitHubStatus(workflow, localRunStatus) {
|
|
430
708
|
if (localRunStatus === "success") {
|
|
431
709
|
return {
|
|
@@ -544,6 +822,49 @@ function validateReleaseRequestCompleteness(request) {
|
|
|
544
822
|
}
|
|
545
823
|
return request;
|
|
546
824
|
}
|
|
825
|
+
function validatePipelineRequestCompleteness(request) {
|
|
826
|
+
const evidenceSignalCount = request.evidenceSources.length + request.qaReportRefs.length + request.securityReportRefs.length + request.releaseReportRefs.length;
|
|
827
|
+
if (evidenceSignalCount === 0) {
|
|
828
|
+
throw new Error("Pipeline request is underspecified. Add at least one of evidenceSources, qaReportRefs, securityReportRefs, or releaseReportRefs.");
|
|
829
|
+
}
|
|
830
|
+
return request;
|
|
831
|
+
}
|
|
832
|
+
function validateDeploymentRequestCompleteness(request) {
|
|
833
|
+
const evidenceSignalCount = request.evidenceSources.length +
|
|
834
|
+
request.qaReportRefs.length +
|
|
835
|
+
request.securityReportRefs.length +
|
|
836
|
+
request.releaseReportRefs.length +
|
|
837
|
+
request.pipelineReportRefs.length;
|
|
838
|
+
if (evidenceSignalCount === 0) {
|
|
839
|
+
throw new Error("Deployment request is underspecified. Add at least one of evidenceSources, qaReportRefs, securityReportRefs, releaseReportRefs, or pipelineReportRefs.");
|
|
840
|
+
}
|
|
841
|
+
return request;
|
|
842
|
+
}
|
|
843
|
+
function validatePromotionRequestCompleteness(request) {
|
|
844
|
+
const evidenceSignalCount = request.evidenceSources.length +
|
|
845
|
+
request.qaReportRefs.length +
|
|
846
|
+
request.securityReportRefs.length +
|
|
847
|
+
request.releaseReportRefs.length +
|
|
848
|
+
request.deploymentGateReportRefs.length;
|
|
849
|
+
if (evidenceSignalCount === 0) {
|
|
850
|
+
throw new Error("Promotion request is underspecified. Add at least one of evidenceSources, qaReportRefs, securityReportRefs, releaseReportRefs, or deploymentGateReportRefs.");
|
|
851
|
+
}
|
|
852
|
+
if (request.releaseReportRefs.length === 0 || request.deploymentGateReportRefs.length === 0) {
|
|
853
|
+
throw new Error("Promotion request is underspecified. Add at least one releaseReportRef and one deploymentGateReportRef.");
|
|
854
|
+
}
|
|
855
|
+
return request;
|
|
856
|
+
}
|
|
857
|
+
function addSourceReferences(refs, incoming) {
|
|
858
|
+
for (const issueRef of incoming.issueRefs) {
|
|
859
|
+
refs.issueRefs.add(issueRef);
|
|
860
|
+
}
|
|
861
|
+
for (const scmRef of incoming.scmRefs) {
|
|
862
|
+
refs.scmRefMap.set(scmRef.canonical, scmRef);
|
|
863
|
+
}
|
|
864
|
+
for (const githubRef of incoming.githubRefs) {
|
|
865
|
+
refs.githubRefMap.set(githubRef.canonical, githubRef);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
547
868
|
function loadLifecycleArtifactKinds(root, bundleRef) {
|
|
548
869
|
const bundlePath = join(root, bundleRef);
|
|
549
870
|
if (!existsSync(bundlePath)) {
|
|
@@ -558,22 +879,31 @@ function loadLifecycleArtifactSourceReferences(root, bundleRef) {
|
|
|
558
879
|
throw new Error(`Referenced bundle not found: ${bundleRef}`);
|
|
559
880
|
}
|
|
560
881
|
const bundle = auditBundleSchema.parse(JSON.parse(readFileSync(bundlePath, "utf8")));
|
|
561
|
-
const
|
|
882
|
+
const scmRepoContext = inferScmRepoContext(root);
|
|
883
|
+
const gitHubRepoContext = inferGitHubRepoContext(root);
|
|
562
884
|
const issueRefs = new Set();
|
|
885
|
+
const scmRefs = new Map();
|
|
563
886
|
const githubRefs = new Map();
|
|
564
887
|
for (const artifact of bundle.lifecycleArtifacts) {
|
|
565
888
|
for (const issueRef of artifact.source.issueRefs) {
|
|
566
889
|
issueRefs.add(issueRef);
|
|
567
890
|
}
|
|
891
|
+
for (const scmRef of artifact.source.scmRefs ?? []) {
|
|
892
|
+
scmRefs.set(scmRef.canonical, scmRef);
|
|
893
|
+
}
|
|
568
894
|
for (const githubRef of artifact.source.githubRefs ?? []) {
|
|
569
895
|
githubRefs.set(githubRef.canonical, githubRef);
|
|
570
896
|
}
|
|
571
|
-
for (const
|
|
897
|
+
for (const scmRef of normalizeScmReferences(artifact.source.issueRefs, scmRepoContext)) {
|
|
898
|
+
scmRefs.set(scmRef.canonical, scmRef);
|
|
899
|
+
}
|
|
900
|
+
for (const githubRef of normalizeGitHubReferences(artifact.source.issueRefs, gitHubRepoContext)) {
|
|
572
901
|
githubRefs.set(githubRef.canonical, githubRef);
|
|
573
902
|
}
|
|
574
903
|
}
|
|
575
904
|
return {
|
|
576
905
|
issueRefs: [...issueRefs],
|
|
906
|
+
scmRefs: [...scmRefs.values()],
|
|
577
907
|
githubRefs: [...githubRefs.values()]
|
|
578
908
|
};
|
|
579
909
|
}
|
|
@@ -584,9 +914,11 @@ function prepareWorkflowInputs(workflow, root, policyEngine) {
|
|
|
584
914
|
const requestPath = ".agentops/requests/planning.yaml";
|
|
585
915
|
ensureReadablePath(policyEngine, requestPath, "planning request");
|
|
586
916
|
const planningRequest = validatePlanningRequestCompleteness(readYamlFile(join(root, requestPath), planningRequestSchema, "planning request"));
|
|
917
|
+
const planningScmRefs = normalizeScmReferences(planningRequest.issueRefs, inferScmRepoContext(root));
|
|
587
918
|
const planningGithubRefs = normalizeGitHubReferences(planningRequest.issueRefs, inferGitHubRepoContext(root));
|
|
588
919
|
return {
|
|
589
920
|
planningRequest,
|
|
921
|
+
planningScmRefs,
|
|
590
922
|
planningGithubRefs,
|
|
591
923
|
requestFile: requestPath
|
|
592
924
|
};
|
|
@@ -628,10 +960,11 @@ function prepareWorkflowInputs(workflow, root, policyEngine) {
|
|
|
628
960
|
}
|
|
629
961
|
const referencedSourceRefs = qaRequest.targetRef.endsWith("bundle.json")
|
|
630
962
|
? loadLifecycleArtifactSourceReferences(root, qaRequest.targetRef)
|
|
631
|
-
: { issueRefs: [], githubRefs: [] };
|
|
963
|
+
: { issueRefs: [], scmRefs: [], githubRefs: [] };
|
|
632
964
|
return {
|
|
633
965
|
qaRequest: qaRequest,
|
|
634
966
|
qaIssueRefs: referencedSourceRefs.issueRefs,
|
|
967
|
+
qaScmRefs: referencedSourceRefs.scmRefs,
|
|
635
968
|
qaGithubRefs: referencedSourceRefs.githubRefs,
|
|
636
969
|
requestFile: requestPath
|
|
637
970
|
};
|
|
@@ -656,20 +989,68 @@ function prepareWorkflowInputs(workflow, root, policyEngine) {
|
|
|
656
989
|
}
|
|
657
990
|
const referencedSourceRefs = securityRequest.targetRef.endsWith("bundle.json")
|
|
658
991
|
? loadLifecycleArtifactSourceReferences(root, securityRequest.targetRef)
|
|
659
|
-
: { issueRefs: [], githubRefs: [] };
|
|
992
|
+
: { issueRefs: [], scmRefs: [], githubRefs: [] };
|
|
660
993
|
return {
|
|
661
994
|
securityRequest: securityRequest,
|
|
662
995
|
securityTargetArtifactKinds: referencedArtifactKinds,
|
|
663
996
|
securityIssueRefs: referencedSourceRefs.issueRefs,
|
|
997
|
+
securityScmRefs: referencedSourceRefs.scmRefs,
|
|
664
998
|
securityGithubRefs: referencedSourceRefs.githubRefs,
|
|
665
999
|
requestFile: requestPath
|
|
666
1000
|
};
|
|
667
1001
|
}
|
|
1002
|
+
if (workflow.name === "pipeline-evidence-review") {
|
|
1003
|
+
const requestPath = ".agentops/requests/pipeline.yaml";
|
|
1004
|
+
ensureReadablePath(policyEngine, requestPath, "pipeline request");
|
|
1005
|
+
const pipelineRequest = validatePipelineRequestCompleteness(readYamlFile(join(root, requestPath), pipelineRequestSchema, "pipeline request"));
|
|
1006
|
+
const scmRepoContext = inferScmRepoContext(root);
|
|
1007
|
+
const gitHubRepoContext = inferGitHubRepoContext(root);
|
|
1008
|
+
const pipelineRefs = {
|
|
1009
|
+
issueRefs: new Set(pipelineRequest.issueRefs),
|
|
1010
|
+
scmRefMap: new Map(),
|
|
1011
|
+
githubRefMap: new Map()
|
|
1012
|
+
};
|
|
1013
|
+
for (const scmRef of normalizeScmReferences(pipelineRequest.issueRefs, scmRepoContext)) {
|
|
1014
|
+
pipelineRefs.scmRefMap.set(scmRef.canonical, scmRef);
|
|
1015
|
+
}
|
|
1016
|
+
for (const githubRef of normalizeGitHubReferences(pipelineRequest.issueRefs, gitHubRepoContext)) {
|
|
1017
|
+
pipelineRefs.githubRefMap.set(githubRef.canonical, githubRef);
|
|
1018
|
+
}
|
|
1019
|
+
for (const qaReportRef of pipelineRequest.qaReportRefs) {
|
|
1020
|
+
ensureReadablePath(policyEngine, qaReportRef, "QA report reference");
|
|
1021
|
+
ensureBundleContainsArtifactKind(root, qaReportRef, "qa-report", "QA report reference");
|
|
1022
|
+
addSourceReferences(pipelineRefs, loadLifecycleArtifactSourceReferences(root, qaReportRef));
|
|
1023
|
+
}
|
|
1024
|
+
for (const securityReportRef of pipelineRequest.securityReportRefs) {
|
|
1025
|
+
ensureReadablePath(policyEngine, securityReportRef, "security report reference");
|
|
1026
|
+
ensureBundleContainsArtifactKind(root, securityReportRef, "security-report", "security report reference");
|
|
1027
|
+
addSourceReferences(pipelineRefs, loadLifecycleArtifactSourceReferences(root, securityReportRef));
|
|
1028
|
+
}
|
|
1029
|
+
for (const releaseReportRef of pipelineRequest.releaseReportRefs) {
|
|
1030
|
+
ensureReadablePath(policyEngine, releaseReportRef, "release report reference");
|
|
1031
|
+
ensureBundleContainsArtifactKind(root, releaseReportRef, "release-report", "release report reference");
|
|
1032
|
+
addSourceReferences(pipelineRefs, loadLifecycleArtifactSourceReferences(root, releaseReportRef));
|
|
1033
|
+
}
|
|
1034
|
+
for (const evidenceSource of pipelineRequest.evidenceSources) {
|
|
1035
|
+
ensureReadablePath(policyEngine, evidenceSource, "pipeline evidence source");
|
|
1036
|
+
if (!existsSync(join(root, evidenceSource))) {
|
|
1037
|
+
throw new Error(`Pipeline evidence source not found: ${evidenceSource}`);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
return {
|
|
1041
|
+
pipelineRequest: pipelineRequest,
|
|
1042
|
+
pipelineIssueRefs: [...pipelineRefs.issueRefs],
|
|
1043
|
+
pipelineScmRefs: [...pipelineRefs.scmRefMap.values()],
|
|
1044
|
+
pipelineGithubRefs: [...pipelineRefs.githubRefMap.values()],
|
|
1045
|
+
requestFile: requestPath
|
|
1046
|
+
};
|
|
1047
|
+
}
|
|
668
1048
|
if (workflow.name === "release-readiness") {
|
|
669
1049
|
const requestPath = ".agentops/requests/release.yaml";
|
|
670
1050
|
ensureReadablePath(policyEngine, requestPath, "release request");
|
|
671
1051
|
const releaseRequest = validateReleaseRequestCompleteness(readYamlFile(join(root, requestPath), releaseRequestSchema, "release request"));
|
|
672
1052
|
const releaseIssueRefs = new Set();
|
|
1053
|
+
const releaseScmRefMap = new Map();
|
|
673
1054
|
const releaseGithubRefMap = new Map();
|
|
674
1055
|
for (const qaReportRef of releaseRequest.qaReportRefs) {
|
|
675
1056
|
ensureReadablePath(policyEngine, qaReportRef, "QA report reference");
|
|
@@ -678,6 +1059,9 @@ function prepareWorkflowInputs(workflow, root, policyEngine) {
|
|
|
678
1059
|
for (const issueRef of refs.issueRefs) {
|
|
679
1060
|
releaseIssueRefs.add(issueRef);
|
|
680
1061
|
}
|
|
1062
|
+
for (const scmRef of refs.scmRefs) {
|
|
1063
|
+
releaseScmRefMap.set(scmRef.canonical, scmRef);
|
|
1064
|
+
}
|
|
681
1065
|
for (const githubRef of refs.githubRefs) {
|
|
682
1066
|
releaseGithubRefMap.set(githubRef.canonical, githubRef);
|
|
683
1067
|
}
|
|
@@ -689,6 +1073,9 @@ function prepareWorkflowInputs(workflow, root, policyEngine) {
|
|
|
689
1073
|
for (const issueRef of refs.issueRefs) {
|
|
690
1074
|
releaseIssueRefs.add(issueRef);
|
|
691
1075
|
}
|
|
1076
|
+
for (const scmRef of refs.scmRefs) {
|
|
1077
|
+
releaseScmRefMap.set(scmRef.canonical, scmRef);
|
|
1078
|
+
}
|
|
692
1079
|
for (const githubRef of refs.githubRefs) {
|
|
693
1080
|
releaseGithubRefMap.set(githubRef.canonical, githubRef);
|
|
694
1081
|
}
|
|
@@ -702,18 +1089,126 @@ function prepareWorkflowInputs(workflow, root, policyEngine) {
|
|
|
702
1089
|
return {
|
|
703
1090
|
releaseRequest: releaseRequest,
|
|
704
1091
|
releaseIssueRefs: [...releaseIssueRefs],
|
|
1092
|
+
releaseScmRefs: [...releaseScmRefMap.values()],
|
|
705
1093
|
releaseGithubRefs: [...releaseGithubRefMap.values()],
|
|
706
1094
|
requestFile: requestPath
|
|
707
1095
|
};
|
|
708
1096
|
}
|
|
1097
|
+
if (workflow.name === "deployment-gate-review") {
|
|
1098
|
+
const requestPath = ".agentops/requests/deployment.yaml";
|
|
1099
|
+
ensureReadablePath(policyEngine, requestPath, "deployment request");
|
|
1100
|
+
const deploymentRequest = validateDeploymentRequestCompleteness(readYamlFile(join(root, requestPath), deploymentRequestSchema, "deployment request"));
|
|
1101
|
+
const scmRepoContext = inferScmRepoContext(root);
|
|
1102
|
+
const gitHubRepoContext = inferGitHubRepoContext(root);
|
|
1103
|
+
const deploymentRefs = {
|
|
1104
|
+
issueRefs: new Set(deploymentRequest.issueRefs),
|
|
1105
|
+
scmRefMap: new Map(),
|
|
1106
|
+
githubRefMap: new Map()
|
|
1107
|
+
};
|
|
1108
|
+
for (const scmRef of normalizeScmReferences(deploymentRequest.issueRefs, scmRepoContext)) {
|
|
1109
|
+
deploymentRefs.scmRefMap.set(scmRef.canonical, scmRef);
|
|
1110
|
+
}
|
|
1111
|
+
for (const githubRef of normalizeGitHubReferences(deploymentRequest.issueRefs, gitHubRepoContext)) {
|
|
1112
|
+
deploymentRefs.githubRefMap.set(githubRef.canonical, githubRef);
|
|
1113
|
+
}
|
|
1114
|
+
for (const qaReportRef of deploymentRequest.qaReportRefs) {
|
|
1115
|
+
ensureReadablePath(policyEngine, qaReportRef, "QA report reference");
|
|
1116
|
+
ensureBundleContainsArtifactKind(root, qaReportRef, "qa-report", "QA report reference");
|
|
1117
|
+
addSourceReferences(deploymentRefs, loadLifecycleArtifactSourceReferences(root, qaReportRef));
|
|
1118
|
+
}
|
|
1119
|
+
for (const securityReportRef of deploymentRequest.securityReportRefs) {
|
|
1120
|
+
ensureReadablePath(policyEngine, securityReportRef, "security report reference");
|
|
1121
|
+
ensureBundleContainsArtifactKind(root, securityReportRef, "security-report", "security report reference");
|
|
1122
|
+
addSourceReferences(deploymentRefs, loadLifecycleArtifactSourceReferences(root, securityReportRef));
|
|
1123
|
+
}
|
|
1124
|
+
for (const releaseReportRef of deploymentRequest.releaseReportRefs) {
|
|
1125
|
+
ensureReadablePath(policyEngine, releaseReportRef, "release report reference");
|
|
1126
|
+
ensureBundleContainsArtifactKind(root, releaseReportRef, "release-report", "release report reference");
|
|
1127
|
+
addSourceReferences(deploymentRefs, loadLifecycleArtifactSourceReferences(root, releaseReportRef));
|
|
1128
|
+
}
|
|
1129
|
+
for (const pipelineReportRef of deploymentRequest.pipelineReportRefs) {
|
|
1130
|
+
ensureReadablePath(policyEngine, pipelineReportRef, "pipeline report reference");
|
|
1131
|
+
ensureBundleContainsArtifactKind(root, pipelineReportRef, "pipeline-report", "pipeline report reference");
|
|
1132
|
+
addSourceReferences(deploymentRefs, loadLifecycleArtifactSourceReferences(root, pipelineReportRef));
|
|
1133
|
+
}
|
|
1134
|
+
for (const evidenceSource of deploymentRequest.evidenceSources) {
|
|
1135
|
+
ensureReadablePath(policyEngine, evidenceSource, "deployment evidence source");
|
|
1136
|
+
if (!existsSync(join(root, evidenceSource))) {
|
|
1137
|
+
throw new Error(`Deployment evidence source not found: ${evidenceSource}`);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
return {
|
|
1141
|
+
deploymentRequest: deploymentRequest,
|
|
1142
|
+
deploymentIssueRefs: [...deploymentRefs.issueRefs],
|
|
1143
|
+
deploymentScmRefs: [...deploymentRefs.scmRefMap.values()],
|
|
1144
|
+
deploymentGithubRefs: [...deploymentRefs.githubRefMap.values()],
|
|
1145
|
+
requestFile: requestPath
|
|
1146
|
+
};
|
|
1147
|
+
}
|
|
1148
|
+
if (workflow.name === "promotion-approval") {
|
|
1149
|
+
const requestPath = ".agentops/requests/promotion.yaml";
|
|
1150
|
+
ensureReadablePath(policyEngine, requestPath, "promotion request");
|
|
1151
|
+
const promotionRequest = validatePromotionRequestCompleteness(readYamlFile(join(root, requestPath), promotionRequestSchema, "promotion request"));
|
|
1152
|
+
const scmRepoContext = inferScmRepoContext(root);
|
|
1153
|
+
const gitHubRepoContext = inferGitHubRepoContext(root);
|
|
1154
|
+
const promotionRefs = {
|
|
1155
|
+
issueRefs: new Set(promotionRequest.issueRefs),
|
|
1156
|
+
scmRefMap: new Map(),
|
|
1157
|
+
githubRefMap: new Map()
|
|
1158
|
+
};
|
|
1159
|
+
for (const scmRef of normalizeScmReferences(promotionRequest.issueRefs, scmRepoContext)) {
|
|
1160
|
+
promotionRefs.scmRefMap.set(scmRef.canonical, scmRef);
|
|
1161
|
+
}
|
|
1162
|
+
for (const githubRef of normalizeGitHubReferences(promotionRequest.issueRefs, gitHubRepoContext)) {
|
|
1163
|
+
promotionRefs.githubRefMap.set(githubRef.canonical, githubRef);
|
|
1164
|
+
}
|
|
1165
|
+
for (const qaReportRef of promotionRequest.qaReportRefs) {
|
|
1166
|
+
ensureReadablePath(policyEngine, qaReportRef, "QA report reference");
|
|
1167
|
+
ensureBundleContainsArtifactKind(root, qaReportRef, "qa-report", "QA report reference");
|
|
1168
|
+
addSourceReferences(promotionRefs, loadLifecycleArtifactSourceReferences(root, qaReportRef));
|
|
1169
|
+
}
|
|
1170
|
+
for (const securityReportRef of promotionRequest.securityReportRefs) {
|
|
1171
|
+
ensureReadablePath(policyEngine, securityReportRef, "security report reference");
|
|
1172
|
+
ensureBundleContainsArtifactKind(root, securityReportRef, "security-report", "security report reference");
|
|
1173
|
+
addSourceReferences(promotionRefs, loadLifecycleArtifactSourceReferences(root, securityReportRef));
|
|
1174
|
+
}
|
|
1175
|
+
for (const releaseReportRef of promotionRequest.releaseReportRefs) {
|
|
1176
|
+
ensureReadablePath(policyEngine, releaseReportRef, "release report reference");
|
|
1177
|
+
ensureBundleContainsArtifactKind(root, releaseReportRef, "release-report", "release report reference");
|
|
1178
|
+
addSourceReferences(promotionRefs, loadLifecycleArtifactSourceReferences(root, releaseReportRef));
|
|
1179
|
+
}
|
|
1180
|
+
for (const deploymentGateReportRef of promotionRequest.deploymentGateReportRefs) {
|
|
1181
|
+
ensureReadablePath(policyEngine, deploymentGateReportRef, "deployment gate report reference");
|
|
1182
|
+
ensureBundleContainsArtifactKind(root, deploymentGateReportRef, "deployment-gate-report", "deployment gate report reference");
|
|
1183
|
+
addSourceReferences(promotionRefs, loadLifecycleArtifactSourceReferences(root, deploymentGateReportRef));
|
|
1184
|
+
}
|
|
1185
|
+
for (const evidenceSource of promotionRequest.evidenceSources) {
|
|
1186
|
+
ensureReadablePath(policyEngine, evidenceSource, "promotion evidence source");
|
|
1187
|
+
if (!existsSync(join(root, evidenceSource))) {
|
|
1188
|
+
throw new Error(`Promotion evidence source not found: ${evidenceSource}`);
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
return {
|
|
1192
|
+
promotionRequest: promotionRequest,
|
|
1193
|
+
promotionIssueRefs: [...promotionRefs.issueRefs],
|
|
1194
|
+
promotionScmRefs: [...promotionRefs.scmRefMap.values()],
|
|
1195
|
+
promotionGithubRefs: [...promotionRefs.githubRefMap.values()],
|
|
1196
|
+
requestFile: requestPath
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
709
1199
|
if (workflow.name === "incident-handoff") {
|
|
710
1200
|
const requestPath = ".agentops/requests/incident.yaml";
|
|
711
1201
|
ensureReadablePath(policyEngine, requestPath, "incident request");
|
|
712
1202
|
const incidentRequest = validateIncidentRequestCompleteness(readYamlFile(join(root, requestPath), incidentRequestSchema, "incident request"));
|
|
713
|
-
const
|
|
1203
|
+
const scmRepoContext = inferScmRepoContext(root);
|
|
1204
|
+
const gitHubRepoContext = inferGitHubRepoContext(root);
|
|
714
1205
|
const incidentIssueRefs = new Set(incidentRequest.issueRefs);
|
|
1206
|
+
const incidentScmRefMap = new Map();
|
|
715
1207
|
const incidentGithubRefMap = new Map();
|
|
716
|
-
for (const
|
|
1208
|
+
for (const scmRef of normalizeScmReferences(incidentRequest.issueRefs, scmRepoContext)) {
|
|
1209
|
+
incidentScmRefMap.set(scmRef.canonical, scmRef);
|
|
1210
|
+
}
|
|
1211
|
+
for (const githubRef of normalizeGitHubReferences(incidentRequest.issueRefs, gitHubRepoContext)) {
|
|
717
1212
|
incidentGithubRefMap.set(githubRef.canonical, githubRef);
|
|
718
1213
|
}
|
|
719
1214
|
for (const releaseReportRef of incidentRequest.releaseReportRefs) {
|
|
@@ -723,6 +1218,9 @@ function prepareWorkflowInputs(workflow, root, policyEngine) {
|
|
|
723
1218
|
for (const issueRef of refs.issueRefs) {
|
|
724
1219
|
incidentIssueRefs.add(issueRef);
|
|
725
1220
|
}
|
|
1221
|
+
for (const scmRef of refs.scmRefs) {
|
|
1222
|
+
incidentScmRefMap.set(scmRef.canonical, scmRef);
|
|
1223
|
+
}
|
|
726
1224
|
for (const githubRef of refs.githubRefs) {
|
|
727
1225
|
incidentGithubRefMap.set(githubRef.canonical, githubRef);
|
|
728
1226
|
}
|
|
@@ -736,6 +1234,7 @@ function prepareWorkflowInputs(workflow, root, policyEngine) {
|
|
|
736
1234
|
return {
|
|
737
1235
|
incidentRequest: incidentRequest,
|
|
738
1236
|
incidentIssueRefs: [...incidentIssueRefs],
|
|
1237
|
+
incidentScmRefs: [...incidentScmRefMap.values()],
|
|
739
1238
|
incidentGithubRefs: [...incidentGithubRefMap.values()],
|
|
740
1239
|
requestFile: requestPath
|
|
741
1240
|
};
|
|
@@ -744,10 +1243,15 @@ function prepareWorkflowInputs(workflow, root, policyEngine) {
|
|
|
744
1243
|
const requestPath = ".agentops/requests/maintenance.yaml";
|
|
745
1244
|
ensureReadablePath(policyEngine, requestPath, "maintenance request");
|
|
746
1245
|
const maintenanceRequest = validateMaintenanceRequestCompleteness(readYamlFile(join(root, requestPath), maintenanceRequestSchema, "maintenance request"));
|
|
747
|
-
const
|
|
1246
|
+
const scmRepoContext = inferScmRepoContext(root);
|
|
1247
|
+
const gitHubRepoContext = inferGitHubRepoContext(root);
|
|
748
1248
|
const maintenanceIssueRefs = new Set(maintenanceRequest.issueRefs);
|
|
1249
|
+
const maintenanceScmRefMap = new Map();
|
|
749
1250
|
const maintenanceGithubRefMap = new Map();
|
|
750
|
-
for (const
|
|
1251
|
+
for (const scmRef of normalizeScmReferences(maintenanceRequest.issueRefs, scmRepoContext)) {
|
|
1252
|
+
maintenanceScmRefMap.set(scmRef.canonical, scmRef);
|
|
1253
|
+
}
|
|
1254
|
+
for (const githubRef of normalizeGitHubReferences(maintenanceRequest.issueRefs, gitHubRepoContext)) {
|
|
751
1255
|
maintenanceGithubRefMap.set(githubRef.canonical, githubRef);
|
|
752
1256
|
}
|
|
753
1257
|
for (const releaseReportRef of maintenanceRequest.releaseReportRefs) {
|
|
@@ -757,6 +1261,9 @@ function prepareWorkflowInputs(workflow, root, policyEngine) {
|
|
|
757
1261
|
for (const issueRef of refs.issueRefs) {
|
|
758
1262
|
maintenanceIssueRefs.add(issueRef);
|
|
759
1263
|
}
|
|
1264
|
+
for (const scmRef of refs.scmRefs) {
|
|
1265
|
+
maintenanceScmRefMap.set(scmRef.canonical, scmRef);
|
|
1266
|
+
}
|
|
760
1267
|
for (const githubRef of refs.githubRefs) {
|
|
761
1268
|
maintenanceGithubRefMap.set(githubRef.canonical, githubRef);
|
|
762
1269
|
}
|
|
@@ -776,6 +1283,7 @@ function prepareWorkflowInputs(workflow, root, policyEngine) {
|
|
|
776
1283
|
return {
|
|
777
1284
|
maintenanceRequest: maintenanceRequest,
|
|
778
1285
|
maintenanceIssueRefs: [...maintenanceIssueRefs],
|
|
1286
|
+
maintenanceScmRefs: [...maintenanceScmRefMap.values()],
|
|
779
1287
|
maintenanceGithubRefs: [...maintenanceGithubRefMap.values()],
|
|
780
1288
|
requestFile: requestPath
|
|
781
1289
|
};
|
|
@@ -1421,6 +1929,18 @@ function ensureInitFiles(root) {
|
|
|
1421
1929
|
path: join(workflowsDir, "release-readiness.yaml"),
|
|
1422
1930
|
contents: releaseWorkflowTemplate
|
|
1423
1931
|
},
|
|
1932
|
+
{
|
|
1933
|
+
path: join(workflowsDir, "pipeline-evidence-review.yaml"),
|
|
1934
|
+
contents: pipelineWorkflowTemplate
|
|
1935
|
+
},
|
|
1936
|
+
{
|
|
1937
|
+
path: join(workflowsDir, "deployment-gate-review.yaml"),
|
|
1938
|
+
contents: deploymentGateWorkflowTemplate
|
|
1939
|
+
},
|
|
1940
|
+
{
|
|
1941
|
+
path: join(workflowsDir, "promotion-approval.yaml"),
|
|
1942
|
+
contents: promotionApprovalWorkflowTemplate
|
|
1943
|
+
},
|
|
1424
1944
|
{
|
|
1425
1945
|
path: join(workflowsDir, "incident-handoff.yaml"),
|
|
1426
1946
|
contents: incidentWorkflowTemplate
|