@attalabs/vinaya 0.4.3 → 0.4.4
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/aeg-root/enforcement.md +1 -1
- package/aeg-root/state-machine.md +1 -1
- package/dist/checks/bin/check-branch-topology.js +44 -31
- package/dist/checks/bin/check-brief-shape.js +44 -31
- package/dist/checks/bin/check-closes-n.js +44 -31
- package/dist/checks/bin/check-coherence.js +44 -31
- package/dist/checks/bin/check-dead-branch-push.js +44 -31
- package/dist/checks/bin/check-dispatch-readiness.js +44 -31
- package/dist/checks/bin/check-doc-coverage-push.js +221 -34
- package/dist/checks/bin/check-doc-coverage.js +221 -34
- package/dist/checks/bin/check-first-push-dispatch.js +44 -31
- package/dist/checks/bin/check-issue-assignment.js +44 -31
- package/dist/checks/bin/check-no-disk-state.js +44 -31
- package/dist/checks/bin/check-reader-resolvable-prose.js +44 -31
- package/dist/checks/bin/check-registry-gates.js +44 -31
- package/dist/checks/bin/check-review-gate.js +222 -36
- package/dist/checks/bin/check-single-plan-pr.js +44 -31
- package/dist/checks/bin/check-test-plan.js +44 -31
- package/dist/index.js +116 -34
- package/package.json +1 -1
- package/studio-standalone/.worktrees/fix/bump-0.4.4/.vinaya/projects.md +63 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/aeg-manual-flow.md +216 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/contracts/archivist-tranche-archivist.md +92 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/contracts/brief-developer.md +140 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/contracts/developer-reviewer.md +106 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/contracts/planner-brief.md +130 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/contracts/reviewer-archivist.md +96 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/contracts/tranche-archivist-planner.md +116 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/coordination.md +293 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/documentation-coherence.md +65 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/enforcement.md +161 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/glossary.md +36 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/process.md +371 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/reviewer-prompt.md +68 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/archivist.md +167 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/brief-author.md +108 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/developer.md +429 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/planner.md +285 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/principal.md +107 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/reviewer.md +130 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/security.md +121 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/tranche-archivist.md +257 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/skills/aeg/SKILL.md +90 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/skills/aeg-roles/SKILL.md +58 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/skills/brief-authoring/SKILL.md +497 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/state-machine.md +656 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/templates/brief-template.md +103 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/templates/issue-rationale-template.md +35 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/templates/pr-report-template.md +68 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranche-model.md +306 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-coherence-v1.md +55 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-coherence-v1.tokens.md +13 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-consolidation.md +28 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-governance-hardening.md +80 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-governance-ui-v2.md +168 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-governance-ui-v2.tokens.md +18 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-studio-cleanup.md +37 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-ui-v1.md +176 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-ui-v1.tokens.md +17 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/herald-agents-v2.md +35 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/herald-agents-v2.tokens.md +11 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/herald-onto-engine.md +99 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/vada-agents-v2.md +220 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/apps/vinaya/cli/tests/fixtures/checks/vinaya.config.json +9 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/node_modules/@attalabs/vinaya/tests/fixtures/checks/vinaya.config.json +9 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/vinaya.config.json +36 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/.vinaya/projects.md +63 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/aeg-manual-flow.md +216 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/contracts/archivist-tranche-archivist.md +92 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/contracts/brief-developer.md +140 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/contracts/developer-reviewer.md +106 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/contracts/planner-brief.md +130 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/contracts/reviewer-archivist.md +96 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/contracts/tranche-archivist-planner.md +116 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/coordination.md +293 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/documentation-coherence.md +65 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/enforcement.md +161 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/glossary.md +36 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/process.md +371 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/reviewer-prompt.md +68 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/archivist.md +167 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/brief-author.md +108 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/developer.md +429 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/planner.md +285 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/principal.md +107 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/reviewer.md +130 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/security.md +121 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/tranche-archivist.md +257 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/skills/aeg/SKILL.md +90 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/skills/aeg-roles/SKILL.md +58 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/skills/brief-authoring/SKILL.md +497 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/state-machine.md +656 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/templates/brief-template.md +103 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/templates/issue-rationale-template.md +35 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/templates/pr-report-template.md +68 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranche-model.md +306 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-coherence-v1.md +55 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-coherence-v1.tokens.md +13 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-consolidation.md +28 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-governance-hardening.md +80 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-governance-ui-v2.md +168 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-governance-ui-v2.tokens.md +18 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-studio-cleanup.md +37 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-ui-v1.md +176 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-ui-v1.tokens.md +17 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/herald-agents-v2.md +35 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/herald-agents-v2.tokens.md +11 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/herald-onto-engine.md +99 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/vada-agents-v2.md +220 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/apps/vinaya/cli/tests/fixtures/checks/vinaya.config.json +9 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/node_modules/@attalabs/vinaya/tests/fixtures/checks/vinaya.config.json +9 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/vinaya.config.json +36 -0
- package/studio-standalone/_node_modules/@atta/vinaya-cli/aeg-root/enforcement.md +1 -1
- package/studio-standalone/_node_modules/@atta/vinaya-cli/aeg-root/state-machine.md +1 -1
- package/studio-standalone/_node_modules/@attalabs/vinaya/aeg-root/enforcement.md +1 -1
- package/studio-standalone/_node_modules/@attalabs/vinaya/aeg-root/state-machine.md +1 -1
- package/studio-standalone/apps/vinaya/cli/aeg-root/enforcement.md +1 -1
- package/studio-standalone/apps/vinaya/cli/aeg-root/state-machine.md +1 -1
- package/studio-standalone/apps/vinaya/web/.next/BUILD_ID +1 -1
- package/studio-standalone/apps/vinaya/web/.next/build-manifest.json +3 -3
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/cli/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/config/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/docs/(standalone)/cli/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/docs/(standalone)/harness/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/docs/(standalone)/state-machine/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/docs/(with-sidebar)/[...slug]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/docs/(with-sidebar)/reference/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/docs/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/install/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/roadmap/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/archive/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/brief/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/develop/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/overview/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/plan/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/quick/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/review/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/security/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/wrap-up/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/state-machine/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/the-harness/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/the-studio/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.html +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.rsc +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/api/coherence/route.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/studio/backlog/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/studio/docs/[...slug]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/studio/docs/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/studio/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/studio/projects/[name]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/studio/projects/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/studio/tranches/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/chunks/ssr/[root-of-the-server]__0kqmrho._.js +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/chunks/ssr/[root-of-the-server]__1dxaovd._.js +2 -2
- package/studio-standalone/apps/vinaya/web/.next/server/middleware-build-manifest.js +3 -3
- package/studio-standalone/apps/vinaya/web/.next/server/pages/500.html +1 -1
- /package/studio-standalone/apps/vinaya/web/.next/static/{Afs41Lu9uNQ-T6uC-tm4_ → mSHYKKSLd91iaLw52dYpD}/_buildManifest.js +0 -0
- /package/studio-standalone/apps/vinaya/web/.next/static/{Afs41Lu9uNQ-T6uC-tm4_ → mSHYKKSLd91iaLw52dYpD}/_clientMiddlewareManifest.js +0 -0
- /package/studio-standalone/apps/vinaya/web/.next/static/{Afs41Lu9uNQ-T6uC-tm4_ → mSHYKKSLd91iaLw52dYpD}/_ssgManifest.js +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/checks/bin/check-review-gate.ts
|
|
4
|
-
import { execFileSync as
|
|
4
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
5
5
|
// ../../../packages/aeg-core/src/anchored-region.ts
|
|
6
6
|
function maskCode(body) {
|
|
7
7
|
const fill = (line) => " ".repeat(line.length);
|
|
@@ -1451,12 +1451,16 @@ function isCodeFile(p) {
|
|
|
1451
1451
|
var WAIVER_LABEL = label("waiver-docs");
|
|
1452
1452
|
var WAIVER_LABEL_REVIEW = label("waiver-review");
|
|
1453
1453
|
var PRINCIPAL_ALLOWLIST = ["daniboomerang"];
|
|
1454
|
+
function isPrincipal(login, principalAllowlist) {
|
|
1455
|
+
if (login === null)
|
|
1456
|
+
return false;
|
|
1457
|
+
const normalized = login.toLowerCase();
|
|
1458
|
+
return principalAllowlist.some((p) => p.toLowerCase() === normalized);
|
|
1459
|
+
}
|
|
1454
1460
|
function isWaiverLabelActorVerified(opts) {
|
|
1455
1461
|
if (!opts.labels.includes(opts.label))
|
|
1456
1462
|
return false;
|
|
1457
|
-
|
|
1458
|
-
return false;
|
|
1459
|
-
return opts.principalAllowlist.includes(opts.labelActor);
|
|
1463
|
+
return isPrincipal(opts.labelActor, opts.principalAllowlist);
|
|
1460
1464
|
}
|
|
1461
1465
|
|
|
1462
1466
|
// ../../../packages/aeg-core/src/doc-owners.ts
|
|
@@ -1644,6 +1648,27 @@ function overrideActive(opts) {
|
|
|
1644
1648
|
// ../../../packages/aeg-core/src/premise-check.ts
|
|
1645
1649
|
var ASSERTION_KINDS = new Set(["contains", "absent", "sha256"]);
|
|
1646
1650
|
|
|
1651
|
+
// ../../../packages/aeg-core/src/test-plan-section.ts
|
|
1652
|
+
var HEADING_FORM_RE = /^#{1,4}[ \t]*(?:\d+[a-z]?\.[ \t]*)?\*{0,2}Test Plan\*{0,2}[ \t]*$/im;
|
|
1653
|
+
var INLINE_FORM_RE = /^[ \t]*\*{0,2}Test Plan:?\*{0,2}/im;
|
|
1654
|
+
var NEXT_SECTION_RE = /\n(?:#{1,3}[ \t]|\*\*[A-Z][^*\n]*:\*\*)/;
|
|
1655
|
+
function locateTestPlanSection(body) {
|
|
1656
|
+
const region = anchoredRegion(body, "TEST-PLAN");
|
|
1657
|
+
if (region !== null)
|
|
1658
|
+
return { found: true, section: region };
|
|
1659
|
+
const headingMatch = HEADING_FORM_RE.exec(body);
|
|
1660
|
+
const match = headingMatch ?? INLINE_FORM_RE.exec(body);
|
|
1661
|
+
if (!match || match.index === undefined)
|
|
1662
|
+
return { found: false };
|
|
1663
|
+
const sectionBody = body.slice(match.index);
|
|
1664
|
+
const firstLineEnd = sectionBody.indexOf(`
|
|
1665
|
+
`);
|
|
1666
|
+
const searchFrom = firstLineEnd === -1 ? sectionBody.length : firstLineEnd + 1;
|
|
1667
|
+
const nextMatch = sectionBody.slice(searchFrom).match(NEXT_SECTION_RE);
|
|
1668
|
+
const sectionEnd = nextMatch ? searchFrom + (nextMatch.index ?? 0) : sectionBody.length;
|
|
1669
|
+
return { found: true, section: sectionBody.slice(0, sectionEnd) };
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1647
1672
|
// ../../../packages/aeg-core/src/brief-validation.ts
|
|
1648
1673
|
function headerRegion(prBody) {
|
|
1649
1674
|
const m = prBody.match(/^##\s/m);
|
|
@@ -1682,10 +1707,15 @@ function checkTierField(prBody, readTier) {
|
|
|
1682
1707
|
};
|
|
1683
1708
|
}
|
|
1684
1709
|
var TEST_PLAN_UNIT_TESTS_ONLY_RE = /(?:\*\*)?Test Plan(?:\*\*)?\s*:\s*(?:\*\*)?\s*unit-tests-only/i;
|
|
1710
|
+
function testPlanRegion(prBody) {
|
|
1711
|
+
const located = locateTestPlanSection(prBody);
|
|
1712
|
+
return located.found ? located.section : prBody;
|
|
1713
|
+
}
|
|
1685
1714
|
function checkTestPlan(prBody) {
|
|
1686
|
-
|
|
1715
|
+
const region = testPlanRegion(prBody);
|
|
1716
|
+
if (TEST_PLAN_UNIT_TESTS_ONLY_RE.test(region))
|
|
1687
1717
|
return { status: "pass", errors: [] };
|
|
1688
|
-
if (/\*\*\[(?:agent|principal)\]\*\*/.test(
|
|
1718
|
+
if (/\*\*\[(?:agent|principal)\]\*\*/.test(region))
|
|
1689
1719
|
return { status: "pass", errors: [] };
|
|
1690
1720
|
return {
|
|
1691
1721
|
status: "fail",
|
|
@@ -1695,9 +1725,10 @@ function checkTestPlan(prBody) {
|
|
|
1695
1725
|
};
|
|
1696
1726
|
}
|
|
1697
1727
|
function checkTestPlanExclusivity(prBody) {
|
|
1698
|
-
|
|
1728
|
+
const region = testPlanRegion(prBody);
|
|
1729
|
+
if (!TEST_PLAN_UNIT_TESTS_ONLY_RE.test(region))
|
|
1699
1730
|
return { status: "pass", errors: [] };
|
|
1700
|
-
if (/^-\s*\[[ xX]\]\s*\*{2}\[(?:agent|principal)\]\*{2}/im.test(
|
|
1731
|
+
if (/^-\s*\[[ xX]\]\s*\*{2}\[(?:agent|principal)\]\*{2}/im.test(region)) {
|
|
1701
1732
|
return {
|
|
1702
1733
|
status: "fail",
|
|
1703
1734
|
errors: [
|
|
@@ -1708,8 +1739,9 @@ function checkTestPlanExclusivity(prBody) {
|
|
|
1708
1739
|
return { status: "pass", errors: [] };
|
|
1709
1740
|
}
|
|
1710
1741
|
function checkPrincipalPlaceholder(prBody) {
|
|
1742
|
+
const region = testPlanRegion(prBody);
|
|
1711
1743
|
const lineRe = /^-\s*\[[ xX]\]\s*\*{2}\[principal\]\*{2}(.*)$/gim;
|
|
1712
|
-
for (const m of
|
|
1744
|
+
for (const m of region.matchAll(lineRe)) {
|
|
1713
1745
|
const content = m[1] ?? "";
|
|
1714
1746
|
if (/^\s*None\b/i.test(content)) {
|
|
1715
1747
|
return {
|
|
@@ -2157,11 +2189,12 @@ function isReviewGateExemptBranch(branch) {
|
|
|
2157
2189
|
return branch.startsWith("plan/");
|
|
2158
2190
|
}
|
|
2159
2191
|
function checkReviewGate(input) {
|
|
2192
|
+
const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
|
|
2160
2193
|
const waived = isWaiverLabelActorVerified({
|
|
2161
2194
|
label: WAIVER_LABEL_REVIEW,
|
|
2162
2195
|
labels: input.labels,
|
|
2163
2196
|
labelActor: input.waiverLabelActor,
|
|
2164
|
-
principalAllowlist
|
|
2197
|
+
principalAllowlist
|
|
2165
2198
|
});
|
|
2166
2199
|
if (waived) {
|
|
2167
2200
|
return {
|
|
@@ -2170,8 +2203,8 @@ function checkReviewGate(input) {
|
|
|
2170
2203
|
waived: true
|
|
2171
2204
|
};
|
|
2172
2205
|
}
|
|
2173
|
-
const verified = input.comments.filter((c) => c.author
|
|
2174
|
-
const ignoredCount = input.comments.filter((c) => (c.author
|
|
2206
|
+
const verified = input.comments.filter((c) => isPrincipal(c.author, principalAllowlist));
|
|
2207
|
+
const ignoredCount = input.comments.filter((c) => !isPrincipal(c.author, principalAllowlist) && c.body.includes("VERDICT")).length;
|
|
2175
2208
|
const verifiedBodies = verified.map((c) => c.body);
|
|
2176
2209
|
const codeReview = extractCodeReviewVerdict(verifiedBodies);
|
|
2177
2210
|
const security = extractSecurityReviewVerdict(verifiedBodies);
|
|
@@ -2724,26 +2757,6 @@ function decideIssueAssignment(input) {
|
|
|
2724
2757
|
reason: `First push of \`${branch}\` — assigning Issue #${issue} to @${login} (the authenticated pusher).`
|
|
2725
2758
|
};
|
|
2726
2759
|
}
|
|
2727
|
-
// ../../../packages/aeg-core/src/test-plan-section.ts
|
|
2728
|
-
var HEADING_FORM_RE = /^#{1,4}[ \t]*(?:\d+[a-z]?\.[ \t]*)?\*{0,2}Test Plan\*{0,2}[ \t]*$/im;
|
|
2729
|
-
var INLINE_FORM_RE = /^[ \t]*\*{0,2}Test Plan:?\*{0,2}/im;
|
|
2730
|
-
var NEXT_SECTION_RE = /\n(?:#{1,3}[ \t]|\*\*[A-Z][^*\n]*:\*\*)/;
|
|
2731
|
-
function locateTestPlanSection(body) {
|
|
2732
|
-
const region = anchoredRegion(body, "TEST-PLAN");
|
|
2733
|
-
if (region !== null)
|
|
2734
|
-
return { found: true, section: region };
|
|
2735
|
-
const headingMatch = HEADING_FORM_RE.exec(body);
|
|
2736
|
-
const match = headingMatch ?? INLINE_FORM_RE.exec(body);
|
|
2737
|
-
if (!match || match.index === undefined)
|
|
2738
|
-
return { found: false };
|
|
2739
|
-
const sectionBody = body.slice(match.index);
|
|
2740
|
-
const firstLineEnd = sectionBody.indexOf(`
|
|
2741
|
-
`);
|
|
2742
|
-
const searchFrom = firstLineEnd === -1 ? sectionBody.length : firstLineEnd + 1;
|
|
2743
|
-
const nextMatch = sectionBody.slice(searchFrom).match(NEXT_SECTION_RE);
|
|
2744
|
-
const sectionEnd = nextMatch ? searchFrom + (nextMatch.index ?? 0) : sectionBody.length;
|
|
2745
|
-
return { found: true, section: sectionBody.slice(0, sectionEnd) };
|
|
2746
|
-
}
|
|
2747
2760
|
// ../../../packages/aeg-core/src/test-plan-gate.ts
|
|
2748
2761
|
var TASK_BRANCH_PATTERN = /^task\/[^/]+\/[^/]+$/;
|
|
2749
2762
|
function evaluateTestPlanGate(body, branch) {
|
|
@@ -2815,18 +2828,190 @@ function emitCheckError(error) {
|
|
|
2815
2828
|
`);
|
|
2816
2829
|
}
|
|
2817
2830
|
|
|
2831
|
+
// src/lib/config.ts
|
|
2832
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
2833
|
+
import { homedir } from "node:os";
|
|
2834
|
+
import { dirname, join } from "node:path";
|
|
2835
|
+
import { z } from "zod";
|
|
2836
|
+
var EnvEntrySchema = z.union([
|
|
2837
|
+
z.literal(true),
|
|
2838
|
+
z.object({ optional: z.literal(true) }),
|
|
2839
|
+
z.object({ anyOf: z.array(z.string()).min(2) }),
|
|
2840
|
+
z.string()
|
|
2841
|
+
]);
|
|
2842
|
+
var CheckEntrySchema = z.object({
|
|
2843
|
+
run: z.string(),
|
|
2844
|
+
scope: z.enum(["diff", "full"]),
|
|
2845
|
+
include: z.array(z.string()).optional(),
|
|
2846
|
+
args: z.array(z.string()).optional(),
|
|
2847
|
+
timeoutMs: z.number().optional(),
|
|
2848
|
+
env: z.record(z.string(), EnvEntrySchema).optional(),
|
|
2849
|
+
requiresOpenPr: z.boolean().optional()
|
|
2850
|
+
}).superRefine((entry2, ctx) => {
|
|
2851
|
+
if (!entry2.env)
|
|
2852
|
+
return;
|
|
2853
|
+
for (const [key, value] of Object.entries(entry2.env)) {
|
|
2854
|
+
if (typeof value !== "object" || value === null || !("anyOf" in value))
|
|
2855
|
+
continue;
|
|
2856
|
+
const members = value.anyOf;
|
|
2857
|
+
if (new Set(members).size !== members.length) {
|
|
2858
|
+
ctx.addIssue({
|
|
2859
|
+
code: z.ZodIssueCode.custom,
|
|
2860
|
+
message: `env.${key}.anyOf has duplicate members`,
|
|
2861
|
+
path: ["env", key, "anyOf"]
|
|
2862
|
+
});
|
|
2863
|
+
}
|
|
2864
|
+
if (!members.includes(key)) {
|
|
2865
|
+
ctx.addIssue({
|
|
2866
|
+
code: z.ZodIssueCode.custom,
|
|
2867
|
+
message: `env.${key}.anyOf must include "${key}" itself as a member`,
|
|
2868
|
+
path: ["env", key, "anyOf"]
|
|
2869
|
+
});
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2872
|
+
});
|
|
2873
|
+
var BRIEF_BUILTINS = [
|
|
2874
|
+
"tier",
|
|
2875
|
+
"testPlan",
|
|
2876
|
+
"testPlanExclusivity",
|
|
2877
|
+
"principalPlaceholder",
|
|
2878
|
+
"surfaceMap",
|
|
2879
|
+
"docUpdateList",
|
|
2880
|
+
"worktreeStep0",
|
|
2881
|
+
"stopConditions",
|
|
2882
|
+
"autonomyClause",
|
|
2883
|
+
"project",
|
|
2884
|
+
"for",
|
|
2885
|
+
"closesN",
|
|
2886
|
+
"premiseCoverage",
|
|
2887
|
+
"issueRationale"
|
|
2888
|
+
];
|
|
2889
|
+
var BriefSectionSchema = z.union([
|
|
2890
|
+
z.object({ builtin: z.enum(BRIEF_BUILTINS) }),
|
|
2891
|
+
z.object({ heading: z.string().min(1), name: z.string().optional() }),
|
|
2892
|
+
z.object({ field: z.string().min(1), name: z.string().optional() }),
|
|
2893
|
+
z.object({ phrase: z.string().min(1), name: z.string().optional() })
|
|
2894
|
+
]);
|
|
2895
|
+
var BriefSchemaSchema = z.object({
|
|
2896
|
+
pr: z.object({ sections: z.array(BriefSectionSchema) }).optional(),
|
|
2897
|
+
issue: z.object({ sections: z.array(BriefSectionSchema) }).optional()
|
|
2898
|
+
});
|
|
2899
|
+
function isSafeRepoRelPath(p) {
|
|
2900
|
+
if (p.length === 0)
|
|
2901
|
+
return false;
|
|
2902
|
+
if (p.startsWith("/") || /^[a-zA-Z]:[\\/]/.test(p))
|
|
2903
|
+
return false;
|
|
2904
|
+
return p.split(/[\\/]/).every((seg) => seg !== ".." && seg !== "");
|
|
2905
|
+
}
|
|
2906
|
+
var SafeRepoRelPath = z.string().refine(isSafeRepoRelPath, {
|
|
2907
|
+
message: "must be a repo-root-relative path with no `..` segment or absolute root"
|
|
2908
|
+
});
|
|
2909
|
+
var ManagedBlockRecordSchema = z.object({
|
|
2910
|
+
path: SafeRepoRelPath,
|
|
2911
|
+
marker: z.string(),
|
|
2912
|
+
comment: z.enum(["hash", "html"])
|
|
2913
|
+
});
|
|
2914
|
+
var ManagedManifestSchema = z.object({
|
|
2915
|
+
version: z.number().int().positive(),
|
|
2916
|
+
files: z.array(SafeRepoRelPath),
|
|
2917
|
+
blocks: z.array(ManagedBlockRecordSchema),
|
|
2918
|
+
labels: z.array(z.string())
|
|
2919
|
+
});
|
|
2920
|
+
var VinayaConfigSchema = z.object({
|
|
2921
|
+
rings: z.object({
|
|
2922
|
+
ring1_forgeWriteInterception: z.boolean(),
|
|
2923
|
+
ring2_asyncAudits: z.boolean()
|
|
2924
|
+
}).optional(),
|
|
2925
|
+
checks: z.record(z.string(), CheckEntrySchema).optional(),
|
|
2926
|
+
briefSchema: BriefSchemaSchema.optional(),
|
|
2927
|
+
managed: ManagedManifestSchema.optional(),
|
|
2928
|
+
principals: z.array(z.string()).min(1).optional()
|
|
2929
|
+
});
|
|
2930
|
+
var GLOBAL_VINAYA_HOME = join(homedir(), ".vinaya");
|
|
2931
|
+
var GLOBAL_CONFIG_PATH = join(GLOBAL_VINAYA_HOME, "config.json");
|
|
2932
|
+
var LOCAL_CONFIG_FILENAME = "vinaya.config.json";
|
|
2933
|
+
function resolvePrincipalAllowlist(config) {
|
|
2934
|
+
return config?.principals ?? PRINCIPAL_ALLOWLIST;
|
|
2935
|
+
}
|
|
2936
|
+
function trustAnchorRepo() {
|
|
2937
|
+
const wellFormed = (slug) => /^[^/\s]+\/[^/\s]+$/.test(slug) ? slug : null;
|
|
2938
|
+
const fromRunner = process.env.GITHUB_REPOSITORY?.trim();
|
|
2939
|
+
if (fromRunner) {
|
|
2940
|
+
const validated = wellFormed(fromRunner);
|
|
2941
|
+
if (validated)
|
|
2942
|
+
return validated;
|
|
2943
|
+
}
|
|
2944
|
+
try {
|
|
2945
|
+
const url = execFileSync2("git", ["remote", "get-url", "origin"], {
|
|
2946
|
+
encoding: "utf-8",
|
|
2947
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
2948
|
+
}).trim();
|
|
2949
|
+
const m = url.match(/github\.com[:/]([^/]+)\/(.+?)(?:\.git)?\/?$/);
|
|
2950
|
+
return m?.[1] && m[2] ? wellFormed(`${m[1]}/${m[2]}`) : null;
|
|
2951
|
+
} catch {
|
|
2952
|
+
return null;
|
|
2953
|
+
}
|
|
2954
|
+
}
|
|
2955
|
+
function ghFetchTrustAnchorConfig() {
|
|
2956
|
+
const repo = trustAnchorRepo();
|
|
2957
|
+
if (!repo)
|
|
2958
|
+
throw new Error("could not resolve repo identity for the trust-anchor read");
|
|
2959
|
+
return execFileSync2("gh", ["api", `repos/${repo}/contents/${LOCAL_CONFIG_FILENAME}`, "--jq", ".content"], {
|
|
2960
|
+
encoding: "utf-8",
|
|
2961
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
2962
|
+
});
|
|
2963
|
+
}
|
|
2964
|
+
function firstLine(err) {
|
|
2965
|
+
return err?.message?.split(`
|
|
2966
|
+
`)[0] ?? "unknown error";
|
|
2967
|
+
}
|
|
2968
|
+
function isMissingFileError(err) {
|
|
2969
|
+
const stderr = err?.stderr;
|
|
2970
|
+
const haystack = [
|
|
2971
|
+
err?.message ?? "",
|
|
2972
|
+
typeof stderr === "string" ? stderr : stderr?.toString() ?? ""
|
|
2973
|
+
].join(`
|
|
2974
|
+
`);
|
|
2975
|
+
return /\b404\b|not found/i.test(haystack);
|
|
2976
|
+
}
|
|
2977
|
+
function loadTrustAnchorConfig(fetcher = ghFetchTrustAnchorConfig) {
|
|
2978
|
+
const warn = (why) => process.stdout.write(`⚠ could not read \`principals\` from the default branch (${why}) — falling back to vinaya's built-in principal allowlist.
|
|
2979
|
+
`);
|
|
2980
|
+
let base64;
|
|
2981
|
+
try {
|
|
2982
|
+
base64 = fetcher().trim();
|
|
2983
|
+
} catch (err) {
|
|
2984
|
+
if (!isMissingFileError(err))
|
|
2985
|
+
warn(firstLine(err));
|
|
2986
|
+
return null;
|
|
2987
|
+
}
|
|
2988
|
+
if (!base64)
|
|
2989
|
+
return null;
|
|
2990
|
+
try {
|
|
2991
|
+
const raw = Buffer.from(base64, "base64").toString("utf-8");
|
|
2992
|
+
const parsed = VinayaConfigSchema.safeParse(JSON.parse(raw));
|
|
2993
|
+
if (parsed.success)
|
|
2994
|
+
return parsed.data;
|
|
2995
|
+
warn("it did not satisfy the config schema");
|
|
2996
|
+
return null;
|
|
2997
|
+
} catch {
|
|
2998
|
+
warn("it was not readable as JSON");
|
|
2999
|
+
return null;
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
|
|
2818
3003
|
// src/checks/bin/check-review-gate.ts
|
|
2819
3004
|
var CHECK_NAME = "review-gate";
|
|
2820
3005
|
function git(args) {
|
|
2821
3006
|
try {
|
|
2822
|
-
return
|
|
3007
|
+
return execFileSync3("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
2823
3008
|
} catch {
|
|
2824
3009
|
return "";
|
|
2825
3010
|
}
|
|
2826
3011
|
}
|
|
2827
3012
|
function fetchPr(prNumber) {
|
|
2828
3013
|
try {
|
|
2829
|
-
const out =
|
|
3014
|
+
const out = execFileSync3("gh", ["pr", "view", String(prNumber), "--json", "number,comments,labels"], {
|
|
2830
3015
|
encoding: "utf8",
|
|
2831
3016
|
stdio: ["ignore", "pipe", "pipe"]
|
|
2832
3017
|
});
|
|
@@ -2837,7 +3022,7 @@ function fetchPr(prNumber) {
|
|
|
2837
3022
|
}
|
|
2838
3023
|
function fetchWaiverLabelActor(prNumber, label2) {
|
|
2839
3024
|
try {
|
|
2840
|
-
const out =
|
|
3025
|
+
const out = execFileSync3("gh", ["api", `repos/{owner}/{repo}/issues/${prNumber}/timeline`, "--paginate"], {
|
|
2841
3026
|
encoding: "utf8",
|
|
2842
3027
|
stdio: ["ignore", "pipe", "pipe"]
|
|
2843
3028
|
});
|
|
@@ -2875,7 +3060,8 @@ function main() {
|
|
|
2875
3060
|
const result = checkReviewGate({
|
|
2876
3061
|
comments: pr.comments.map((c) => ({ body: c.body, author: c.author?.login ?? null })),
|
|
2877
3062
|
labels,
|
|
2878
|
-
waiverLabelActor
|
|
3063
|
+
waiverLabelActor,
|
|
3064
|
+
principalAllowlist: resolvePrincipalAllowlist(loadTrustAnchorConfig())
|
|
2879
3065
|
});
|
|
2880
3066
|
if (result.verdict === "fail") {
|
|
2881
3067
|
emitCheckError({
|
|
@@ -1451,12 +1451,16 @@ function isCodeFile(p) {
|
|
|
1451
1451
|
var WAIVER_LABEL = label("waiver-docs");
|
|
1452
1452
|
var WAIVER_LABEL_REVIEW = label("waiver-review");
|
|
1453
1453
|
var PRINCIPAL_ALLOWLIST = ["daniboomerang"];
|
|
1454
|
+
function isPrincipal(login, principalAllowlist) {
|
|
1455
|
+
if (login === null)
|
|
1456
|
+
return false;
|
|
1457
|
+
const normalized = login.toLowerCase();
|
|
1458
|
+
return principalAllowlist.some((p) => p.toLowerCase() === normalized);
|
|
1459
|
+
}
|
|
1454
1460
|
function isWaiverLabelActorVerified(opts) {
|
|
1455
1461
|
if (!opts.labels.includes(opts.label))
|
|
1456
1462
|
return false;
|
|
1457
|
-
|
|
1458
|
-
return false;
|
|
1459
|
-
return opts.principalAllowlist.includes(opts.labelActor);
|
|
1463
|
+
return isPrincipal(opts.labelActor, opts.principalAllowlist);
|
|
1460
1464
|
}
|
|
1461
1465
|
|
|
1462
1466
|
// ../../../packages/aeg-core/src/doc-owners.ts
|
|
@@ -1644,6 +1648,27 @@ function overrideActive(opts) {
|
|
|
1644
1648
|
// ../../../packages/aeg-core/src/premise-check.ts
|
|
1645
1649
|
var ASSERTION_KINDS = new Set(["contains", "absent", "sha256"]);
|
|
1646
1650
|
|
|
1651
|
+
// ../../../packages/aeg-core/src/test-plan-section.ts
|
|
1652
|
+
var HEADING_FORM_RE = /^#{1,4}[ \t]*(?:\d+[a-z]?\.[ \t]*)?\*{0,2}Test Plan\*{0,2}[ \t]*$/im;
|
|
1653
|
+
var INLINE_FORM_RE = /^[ \t]*\*{0,2}Test Plan:?\*{0,2}/im;
|
|
1654
|
+
var NEXT_SECTION_RE = /\n(?:#{1,3}[ \t]|\*\*[A-Z][^*\n]*:\*\*)/;
|
|
1655
|
+
function locateTestPlanSection(body) {
|
|
1656
|
+
const region = anchoredRegion(body, "TEST-PLAN");
|
|
1657
|
+
if (region !== null)
|
|
1658
|
+
return { found: true, section: region };
|
|
1659
|
+
const headingMatch = HEADING_FORM_RE.exec(body);
|
|
1660
|
+
const match = headingMatch ?? INLINE_FORM_RE.exec(body);
|
|
1661
|
+
if (!match || match.index === undefined)
|
|
1662
|
+
return { found: false };
|
|
1663
|
+
const sectionBody = body.slice(match.index);
|
|
1664
|
+
const firstLineEnd = sectionBody.indexOf(`
|
|
1665
|
+
`);
|
|
1666
|
+
const searchFrom = firstLineEnd === -1 ? sectionBody.length : firstLineEnd + 1;
|
|
1667
|
+
const nextMatch = sectionBody.slice(searchFrom).match(NEXT_SECTION_RE);
|
|
1668
|
+
const sectionEnd = nextMatch ? searchFrom + (nextMatch.index ?? 0) : sectionBody.length;
|
|
1669
|
+
return { found: true, section: sectionBody.slice(0, sectionEnd) };
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1647
1672
|
// ../../../packages/aeg-core/src/brief-validation.ts
|
|
1648
1673
|
function headerRegion(prBody) {
|
|
1649
1674
|
const m = prBody.match(/^##\s/m);
|
|
@@ -1682,10 +1707,15 @@ function checkTierField(prBody, readTier) {
|
|
|
1682
1707
|
};
|
|
1683
1708
|
}
|
|
1684
1709
|
var TEST_PLAN_UNIT_TESTS_ONLY_RE = /(?:\*\*)?Test Plan(?:\*\*)?\s*:\s*(?:\*\*)?\s*unit-tests-only/i;
|
|
1710
|
+
function testPlanRegion(prBody) {
|
|
1711
|
+
const located = locateTestPlanSection(prBody);
|
|
1712
|
+
return located.found ? located.section : prBody;
|
|
1713
|
+
}
|
|
1685
1714
|
function checkTestPlan(prBody) {
|
|
1686
|
-
|
|
1715
|
+
const region = testPlanRegion(prBody);
|
|
1716
|
+
if (TEST_PLAN_UNIT_TESTS_ONLY_RE.test(region))
|
|
1687
1717
|
return { status: "pass", errors: [] };
|
|
1688
|
-
if (/\*\*\[(?:agent|principal)\]\*\*/.test(
|
|
1718
|
+
if (/\*\*\[(?:agent|principal)\]\*\*/.test(region))
|
|
1689
1719
|
return { status: "pass", errors: [] };
|
|
1690
1720
|
return {
|
|
1691
1721
|
status: "fail",
|
|
@@ -1695,9 +1725,10 @@ function checkTestPlan(prBody) {
|
|
|
1695
1725
|
};
|
|
1696
1726
|
}
|
|
1697
1727
|
function checkTestPlanExclusivity(prBody) {
|
|
1698
|
-
|
|
1728
|
+
const region = testPlanRegion(prBody);
|
|
1729
|
+
if (!TEST_PLAN_UNIT_TESTS_ONLY_RE.test(region))
|
|
1699
1730
|
return { status: "pass", errors: [] };
|
|
1700
|
-
if (/^-\s*\[[ xX]\]\s*\*{2}\[(?:agent|principal)\]\*{2}/im.test(
|
|
1731
|
+
if (/^-\s*\[[ xX]\]\s*\*{2}\[(?:agent|principal)\]\*{2}/im.test(region)) {
|
|
1701
1732
|
return {
|
|
1702
1733
|
status: "fail",
|
|
1703
1734
|
errors: [
|
|
@@ -1708,8 +1739,9 @@ function checkTestPlanExclusivity(prBody) {
|
|
|
1708
1739
|
return { status: "pass", errors: [] };
|
|
1709
1740
|
}
|
|
1710
1741
|
function checkPrincipalPlaceholder(prBody) {
|
|
1742
|
+
const region = testPlanRegion(prBody);
|
|
1711
1743
|
const lineRe = /^-\s*\[[ xX]\]\s*\*{2}\[principal\]\*{2}(.*)$/gim;
|
|
1712
|
-
for (const m of
|
|
1744
|
+
for (const m of region.matchAll(lineRe)) {
|
|
1713
1745
|
const content = m[1] ?? "";
|
|
1714
1746
|
if (/^\s*None\b/i.test(content)) {
|
|
1715
1747
|
return {
|
|
@@ -2157,11 +2189,12 @@ function isReviewGateExemptBranch(branch) {
|
|
|
2157
2189
|
return branch.startsWith("plan/");
|
|
2158
2190
|
}
|
|
2159
2191
|
function checkReviewGate(input) {
|
|
2192
|
+
const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
|
|
2160
2193
|
const waived = isWaiverLabelActorVerified({
|
|
2161
2194
|
label: WAIVER_LABEL_REVIEW,
|
|
2162
2195
|
labels: input.labels,
|
|
2163
2196
|
labelActor: input.waiverLabelActor,
|
|
2164
|
-
principalAllowlist
|
|
2197
|
+
principalAllowlist
|
|
2165
2198
|
});
|
|
2166
2199
|
if (waived) {
|
|
2167
2200
|
return {
|
|
@@ -2170,8 +2203,8 @@ function checkReviewGate(input) {
|
|
|
2170
2203
|
waived: true
|
|
2171
2204
|
};
|
|
2172
2205
|
}
|
|
2173
|
-
const verified = input.comments.filter((c) => c.author
|
|
2174
|
-
const ignoredCount = input.comments.filter((c) => (c.author
|
|
2206
|
+
const verified = input.comments.filter((c) => isPrincipal(c.author, principalAllowlist));
|
|
2207
|
+
const ignoredCount = input.comments.filter((c) => !isPrincipal(c.author, principalAllowlist) && c.body.includes("VERDICT")).length;
|
|
2175
2208
|
const verifiedBodies = verified.map((c) => c.body);
|
|
2176
2209
|
const codeReview = extractCodeReviewVerdict(verifiedBodies);
|
|
2177
2210
|
const security = extractSecurityReviewVerdict(verifiedBodies);
|
|
@@ -2724,26 +2757,6 @@ function decideIssueAssignment(input) {
|
|
|
2724
2757
|
reason: `First push of \`${branch}\` — assigning Issue #${issue} to @${login} (the authenticated pusher).`
|
|
2725
2758
|
};
|
|
2726
2759
|
}
|
|
2727
|
-
// ../../../packages/aeg-core/src/test-plan-section.ts
|
|
2728
|
-
var HEADING_FORM_RE = /^#{1,4}[ \t]*(?:\d+[a-z]?\.[ \t]*)?\*{0,2}Test Plan\*{0,2}[ \t]*$/im;
|
|
2729
|
-
var INLINE_FORM_RE = /^[ \t]*\*{0,2}Test Plan:?\*{0,2}/im;
|
|
2730
|
-
var NEXT_SECTION_RE = /\n(?:#{1,3}[ \t]|\*\*[A-Z][^*\n]*:\*\*)/;
|
|
2731
|
-
function locateTestPlanSection(body) {
|
|
2732
|
-
const region = anchoredRegion(body, "TEST-PLAN");
|
|
2733
|
-
if (region !== null)
|
|
2734
|
-
return { found: true, section: region };
|
|
2735
|
-
const headingMatch = HEADING_FORM_RE.exec(body);
|
|
2736
|
-
const match = headingMatch ?? INLINE_FORM_RE.exec(body);
|
|
2737
|
-
if (!match || match.index === undefined)
|
|
2738
|
-
return { found: false };
|
|
2739
|
-
const sectionBody = body.slice(match.index);
|
|
2740
|
-
const firstLineEnd = sectionBody.indexOf(`
|
|
2741
|
-
`);
|
|
2742
|
-
const searchFrom = firstLineEnd === -1 ? sectionBody.length : firstLineEnd + 1;
|
|
2743
|
-
const nextMatch = sectionBody.slice(searchFrom).match(NEXT_SECTION_RE);
|
|
2744
|
-
const sectionEnd = nextMatch ? searchFrom + (nextMatch.index ?? 0) : sectionBody.length;
|
|
2745
|
-
return { found: true, section: sectionBody.slice(0, sectionEnd) };
|
|
2746
|
-
}
|
|
2747
2760
|
// ../../../packages/aeg-core/src/test-plan-gate.ts
|
|
2748
2761
|
var TASK_BRANCH_PATTERN = /^task\/[^/]+\/[^/]+$/;
|
|
2749
2762
|
function evaluateTestPlanGate(body, branch) {
|
|
@@ -1448,12 +1448,16 @@ function isCodeFile(p) {
|
|
|
1448
1448
|
var WAIVER_LABEL = label("waiver-docs");
|
|
1449
1449
|
var WAIVER_LABEL_REVIEW = label("waiver-review");
|
|
1450
1450
|
var PRINCIPAL_ALLOWLIST = ["daniboomerang"];
|
|
1451
|
+
function isPrincipal(login, principalAllowlist) {
|
|
1452
|
+
if (login === null)
|
|
1453
|
+
return false;
|
|
1454
|
+
const normalized = login.toLowerCase();
|
|
1455
|
+
return principalAllowlist.some((p) => p.toLowerCase() === normalized);
|
|
1456
|
+
}
|
|
1451
1457
|
function isWaiverLabelActorVerified(opts) {
|
|
1452
1458
|
if (!opts.labels.includes(opts.label))
|
|
1453
1459
|
return false;
|
|
1454
|
-
|
|
1455
|
-
return false;
|
|
1456
|
-
return opts.principalAllowlist.includes(opts.labelActor);
|
|
1460
|
+
return isPrincipal(opts.labelActor, opts.principalAllowlist);
|
|
1457
1461
|
}
|
|
1458
1462
|
|
|
1459
1463
|
// ../../../packages/aeg-core/src/doc-owners.ts
|
|
@@ -1641,6 +1645,27 @@ function overrideActive(opts) {
|
|
|
1641
1645
|
// ../../../packages/aeg-core/src/premise-check.ts
|
|
1642
1646
|
var ASSERTION_KINDS = new Set(["contains", "absent", "sha256"]);
|
|
1643
1647
|
|
|
1648
|
+
// ../../../packages/aeg-core/src/test-plan-section.ts
|
|
1649
|
+
var HEADING_FORM_RE = /^#{1,4}[ \t]*(?:\d+[a-z]?\.[ \t]*)?\*{0,2}Test Plan\*{0,2}[ \t]*$/im;
|
|
1650
|
+
var INLINE_FORM_RE = /^[ \t]*\*{0,2}Test Plan:?\*{0,2}/im;
|
|
1651
|
+
var NEXT_SECTION_RE = /\n(?:#{1,3}[ \t]|\*\*[A-Z][^*\n]*:\*\*)/;
|
|
1652
|
+
function locateTestPlanSection(body) {
|
|
1653
|
+
const region = anchoredRegion(body, "TEST-PLAN");
|
|
1654
|
+
if (region !== null)
|
|
1655
|
+
return { found: true, section: region };
|
|
1656
|
+
const headingMatch = HEADING_FORM_RE.exec(body);
|
|
1657
|
+
const match = headingMatch ?? INLINE_FORM_RE.exec(body);
|
|
1658
|
+
if (!match || match.index === undefined)
|
|
1659
|
+
return { found: false };
|
|
1660
|
+
const sectionBody = body.slice(match.index);
|
|
1661
|
+
const firstLineEnd = sectionBody.indexOf(`
|
|
1662
|
+
`);
|
|
1663
|
+
const searchFrom = firstLineEnd === -1 ? sectionBody.length : firstLineEnd + 1;
|
|
1664
|
+
const nextMatch = sectionBody.slice(searchFrom).match(NEXT_SECTION_RE);
|
|
1665
|
+
const sectionEnd = nextMatch ? searchFrom + (nextMatch.index ?? 0) : sectionBody.length;
|
|
1666
|
+
return { found: true, section: sectionBody.slice(0, sectionEnd) };
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1644
1669
|
// ../../../packages/aeg-core/src/brief-validation.ts
|
|
1645
1670
|
function headerRegion(prBody) {
|
|
1646
1671
|
const m = prBody.match(/^##\s/m);
|
|
@@ -1679,10 +1704,15 @@ function checkTierField(prBody, readTier) {
|
|
|
1679
1704
|
};
|
|
1680
1705
|
}
|
|
1681
1706
|
var TEST_PLAN_UNIT_TESTS_ONLY_RE = /(?:\*\*)?Test Plan(?:\*\*)?\s*:\s*(?:\*\*)?\s*unit-tests-only/i;
|
|
1707
|
+
function testPlanRegion(prBody) {
|
|
1708
|
+
const located = locateTestPlanSection(prBody);
|
|
1709
|
+
return located.found ? located.section : prBody;
|
|
1710
|
+
}
|
|
1682
1711
|
function checkTestPlan(prBody) {
|
|
1683
|
-
|
|
1712
|
+
const region = testPlanRegion(prBody);
|
|
1713
|
+
if (TEST_PLAN_UNIT_TESTS_ONLY_RE.test(region))
|
|
1684
1714
|
return { status: "pass", errors: [] };
|
|
1685
|
-
if (/\*\*\[(?:agent|principal)\]\*\*/.test(
|
|
1715
|
+
if (/\*\*\[(?:agent|principal)\]\*\*/.test(region))
|
|
1686
1716
|
return { status: "pass", errors: [] };
|
|
1687
1717
|
return {
|
|
1688
1718
|
status: "fail",
|
|
@@ -1692,9 +1722,10 @@ function checkTestPlan(prBody) {
|
|
|
1692
1722
|
};
|
|
1693
1723
|
}
|
|
1694
1724
|
function checkTestPlanExclusivity(prBody) {
|
|
1695
|
-
|
|
1725
|
+
const region = testPlanRegion(prBody);
|
|
1726
|
+
if (!TEST_PLAN_UNIT_TESTS_ONLY_RE.test(region))
|
|
1696
1727
|
return { status: "pass", errors: [] };
|
|
1697
|
-
if (/^-\s*\[[ xX]\]\s*\*{2}\[(?:agent|principal)\]\*{2}/im.test(
|
|
1728
|
+
if (/^-\s*\[[ xX]\]\s*\*{2}\[(?:agent|principal)\]\*{2}/im.test(region)) {
|
|
1698
1729
|
return {
|
|
1699
1730
|
status: "fail",
|
|
1700
1731
|
errors: [
|
|
@@ -1705,8 +1736,9 @@ function checkTestPlanExclusivity(prBody) {
|
|
|
1705
1736
|
return { status: "pass", errors: [] };
|
|
1706
1737
|
}
|
|
1707
1738
|
function checkPrincipalPlaceholder(prBody) {
|
|
1739
|
+
const region = testPlanRegion(prBody);
|
|
1708
1740
|
const lineRe = /^-\s*\[[ xX]\]\s*\*{2}\[principal\]\*{2}(.*)$/gim;
|
|
1709
|
-
for (const m of
|
|
1741
|
+
for (const m of region.matchAll(lineRe)) {
|
|
1710
1742
|
const content = m[1] ?? "";
|
|
1711
1743
|
if (/^\s*None\b/i.test(content)) {
|
|
1712
1744
|
return {
|
|
@@ -2154,11 +2186,12 @@ function isReviewGateExemptBranch(branch) {
|
|
|
2154
2186
|
return branch.startsWith("plan/");
|
|
2155
2187
|
}
|
|
2156
2188
|
function checkReviewGate(input) {
|
|
2189
|
+
const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
|
|
2157
2190
|
const waived = isWaiverLabelActorVerified({
|
|
2158
2191
|
label: WAIVER_LABEL_REVIEW,
|
|
2159
2192
|
labels: input.labels,
|
|
2160
2193
|
labelActor: input.waiverLabelActor,
|
|
2161
|
-
principalAllowlist
|
|
2194
|
+
principalAllowlist
|
|
2162
2195
|
});
|
|
2163
2196
|
if (waived) {
|
|
2164
2197
|
return {
|
|
@@ -2167,8 +2200,8 @@ function checkReviewGate(input) {
|
|
|
2167
2200
|
waived: true
|
|
2168
2201
|
};
|
|
2169
2202
|
}
|
|
2170
|
-
const verified = input.comments.filter((c) => c.author
|
|
2171
|
-
const ignoredCount = input.comments.filter((c) => (c.author
|
|
2203
|
+
const verified = input.comments.filter((c) => isPrincipal(c.author, principalAllowlist));
|
|
2204
|
+
const ignoredCount = input.comments.filter((c) => !isPrincipal(c.author, principalAllowlist) && c.body.includes("VERDICT")).length;
|
|
2172
2205
|
const verifiedBodies = verified.map((c) => c.body);
|
|
2173
2206
|
const codeReview = extractCodeReviewVerdict(verifiedBodies);
|
|
2174
2207
|
const security = extractSecurityReviewVerdict(verifiedBodies);
|
|
@@ -2721,26 +2754,6 @@ function decideIssueAssignment(input) {
|
|
|
2721
2754
|
reason: `First push of \`${branch}\` — assigning Issue #${issue} to @${login} (the authenticated pusher).`
|
|
2722
2755
|
};
|
|
2723
2756
|
}
|
|
2724
|
-
// ../../../packages/aeg-core/src/test-plan-section.ts
|
|
2725
|
-
var HEADING_FORM_RE = /^#{1,4}[ \t]*(?:\d+[a-z]?\.[ \t]*)?\*{0,2}Test Plan\*{0,2}[ \t]*$/im;
|
|
2726
|
-
var INLINE_FORM_RE = /^[ \t]*\*{0,2}Test Plan:?\*{0,2}/im;
|
|
2727
|
-
var NEXT_SECTION_RE = /\n(?:#{1,3}[ \t]|\*\*[A-Z][^*\n]*:\*\*)/;
|
|
2728
|
-
function locateTestPlanSection(body) {
|
|
2729
|
-
const region = anchoredRegion(body, "TEST-PLAN");
|
|
2730
|
-
if (region !== null)
|
|
2731
|
-
return { found: true, section: region };
|
|
2732
|
-
const headingMatch = HEADING_FORM_RE.exec(body);
|
|
2733
|
-
const match = headingMatch ?? INLINE_FORM_RE.exec(body);
|
|
2734
|
-
if (!match || match.index === undefined)
|
|
2735
|
-
return { found: false };
|
|
2736
|
-
const sectionBody = body.slice(match.index);
|
|
2737
|
-
const firstLineEnd = sectionBody.indexOf(`
|
|
2738
|
-
`);
|
|
2739
|
-
const searchFrom = firstLineEnd === -1 ? sectionBody.length : firstLineEnd + 1;
|
|
2740
|
-
const nextMatch = sectionBody.slice(searchFrom).match(NEXT_SECTION_RE);
|
|
2741
|
-
const sectionEnd = nextMatch ? searchFrom + (nextMatch.index ?? 0) : sectionBody.length;
|
|
2742
|
-
return { found: true, section: sectionBody.slice(0, sectionEnd) };
|
|
2743
|
-
}
|
|
2744
2757
|
// ../../../packages/aeg-core/src/test-plan-gate.ts
|
|
2745
2758
|
var TASK_BRANCH_PATTERN = /^task\/[^/]+\/[^/]+$/;
|
|
2746
2759
|
function evaluateTestPlanGate(body, branch) {
|