@biffo/cli 0.276.0 → 0.276.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +249 -154
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10065,12 +10065,102 @@ async function runBranchProtectionCheck(explicitRepo, options = {}) {
|
|
|
10065
10065
|
console.log(`\u2713 branch-protection guard: ${owner}/${repo} (${audited.join(", ")}) OK`);
|
|
10066
10066
|
}
|
|
10067
10067
|
|
|
10068
|
-
// src/scripts/check-
|
|
10068
|
+
// src/scripts/check-codeql-suppression.ts
|
|
10069
|
+
import { readFileSync as readFileSync28 } from "fs";
|
|
10070
|
+
import { join as join38, relative as relative6 } from "path";
|
|
10069
10071
|
import { execa as execa8 } from "execa";
|
|
10070
10072
|
|
|
10071
|
-
// src/lib/
|
|
10073
|
+
// src/lib/codeql-suppression-guard.ts
|
|
10072
10074
|
import { readdirSync as readdirSync14, readFileSync as readFileSync27, statSync as statSync7 } from "fs";
|
|
10073
10075
|
import { join as join37 } from "path";
|
|
10076
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
10077
|
+
".git",
|
|
10078
|
+
".worktrees",
|
|
10079
|
+
"node_modules",
|
|
10080
|
+
"dist",
|
|
10081
|
+
"build",
|
|
10082
|
+
".venv",
|
|
10083
|
+
".turbo",
|
|
10084
|
+
"coverage"
|
|
10085
|
+
]);
|
|
10086
|
+
var SCAN_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".mjs", ".py"]);
|
|
10087
|
+
var SUPPRESSION_COMMENT = /^\s*(?:\/\/|#|\*)\s*codeql\[[^\]]+\]/;
|
|
10088
|
+
function findCodeqlSuppressionComments(source) {
|
|
10089
|
+
const lines = source.split("\n");
|
|
10090
|
+
const hits = [];
|
|
10091
|
+
lines.forEach((line, index) => {
|
|
10092
|
+
if (SUPPRESSION_COMMENT.test(line)) hits.push(index + 1);
|
|
10093
|
+
});
|
|
10094
|
+
return hits;
|
|
10095
|
+
}
|
|
10096
|
+
function walkSourceFiles(root) {
|
|
10097
|
+
const out = [];
|
|
10098
|
+
const walk2 = (dir) => {
|
|
10099
|
+
let entries;
|
|
10100
|
+
try {
|
|
10101
|
+
entries = readdirSync14(dir);
|
|
10102
|
+
} catch {
|
|
10103
|
+
return;
|
|
10104
|
+
}
|
|
10105
|
+
for (const entry of entries) {
|
|
10106
|
+
const p = join37(dir, entry);
|
|
10107
|
+
let st;
|
|
10108
|
+
try {
|
|
10109
|
+
st = statSync7(p);
|
|
10110
|
+
} catch {
|
|
10111
|
+
continue;
|
|
10112
|
+
}
|
|
10113
|
+
if (st.isDirectory()) {
|
|
10114
|
+
if (SKIP_DIRS.has(entry)) continue;
|
|
10115
|
+
walk2(p);
|
|
10116
|
+
continue;
|
|
10117
|
+
}
|
|
10118
|
+
const dot = entry.lastIndexOf(".");
|
|
10119
|
+
if (dot === -1) continue;
|
|
10120
|
+
if (SCAN_EXTENSIONS.has(entry.slice(dot))) out.push(p);
|
|
10121
|
+
}
|
|
10122
|
+
};
|
|
10123
|
+
walk2(root);
|
|
10124
|
+
return out.sort();
|
|
10125
|
+
}
|
|
10126
|
+
function sweepCodeqlSuppressionComments(root) {
|
|
10127
|
+
const hits = [];
|
|
10128
|
+
for (const path of walkSourceFiles(root)) {
|
|
10129
|
+
const text = readFileSync27(path, "utf8");
|
|
10130
|
+
for (const line of findCodeqlSuppressionComments(text)) {
|
|
10131
|
+
hits.push({ path, line, text: text.split("\n")[line - 1] ?? "" });
|
|
10132
|
+
}
|
|
10133
|
+
}
|
|
10134
|
+
return hits;
|
|
10135
|
+
}
|
|
10136
|
+
|
|
10137
|
+
// src/scripts/check-codeql-suppression.ts
|
|
10138
|
+
async function runCodeqlSuppressionCheck() {
|
|
10139
|
+
const root = (await execa8("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
10140
|
+
const hits = sweepCodeqlSuppressionComments(join38(root, "cli", "src"));
|
|
10141
|
+
if (hits.length > 0) {
|
|
10142
|
+
console.error(
|
|
10143
|
+
"\u2717 codeql-suppression guard: found a `codeql[...]`-shaped comment, which does not suppress anything in this repo (#1491) \u2014 dismiss the real alert instead (UI, or `PATCH .../code-scanning/alerts/<n>` with a recorded reason)\n"
|
|
10144
|
+
);
|
|
10145
|
+
for (const hit of hits) {
|
|
10146
|
+
console.error(` ${relative6(root, hit.path)}:${hit.line} ${hit.text.trim()}`);
|
|
10147
|
+
}
|
|
10148
|
+
process.exit(1);
|
|
10149
|
+
}
|
|
10150
|
+
const probe = readFileSync28(join38(root, "cli", "src", "lib", "codeql-suppression-guard.ts"), "utf8");
|
|
10151
|
+
if (probe.length === 0) {
|
|
10152
|
+
console.error("\u2717 codeql-suppression guard: scan target read empty \u2014 refusing a false green.");
|
|
10153
|
+
process.exit(1);
|
|
10154
|
+
}
|
|
10155
|
+
console.log("\u2713 codeql-suppression guard: no dead `codeql[...]` suppression comment found");
|
|
10156
|
+
}
|
|
10157
|
+
|
|
10158
|
+
// src/scripts/check-cognito-invite-template.ts
|
|
10159
|
+
import { execa as execa9 } from "execa";
|
|
10160
|
+
|
|
10161
|
+
// src/lib/cognito-invite-template-guard.ts
|
|
10162
|
+
import { readdirSync as readdirSync15, readFileSync as readFileSync29, statSync as statSync8 } from "fs";
|
|
10163
|
+
import { join as join39 } from "path";
|
|
10074
10164
|
var REQUIRED_INVITE_MEMBERS = ["email_subject", "email_message", "sms_message"];
|
|
10075
10165
|
var REQUIRED_INVITE_PLACEHOLDERS = ["{username}", "{####}"];
|
|
10076
10166
|
var PLACEHOLDER_MEMBERS = ["email_message", "sms_message"];
|
|
@@ -10144,36 +10234,36 @@ function memberBody(blockBody, member) {
|
|
|
10144
10234
|
}
|
|
10145
10235
|
function findModuleTerraformFiles(repoRoot) {
|
|
10146
10236
|
const found = [];
|
|
10147
|
-
const walk2 = (dir,
|
|
10237
|
+
const walk2 = (dir, relative9) => {
|
|
10148
10238
|
let entries;
|
|
10149
10239
|
try {
|
|
10150
|
-
entries =
|
|
10240
|
+
entries = readdirSync15(dir);
|
|
10151
10241
|
} catch {
|
|
10152
10242
|
return;
|
|
10153
10243
|
}
|
|
10154
10244
|
for (const entry of entries) {
|
|
10155
10245
|
if (entry === "node_modules" || entry === ".git" || entry === ".worktrees") continue;
|
|
10156
|
-
const full =
|
|
10157
|
-
const rel = `${
|
|
10158
|
-
if (
|
|
10246
|
+
const full = join39(dir, entry);
|
|
10247
|
+
const rel = `${relative9}/${entry}`;
|
|
10248
|
+
if (statSync8(full).isDirectory()) {
|
|
10159
10249
|
walk2(full, rel);
|
|
10160
10250
|
} else if (entry.endsWith(".tf")) {
|
|
10161
10251
|
found.push(rel);
|
|
10162
10252
|
}
|
|
10163
10253
|
}
|
|
10164
10254
|
};
|
|
10165
|
-
walk2(
|
|
10255
|
+
walk2(join39(repoRoot, "modules"), "modules");
|
|
10166
10256
|
return found.sort();
|
|
10167
10257
|
}
|
|
10168
10258
|
function checkCognitoInviteTemplates(repoRoot) {
|
|
10169
10259
|
return findModuleTerraformFiles(repoRoot).flatMap(
|
|
10170
|
-
(file) => checkInviteTemplateSource(file,
|
|
10260
|
+
(file) => checkInviteTemplateSource(file, readFileSync29(join39(repoRoot, file), "utf8"))
|
|
10171
10261
|
);
|
|
10172
10262
|
}
|
|
10173
10263
|
|
|
10174
10264
|
// src/scripts/check-cognito-invite-template.ts
|
|
10175
10265
|
async function runCognitoInviteTemplateCheck() {
|
|
10176
|
-
const root = (await
|
|
10266
|
+
const root = (await execa9("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
10177
10267
|
const files = findModuleTerraformFiles(root);
|
|
10178
10268
|
console.log(`audited ${files.length} .tf file(s) under modules/ under ${root}`);
|
|
10179
10269
|
if (files.length === 0) {
|
|
@@ -10195,12 +10285,12 @@ async function runCognitoInviteTemplateCheck() {
|
|
|
10195
10285
|
}
|
|
10196
10286
|
|
|
10197
10287
|
// src/scripts/check-core-direct-paths.ts
|
|
10198
|
-
import { join as
|
|
10199
|
-
import { execa as
|
|
10288
|
+
import { join as join41 } from "path";
|
|
10289
|
+
import { execa as execa10 } from "execa";
|
|
10200
10290
|
|
|
10201
10291
|
// src/lib/core-direct-paths-audit.ts
|
|
10202
|
-
import { existsSync as existsSync36, readFileSync as
|
|
10203
|
-
import { join as
|
|
10292
|
+
import { existsSync as existsSync36, readFileSync as readFileSync30, readdirSync as readdirSync16, statSync as statSync9 } from "fs";
|
|
10293
|
+
import { join as join40 } from "path";
|
|
10204
10294
|
var EXTERNAL_BASE_IDENTIFIERS = ["CORE_API_URL"];
|
|
10205
10295
|
var API_ROUTE_PREFIX = "/api/v1";
|
|
10206
10296
|
var TEST_FILE_SUFFIXES = [".test.ts", ".test.tsx", ".spec.ts", ".spec.tsx"];
|
|
@@ -10359,15 +10449,15 @@ function walkFiles(root, accept, skipDir) {
|
|
|
10359
10449
|
const walk2 = (dir) => {
|
|
10360
10450
|
let entries;
|
|
10361
10451
|
try {
|
|
10362
|
-
entries =
|
|
10452
|
+
entries = readdirSync16(dir);
|
|
10363
10453
|
} catch {
|
|
10364
10454
|
return;
|
|
10365
10455
|
}
|
|
10366
10456
|
for (const entry of entries) {
|
|
10367
|
-
const p =
|
|
10457
|
+
const p = join40(dir, entry);
|
|
10368
10458
|
let st;
|
|
10369
10459
|
try {
|
|
10370
|
-
st =
|
|
10460
|
+
st = statSync9(p);
|
|
10371
10461
|
} catch {
|
|
10372
10462
|
continue;
|
|
10373
10463
|
}
|
|
@@ -10394,7 +10484,7 @@ function auditFrontendExtraction(frontendSrcDir, externalBases = EXTERNAL_BASE_I
|
|
|
10394
10484
|
const extracted = [];
|
|
10395
10485
|
let rawTotal = 0;
|
|
10396
10486
|
for (const file of files) {
|
|
10397
|
-
const text =
|
|
10487
|
+
const text = readFileSync30(file, "utf8");
|
|
10398
10488
|
rawTotal += countRawExternalOccurrences(text, externalBases);
|
|
10399
10489
|
extracted.push(...extractCoreDirectPaths(text, file, externalBases));
|
|
10400
10490
|
}
|
|
@@ -10443,7 +10533,7 @@ function auditCoreRouteExtraction(apiSrcDir) {
|
|
|
10443
10533
|
const prefixSet = /* @__PURE__ */ new Set();
|
|
10444
10534
|
let rawApiRouterCount = 0;
|
|
10445
10535
|
for (const file of files) {
|
|
10446
|
-
const text =
|
|
10536
|
+
const text = readFileSync30(file, "utf8");
|
|
10447
10537
|
const extraction = extractCoreRoutePrefixes(text);
|
|
10448
10538
|
rawApiRouterCount += extraction.rawApiRouterCount;
|
|
10449
10539
|
for (const p of extraction.prefixes) prefixSet.add(normalizePrefix(p));
|
|
@@ -10459,10 +10549,10 @@ function pathMatchesAnyCorePrefix(normalized, corePrefixes, apiRoutePrefix = API
|
|
|
10459
10549
|
}
|
|
10460
10550
|
function resolveSiblingCoreSrc(params) {
|
|
10461
10551
|
const { estateDir, sibling } = params;
|
|
10462
|
-
const configPath =
|
|
10552
|
+
const configPath = join40(estateDir, sibling, "biffo.sibling.json");
|
|
10463
10553
|
let raw;
|
|
10464
10554
|
try {
|
|
10465
|
-
raw =
|
|
10555
|
+
raw = readFileSync30(configPath, "utf8");
|
|
10466
10556
|
} catch (err) {
|
|
10467
10557
|
throw new Error(
|
|
10468
10558
|
`cannot resolve ${sibling}'s core: ${configPath} does not exist or is unreadable (${err.message}) -- refusing to guess which core serves this sibling.`
|
|
@@ -10482,7 +10572,7 @@ function resolveSiblingCoreSrc(params) {
|
|
|
10482
10572
|
`cannot resolve ${sibling}'s core: ${configPath} has no non-empty "core_project" field.`
|
|
10483
10573
|
);
|
|
10484
10574
|
}
|
|
10485
|
-
const coreApiSrcDir =
|
|
10575
|
+
const coreApiSrcDir = join40(estateDir, coreProject, "services", "api", "src");
|
|
10486
10576
|
if (!existsSync36(coreApiSrcDir)) {
|
|
10487
10577
|
throw new Error(
|
|
10488
10578
|
`cannot resolve ${sibling}'s core: biffo.sibling.json names core_project "${coreProject}", but ${coreApiSrcDir} does not exist -- the instance is missing from this estate checkout, not merely unmatched. Refusing to silently skip ${sibling} and shrink the audit's denominator.`
|
|
@@ -10524,9 +10614,9 @@ function auditSiblingCoreDirectPaths(params) {
|
|
|
10524
10614
|
|
|
10525
10615
|
// src/scripts/check-core-direct-paths.ts
|
|
10526
10616
|
async function runCoreDirectPathsCheck(opts = {}) {
|
|
10527
|
-
const root = (await
|
|
10617
|
+
const root = (await execa10("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
10528
10618
|
const sibling = opts.sibling ?? "sibling-template (self-check)";
|
|
10529
|
-
const frontendSrcDir = opts.frontendSrc ??
|
|
10619
|
+
const frontendSrcDir = opts.frontendSrc ?? join41(root, "_skeletons", "sibling-template", "apps", "frontend", "src");
|
|
10530
10620
|
let coreApiSrcDir;
|
|
10531
10621
|
let coreProject = null;
|
|
10532
10622
|
if (opts.coreSrc) {
|
|
@@ -10542,7 +10632,7 @@ async function runCoreDirectPathsCheck(opts = {}) {
|
|
|
10542
10632
|
coreApiSrcDir = resolution.coreApiSrcDir;
|
|
10543
10633
|
coreProject = resolution.coreProject;
|
|
10544
10634
|
} else {
|
|
10545
|
-
coreApiSrcDir =
|
|
10635
|
+
coreApiSrcDir = join41(root, "services", "api", "src");
|
|
10546
10636
|
}
|
|
10547
10637
|
const report = auditSiblingCoreDirectPaths({ sibling, frontendSrcDir, coreApiSrcDir });
|
|
10548
10638
|
console.log(
|
|
@@ -10578,7 +10668,7 @@ async function runCoreDirectPathsCheck(opts = {}) {
|
|
|
10578
10668
|
}
|
|
10579
10669
|
|
|
10580
10670
|
// src/scripts/check-core-ownership.ts
|
|
10581
|
-
import { execa as
|
|
10671
|
+
import { execa as execa11 } from "execa";
|
|
10582
10672
|
var BOLD = "\x1B[1m";
|
|
10583
10673
|
var DIM = "\x1B[2m";
|
|
10584
10674
|
var RED = "\x1B[31m";
|
|
@@ -10589,7 +10679,7 @@ async function runOwnershipCheck(argv) {
|
|
|
10589
10679
|
const stagedFlag = args.indexOf("--staged");
|
|
10590
10680
|
const staged = stagedFlag !== -1;
|
|
10591
10681
|
const messageFile = staged ? args[stagedFlag + 1] : void 0;
|
|
10592
|
-
const root = (await
|
|
10682
|
+
const root = (await execa11("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
10593
10683
|
const ownership = classifyRepoOwnership(root);
|
|
10594
10684
|
if (ownership === "template") {
|
|
10595
10685
|
console.log("\u2713 core ownership guard: skipped \u2014 this is the template, which owns these paths.");
|
|
@@ -10605,11 +10695,11 @@ async function runOwnershipCheck(argv) {
|
|
|
10605
10695
|
let deletedFiles = [];
|
|
10606
10696
|
let commitMessage = "";
|
|
10607
10697
|
if (staged) {
|
|
10608
|
-
const { stdout } = await
|
|
10698
|
+
const { stdout } = await execa11("git", ["diff", "--cached", "--name-status"], { cwd: root });
|
|
10609
10699
|
({ changed: changedFiles, deleted: deletedFiles } = parseNameStatus(stdout));
|
|
10610
10700
|
if (messageFile) {
|
|
10611
|
-
const { readFileSync:
|
|
10612
|
-
if (existsSync45(messageFile)) commitMessage =
|
|
10701
|
+
const { readFileSync: readFileSync39, existsSync: existsSync45 } = await import("fs");
|
|
10702
|
+
if (existsSync45(messageFile)) commitMessage = readFileSync39(messageFile, "utf8");
|
|
10613
10703
|
}
|
|
10614
10704
|
} else {
|
|
10615
10705
|
const base = process.env["GITHUB_BASE_REF"] ?? args[0];
|
|
@@ -10617,18 +10707,18 @@ async function runOwnershipCheck(argv) {
|
|
|
10617
10707
|
console.error("No base ref: set GITHUB_BASE_REF or pass a base branch as the first argument.");
|
|
10618
10708
|
process.exit(2);
|
|
10619
10709
|
}
|
|
10620
|
-
await
|
|
10621
|
-
const { stdout } = await
|
|
10710
|
+
await execa11("git", ["fetch", "--quiet", "origin", base], { cwd: root, reject: false });
|
|
10711
|
+
const { stdout } = await execa11("git", ["diff", "--name-status", `origin/${base}...HEAD`], {
|
|
10622
10712
|
cwd: root
|
|
10623
10713
|
});
|
|
10624
10714
|
({ changed: changedFiles, deleted: deletedFiles } = parseNameStatus(stdout));
|
|
10625
|
-
const { stdout: log2 } = await
|
|
10715
|
+
const { stdout: log2 } = await execa11("git", ["log", "--format=%B", `origin/${base}..HEAD`], {
|
|
10626
10716
|
cwd: root,
|
|
10627
10717
|
reject: false
|
|
10628
10718
|
});
|
|
10629
10719
|
commitMessage = log2;
|
|
10630
10720
|
}
|
|
10631
|
-
const { stdout: gitBranch } = await
|
|
10721
|
+
const { stdout: gitBranch } = await execa11("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
|
|
10632
10722
|
cwd: root,
|
|
10633
10723
|
reject: false
|
|
10634
10724
|
});
|
|
@@ -10710,12 +10800,12 @@ ${BOLD}If the divergence is deliberate${OFF}
|
|
|
10710
10800
|
}
|
|
10711
10801
|
|
|
10712
10802
|
// src/scripts/check-eventbridge-log-permissions.ts
|
|
10713
|
-
import { execa as
|
|
10803
|
+
import { execa as execa12 } from "execa";
|
|
10714
10804
|
|
|
10715
10805
|
// src/lib/eventbridge-log-permission-guard.ts
|
|
10716
|
-
import { readFileSync as
|
|
10717
|
-
import { join as
|
|
10718
|
-
var
|
|
10806
|
+
import { readFileSync as readFileSync31, readdirSync as readdirSync17, statSync as statSync10 } from "fs";
|
|
10807
|
+
import { join as join42 } from "path";
|
|
10808
|
+
var SKIP_DIRS2 = /* @__PURE__ */ new Set(["node_modules", ".git", ".terraform", ".worktrees", "dist"]);
|
|
10719
10809
|
var EVENT_TARGET_TYPE = "aws_cloudwatch_event_target";
|
|
10720
10810
|
var LOG_RESOURCE_POLICY_TYPE = "aws_cloudwatch_log_resource_policy";
|
|
10721
10811
|
var LOG_GROUP_ARN_REF = /aws_cloudwatch_log_group\.([\w-]+)(?:\[[^\]]*\])?\.arn/g;
|
|
@@ -10786,20 +10876,20 @@ function walkTerraformFiles(root) {
|
|
|
10786
10876
|
const walk2 = (dir) => {
|
|
10787
10877
|
let entries;
|
|
10788
10878
|
try {
|
|
10789
|
-
entries =
|
|
10879
|
+
entries = readdirSync17(dir);
|
|
10790
10880
|
} catch {
|
|
10791
10881
|
return;
|
|
10792
10882
|
}
|
|
10793
10883
|
for (const entry of entries) {
|
|
10794
|
-
const p =
|
|
10884
|
+
const p = join42(dir, entry);
|
|
10795
10885
|
let st;
|
|
10796
10886
|
try {
|
|
10797
|
-
st =
|
|
10887
|
+
st = statSync10(p);
|
|
10798
10888
|
} catch {
|
|
10799
10889
|
continue;
|
|
10800
10890
|
}
|
|
10801
10891
|
if (st.isDirectory()) {
|
|
10802
|
-
if (
|
|
10892
|
+
if (SKIP_DIRS2.has(entry)) continue;
|
|
10803
10893
|
walk2(p);
|
|
10804
10894
|
continue;
|
|
10805
10895
|
}
|
|
@@ -10834,7 +10924,7 @@ function auditEventBridgeLogPermissions(root) {
|
|
|
10834
10924
|
let rawEventTargetCount = 0;
|
|
10835
10925
|
let rawLogPolicyCount = 0;
|
|
10836
10926
|
for (const file of files) {
|
|
10837
|
-
const text =
|
|
10927
|
+
const text = readFileSync31(file, "utf8");
|
|
10838
10928
|
rawEventTargetCount += countRawResourceDeclarations(text, EVENT_TARGET_TYPE);
|
|
10839
10929
|
rawLogPolicyCount += countRawResourceDeclarations(text, LOG_RESOURCE_POLICY_TYPE);
|
|
10840
10930
|
eventTargetBlocks.push(...findResourceBlocks(text, file, EVENT_TARGET_TYPE));
|
|
@@ -10887,7 +10977,7 @@ function auditEventBridgeLogPermissions(root) {
|
|
|
10887
10977
|
|
|
10888
10978
|
// src/scripts/check-eventbridge-log-permissions.ts
|
|
10889
10979
|
async function runEventBridgeLogPermissionCheck() {
|
|
10890
|
-
const root = (await
|
|
10980
|
+
const root = (await execa12("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
10891
10981
|
let report;
|
|
10892
10982
|
try {
|
|
10893
10983
|
report = auditEventBridgeLogPermissions(root);
|
|
@@ -10924,15 +11014,15 @@ async function runEventBridgeLogPermissionCheck() {
|
|
|
10924
11014
|
}
|
|
10925
11015
|
|
|
10926
11016
|
// src/scripts/check-lambda-output.ts
|
|
10927
|
-
import { execa as
|
|
11017
|
+
import { execa as execa13 } from "execa";
|
|
10928
11018
|
|
|
10929
11019
|
// src/lib/lambda-output-guard.ts
|
|
10930
|
-
import { readFileSync as
|
|
10931
|
-
import { join as
|
|
11020
|
+
import { readFileSync as readFileSync33 } from "fs";
|
|
11021
|
+
import { join as join44 } from "path";
|
|
10932
11022
|
|
|
10933
11023
|
// src/lib/terraform-input-guard.ts
|
|
10934
|
-
import { readdirSync as
|
|
10935
|
-
import { join as
|
|
11024
|
+
import { readdirSync as readdirSync18, readFileSync as readFileSync32, statSync as statSync11 } from "fs";
|
|
11025
|
+
import { join as join43 } from "path";
|
|
10936
11026
|
var GUARDED_SUBCOMMANDS = [
|
|
10937
11027
|
"init",
|
|
10938
11028
|
"plan",
|
|
@@ -10947,20 +11037,20 @@ function stripComments2(source) {
|
|
|
10947
11037
|
}
|
|
10948
11038
|
function findWorkflowFiles(repoRoot) {
|
|
10949
11039
|
const found = [];
|
|
10950
|
-
const walk2 = (dir,
|
|
11040
|
+
const walk2 = (dir, relative9) => {
|
|
10951
11041
|
let entries;
|
|
10952
11042
|
try {
|
|
10953
|
-
entries =
|
|
11043
|
+
entries = readdirSync18(dir);
|
|
10954
11044
|
} catch {
|
|
10955
11045
|
return;
|
|
10956
11046
|
}
|
|
10957
11047
|
for (const entry of entries) {
|
|
10958
11048
|
if (entry === "node_modules" || entry === ".git" || entry === ".worktrees") continue;
|
|
10959
|
-
const full =
|
|
10960
|
-
const rel =
|
|
10961
|
-
if (
|
|
11049
|
+
const full = join43(dir, entry);
|
|
11050
|
+
const rel = relative9 ? `${relative9}/${entry}` : entry;
|
|
11051
|
+
if (statSync11(full).isDirectory()) {
|
|
10962
11052
|
walk2(full, rel);
|
|
10963
|
-
} else if (/\.ya?ml$/.test(entry) &&
|
|
11053
|
+
} else if (/\.ya?ml$/.test(entry) && relative9.endsWith(".github/workflows")) {
|
|
10964
11054
|
found.push(rel);
|
|
10965
11055
|
}
|
|
10966
11056
|
}
|
|
@@ -11000,7 +11090,7 @@ function checkWorkflowSource(file, rawSource) {
|
|
|
11000
11090
|
}
|
|
11001
11091
|
function checkTerraformInput(repoRoot) {
|
|
11002
11092
|
return findWorkflowFiles(repoRoot).flatMap(
|
|
11003
|
-
(file) => checkWorkflowSource(file,
|
|
11093
|
+
(file) => checkWorkflowSource(file, readFileSync32(join43(repoRoot, file), "utf8"))
|
|
11004
11094
|
);
|
|
11005
11095
|
}
|
|
11006
11096
|
|
|
@@ -11058,13 +11148,13 @@ function checkWorkflowSource2(file, rawSource) {
|
|
|
11058
11148
|
}
|
|
11059
11149
|
function checkLambdaOutput(repoRoot) {
|
|
11060
11150
|
return findWorkflowFiles(repoRoot).flatMap(
|
|
11061
|
-
(file) => checkWorkflowSource2(file,
|
|
11151
|
+
(file) => checkWorkflowSource2(file, readFileSync33(join44(repoRoot, file), "utf8"))
|
|
11062
11152
|
);
|
|
11063
11153
|
}
|
|
11064
11154
|
|
|
11065
11155
|
// src/scripts/check-lambda-output.ts
|
|
11066
11156
|
async function runLambdaOutputCheck() {
|
|
11067
|
-
const root = (await
|
|
11157
|
+
const root = (await execa13("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
11068
11158
|
const files = findWorkflowFiles(root);
|
|
11069
11159
|
console.log(`audited ${files.length} workflow file(s) under ${root}`);
|
|
11070
11160
|
if (files.length === 0) {
|
|
@@ -11086,9 +11176,9 @@ async function runLambdaOutputCheck() {
|
|
|
11086
11176
|
}
|
|
11087
11177
|
|
|
11088
11178
|
// src/scripts/check-pipe-trap.ts
|
|
11089
|
-
import { readFileSync as
|
|
11090
|
-
import { join as
|
|
11091
|
-
import { execa as
|
|
11179
|
+
import { readFileSync as readFileSync34, readdirSync as readdirSync19 } from "fs";
|
|
11180
|
+
import { join as join45, relative as relative7 } from "path";
|
|
11181
|
+
import { execa as execa14 } from "execa";
|
|
11092
11182
|
|
|
11093
11183
|
// src/lib/pipe-trap-guard.ts
|
|
11094
11184
|
var STATUS_BEARING = [
|
|
@@ -11184,23 +11274,23 @@ function findPipeTraps(source) {
|
|
|
11184
11274
|
function shellFiles(root) {
|
|
11185
11275
|
const out = [];
|
|
11186
11276
|
for (const dir of ["scripts", ".githooks"]) {
|
|
11187
|
-
const full =
|
|
11277
|
+
const full = join45(root, dir);
|
|
11188
11278
|
let entries;
|
|
11189
11279
|
try {
|
|
11190
|
-
entries =
|
|
11280
|
+
entries = readdirSync19(full, { withFileTypes: true });
|
|
11191
11281
|
} catch {
|
|
11192
11282
|
continue;
|
|
11193
11283
|
}
|
|
11194
11284
|
for (const entry of entries) {
|
|
11195
11285
|
if (!entry.isFile()) continue;
|
|
11196
11286
|
if (dir === "scripts" && !entry.name.endsWith(".sh")) continue;
|
|
11197
|
-
out.push(
|
|
11287
|
+
out.push(join45(full, entry.name));
|
|
11198
11288
|
}
|
|
11199
11289
|
}
|
|
11200
11290
|
return out;
|
|
11201
11291
|
}
|
|
11202
11292
|
async function runPipeTrapCheck() {
|
|
11203
|
-
const root = (await
|
|
11293
|
+
const root = (await execa14("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
11204
11294
|
const files = shellFiles(root);
|
|
11205
11295
|
console.log(`audited ${files.length} shell file(s) under scripts/ and .githooks/ under ${root}`);
|
|
11206
11296
|
if (files.length === 0) {
|
|
@@ -11210,8 +11300,8 @@ async function runPipeTrapCheck() {
|
|
|
11210
11300
|
process.exit(1);
|
|
11211
11301
|
}
|
|
11212
11302
|
const findings = files.flatMap(
|
|
11213
|
-
(file) => findPipeTraps(
|
|
11214
|
-
(t) => `${
|
|
11303
|
+
(file) => findPipeTraps(readFileSync34(file, "utf8")).map(
|
|
11304
|
+
(t) => `${relative7(root, file)}:${t.line} ${t.text}
|
|
11215
11305
|
${t.reason}`
|
|
11216
11306
|
)
|
|
11217
11307
|
);
|
|
@@ -11228,33 +11318,33 @@ async function runPipeTrapCheck() {
|
|
|
11228
11318
|
|
|
11229
11319
|
// src/scripts/check-plugin-collisions.ts
|
|
11230
11320
|
import { existsSync as existsSync38 } from "fs";
|
|
11231
|
-
import { join as
|
|
11232
|
-
import { execa as
|
|
11321
|
+
import { join as join47 } from "path";
|
|
11322
|
+
import { execa as execa15 } from "execa";
|
|
11233
11323
|
|
|
11234
11324
|
// src/lib/plugin-collision-guard.ts
|
|
11235
|
-
import { existsSync as existsSync37, readdirSync as
|
|
11236
|
-
import { join as
|
|
11325
|
+
import { existsSync as existsSync37, readdirSync as readdirSync20, statSync as statSync12 } from "fs";
|
|
11326
|
+
import { join as join46 } from "path";
|
|
11237
11327
|
var PYTEST_SPECIAL = /* @__PURE__ */ new Set(["conftest.py"]);
|
|
11238
11328
|
var IGNORED_DIRS = /* @__PURE__ */ new Set([".venv", "node_modules", "__pycache__", ".git", "dist", "build"]);
|
|
11239
11329
|
function subdirectories(dir) {
|
|
11240
11330
|
if (!existsSync37(dir)) return [];
|
|
11241
|
-
return
|
|
11331
|
+
return readdirSync20(dir).filter((entry) => {
|
|
11242
11332
|
if (IGNORED_DIRS.has(entry) || entry.startsWith(".")) return false;
|
|
11243
11333
|
try {
|
|
11244
|
-
return
|
|
11334
|
+
return statSync12(join46(dir, entry)).isDirectory();
|
|
11245
11335
|
} catch {
|
|
11246
11336
|
return false;
|
|
11247
11337
|
}
|
|
11248
11338
|
});
|
|
11249
11339
|
}
|
|
11250
11340
|
function regularPackagesOf(pluginDir2) {
|
|
11251
|
-
return subdirectories(pluginDir2).filter((name) => existsSync37(
|
|
11341
|
+
return subdirectories(pluginDir2).filter((name) => existsSync37(join46(pluginDir2, name, "__init__.py"))).sort();
|
|
11252
11342
|
}
|
|
11253
11343
|
function bareTestModulesOf(pluginDir2) {
|
|
11254
|
-
const testsDir =
|
|
11344
|
+
const testsDir = join46(pluginDir2, "tests");
|
|
11255
11345
|
if (!existsSync37(testsDir)) return [];
|
|
11256
|
-
if (existsSync37(
|
|
11257
|
-
return
|
|
11346
|
+
if (existsSync37(join46(testsDir, "__init__.py"))) return [];
|
|
11347
|
+
return readdirSync20(testsDir).filter((f) => f.endsWith(".py") && !PYTEST_SPECIAL.has(f)).sort();
|
|
11258
11348
|
}
|
|
11259
11349
|
function findCollisions(servicesDir, pluginDirs) {
|
|
11260
11350
|
const plugins = (pluginDirs ?? subdirectories(servicesDir)).filter((name) => !name.startsWith("_")).filter((name) => name !== "api").sort();
|
|
@@ -11262,7 +11352,7 @@ function findCollisions(servicesDir, pluginDirs) {
|
|
|
11262
11352
|
const gather = (kind, namesOf) => {
|
|
11263
11353
|
const claims = /* @__PURE__ */ new Map();
|
|
11264
11354
|
for (const plugin of plugins) {
|
|
11265
|
-
for (const name of namesOf(
|
|
11355
|
+
for (const name of namesOf(join46(servicesDir, plugin))) {
|
|
11266
11356
|
claims.set(name, [...claims.get(name) ?? [], plugin]);
|
|
11267
11357
|
}
|
|
11268
11358
|
}
|
|
@@ -11299,8 +11389,8 @@ function formatCollisions(collisions) {
|
|
|
11299
11389
|
|
|
11300
11390
|
// src/scripts/check-plugin-collisions.ts
|
|
11301
11391
|
async function runPluginCollisionCheck() {
|
|
11302
|
-
const root = (await
|
|
11303
|
-
const servicesDir =
|
|
11392
|
+
const root = (await execa15("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
11393
|
+
const servicesDir = join47(root, "services");
|
|
11304
11394
|
if (!existsSync38(servicesDir)) {
|
|
11305
11395
|
console.log("\u2713 plugin collision guard: no services/ directory \u2014 nothing to compare");
|
|
11306
11396
|
return;
|
|
@@ -11318,28 +11408,28 @@ async function runPluginCollisionCheck() {
|
|
|
11318
11408
|
}
|
|
11319
11409
|
|
|
11320
11410
|
// src/scripts/check-plugin-terraform.ts
|
|
11321
|
-
import { execa as
|
|
11411
|
+
import { execa as execa16 } from "execa";
|
|
11322
11412
|
|
|
11323
11413
|
// src/lib/plugin-terraform-guard.ts
|
|
11324
|
-
import { existsSync as existsSync39, readFileSync as
|
|
11325
|
-
import { dirname as dirname10, join as
|
|
11326
|
-
var
|
|
11414
|
+
import { existsSync as existsSync39, readFileSync as readFileSync35, readdirSync as readdirSync21 } from "fs";
|
|
11415
|
+
import { dirname as dirname10, join as join48, relative as relative8, sep as sep3 } from "path";
|
|
11416
|
+
var SKIP_DIRS3 = /* @__PURE__ */ new Set(["node_modules", ".git", ".worktrees", "dist", ".venv", "__pycache__"]);
|
|
11327
11417
|
var PLUGIN_MANIFEST_FILE2 = "biffo.plugin.json";
|
|
11328
11418
|
function findPluginManifests(root) {
|
|
11329
11419
|
const found = [];
|
|
11330
11420
|
const walk2 = (dir) => {
|
|
11331
11421
|
let entries;
|
|
11332
11422
|
try {
|
|
11333
|
-
entries =
|
|
11423
|
+
entries = readdirSync21(dir, { withFileTypes: true });
|
|
11334
11424
|
} catch {
|
|
11335
11425
|
return;
|
|
11336
11426
|
}
|
|
11337
11427
|
for (const entry of entries) {
|
|
11338
11428
|
if (entry.isDirectory()) {
|
|
11339
|
-
if (
|
|
11340
|
-
walk2(
|
|
11429
|
+
if (SKIP_DIRS3.has(entry.name)) continue;
|
|
11430
|
+
walk2(join48(dir, entry.name));
|
|
11341
11431
|
} else if (entry.isFile() && entry.name === PLUGIN_MANIFEST_FILE2) {
|
|
11342
|
-
found.push(
|
|
11432
|
+
found.push(relative8(root, join48(dir, entry.name)).split(sep3).join("/"));
|
|
11343
11433
|
}
|
|
11344
11434
|
}
|
|
11345
11435
|
};
|
|
@@ -11349,7 +11439,7 @@ function findPluginManifests(root) {
|
|
|
11349
11439
|
function readSubscriptions(absManifestPath) {
|
|
11350
11440
|
let parsed;
|
|
11351
11441
|
try {
|
|
11352
|
-
parsed = JSON.parse(
|
|
11442
|
+
parsed = JSON.parse(readFileSync35(absManifestPath, "utf8"));
|
|
11353
11443
|
} catch {
|
|
11354
11444
|
return null;
|
|
11355
11445
|
}
|
|
@@ -11364,15 +11454,15 @@ function readSubscriptions(absManifestPath) {
|
|
|
11364
11454
|
}
|
|
11365
11455
|
function checkPluginTerraform(root) {
|
|
11366
11456
|
const violations = [];
|
|
11367
|
-
const coreManifest = existsSync39(
|
|
11457
|
+
const coreManifest = existsSync39(join48(root, CORE_MANIFEST_FILE)) ? readCoreManifest(root) : null;
|
|
11368
11458
|
for (const manifest of findPluginManifests(root)) {
|
|
11369
11459
|
if (coreManifest && !isTemplateOwned(manifest, coreManifest)) continue;
|
|
11370
|
-
const absManifest =
|
|
11460
|
+
const absManifest = join48(root, manifest);
|
|
11371
11461
|
const subscriptions = readSubscriptions(absManifest);
|
|
11372
11462
|
if (subscriptions === null) continue;
|
|
11373
11463
|
const pluginDir2 = dirname10(absManifest);
|
|
11374
|
-
if (existsSync39(
|
|
11375
|
-
const relPluginDir =
|
|
11464
|
+
if (existsSync39(join48(pluginDir2, "terraform"))) continue;
|
|
11465
|
+
const relPluginDir = relative8(root, pluginDir2).split(sep3).join("/");
|
|
11376
11466
|
violations.push({
|
|
11377
11467
|
manifest,
|
|
11378
11468
|
expectedTerraformDir: relPluginDir ? `${relPluginDir}/terraform` : "terraform",
|
|
@@ -11391,7 +11481,7 @@ function formatViolations(violations) {
|
|
|
11391
11481
|
|
|
11392
11482
|
// src/scripts/check-plugin-terraform.ts
|
|
11393
11483
|
async function runPluginTerraformCheck() {
|
|
11394
|
-
const root = (await
|
|
11484
|
+
const root = (await execa16("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
11395
11485
|
const violations = checkPluginTerraform(root);
|
|
11396
11486
|
if (violations.length > 0) {
|
|
11397
11487
|
console.error("\u2717 plugin Terraform guard: event subscriptions with no infrastructure\n");
|
|
@@ -11403,12 +11493,12 @@ async function runPluginTerraformCheck() {
|
|
|
11403
11493
|
|
|
11404
11494
|
// src/scripts/check-plugin-tool-supply.ts
|
|
11405
11495
|
import { existsSync as existsSync41 } from "fs";
|
|
11406
|
-
import { join as
|
|
11407
|
-
import { execa as
|
|
11496
|
+
import { join as join50 } from "path";
|
|
11497
|
+
import { execa as execa17 } from "execa";
|
|
11408
11498
|
|
|
11409
11499
|
// src/lib/plugin-tool-supply-audit.ts
|
|
11410
|
-
import { existsSync as existsSync40, readFileSync as
|
|
11411
|
-
import { join as
|
|
11500
|
+
import { existsSync as existsSync40, readFileSync as readFileSync36, readdirSync as readdirSync22, statSync as statSync13 } from "fs";
|
|
11501
|
+
import { join as join49 } from "path";
|
|
11412
11502
|
|
|
11413
11503
|
// src/lib/openrouter-model-snapshot.ts
|
|
11414
11504
|
var OPENROUTER_MODEL_SNAPSHOT_FETCHED_AT = "2026-08-10T06:39:01Z";
|
|
@@ -11819,13 +11909,13 @@ var OPENROUTER_MODEL_IDS = [
|
|
|
11819
11909
|
function listDirs(root) {
|
|
11820
11910
|
let entries;
|
|
11821
11911
|
try {
|
|
11822
|
-
entries =
|
|
11912
|
+
entries = readdirSync22(root);
|
|
11823
11913
|
} catch {
|
|
11824
11914
|
return [];
|
|
11825
11915
|
}
|
|
11826
11916
|
return entries.filter((e) => {
|
|
11827
11917
|
try {
|
|
11828
|
-
return
|
|
11918
|
+
return statSync13(join49(root, e)).isDirectory();
|
|
11829
11919
|
} catch {
|
|
11830
11920
|
return false;
|
|
11831
11921
|
}
|
|
@@ -11836,15 +11926,15 @@ function walkFiles2(root, accept, skipDir) {
|
|
|
11836
11926
|
const walk2 = (dir) => {
|
|
11837
11927
|
let entries;
|
|
11838
11928
|
try {
|
|
11839
|
-
entries =
|
|
11929
|
+
entries = readdirSync22(dir);
|
|
11840
11930
|
} catch {
|
|
11841
11931
|
return;
|
|
11842
11932
|
}
|
|
11843
11933
|
for (const entry of entries) {
|
|
11844
|
-
const p =
|
|
11934
|
+
const p = join49(dir, entry);
|
|
11845
11935
|
let st;
|
|
11846
11936
|
try {
|
|
11847
|
-
st =
|
|
11937
|
+
st = statSync13(p);
|
|
11848
11938
|
} catch {
|
|
11849
11939
|
continue;
|
|
11850
11940
|
}
|
|
@@ -11867,14 +11957,14 @@ function pluginPythonFiles(pluginDir2) {
|
|
|
11867
11957
|
);
|
|
11868
11958
|
}
|
|
11869
11959
|
function pluginTerraformFiles(pluginDir2) {
|
|
11870
|
-
const tfDir =
|
|
11960
|
+
const tfDir = join49(pluginDir2, "terraform");
|
|
11871
11961
|
let entries;
|
|
11872
11962
|
try {
|
|
11873
|
-
entries =
|
|
11963
|
+
entries = readdirSync22(tfDir);
|
|
11874
11964
|
} catch {
|
|
11875
11965
|
return [];
|
|
11876
11966
|
}
|
|
11877
|
-
return entries.filter((e) => e.endsWith(".tf")).map((e) =>
|
|
11967
|
+
return entries.filter((e) => e.endsWith(".tf")).map((e) => join49(tfDir, e)).sort();
|
|
11878
11968
|
}
|
|
11879
11969
|
function extractManifestTools(manifestText) {
|
|
11880
11970
|
let parsed;
|
|
@@ -12126,8 +12216,8 @@ function isSnapshotStale(fetchedAt, now) {
|
|
|
12126
12216
|
function normalizeModelId(id) {
|
|
12127
12217
|
return id.endsWith(":online") ? id.slice(0, -":online".length) : id;
|
|
12128
12218
|
}
|
|
12129
|
-
var CONFIG_PY_PATH =
|
|
12130
|
-
var ORCHESTRATION_SCHEMA_PATH =
|
|
12219
|
+
var CONFIG_PY_PATH = join49("services", "api", "src", "api", "config.py");
|
|
12220
|
+
var ORCHESTRATION_SCHEMA_PATH = join49(
|
|
12131
12221
|
"services",
|
|
12132
12222
|
"api",
|
|
12133
12223
|
"src",
|
|
@@ -12139,8 +12229,8 @@ function auditDeclaredModelIds(repoRoot, options = {}) {
|
|
|
12139
12229
|
const knownModelIds = options.knownModelIds ?? OPENROUTER_MODEL_IDS;
|
|
12140
12230
|
const snapshotFetchedAt = options.snapshotFetchedAt ?? OPENROUTER_MODEL_SNAPSHOT_FETCHED_AT;
|
|
12141
12231
|
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
12142
|
-
const configPath =
|
|
12143
|
-
const orchestrationPath =
|
|
12232
|
+
const configPath = join49(repoRoot, CONFIG_PY_PATH);
|
|
12233
|
+
const orchestrationPath = join49(repoRoot, ORCHESTRATION_SCHEMA_PATH);
|
|
12144
12234
|
const configMissing = !existsSync40(configPath);
|
|
12145
12235
|
const orchestrationSchemaMissing = !existsSync40(orchestrationPath);
|
|
12146
12236
|
const knownSet = new Set(knownModelIds);
|
|
@@ -12160,13 +12250,13 @@ function auditDeclaredModelIds(repoRoot, options = {}) {
|
|
|
12160
12250
|
};
|
|
12161
12251
|
let settingsBlind = false;
|
|
12162
12252
|
if (!configMissing) {
|
|
12163
|
-
const settingsFields = extractSettingsModelFields(
|
|
12253
|
+
const settingsFields = extractSettingsModelFields(readFileSync36(configPath, "utf8"));
|
|
12164
12254
|
if (settingsFields.length === 0) settingsBlind = true;
|
|
12165
12255
|
for (const { field, value } of settingsFields) record(`${CONFIG_PY_PATH}#${field}`, value);
|
|
12166
12256
|
}
|
|
12167
12257
|
let curatedFieldsBlind = false;
|
|
12168
12258
|
if (!orchestrationSchemaMissing) {
|
|
12169
|
-
const curated = extractCuratedModelFields(
|
|
12259
|
+
const curated = extractCuratedModelFields(readFileSync36(orchestrationPath, "utf8"));
|
|
12170
12260
|
if (curated.rawFieldCount > 0 && curated.fields.every((f) => f.defaultValue === null && f.optionValues.length === 0)) {
|
|
12171
12261
|
curatedFieldsBlind = true;
|
|
12172
12262
|
}
|
|
@@ -12213,7 +12303,7 @@ function auditDeclaredModelIds(repoRoot, options = {}) {
|
|
|
12213
12303
|
function discoverPluginDirs(pluginsRoot) {
|
|
12214
12304
|
return listDirs(pluginsRoot).filter((name) => {
|
|
12215
12305
|
try {
|
|
12216
|
-
return
|
|
12306
|
+
return statSync13(join49(pluginsRoot, name, "biffo.plugin.json")).isFile();
|
|
12217
12307
|
} catch {
|
|
12218
12308
|
return false;
|
|
12219
12309
|
}
|
|
@@ -12226,8 +12316,8 @@ function auditPluginToolSupply(pluginsRoot) {
|
|
|
12226
12316
|
let terraformBlind = false;
|
|
12227
12317
|
let totalDeclaredTools = 0;
|
|
12228
12318
|
for (const name of pluginNames) {
|
|
12229
|
-
const pluginDir2 =
|
|
12230
|
-
const manifestText =
|
|
12319
|
+
const pluginDir2 = join49(pluginsRoot, name);
|
|
12320
|
+
const manifestText = readFileSync36(join49(pluginDir2, "biffo.plugin.json"), "utf8");
|
|
12231
12321
|
const manifest = extractManifestTools(manifestText);
|
|
12232
12322
|
if (manifest.parseError) {
|
|
12233
12323
|
findings.push({
|
|
@@ -12245,13 +12335,13 @@ function auditPluginToolSupply(pluginsRoot) {
|
|
|
12245
12335
|
totalDeclaredTools += manifest.tools.length;
|
|
12246
12336
|
const pySources = pluginPythonFiles(pluginDir2).map((f) => ({
|
|
12247
12337
|
file: f,
|
|
12248
|
-
text:
|
|
12338
|
+
text: readFileSync36(f, "utf8")
|
|
12249
12339
|
}));
|
|
12250
12340
|
const resolver = buildSymbolResolver(pySources);
|
|
12251
12341
|
const registry = extractToolRegistryEntries(pySources, resolver);
|
|
12252
12342
|
if (registry.rawToolDefinitionCount > 0 && registry.entries.length === 0) registryBlind = true;
|
|
12253
12343
|
const tfFiles = pluginTerraformFiles(pluginDir2);
|
|
12254
|
-
const tfText = tfFiles.map((f) =>
|
|
12344
|
+
const tfText = tfFiles.map((f) => readFileSync36(f, "utf8")).join("\n");
|
|
12255
12345
|
const terraform = extractTerraformEnvKeys(tfText);
|
|
12256
12346
|
if (terraform.rawMarkerCount > 0 && terraform.resolvedBlockCount === 0) terraformBlind = true;
|
|
12257
12347
|
for (const toolName of manifest.tools) {
|
|
@@ -12325,7 +12415,7 @@ function auditPluginToolSupply(pluginsRoot) {
|
|
|
12325
12415
|
requiredEnvVars: envResult.envVars,
|
|
12326
12416
|
missingEnvVars: anyWired ? [] : envResult.envVars,
|
|
12327
12417
|
status: anyWired ? "ok" : "missing-env",
|
|
12328
|
-
detail: anyWired ? `${entry.predicate}() is satisfiable: at least one of ${JSON.stringify(envResult.envVars)} is wired in Terraform` : `${entry.predicate}() reads ${JSON.stringify(envResult.envVars)} \u2014 NONE of these are wired by any environment_variables block under ${
|
|
12418
|
+
detail: anyWired ? `${entry.predicate}() is satisfiable: at least one of ${JSON.stringify(envResult.envVars)} is wired in Terraform` : `${entry.predicate}() reads ${JSON.stringify(envResult.envVars)} \u2014 NONE of these are wired by any environment_variables block under ${join49(pluginDir2, "terraform")}, so this deployment can never supply it`
|
|
12329
12419
|
});
|
|
12330
12420
|
}
|
|
12331
12421
|
}
|
|
@@ -12356,9 +12446,9 @@ function auditPluginToolSupply(pluginsRoot) {
|
|
|
12356
12446
|
|
|
12357
12447
|
// src/scripts/check-plugin-tool-supply.ts
|
|
12358
12448
|
async function runPluginToolSupplyCheck() {
|
|
12359
|
-
const root = (await
|
|
12449
|
+
const root = (await execa17("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
12360
12450
|
let allOk = true;
|
|
12361
|
-
const pluginsRoot =
|
|
12451
|
+
const pluginsRoot = join50(root, "services", "_plugins");
|
|
12362
12452
|
if (!existsSync41(pluginsRoot)) {
|
|
12363
12453
|
console.log("\u2713 plugin tool-supply guard: no services/_plugins/ \u2014 nothing to audit");
|
|
12364
12454
|
} else {
|
|
@@ -12389,7 +12479,7 @@ async function runPluginToolSupplyCheck() {
|
|
|
12389
12479
|
console.log(`\u2713 plugin tool-supply guard: ${report.summary}`);
|
|
12390
12480
|
}
|
|
12391
12481
|
}
|
|
12392
|
-
const servicesApiRoot =
|
|
12482
|
+
const servicesApiRoot = join50(root, "services", "api");
|
|
12393
12483
|
if (!existsSync41(servicesApiRoot)) {
|
|
12394
12484
|
console.log("\u2713 plugin model-id guard: no services/api/ \u2014 nothing to audit");
|
|
12395
12485
|
} else {
|
|
@@ -12436,7 +12526,7 @@ async function runPluginToolSupplyCheck() {
|
|
|
12436
12526
|
}
|
|
12437
12527
|
|
|
12438
12528
|
// src/scripts/check-release-subject.ts
|
|
12439
|
-
import { execa as
|
|
12529
|
+
import { execa as execa18 } from "execa";
|
|
12440
12530
|
|
|
12441
12531
|
// src/lib/release-version.ts
|
|
12442
12532
|
var MINOR_TYPES = /* @__PURE__ */ new Set(["feat"]);
|
|
@@ -12473,7 +12563,7 @@ async function fetchPrTitleViaGh({
|
|
|
12473
12563
|
PR_NUMBER,
|
|
12474
12564
|
GH_REPO
|
|
12475
12565
|
}) {
|
|
12476
|
-
const { stdout } = await
|
|
12566
|
+
const { stdout } = await execa18(
|
|
12477
12567
|
"gh",
|
|
12478
12568
|
["pr", "view", PR_NUMBER, "--repo", GH_REPO, "--json", "title", "--jq", ".title"],
|
|
12479
12569
|
{ env: { ...process.env, GH_TOKEN } }
|
|
@@ -12509,7 +12599,7 @@ async function resolveReleaseSubject({
|
|
|
12509
12599
|
);
|
|
12510
12600
|
}
|
|
12511
12601
|
}
|
|
12512
|
-
return (await
|
|
12602
|
+
return (await execa18("git", ["log", "-1", "--format=%s"], { cwd })).stdout.trim();
|
|
12513
12603
|
}
|
|
12514
12604
|
async function runReleaseSubjectCheck(argv) {
|
|
12515
12605
|
const base = process.env["GITHUB_BASE_REF"] ?? argv[0];
|
|
@@ -12517,9 +12607,9 @@ async function runReleaseSubjectCheck(argv) {
|
|
|
12517
12607
|
console.error("No base ref: set GITHUB_BASE_REF or pass a base branch as the first argument.");
|
|
12518
12608
|
process.exit(2);
|
|
12519
12609
|
}
|
|
12520
|
-
const root = (await
|
|
12521
|
-
await
|
|
12522
|
-
const { stdout } = await
|
|
12610
|
+
const root = (await execa18("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
12611
|
+
await execa18("git", ["fetch", "--quiet", "origin", base], { cwd: root, reject: false });
|
|
12612
|
+
const { stdout } = await execa18("git", ["diff", "--name-only", `origin/${base}...HEAD`], {
|
|
12523
12613
|
cwd: root
|
|
12524
12614
|
});
|
|
12525
12615
|
const changedFiles = stdout.split("\n").map((s) => s.trim()).filter(Boolean);
|
|
@@ -12567,13 +12657,13 @@ async function runReleaseSubjectCheck(argv) {
|
|
|
12567
12657
|
}
|
|
12568
12658
|
|
|
12569
12659
|
// src/scripts/check-skeleton-drift.ts
|
|
12570
|
-
import { existsSync as existsSync42, readdirSync as
|
|
12571
|
-
import { join as
|
|
12572
|
-
import { execa as
|
|
12660
|
+
import { existsSync as existsSync42, readdirSync as readdirSync24 } from "fs";
|
|
12661
|
+
import { join as join52 } from "path";
|
|
12662
|
+
import { execa as execa19 } from "execa";
|
|
12573
12663
|
|
|
12574
12664
|
// src/lib/skeleton-drift-guard.ts
|
|
12575
|
-
import { readFileSync as
|
|
12576
|
-
import { join as
|
|
12665
|
+
import { readFileSync as readFileSync37, readdirSync as readdirSync23, statSync as statSync14 } from "fs";
|
|
12666
|
+
import { join as join51 } from "path";
|
|
12577
12667
|
var isWorkflow = (rel) => rel.startsWith(".github/workflows/") && (rel.endsWith(".yml") || rel.endsWith(".yaml"));
|
|
12578
12668
|
var isRootLayout = (rel) => rel.endsWith("src/app/layout.tsx");
|
|
12579
12669
|
var uncommented = (contents) => contents.split("\n").filter((line) => !/^\s*(\/\/|\/\*|\*)/.test(line)).join("\n");
|
|
@@ -12631,16 +12721,16 @@ function walk(dir, base = dir) {
|
|
|
12631
12721
|
const out = [];
|
|
12632
12722
|
let entries;
|
|
12633
12723
|
try {
|
|
12634
|
-
entries =
|
|
12724
|
+
entries = readdirSync23(dir);
|
|
12635
12725
|
} catch {
|
|
12636
12726
|
return out;
|
|
12637
12727
|
}
|
|
12638
12728
|
for (const entry of entries) {
|
|
12639
12729
|
if (entry === ".venv" || entry === "node_modules" || entry === ".git") continue;
|
|
12640
|
-
const abs =
|
|
12730
|
+
const abs = join51(dir, entry);
|
|
12641
12731
|
let isDir;
|
|
12642
12732
|
try {
|
|
12643
|
-
isDir =
|
|
12733
|
+
isDir = statSync14(abs).isDirectory();
|
|
12644
12734
|
} catch {
|
|
12645
12735
|
continue;
|
|
12646
12736
|
}
|
|
@@ -12659,7 +12749,7 @@ function auditSkeleton(skeletonRoot, name, rules = SKELETON_RULES) {
|
|
|
12659
12749
|
if (!rule.appliesTo(rel)) continue;
|
|
12660
12750
|
let contents;
|
|
12661
12751
|
try {
|
|
12662
|
-
contents =
|
|
12752
|
+
contents = readFileSync37(join51(skeletonRoot, rel), "utf8");
|
|
12663
12753
|
} catch {
|
|
12664
12754
|
continue;
|
|
12665
12755
|
}
|
|
@@ -12688,23 +12778,23 @@ function formatViolations2(violations) {
|
|
|
12688
12778
|
|
|
12689
12779
|
// src/scripts/check-skeleton-drift.ts
|
|
12690
12780
|
function discoverSkeletons(root) {
|
|
12691
|
-
const skeletonsDir =
|
|
12781
|
+
const skeletonsDir = join52(root, "_skeletons");
|
|
12692
12782
|
let entries;
|
|
12693
12783
|
try {
|
|
12694
|
-
entries =
|
|
12784
|
+
entries = readdirSync24(skeletonsDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
12695
12785
|
} catch {
|
|
12696
12786
|
return [];
|
|
12697
12787
|
}
|
|
12698
|
-
return entries.filter((name) => existsSync42(
|
|
12788
|
+
return entries.filter((name) => existsSync42(join52(skeletonsDir, name, ".github", "workflows", "ci.yml"))).sort();
|
|
12699
12789
|
}
|
|
12700
12790
|
async function runSkeletonDriftCheck() {
|
|
12701
|
-
const root = (await
|
|
12791
|
+
const root = (await execa19("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
12702
12792
|
const skeletons = discoverSkeletons(root);
|
|
12703
12793
|
let filesConsidered = 0;
|
|
12704
12794
|
for (const name of skeletons) {
|
|
12705
|
-
const skeletonRoot =
|
|
12795
|
+
const skeletonRoot = join52(root, "_skeletons", name);
|
|
12706
12796
|
filesConsidered += findWorkflowFiles(skeletonRoot).length;
|
|
12707
|
-
if (existsSync42(
|
|
12797
|
+
if (existsSync42(join52(skeletonRoot, "apps", "frontend", "src", "app", "layout.tsx"))) {
|
|
12708
12798
|
filesConsidered += 1;
|
|
12709
12799
|
}
|
|
12710
12800
|
}
|
|
@@ -12718,7 +12808,7 @@ async function runSkeletonDriftCheck() {
|
|
|
12718
12808
|
process.exit(1);
|
|
12719
12809
|
}
|
|
12720
12810
|
const violations = skeletons.flatMap(
|
|
12721
|
-
(name) => auditSkeleton(
|
|
12811
|
+
(name) => auditSkeleton(join52(root, "_skeletons", name), name)
|
|
12722
12812
|
);
|
|
12723
12813
|
if (violations.length > 0) {
|
|
12724
12814
|
console.error("\u2717 Skeleton-drift guard: drift found between this repo and its scaffolding\n");
|
|
@@ -12730,9 +12820,9 @@ async function runSkeletonDriftCheck() {
|
|
|
12730
12820
|
}
|
|
12731
12821
|
|
|
12732
12822
|
// src/scripts/check-terraform-input.ts
|
|
12733
|
-
import { execa as
|
|
12823
|
+
import { execa as execa20 } from "execa";
|
|
12734
12824
|
async function runTerraformInputCheck() {
|
|
12735
|
-
const root = (await
|
|
12825
|
+
const root = (await execa20("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
12736
12826
|
const files = findWorkflowFiles(root);
|
|
12737
12827
|
console.log(`audited ${files.length} workflow file(s) under ${root}`);
|
|
12738
12828
|
if (files.length === 0) {
|
|
@@ -12755,7 +12845,7 @@ async function runTerraformInputCheck() {
|
|
|
12755
12845
|
|
|
12756
12846
|
// src/commands/check.ts
|
|
12757
12847
|
var checkCommand = new Command23("check").description(
|
|
12758
|
-
"Repo guards (ownership, release subject, plugin terraform, plugin collisions, eventbridge-log-permissions, plugin-tool-supply, core-direct-paths, cognito-invite-template, lambda-output, pipe-trap, skeleton-drift, terraform-input) run in CI and git hooks, plus out-of-band audits (branch protection)"
|
|
12848
|
+
"Repo guards (ownership, release subject, plugin terraform, plugin collisions, eventbridge-log-permissions, plugin-tool-supply, core-direct-paths, cognito-invite-template, lambda-output, pipe-trap, codeql-suppression, skeleton-drift, terraform-input) run in CI and git hooks, plus out-of-band audits (branch protection)"
|
|
12759
12849
|
);
|
|
12760
12850
|
checkCommand.command("ownership").description("Refuse changes to template-owned paths in an instance (#370)").argument("[base]", "Base branch to diff against; defaults to $GITHUB_BASE_REF").option("--staged <messageFile>", "Check staged changes instead of a branch diff (commit hook)").allowExcessArguments(true).action(async () => {
|
|
12761
12851
|
await runOwnershipCheck(rawArgsAfter("ownership"));
|
|
@@ -12812,6 +12902,11 @@ checkCommand.command("pipe-trap").description(
|
|
|
12812
12902
|
).action(async () => {
|
|
12813
12903
|
await runPipeTrapCheck();
|
|
12814
12904
|
});
|
|
12905
|
+
checkCommand.command("codeql-suppression").description(
|
|
12906
|
+
"Refuse a `// codeql[query-id]` comment anywhere in cli/src (#1491) \u2014 it does not suppress anything in this repo's CodeQL setup; alert #21 stayed open under one"
|
|
12907
|
+
).action(async () => {
|
|
12908
|
+
await runCodeqlSuppressionCheck();
|
|
12909
|
+
});
|
|
12815
12910
|
checkCommand.command("skeleton-drift").description(
|
|
12816
12911
|
"Refuse a fix this repo made for itself that never reached _skeletons/ \u2014 a hardcoded runner, the paid gitleaks action, an unhardened dependency audit, a hard-coded app title"
|
|
12817
12912
|
).action(async () => {
|
|
@@ -12836,8 +12931,8 @@ function rawArgsAfter(subcommand) {
|
|
|
12836
12931
|
}
|
|
12837
12932
|
|
|
12838
12933
|
// src/commands/doctor.ts
|
|
12839
|
-
import { existsSync as existsSync43, readFileSync as
|
|
12840
|
-
import { join as
|
|
12934
|
+
import { existsSync as existsSync43, readFileSync as readFileSync38 } from "fs";
|
|
12935
|
+
import { join as join53, resolve as resolve18 } from "path";
|
|
12841
12936
|
import chalk21 from "chalk";
|
|
12842
12937
|
import { Command as Command24 } from "commander";
|
|
12843
12938
|
|
|
@@ -13012,10 +13107,10 @@ async function runDoctor(options, deps = { git: new GitAdapter() }) {
|
|
|
13012
13107
|
return runDoctorChecks(facts);
|
|
13013
13108
|
}
|
|
13014
13109
|
function readLocalCoreVersion(cwd) {
|
|
13015
|
-
const path =
|
|
13110
|
+
const path = join53(cwd, INSTANCE_CORE_FILE);
|
|
13016
13111
|
if (!existsSync43(path)) return null;
|
|
13017
13112
|
try {
|
|
13018
|
-
return parseCoreRecord(
|
|
13113
|
+
return parseCoreRecord(readFileSync38(path, "utf8"));
|
|
13019
13114
|
} catch {
|
|
13020
13115
|
return null;
|
|
13021
13116
|
}
|
|
@@ -13030,10 +13125,10 @@ function parseCoreRecord(contents) {
|
|
|
13030
13125
|
}
|
|
13031
13126
|
}
|
|
13032
13127
|
function readFossil(cwd) {
|
|
13033
|
-
const path =
|
|
13128
|
+
const path = join53(cwd, CORE_VERSION_FILE);
|
|
13034
13129
|
if (!existsSync43(path)) return null;
|
|
13035
13130
|
try {
|
|
13036
|
-
const value =
|
|
13131
|
+
const value = readFileSync38(path, "utf8").trim();
|
|
13037
13132
|
return value === "" ? null : value;
|
|
13038
13133
|
} catch {
|
|
13039
13134
|
return null;
|
|
@@ -13483,11 +13578,11 @@ import { Command as Command26 } from "commander";
|
|
|
13483
13578
|
|
|
13484
13579
|
// src/lib/packaged-scripts.ts
|
|
13485
13580
|
import { existsSync as existsSync44 } from "fs";
|
|
13486
|
-
import { dirname as dirname11, join as
|
|
13581
|
+
import { dirname as dirname11, join as join54 } from "path";
|
|
13487
13582
|
function findPackagedScript(startDir, relativePath) {
|
|
13488
13583
|
let dir = startDir;
|
|
13489
13584
|
for (; ; ) {
|
|
13490
|
-
const candidate =
|
|
13585
|
+
const candidate = join54(dir, relativePath);
|
|
13491
13586
|
if (existsSync44(candidate)) return candidate;
|
|
13492
13587
|
const parent = dirname11(dir);
|
|
13493
13588
|
if (parent === dir) return null;
|