@attalabs/vinaya 0.12.0 → 0.17.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/README.md +33 -3
- package/aeg-root/contracts/planner-brief.md +1 -1
- package/aeg-root/enforcement.md +5 -5
- package/aeg-root/roles/developer.md +1 -0
- package/aeg-root/roles/planner.md +2 -2
- package/aeg-root/roles/reviewer.md +17 -4
- package/aeg-root/roles/security.md +16 -5
- package/aeg-root/skills/aeg/SKILL.md +1 -1
- package/aeg-root/state-machine.md +2 -2
- package/aeg-root/templates/pr-report-template.md +2 -0
- package/aeg-root/tranche-model.md +1 -1
- package/dist/checks/bin/check-body-bare-digits.js +3545 -0
- package/dist/checks/bin/check-branch-topology.js +99 -10
- package/dist/checks/bin/check-brief-shape.js +99 -10
- package/dist/checks/bin/check-closes-n.js +99 -10
- package/dist/checks/bin/check-coherence.js +106 -12
- package/dist/checks/bin/check-dead-branch-push.js +99 -10
- package/dist/checks/bin/check-dispatch-readiness.js +106 -12
- package/dist/checks/bin/check-doc-coverage-push.js +106 -12
- package/dist/checks/bin/check-doc-coverage.js +109 -16
- package/dist/checks/bin/check-evidence-fresh.js +99 -10
- package/dist/checks/bin/check-first-push-dispatch.js +106 -12
- package/dist/checks/bin/check-issue-assignment.js +99 -10
- package/dist/checks/bin/check-no-disk-state.js +99 -10
- package/dist/checks/bin/check-reader-resolvable-prose.js +99 -10
- package/dist/checks/bin/check-registry-gates.js +99 -10
- package/dist/checks/bin/check-review-gate.js +109 -25
- package/dist/checks/bin/check-single-plan-pr.js +99 -10
- package/dist/checks/bin/check-test-plan.js +99 -10
- package/dist/index.js +1325 -236
- package/package.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/BUILD_ID +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/build-manifest.json +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/prerender-manifest.json +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/required-server-files.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.html +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/api/coherence/route.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/[root-of-the-server]__0e95dv5._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/1q96_modules_@clerk_nextjs_dist_esm_app-router_client_keyless-creator-reader_0lom2js.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__029-1ch._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0gw1_g2._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0q56ohl._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0rr_lq7._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0zfjc2o._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__19jyp3m._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1_ojzp1._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__1wsl6ro._.js → [root-of-the-server]__1ccgndq._.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1d_8nm4._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1dfzjrd._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1zkwtx8._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__210ehg9._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0-n77dx._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_00yjcv1._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_01605g7._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0o54suy._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0rix02i._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_1u3abhy._.js → _0x999pb._.js} +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_0ndy563._.js → _1-6rzip._.js} +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_18-d2be._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_087xa25._.js → _1_talrs._.js} +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_11vnfnm._.js → _1ar5uqe._.js} +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_02drwa_._.js → _1c9b9j-._.js} +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1fqw88f._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1gw6vc9._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/apps_vinaya-studio_web_src_app_studio_18kqbvs._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/apps_vinaya-studio_web_src_app_studio_projects_[name]_tranches_[slug]_20yap_f._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_1vo08dj._.js +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/packages_ui_libraries_animate_components_index_ts_186fje1._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/packages_ui_libraries_basic_components_index_ts_0xk1vda._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/middleware-build-manifest.js +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/server/pages/500.html +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.json +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{1mexqnauhtbtp.js → 0_jnwbarv-cqk.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{2ieu4oi-pp_bz.js → 0l_vubs1ephe5.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/0ojfbn3yvy-8_.js +1 -0
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{1jx5_q1g9l-cm.js → 0phqfqwbnt_ey.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0qcu17x3h94a9.js → 17r0szvqeeyhx.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0ve1-nz-mu_lr.js → 18x3rbqzeutpz.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{22y4d5yrovcv-.js → 1bqpfvromtwn1.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{39w6jbw3rleez.js → 24ojyzmt_fkg3.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/27sqffqm2wbxx.css +1 -0
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0tmcnl-z8yt2_.js → 30lyvn0yzwdiz.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{1khy4oilrab6g.js → 3m0_gk59s-rbx.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{1eo32v1tbjy7c.js → 40x7f5hm7a5tk.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0-08g_jjalnd9.js → 453zhecht_m1q.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/server.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/0qu0xgvifbacu.css +0 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/1t7yy_s34022p.js +0 -1
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{ZHVE9Y9G8XKR91g27SgVX → p5sWGp4ANwORiaX4Kk6U2}/_buildManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{ZHVE9Y9G8XKR91g27SgVX → p5sWGp4ANwORiaX4Kk6U2}/_clientMiddlewareManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{ZHVE9Y9G8XKR91g27SgVX → p5sWGp4ANwORiaX4Kk6U2}/_ssgManifest.js +0 -0
|
@@ -7,7 +7,27 @@ import { fileURLToPath } from "node:url";
|
|
|
7
7
|
// ../../packages/aeg-forge-state/src/strip-code.ts
|
|
8
8
|
function maskCode(body) {
|
|
9
9
|
const fill = (line) => " ".repeat(line.length);
|
|
10
|
-
|
|
10
|
+
const blocksMasked = maskIndentedCode(maskFencedCode(body, fill), fill);
|
|
11
|
+
return blocksMasked.split(`
|
|
12
|
+
`).map((line) => replaceInlineSpans(line, (span) => " ".repeat(span.length))).join(`
|
|
13
|
+
`);
|
|
14
|
+
}
|
|
15
|
+
var DETAILS_OPEN = /<details\b[^>]*>/gi;
|
|
16
|
+
var DETAILS_CLOSE = /<\/details\s*>/gi;
|
|
17
|
+
function maskDetailsBlocks(body) {
|
|
18
|
+
const fill = (line) => " ".repeat(line.length);
|
|
19
|
+
const lines = body.split(`
|
|
20
|
+
`);
|
|
21
|
+
let depth = 0;
|
|
22
|
+
const out = lines.map((line) => {
|
|
23
|
+
const opens = line.match(DETAILS_OPEN)?.length ?? 0;
|
|
24
|
+
const closes = line.match(DETAILS_CLOSE)?.length ?? 0;
|
|
25
|
+
const maskThisLine = depth > 0 || opens > 0;
|
|
26
|
+
depth = Math.max(0, depth + opens - closes);
|
|
27
|
+
return maskThisLine ? fill(line) : line;
|
|
28
|
+
});
|
|
29
|
+
return out.join(`
|
|
30
|
+
`);
|
|
11
31
|
}
|
|
12
32
|
function stripCode(body, options = {}) {
|
|
13
33
|
const normalised = body.replace(/\r\n?/g, `
|
|
@@ -16,7 +36,50 @@ function stripCode(body, options = {}) {
|
|
|
16
36
|
const blocksStripped = maskIndentedCode(maskFencedCode(normalised, blank), blank);
|
|
17
37
|
if (options.inlineSpans === "keep")
|
|
18
38
|
return blocksStripped;
|
|
19
|
-
return blocksStripped.
|
|
39
|
+
return blocksStripped.split(`
|
|
40
|
+
`).map((line) => replaceInlineSpans(line, () => "")).join(`
|
|
41
|
+
`);
|
|
42
|
+
}
|
|
43
|
+
function replaceInlineSpans(line, replace) {
|
|
44
|
+
let result = "";
|
|
45
|
+
let i = 0;
|
|
46
|
+
const runLengthAt = (at) => {
|
|
47
|
+
let j = at;
|
|
48
|
+
while (j < line.length && line[j] === "`")
|
|
49
|
+
j++;
|
|
50
|
+
return j - at;
|
|
51
|
+
};
|
|
52
|
+
while (i < line.length) {
|
|
53
|
+
if (line[i] !== "`") {
|
|
54
|
+
result += line[i];
|
|
55
|
+
i++;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const openLen = runLengthAt(i);
|
|
59
|
+
const openEnd = i + openLen;
|
|
60
|
+
let j = openEnd;
|
|
61
|
+
let closeEnd = -1;
|
|
62
|
+
while (j < line.length) {
|
|
63
|
+
if (line[j] !== "`") {
|
|
64
|
+
j++;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const runLen = runLengthAt(j);
|
|
68
|
+
if (runLen === openLen) {
|
|
69
|
+
closeEnd = j + runLen;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
j += runLen;
|
|
73
|
+
}
|
|
74
|
+
if (closeEnd === -1) {
|
|
75
|
+
result += line.slice(i, openEnd);
|
|
76
|
+
i = openEnd;
|
|
77
|
+
} else {
|
|
78
|
+
result += replace(line.slice(i, closeEnd));
|
|
79
|
+
i = closeEnd;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
20
83
|
}
|
|
21
84
|
var FENCE_OPEN = /^ {0,3}(`{3,}|~{3,})([^\r\n]*)\r?$/;
|
|
22
85
|
var FENCE_CLOSE = /^ {0,3}(`+|~+)[ \t]*\r?$/;
|
|
@@ -1755,9 +1818,10 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive,
|
|
|
1755
1818
|
return out;
|
|
1756
1819
|
}
|
|
1757
1820
|
// ../../packages/aeg-core/src/pr-tier.ts
|
|
1821
|
+
var TIER_FIELD = /(\*\*)?\s*Tier\s*(\*\*)?\s*:\s*(\*\*)?\s*([013])\b/i;
|
|
1758
1822
|
function readTierFromPrBody(prBody) {
|
|
1759
1823
|
const searchIn = anchoredRegion(prBody, "TIER") ?? prBody;
|
|
1760
|
-
const m = searchIn.match(
|
|
1824
|
+
const m = searchIn.match(TIER_FIELD);
|
|
1761
1825
|
if (!m)
|
|
1762
1826
|
return null;
|
|
1763
1827
|
const t = Number(m[4]);
|
|
@@ -2370,15 +2434,25 @@ function checkClosesN2(branch, prBody, trancheFiles, taskIssueRefs) {
|
|
|
2370
2434
|
return { ok: true, expectedIssue };
|
|
2371
2435
|
}
|
|
2372
2436
|
// ../../packages/aeg-core/src/verdict-extraction.ts
|
|
2437
|
+
var HEAD_SHA_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Judged head:\s*([0-9a-f]{7,40})(?![A-Za-z0-9])/im;
|
|
2438
|
+
function extractHeadSha(comment) {
|
|
2439
|
+
const m = comment.match(HEAD_SHA_PATTERN);
|
|
2440
|
+
return m ? m[1].toLowerCase() : null;
|
|
2441
|
+
}
|
|
2373
2442
|
function extractVerdict(comments, valuePattern, missingLabel) {
|
|
2374
2443
|
const clearHits = comments.filter((c) => valuePattern.test(c));
|
|
2375
2444
|
if (clearHits.length > 0) {
|
|
2376
2445
|
const latest = clearHits[clearHits.length - 1];
|
|
2377
2446
|
const m = latest.match(valuePattern);
|
|
2378
|
-
return {
|
|
2447
|
+
return {
|
|
2448
|
+
value: m[1].toUpperCase().replace(/[_-]/g, " "),
|
|
2449
|
+
headSha: extractHeadSha(latest),
|
|
2450
|
+
danglingNote: null
|
|
2451
|
+
};
|
|
2379
2452
|
}
|
|
2380
2453
|
return {
|
|
2381
2454
|
value: `no ${missingLabel} pass was run before merge — DANGLING, see below`,
|
|
2455
|
+
headSha: null,
|
|
2382
2456
|
danglingNote: `no ${missingLabel} verdict comment found on this PR`
|
|
2383
2457
|
};
|
|
2384
2458
|
}
|
|
@@ -2389,8 +2463,10 @@ function extractSecurityReviewVerdict(comments) {
|
|
|
2389
2463
|
return extractVerdict(comments, /^[ \t]*(?:\*{1,3}|_{1,3})?VERDICT:\s*(PASS|FAIL)(?![A-Za-z0-9])/im, "security-review");
|
|
2390
2464
|
}
|
|
2391
2465
|
// ../../packages/aeg-core/src/review-gate.ts
|
|
2392
|
-
function
|
|
2393
|
-
|
|
2466
|
+
function isBoundToHead(extraction, headSha) {
|
|
2467
|
+
if (!extraction.headSha)
|
|
2468
|
+
return false;
|
|
2469
|
+
return headSha.toLowerCase().startsWith(extraction.headSha.toLowerCase());
|
|
2394
2470
|
}
|
|
2395
2471
|
function checkReviewGate(input) {
|
|
2396
2472
|
const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
|
|
@@ -2414,18 +2490,26 @@ function checkReviewGate(input) {
|
|
|
2414
2490
|
const security = extractSecurityReviewVerdict(verifiedBodies);
|
|
2415
2491
|
const codeReviewClean = codeReview.value === "APPROVE";
|
|
2416
2492
|
const securityClean = security.value === "PASS";
|
|
2417
|
-
|
|
2493
|
+
const codeReviewBound = isBoundToHead(codeReview, input.headSha);
|
|
2494
|
+
const securityBound = isBoundToHead(security, input.headSha);
|
|
2495
|
+
if (codeReviewClean && codeReviewBound && securityClean && securityBound) {
|
|
2418
2496
|
return {
|
|
2419
2497
|
verdict: "pass",
|
|
2420
|
-
reason:
|
|
2498
|
+
reason: `code-reviewer verdict is a clean APPROVE and security-review verdict is a clean PASS, both covering head ${input.headSha}.`,
|
|
2421
2499
|
waived: false
|
|
2422
2500
|
};
|
|
2423
2501
|
}
|
|
2424
2502
|
const problems = [];
|
|
2425
|
-
if (!codeReviewClean)
|
|
2503
|
+
if (!codeReviewClean) {
|
|
2426
2504
|
problems.push(`code-reviewer verdict is not a clean APPROVE (found: ${codeReview.value})`);
|
|
2427
|
-
if (!
|
|
2505
|
+
} else if (!codeReviewBound) {
|
|
2506
|
+
problems.push(`the newest code-review verdict covers ${codeReview.headSha ?? "no recorded commit"}, head is ${input.headSha}`);
|
|
2507
|
+
}
|
|
2508
|
+
if (!securityClean) {
|
|
2428
2509
|
problems.push(`security-review verdict is not a clean PASS (found: ${security.value})`);
|
|
2510
|
+
} else if (!securityBound) {
|
|
2511
|
+
problems.push(`the newest security-review verdict covers ${security.headSha ?? "no recorded commit"}, head is ${input.headSha}`);
|
|
2512
|
+
}
|
|
2429
2513
|
const ignoredNote = ignoredCount > 0 ? ` ${ignoredCount} verdict-shaped comment(s) from authors outside the principal allowlist were ignored.` : "";
|
|
2430
2514
|
return {
|
|
2431
2515
|
verdict: "fail",
|
|
@@ -2433,6 +2517,11 @@ function checkReviewGate(input) {
|
|
|
2433
2517
|
waived: false
|
|
2434
2518
|
};
|
|
2435
2519
|
}
|
|
2520
|
+
var CHANGESET_RELEASE_BRANCH = "changeset-release/main";
|
|
2521
|
+
var DEFAULT_RELEASE_ACTOR = "github-actions[bot]";
|
|
2522
|
+
function isChangesetsReleasePr(branch, author, expectedAuthor) {
|
|
2523
|
+
return branch === CHANGESET_RELEASE_BRANCH && author === expectedAuthor;
|
|
2524
|
+
}
|
|
2436
2525
|
// ../../packages/aeg-core/src/markdown-table.ts
|
|
2437
2526
|
function splitRow(line) {
|
|
2438
2527
|
const trimmed = line.trim().replace(/^\|/, "").replace(/\|$/, "");
|
|
@@ -7,7 +7,27 @@ import matter2 from "gray-matter";
|
|
|
7
7
|
// ../../packages/aeg-forge-state/src/strip-code.ts
|
|
8
8
|
function maskCode(body) {
|
|
9
9
|
const fill = (line) => " ".repeat(line.length);
|
|
10
|
-
|
|
10
|
+
const blocksMasked = maskIndentedCode(maskFencedCode(body, fill), fill);
|
|
11
|
+
return blocksMasked.split(`
|
|
12
|
+
`).map((line) => replaceInlineSpans(line, (span) => " ".repeat(span.length))).join(`
|
|
13
|
+
`);
|
|
14
|
+
}
|
|
15
|
+
var DETAILS_OPEN = /<details\b[^>]*>/gi;
|
|
16
|
+
var DETAILS_CLOSE = /<\/details\s*>/gi;
|
|
17
|
+
function maskDetailsBlocks(body) {
|
|
18
|
+
const fill = (line) => " ".repeat(line.length);
|
|
19
|
+
const lines = body.split(`
|
|
20
|
+
`);
|
|
21
|
+
let depth = 0;
|
|
22
|
+
const out = lines.map((line) => {
|
|
23
|
+
const opens = line.match(DETAILS_OPEN)?.length ?? 0;
|
|
24
|
+
const closes = line.match(DETAILS_CLOSE)?.length ?? 0;
|
|
25
|
+
const maskThisLine = depth > 0 || opens > 0;
|
|
26
|
+
depth = Math.max(0, depth + opens - closes);
|
|
27
|
+
return maskThisLine ? fill(line) : line;
|
|
28
|
+
});
|
|
29
|
+
return out.join(`
|
|
30
|
+
`);
|
|
11
31
|
}
|
|
12
32
|
function stripCode(body, options = {}) {
|
|
13
33
|
const normalised = body.replace(/\r\n?/g, `
|
|
@@ -16,7 +36,50 @@ function stripCode(body, options = {}) {
|
|
|
16
36
|
const blocksStripped = maskIndentedCode(maskFencedCode(normalised, blank), blank);
|
|
17
37
|
if (options.inlineSpans === "keep")
|
|
18
38
|
return blocksStripped;
|
|
19
|
-
return blocksStripped.
|
|
39
|
+
return blocksStripped.split(`
|
|
40
|
+
`).map((line) => replaceInlineSpans(line, () => "")).join(`
|
|
41
|
+
`);
|
|
42
|
+
}
|
|
43
|
+
function replaceInlineSpans(line, replace) {
|
|
44
|
+
let result = "";
|
|
45
|
+
let i = 0;
|
|
46
|
+
const runLengthAt = (at) => {
|
|
47
|
+
let j = at;
|
|
48
|
+
while (j < line.length && line[j] === "`")
|
|
49
|
+
j++;
|
|
50
|
+
return j - at;
|
|
51
|
+
};
|
|
52
|
+
while (i < line.length) {
|
|
53
|
+
if (line[i] !== "`") {
|
|
54
|
+
result += line[i];
|
|
55
|
+
i++;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const openLen = runLengthAt(i);
|
|
59
|
+
const openEnd = i + openLen;
|
|
60
|
+
let j = openEnd;
|
|
61
|
+
let closeEnd = -1;
|
|
62
|
+
while (j < line.length) {
|
|
63
|
+
if (line[j] !== "`") {
|
|
64
|
+
j++;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const runLen = runLengthAt(j);
|
|
68
|
+
if (runLen === openLen) {
|
|
69
|
+
closeEnd = j + runLen;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
j += runLen;
|
|
73
|
+
}
|
|
74
|
+
if (closeEnd === -1) {
|
|
75
|
+
result += line.slice(i, openEnd);
|
|
76
|
+
i = openEnd;
|
|
77
|
+
} else {
|
|
78
|
+
result += replace(line.slice(i, closeEnd));
|
|
79
|
+
i = closeEnd;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
20
83
|
}
|
|
21
84
|
var FENCE_OPEN = /^ {0,3}(`{3,}|~{3,})([^\r\n]*)\r?$/;
|
|
22
85
|
var FENCE_CLOSE = /^ {0,3}(`+|~+)[ \t]*\r?$/;
|
|
@@ -1755,9 +1818,10 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive,
|
|
|
1755
1818
|
return out;
|
|
1756
1819
|
}
|
|
1757
1820
|
// ../../packages/aeg-core/src/pr-tier.ts
|
|
1821
|
+
var TIER_FIELD = /(\*\*)?\s*Tier\s*(\*\*)?\s*:\s*(\*\*)?\s*([013])\b/i;
|
|
1758
1822
|
function readTierFromPrBody(prBody) {
|
|
1759
1823
|
const searchIn = anchoredRegion(prBody, "TIER") ?? prBody;
|
|
1760
|
-
const m = searchIn.match(
|
|
1824
|
+
const m = searchIn.match(TIER_FIELD);
|
|
1761
1825
|
if (!m)
|
|
1762
1826
|
return null;
|
|
1763
1827
|
const t = Number(m[4]);
|
|
@@ -2370,15 +2434,25 @@ function checkClosesN2(branch, prBody, trancheFiles, taskIssueRefs) {
|
|
|
2370
2434
|
return { ok: true, expectedIssue };
|
|
2371
2435
|
}
|
|
2372
2436
|
// ../../packages/aeg-core/src/verdict-extraction.ts
|
|
2437
|
+
var HEAD_SHA_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Judged head:\s*([0-9a-f]{7,40})(?![A-Za-z0-9])/im;
|
|
2438
|
+
function extractHeadSha(comment) {
|
|
2439
|
+
const m = comment.match(HEAD_SHA_PATTERN);
|
|
2440
|
+
return m ? m[1].toLowerCase() : null;
|
|
2441
|
+
}
|
|
2373
2442
|
function extractVerdict(comments, valuePattern, missingLabel) {
|
|
2374
2443
|
const clearHits = comments.filter((c) => valuePattern.test(c));
|
|
2375
2444
|
if (clearHits.length > 0) {
|
|
2376
2445
|
const latest = clearHits[clearHits.length - 1];
|
|
2377
2446
|
const m = latest.match(valuePattern);
|
|
2378
|
-
return {
|
|
2447
|
+
return {
|
|
2448
|
+
value: m[1].toUpperCase().replace(/[_-]/g, " "),
|
|
2449
|
+
headSha: extractHeadSha(latest),
|
|
2450
|
+
danglingNote: null
|
|
2451
|
+
};
|
|
2379
2452
|
}
|
|
2380
2453
|
return {
|
|
2381
2454
|
value: `no ${missingLabel} pass was run before merge — DANGLING, see below`,
|
|
2455
|
+
headSha: null,
|
|
2382
2456
|
danglingNote: `no ${missingLabel} verdict comment found on this PR`
|
|
2383
2457
|
};
|
|
2384
2458
|
}
|
|
@@ -2389,8 +2463,10 @@ function extractSecurityReviewVerdict(comments) {
|
|
|
2389
2463
|
return extractVerdict(comments, /^[ \t]*(?:\*{1,3}|_{1,3})?VERDICT:\s*(PASS|FAIL)(?![A-Za-z0-9])/im, "security-review");
|
|
2390
2464
|
}
|
|
2391
2465
|
// ../../packages/aeg-core/src/review-gate.ts
|
|
2392
|
-
function
|
|
2393
|
-
|
|
2466
|
+
function isBoundToHead(extraction, headSha) {
|
|
2467
|
+
if (!extraction.headSha)
|
|
2468
|
+
return false;
|
|
2469
|
+
return headSha.toLowerCase().startsWith(extraction.headSha.toLowerCase());
|
|
2394
2470
|
}
|
|
2395
2471
|
function checkReviewGate(input) {
|
|
2396
2472
|
const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
|
|
@@ -2414,18 +2490,26 @@ function checkReviewGate(input) {
|
|
|
2414
2490
|
const security = extractSecurityReviewVerdict(verifiedBodies);
|
|
2415
2491
|
const codeReviewClean = codeReview.value === "APPROVE";
|
|
2416
2492
|
const securityClean = security.value === "PASS";
|
|
2417
|
-
|
|
2493
|
+
const codeReviewBound = isBoundToHead(codeReview, input.headSha);
|
|
2494
|
+
const securityBound = isBoundToHead(security, input.headSha);
|
|
2495
|
+
if (codeReviewClean && codeReviewBound && securityClean && securityBound) {
|
|
2418
2496
|
return {
|
|
2419
2497
|
verdict: "pass",
|
|
2420
|
-
reason:
|
|
2498
|
+
reason: `code-reviewer verdict is a clean APPROVE and security-review verdict is a clean PASS, both covering head ${input.headSha}.`,
|
|
2421
2499
|
waived: false
|
|
2422
2500
|
};
|
|
2423
2501
|
}
|
|
2424
2502
|
const problems = [];
|
|
2425
|
-
if (!codeReviewClean)
|
|
2503
|
+
if (!codeReviewClean) {
|
|
2426
2504
|
problems.push(`code-reviewer verdict is not a clean APPROVE (found: ${codeReview.value})`);
|
|
2427
|
-
if (!
|
|
2505
|
+
} else if (!codeReviewBound) {
|
|
2506
|
+
problems.push(`the newest code-review verdict covers ${codeReview.headSha ?? "no recorded commit"}, head is ${input.headSha}`);
|
|
2507
|
+
}
|
|
2508
|
+
if (!securityClean) {
|
|
2428
2509
|
problems.push(`security-review verdict is not a clean PASS (found: ${security.value})`);
|
|
2510
|
+
} else if (!securityBound) {
|
|
2511
|
+
problems.push(`the newest security-review verdict covers ${security.headSha ?? "no recorded commit"}, head is ${input.headSha}`);
|
|
2512
|
+
}
|
|
2429
2513
|
const ignoredNote = ignoredCount > 0 ? ` ${ignoredCount} verdict-shaped comment(s) from authors outside the principal allowlist were ignored.` : "";
|
|
2430
2514
|
return {
|
|
2431
2515
|
verdict: "fail",
|
|
@@ -2433,6 +2517,11 @@ function checkReviewGate(input) {
|
|
|
2433
2517
|
waived: false
|
|
2434
2518
|
};
|
|
2435
2519
|
}
|
|
2520
|
+
var CHANGESET_RELEASE_BRANCH = "changeset-release/main";
|
|
2521
|
+
var DEFAULT_RELEASE_ACTOR = "github-actions[bot]";
|
|
2522
|
+
function isChangesetsReleasePr(branch, author, expectedAuthor) {
|
|
2523
|
+
return branch === CHANGESET_RELEASE_BRANCH && author === expectedAuthor;
|
|
2524
|
+
}
|
|
2436
2525
|
// ../../packages/aeg-core/src/markdown-table.ts
|
|
2437
2526
|
function splitRow(line) {
|
|
2438
2527
|
const trimmed = line.trim().replace(/^\|/, "").replace(/\|$/, "");
|
|
@@ -5,7 +5,27 @@ import { execFileSync as execFileSync3 } from "node:child_process";
|
|
|
5
5
|
// ../../packages/aeg-forge-state/src/strip-code.ts
|
|
6
6
|
function maskCode(body) {
|
|
7
7
|
const fill = (line) => " ".repeat(line.length);
|
|
8
|
-
|
|
8
|
+
const blocksMasked = maskIndentedCode(maskFencedCode(body, fill), fill);
|
|
9
|
+
return blocksMasked.split(`
|
|
10
|
+
`).map((line) => replaceInlineSpans(line, (span) => " ".repeat(span.length))).join(`
|
|
11
|
+
`);
|
|
12
|
+
}
|
|
13
|
+
var DETAILS_OPEN = /<details\b[^>]*>/gi;
|
|
14
|
+
var DETAILS_CLOSE = /<\/details\s*>/gi;
|
|
15
|
+
function maskDetailsBlocks(body) {
|
|
16
|
+
const fill = (line) => " ".repeat(line.length);
|
|
17
|
+
const lines = body.split(`
|
|
18
|
+
`);
|
|
19
|
+
let depth = 0;
|
|
20
|
+
const out = lines.map((line) => {
|
|
21
|
+
const opens = line.match(DETAILS_OPEN)?.length ?? 0;
|
|
22
|
+
const closes = line.match(DETAILS_CLOSE)?.length ?? 0;
|
|
23
|
+
const maskThisLine = depth > 0 || opens > 0;
|
|
24
|
+
depth = Math.max(0, depth + opens - closes);
|
|
25
|
+
return maskThisLine ? fill(line) : line;
|
|
26
|
+
});
|
|
27
|
+
return out.join(`
|
|
28
|
+
`);
|
|
9
29
|
}
|
|
10
30
|
function stripCode(body, options = {}) {
|
|
11
31
|
const normalised = body.replace(/\r\n?/g, `
|
|
@@ -14,7 +34,50 @@ function stripCode(body, options = {}) {
|
|
|
14
34
|
const blocksStripped = maskIndentedCode(maskFencedCode(normalised, blank), blank);
|
|
15
35
|
if (options.inlineSpans === "keep")
|
|
16
36
|
return blocksStripped;
|
|
17
|
-
return blocksStripped.
|
|
37
|
+
return blocksStripped.split(`
|
|
38
|
+
`).map((line) => replaceInlineSpans(line, () => "")).join(`
|
|
39
|
+
`);
|
|
40
|
+
}
|
|
41
|
+
function replaceInlineSpans(line, replace) {
|
|
42
|
+
let result = "";
|
|
43
|
+
let i = 0;
|
|
44
|
+
const runLengthAt = (at) => {
|
|
45
|
+
let j = at;
|
|
46
|
+
while (j < line.length && line[j] === "`")
|
|
47
|
+
j++;
|
|
48
|
+
return j - at;
|
|
49
|
+
};
|
|
50
|
+
while (i < line.length) {
|
|
51
|
+
if (line[i] !== "`") {
|
|
52
|
+
result += line[i];
|
|
53
|
+
i++;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const openLen = runLengthAt(i);
|
|
57
|
+
const openEnd = i + openLen;
|
|
58
|
+
let j = openEnd;
|
|
59
|
+
let closeEnd = -1;
|
|
60
|
+
while (j < line.length) {
|
|
61
|
+
if (line[j] !== "`") {
|
|
62
|
+
j++;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const runLen = runLengthAt(j);
|
|
66
|
+
if (runLen === openLen) {
|
|
67
|
+
closeEnd = j + runLen;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
j += runLen;
|
|
71
|
+
}
|
|
72
|
+
if (closeEnd === -1) {
|
|
73
|
+
result += line.slice(i, openEnd);
|
|
74
|
+
i = openEnd;
|
|
75
|
+
} else {
|
|
76
|
+
result += replace(line.slice(i, closeEnd));
|
|
77
|
+
i = closeEnd;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return result;
|
|
18
81
|
}
|
|
19
82
|
var FENCE_OPEN = /^ {0,3}(`{3,}|~{3,})([^\r\n]*)\r?$/;
|
|
20
83
|
var FENCE_CLOSE = /^ {0,3}(`+|~+)[ \t]*\r?$/;
|
|
@@ -1753,9 +1816,10 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive,
|
|
|
1753
1816
|
return out;
|
|
1754
1817
|
}
|
|
1755
1818
|
// ../../packages/aeg-core/src/pr-tier.ts
|
|
1819
|
+
var TIER_FIELD = /(\*\*)?\s*Tier\s*(\*\*)?\s*:\s*(\*\*)?\s*([013])\b/i;
|
|
1756
1820
|
function readTierFromPrBody(prBody) {
|
|
1757
1821
|
const searchIn = anchoredRegion(prBody, "TIER") ?? prBody;
|
|
1758
|
-
const m = searchIn.match(
|
|
1822
|
+
const m = searchIn.match(TIER_FIELD);
|
|
1759
1823
|
if (!m)
|
|
1760
1824
|
return null;
|
|
1761
1825
|
const t = Number(m[4]);
|
|
@@ -2368,15 +2432,25 @@ function checkClosesN2(branch, prBody, trancheFiles, taskIssueRefs) {
|
|
|
2368
2432
|
return { ok: true, expectedIssue };
|
|
2369
2433
|
}
|
|
2370
2434
|
// ../../packages/aeg-core/src/verdict-extraction.ts
|
|
2435
|
+
var HEAD_SHA_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Judged head:\s*([0-9a-f]{7,40})(?![A-Za-z0-9])/im;
|
|
2436
|
+
function extractHeadSha(comment) {
|
|
2437
|
+
const m = comment.match(HEAD_SHA_PATTERN);
|
|
2438
|
+
return m ? m[1].toLowerCase() : null;
|
|
2439
|
+
}
|
|
2371
2440
|
function extractVerdict(comments, valuePattern, missingLabel) {
|
|
2372
2441
|
const clearHits = comments.filter((c) => valuePattern.test(c));
|
|
2373
2442
|
if (clearHits.length > 0) {
|
|
2374
2443
|
const latest = clearHits[clearHits.length - 1];
|
|
2375
2444
|
const m = latest.match(valuePattern);
|
|
2376
|
-
return {
|
|
2445
|
+
return {
|
|
2446
|
+
value: m[1].toUpperCase().replace(/[_-]/g, " "),
|
|
2447
|
+
headSha: extractHeadSha(latest),
|
|
2448
|
+
danglingNote: null
|
|
2449
|
+
};
|
|
2377
2450
|
}
|
|
2378
2451
|
return {
|
|
2379
2452
|
value: `no ${missingLabel} pass was run before merge — DANGLING, see below`,
|
|
2453
|
+
headSha: null,
|
|
2380
2454
|
danglingNote: `no ${missingLabel} verdict comment found on this PR`
|
|
2381
2455
|
};
|
|
2382
2456
|
}
|
|
@@ -2387,8 +2461,10 @@ function extractSecurityReviewVerdict(comments) {
|
|
|
2387
2461
|
return extractVerdict(comments, /^[ \t]*(?:\*{1,3}|_{1,3})?VERDICT:\s*(PASS|FAIL)(?![A-Za-z0-9])/im, "security-review");
|
|
2388
2462
|
}
|
|
2389
2463
|
// ../../packages/aeg-core/src/review-gate.ts
|
|
2390
|
-
function
|
|
2391
|
-
|
|
2464
|
+
function isBoundToHead(extraction, headSha) {
|
|
2465
|
+
if (!extraction.headSha)
|
|
2466
|
+
return false;
|
|
2467
|
+
return headSha.toLowerCase().startsWith(extraction.headSha.toLowerCase());
|
|
2392
2468
|
}
|
|
2393
2469
|
function checkReviewGate(input) {
|
|
2394
2470
|
const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
|
|
@@ -2412,18 +2488,26 @@ function checkReviewGate(input) {
|
|
|
2412
2488
|
const security = extractSecurityReviewVerdict(verifiedBodies);
|
|
2413
2489
|
const codeReviewClean = codeReview.value === "APPROVE";
|
|
2414
2490
|
const securityClean = security.value === "PASS";
|
|
2415
|
-
|
|
2491
|
+
const codeReviewBound = isBoundToHead(codeReview, input.headSha);
|
|
2492
|
+
const securityBound = isBoundToHead(security, input.headSha);
|
|
2493
|
+
if (codeReviewClean && codeReviewBound && securityClean && securityBound) {
|
|
2416
2494
|
return {
|
|
2417
2495
|
verdict: "pass",
|
|
2418
|
-
reason:
|
|
2496
|
+
reason: `code-reviewer verdict is a clean APPROVE and security-review verdict is a clean PASS, both covering head ${input.headSha}.`,
|
|
2419
2497
|
waived: false
|
|
2420
2498
|
};
|
|
2421
2499
|
}
|
|
2422
2500
|
const problems = [];
|
|
2423
|
-
if (!codeReviewClean)
|
|
2501
|
+
if (!codeReviewClean) {
|
|
2424
2502
|
problems.push(`code-reviewer verdict is not a clean APPROVE (found: ${codeReview.value})`);
|
|
2425
|
-
if (!
|
|
2503
|
+
} else if (!codeReviewBound) {
|
|
2504
|
+
problems.push(`the newest code-review verdict covers ${codeReview.headSha ?? "no recorded commit"}, head is ${input.headSha}`);
|
|
2505
|
+
}
|
|
2506
|
+
if (!securityClean) {
|
|
2426
2507
|
problems.push(`security-review verdict is not a clean PASS (found: ${security.value})`);
|
|
2508
|
+
} else if (!securityBound) {
|
|
2509
|
+
problems.push(`the newest security-review verdict covers ${security.headSha ?? "no recorded commit"}, head is ${input.headSha}`);
|
|
2510
|
+
}
|
|
2427
2511
|
const ignoredNote = ignoredCount > 0 ? ` ${ignoredCount} verdict-shaped comment(s) from authors outside the principal allowlist were ignored.` : "";
|
|
2428
2512
|
return {
|
|
2429
2513
|
verdict: "fail",
|
|
@@ -2431,6 +2515,11 @@ function checkReviewGate(input) {
|
|
|
2431
2515
|
waived: false
|
|
2432
2516
|
};
|
|
2433
2517
|
}
|
|
2518
|
+
var CHANGESET_RELEASE_BRANCH = "changeset-release/main";
|
|
2519
|
+
var DEFAULT_RELEASE_ACTOR = "github-actions[bot]";
|
|
2520
|
+
function isChangesetsReleasePr(branch, author, expectedAuthor) {
|
|
2521
|
+
return branch === CHANGESET_RELEASE_BRANCH && author === expectedAuthor;
|
|
2522
|
+
}
|
|
2434
2523
|
// ../../packages/aeg-core/src/markdown-table.ts
|
|
2435
2524
|
function splitRow(line) {
|
|
2436
2525
|
const trimmed = line.trim().replace(/^\|/, "").replace(/\|$/, "");
|
|
@@ -3133,7 +3222,9 @@ var VinayaConfigSchema = z.object({
|
|
|
3133
3222
|
briefSchema: BriefSchemaSchema.optional(),
|
|
3134
3223
|
managed: ManagedManifestSchema.optional(),
|
|
3135
3224
|
principals: z.array(z.string()).min(1).optional(),
|
|
3136
|
-
|
|
3225
|
+
releaseActor: z.string().min(1).optional(),
|
|
3226
|
+
ci: z.object({ setup: z.string().min(1) }).optional(),
|
|
3227
|
+
blastRadius: z.object({ extraDomains: z.array(z.string()).optional() }).optional()
|
|
3137
3228
|
});
|
|
3138
3229
|
var GLOBAL_VINAYA_HOME = join(homedir(), ".vinaya");
|
|
3139
3230
|
var GLOBAL_CONFIG_PATH = join(GLOBAL_VINAYA_HOME, "config.json");
|
|
@@ -3141,6 +3232,9 @@ var LOCAL_CONFIG_FILENAME = "vinaya.config.json";
|
|
|
3141
3232
|
function resolvePrincipalAllowlist(config) {
|
|
3142
3233
|
return config?.principals ?? PRINCIPAL_ALLOWLIST;
|
|
3143
3234
|
}
|
|
3235
|
+
function resolveReleaseActor(config) {
|
|
3236
|
+
return config?.releaseActor ?? DEFAULT_RELEASE_ACTOR;
|
|
3237
|
+
}
|
|
3144
3238
|
function trustAnchorRepo() {
|
|
3145
3239
|
const wellFormed = (slug) => /^[^/\s]+\/[^/\s]+$/.test(slug) ? slug : null;
|
|
3146
3240
|
const fromRunner = process.env.GITHUB_REPOSITORY?.trim();
|
|
@@ -3183,7 +3277,7 @@ function isMissingFileError(err) {
|
|
|
3183
3277
|
return /\b404\b|not found/i.test(haystack);
|
|
3184
3278
|
}
|
|
3185
3279
|
function loadTrustAnchorConfig(fetcher = ghFetchTrustAnchorConfig) {
|
|
3186
|
-
const warn = (why) => process.stdout.write(`⚠ could not read \`principals\` from the default branch (${why}) — falling back to vinaya's built-in
|
|
3280
|
+
const warn = (why) => process.stdout.write(`⚠ could not read the trust-anchor config (\`principals\`/\`releaseActor\`) from the default branch (${why}) — falling back to vinaya's built-in defaults.
|
|
3187
3281
|
`);
|
|
3188
3282
|
let base64;
|
|
3189
3283
|
try {
|
|
@@ -3210,16 +3304,9 @@ function loadTrustAnchorConfig(fetcher = ghFetchTrustAnchorConfig) {
|
|
|
3210
3304
|
|
|
3211
3305
|
// src/checks/bin/check-review-gate.ts
|
|
3212
3306
|
var CHECK_NAME = "review-gate";
|
|
3213
|
-
function git(args) {
|
|
3214
|
-
try {
|
|
3215
|
-
return execFileSync3("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
3216
|
-
} catch {
|
|
3217
|
-
return "";
|
|
3218
|
-
}
|
|
3219
|
-
}
|
|
3220
3307
|
function fetchPr(prNumber) {
|
|
3221
3308
|
try {
|
|
3222
|
-
const out = execFileSync3("gh", ["pr", "view", String(prNumber), "--json", "number,comments,labels"], {
|
|
3309
|
+
const out = execFileSync3("gh", ["pr", "view", String(prNumber), "--json", "number,comments,labels,headRefOid"], {
|
|
3223
3310
|
encoding: "utf8",
|
|
3224
3311
|
stdio: ["ignore", "pipe", "pipe"]
|
|
3225
3312
|
});
|
|
@@ -3243,10 +3330,6 @@ function fetchWaiverLabelActor(prNumber, label2) {
|
|
|
3243
3330
|
}
|
|
3244
3331
|
}
|
|
3245
3332
|
function main() {
|
|
3246
|
-
const branch = process.env.BRANCH || git(["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
3247
|
-
if (isReviewGateExemptBranch(branch)) {
|
|
3248
|
-
process.exit(0);
|
|
3249
|
-
}
|
|
3250
3333
|
const prNumberStr = process.env.PR_NUMBER;
|
|
3251
3334
|
if (!prNumberStr) {
|
|
3252
3335
|
process.exit(0);
|
|
@@ -3269,7 +3352,8 @@ function main() {
|
|
|
3269
3352
|
comments: pr.comments.map((c) => ({ body: c.body, author: c.author?.login ?? null })),
|
|
3270
3353
|
labels,
|
|
3271
3354
|
waiverLabelActor,
|
|
3272
|
-
principalAllowlist: resolvePrincipalAllowlist(loadTrustAnchorConfig())
|
|
3355
|
+
principalAllowlist: resolvePrincipalAllowlist(loadTrustAnchorConfig()),
|
|
3356
|
+
headSha: pr.headRefOid
|
|
3273
3357
|
});
|
|
3274
3358
|
if (result.verdict === "fail") {
|
|
3275
3359
|
emitCheckError({
|