border-customs 0.7.1 → 0.8.1

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 CHANGED
@@ -13029,7 +13029,7 @@ var require_micromatch = __commonJS({
13029
13029
 
13030
13030
  // src/index.ts
13031
13031
  import { realpathSync } from "node:fs";
13032
- import { fileURLToPath as fileURLToPath6, pathToFileURL } from "node:url";
13032
+ import { fileURLToPath as fileURLToPath7, pathToFileURL } from "node:url";
13033
13033
 
13034
13034
  // src/cli.ts
13035
13035
  import { parseArgs } from "node:util";
@@ -37459,6 +37459,19 @@ function matchHostProfile(text, _o) {
37459
37459
  flush();
37460
37460
  return hits;
37461
37461
  }
37462
+ var BINDING_TOKEN = String.raw`\b(?:q` + "wen" + String.raw`|deep` + "seek" + String.raw`|kimi|g` + "lm" + String.raw`|ernie|dou` + "bao" + String.raw`|hunyuan|sp` + "ark" + String.raw`)[-\.\d][\w.-]*\b`;
37463
+ var BINDING_VENDOR_RE = new RegExp(BINDING_TOKEN, "gi");
37464
+ var BINDING_CONTEXT_RE = /(?:model|模型|default|默认|provider)/i;
37465
+ function matchMachineBinding(text, _o) {
37466
+ const hits = [];
37467
+ text.split("\n").forEach((body, idx) => {
37468
+ if (!BINDING_CONTEXT_RE.test(body)) return;
37469
+ for (const m of body.matchAll(BINDING_VENDOR_RE)) {
37470
+ hits.push({ rule: "exfil-machine-binding", matched: m[0] ?? "", line: idx + 1, message: "Machine binding: a vendor inference-model id pinned next to model/default/provider context \u2014 device authorization belongs in operator-local config, not portable surfaces (L-MACHINE-LOCAL)." });
37471
+ }
37472
+ });
37473
+ return hits;
37474
+ }
37462
37475
 
37463
37476
  // src/exfil/rules.ts
37464
37477
  var OCTET = "(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])";
@@ -38093,12 +38106,12 @@ function packOnce(o) {
38093
38106
  throw new EngineRunError(`npm pack reported '${report.filename}' but no tarball landed in ${o.distDir}`, null);
38094
38107
  }
38095
38108
  const data = readFileSync3(tarballAbs);
38096
- const sha2564 = createHash3("sha256").update(data).digest("hex");
38109
+ const sha2563 = createHash3("sha256").update(data).digest("hex");
38097
38110
  const sha1 = createHash3("sha1").update(data).digest("hex");
38098
38111
  if (sha1 !== report.shasum || data.byteLength !== report.size) {
38099
38112
  throw new EngineRunError(`npm pack report disagrees with the tarball bytes for ${report.filename} \u2014 corrupted or swapped artifact, failing closed`, null);
38100
38113
  }
38101
- return { filename: report.filename, sha256: sha2564, bytes: data.byteLength, tarballAbs };
38114
+ return { filename: report.filename, sha256: sha2563, bytes: data.byteLength, tarballAbs };
38102
38115
  }
38103
38116
  function publintFinding(o, tarballAbs, identity) {
38104
38117
  const candidates = o.publintBinPath !== void 0 ? [o.publintBinPath] : [
@@ -39141,7 +39154,7 @@ async function runNpmArtifactStage(o) {
39141
39154
  const stateDir = join10(repoDir, BORDER_STATE_DIR);
39142
39155
  const distDir = join10(stateDir, "dist");
39143
39156
  mkdirSync3(distDir, { recursive: true });
39144
- const { filename, sha256: sha2564, bytes, tarballAbs } = packOnce({
39157
+ const { filename, sha256: sha2563, bytes, tarballAbs } = packOnce({
39145
39158
  repoDir,
39146
39159
  distDir,
39147
39160
  ...o.env !== void 0 ? { env: o.env } : {},
@@ -39149,7 +39162,7 @@ async function runNpmArtifactStage(o) {
39149
39162
  ...o.npmTimeoutMs !== void 0 ? { npmTimeoutMs: o.npmTimeoutMs } : {}
39150
39163
  });
39151
39164
  const findings = [];
39152
- const extractDir = join10(stateDir, "tmp", sha2564.slice(0, 8));
39165
+ const extractDir = join10(stateDir, "tmp", sha2563.slice(0, 8));
39153
39166
  rmSync3(extractDir, { recursive: true, force: true });
39154
39167
  mkdirSync3(extractDir, { recursive: true });
39155
39168
  try {
@@ -39254,7 +39267,7 @@ async function runNpmArtifactStage(o) {
39254
39267
  if (publint !== null) findings.push(publint);
39255
39268
  return {
39256
39269
  findings,
39257
- artifact: { file: `${BORDER_STATE_DIR}/dist/${filename}`, sha256: sha2564, bytes }
39270
+ artifact: { file: `${BORDER_STATE_DIR}/dist/${filename}`, sha256: sha2563, bytes }
39258
39271
  };
39259
39272
  }
39260
39273
 
@@ -39649,8 +39662,9 @@ async function computeCheckRulesHash(input2) {
39649
39662
  promptTemplatePaths: existsSync7(template) ? [template] : []
39650
39663
  });
39651
39664
  }
39665
+ var CHECK_LENS_ID = "range+tip-tree/1";
39652
39666
  function computeCheckKey(input2) {
39653
- return sha256(stableStringify({ ...input2 }));
39667
+ return sha256(stableStringify({ ...input2, lens: CHECK_LENS_ID }));
39654
39668
  }
39655
39669
 
39656
39670
  // src/engines/trufflehog.ts
@@ -40354,9 +40368,9 @@ async function runRubygemsArtifactStage(o) {
40354
40368
  throw new EngineRunError(`gem build produced no ${gemName} in ${relative3(repoDir, distDir)} \u2014 failing closed (was the gemspec's literal name/version re-read?)`, null);
40355
40369
  }
40356
40370
  const bytes = readFileSync7(dist);
40357
- const sha2564 = createHash6("sha256").update(bytes).digest("hex");
40371
+ const sha2563 = createHash6("sha256").update(bytes).digest("hex");
40358
40372
  const findings = [];
40359
- const extractDir = join12(stateDir, "tmp", sha2564.slice(0, 8));
40373
+ const extractDir = join12(stateDir, "tmp", sha2563.slice(0, 8));
40360
40374
  rmSync4(extractDir, { recursive: true, force: true });
40361
40375
  mkdirSync4(extractDir, { recursive: true });
40362
40376
  const dataDir = `${extractDir}-data`;
@@ -40434,7 +40448,7 @@ async function runRubygemsArtifactStage(o) {
40434
40448
  }
40435
40449
  return {
40436
40450
  findings,
40437
- artifact: { file: `${BORDER_STATE_DIR}/dist/${gemName}`, sha256: sha2564, bytes: bytes.length }
40451
+ artifact: { file: `${BORDER_STATE_DIR}/dist/${gemName}`, sha256: sha2563, bytes: bytes.length }
40438
40452
  };
40439
40453
  }
40440
40454
 
@@ -41996,9 +42010,9 @@ async function runCargoArtifactStage(o) {
41996
42010
  const dist = join18(distDir, crateName);
41997
42011
  renameSync(packed, dist);
41998
42012
  const bytes = readFileSync11(dist);
41999
- const sha2564 = createHash11("sha256").update(bytes).digest("hex");
42013
+ const sha2563 = createHash11("sha256").update(bytes).digest("hex");
42000
42014
  const findings = [];
42001
- const extractDir = join18(stateDir, "tmp", sha2564.slice(0, 8));
42015
+ const extractDir = join18(stateDir, "tmp", sha2563.slice(0, 8));
42002
42016
  rmSync8(extractDir, { recursive: true, force: true });
42003
42017
  mkdirSync8(extractDir, { recursive: true });
42004
42018
  try {
@@ -42051,7 +42065,7 @@ async function runCargoArtifactStage(o) {
42051
42065
  }
42052
42066
  return {
42053
42067
  findings,
42054
- artifact: { file: `${BORDER_STATE_DIR}/dist/${crateName}`, sha256: sha2564, bytes: bytes.length }
42068
+ artifact: { file: `${BORDER_STATE_DIR}/dist/${crateName}`, sha256: sha2563, bytes: bytes.length }
42055
42069
  };
42056
42070
  } finally {
42057
42071
  rmSync8(targetDir, { recursive: true, force: true });
@@ -42866,7 +42880,8 @@ function exposureSet(cfg, options = {}) {
42866
42880
  }
42867
42881
 
42868
42882
  // src/check.ts
42869
- import { join as join23 } from "node:path";
42883
+ import { createHash as createHash15 } from "node:crypto";
42884
+ import { join as join25 } from "node:path";
42870
42885
 
42871
42886
  // src/rules/aiArtifacts.ts
42872
42887
  import { spawnSync as spawnSync12 } from "node:child_process";
@@ -43050,6 +43065,7 @@ function scanAiArtifacts(o) {
43050
43065
 
43051
43066
  // src/check/exclusions.ts
43052
43067
  import { resolve as resolve11 } from "node:path";
43068
+ var PATH_PATTERN_RULE_PREFIX = "path-pattern:";
43053
43069
  function toRepoRelative(path4, repoDir) {
43054
43070
  if (path4 === void 0 || path4 === "") return null;
43055
43071
  const abs = resolve11(repoDir, path4);
@@ -43062,6 +43078,21 @@ function isBorderStatePath(repoRelPath) {
43062
43078
  function filterBorderStateFindings(findings, repoDir) {
43063
43079
  return findings.filter((f) => !isBorderStatePath(toRepoRelative(f.path, repoDir)));
43064
43080
  }
43081
+ function suppressGateConfigPathPatterns(findings, repoDir, configSource) {
43082
+ const kept = [];
43083
+ let suppressed = 0;
43084
+ const cfgAbs = configSource === void 0 ? "" : resolve11(configSource);
43085
+ if (cfgAbs === "") return { kept: [...findings], suppressed: 0 };
43086
+ for (const f of findings) {
43087
+ const outer = (f.path ?? "").split("!")[0] ?? "";
43088
+ if (f.rule.startsWith(PATH_PATTERN_RULE_PREFIX) && outer !== "" && resolve11(repoDir, outer) === cfgAbs) {
43089
+ suppressed += 1;
43090
+ continue;
43091
+ }
43092
+ kept.push(f);
43093
+ }
43094
+ return { kept, suppressed };
43095
+ }
43065
43096
 
43066
43097
  // src/check/allow.ts
43067
43098
  function scopePath(finding, repoDir) {
@@ -43122,7 +43153,8 @@ var EXFIL_RULE_IDS = [
43122
43153
  "exfil-ssh-target",
43123
43154
  "exfil-home-path",
43124
43155
  "exfil-cred-location",
43125
- "exfil-host-profile"
43156
+ "exfil-host-profile",
43157
+ "exfil-machine-binding"
43126
43158
  ];
43127
43159
  var EXFIL_MESSAGE_ID_SUFFIX = ":message";
43128
43160
  var EXFIL_TABLE_SEVERITY = {
@@ -43130,7 +43162,8 @@ var EXFIL_TABLE_SEVERITY = {
43130
43162
  "exfil-ssh-target": "HIGH",
43131
43163
  "exfil-home-path": "MEDIUM",
43132
43164
  "exfil-cred-location": "MEDIUM",
43133
- "exfil-host-profile": "MEDIUM"
43165
+ "exfil-host-profile": "MEDIUM",
43166
+ "exfil-machine-binding": "MEDIUM"
43134
43167
  };
43135
43168
  var EXFIL_HIGH_FAMILY = ["exfil-rfc1918", "exfil-ssh-target"];
43136
43169
  var EXFIL_SECRET_VALUE_RULES = EXFIL_HIGH_FAMILY;
@@ -43139,19 +43172,21 @@ var TWIN_HIGH = {
43139
43172
  "exfil-ssh-target": "CRITICAL",
43140
43173
  "exfil-home-path": null,
43141
43174
  "exfil-cred-location": null,
43142
- "exfil-host-profile": null
43175
+ "exfil-host-profile": null,
43176
+ "exfil-machine-binding": null
43143
43177
  };
43144
43178
  var NULL_ROW = {
43145
43179
  "exfil-rfc1918": null,
43146
43180
  "exfil-ssh-target": null,
43147
43181
  "exfil-home-path": null,
43148
43182
  "exfil-cred-location": null,
43149
- "exfil-host-profile": null
43183
+ "exfil-host-profile": null,
43184
+ "exfil-machine-binding": null
43150
43185
  };
43151
43186
  var EXFIL_MATRIX = {
43152
43187
  tree: {
43153
43188
  // native tree leg = MEDIUM family补发 only (v2 double-emission revoked).
43154
- native: { ...NULL_ROW, "exfil-home-path": "MEDIUM", "exfil-cred-location": "MEDIUM", "exfil-host-profile": "MEDIUM" },
43189
+ native: { ...NULL_ROW, "exfil-home-path": "MEDIUM", "exfil-cred-location": "MEDIUM", "exfil-host-profile": "MEDIUM", "exfil-machine-binding": "MEDIUM" },
43155
43190
  // gitleaks.ts:81 hardcodes CRITICAL for every ingested finding.
43156
43191
  "gitleaks-twin": TWIN_HIGH,
43157
43192
  // secretlint.ts:299-309 has no HIGH rung — error maps to CRITICAL as-is.
@@ -43202,7 +43237,8 @@ var PREDICATES = {
43202
43237
  "exfil-ssh-target": matchSshTarget,
43203
43238
  "exfil-home-path": matchHomePath,
43204
43239
  "exfil-cred-location": matchCredLocation,
43205
- "exfil-host-profile": matchHostProfile
43240
+ "exfil-host-profile": matchHostProfile,
43241
+ "exfil-machine-binding": matchMachineBinding
43206
43242
  };
43207
43243
  function scanFacet(input2, facet) {
43208
43244
  const channel = "native";
@@ -43287,6 +43323,17 @@ function scanExfilTree(o) {
43287
43323
  return findings;
43288
43324
  }
43289
43325
 
43326
+ // src/check/tipTreeLens.ts
43327
+ import { mkdtempSync as mkdtempSync5, rmSync as rmSync12 } from "node:fs";
43328
+ import { tmpdir as tmpdir4 } from "node:os";
43329
+ import { join as join24 } from "node:path";
43330
+
43331
+ // src/commands/exfil.ts
43332
+ import { createHash as createHash14 } from "node:crypto";
43333
+ import { existsSync as existsSync15, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync4, readFileSync as readFileSync15, rmSync as rmSync11, writeFileSync as writeFileSync5 } from "node:fs";
43334
+ import { tmpdir as tmpdir3 } from "node:os";
43335
+ import { dirname as dirname12, join as join23 } from "node:path";
43336
+
43290
43337
  // src/check/messageScan.ts
43291
43338
  import { spawnSync as spawnSync13 } from "node:child_process";
43292
43339
  import { dirname as dirname10, resolve as resolve13 } from "node:path";
@@ -43404,44 +43451,6 @@ function scanCommitMessages(o) {
43404
43451
  return findings;
43405
43452
  }
43406
43453
 
43407
- // src/check/proofValve.ts
43408
- var ROUNDTRIP_PROOF_MISSING_RULE = "roundtrip-proof-missing";
43409
- var ROUNDTRIP_PROOF_STALE_RULE = "roundtrip-proof-stale";
43410
- var RESIDUE_RULE_IDS = new Set(Object.keys(RESIDUE_SEVERITIES));
43411
- function hasBlockingResidueCapability(findings) {
43412
- return findings.some((f) => RESIDUE_RULE_IDS.has(f.rule) && isBlocking(f.severity));
43413
- }
43414
- function proofFinding(rule, art, cause) {
43415
- return {
43416
- rule,
43417
- severity: "CRITICAL",
43418
- target: "artifact",
43419
- path: art.file,
43420
- engine: "native",
43421
- message: `${art.file} (sha256 ${art.sha256.slice(0, 12)}\u2026) tripped the residue scan while residue.requireProof is on, but ${cause}. Run 'border roundtrip <spec>' for exactly these bytes to mint the ledger proof.`,
43422
- ...redact(`${art.sha256}:${cause}`),
43423
- snippet: `${art.file} ${art.sha256.slice(0, 12)}`
43424
- };
43425
- }
43426
- function proofFindings(o) {
43427
- const out = [];
43428
- for (const art of o.artifacts) {
43429
- const rec = latestRoundtripForSha(o.records, art.sha256);
43430
- if (rec === null) {
43431
- out.push(proofFinding(ROUNDTRIP_PROOF_MISSING_RULE, art, "no roundtrip proof record exists for its digest"));
43432
- } else if (rec.rulesHash !== o.rulesHash) {
43433
- out.push(
43434
- proofFinding(
43435
- ROUNDTRIP_PROOF_STALE_RULE,
43436
- art,
43437
- `its proof record predates the current rules policy (recorded ${rec.rulesHash.slice(0, 12)}\u2026, required ${o.rulesHash.slice(0, 12)}\u2026)`
43438
- )
43439
- );
43440
- }
43441
- }
43442
- return out;
43443
- }
43444
-
43445
43454
  // src/check/tagScan.ts
43446
43455
  import { spawnSync as spawnSync14 } from "node:child_process";
43447
43456
  import { mkdtempSync as mkdtempSync3, rmSync as rmSync10, writeFileSync as writeFileSync4 } from "node:fs";
@@ -43556,266 +43565,6 @@ function scanTagMessages(o) {
43556
43565
  }
43557
43566
  }
43558
43567
 
43559
- // src/check.ts
43560
- var TRACKED_BORDER_RULE = "repo-tracks-border-state";
43561
- var GUARD_PATH_CAP = 50;
43562
- function trackedBorderStateFinding(repoDir, headSha, env2) {
43563
- const listing = runGitChecked(repoDir, ["ls-files", "--", `${BORDER_STATE_DIR}/`], { ...env2 !== void 0 ? { env: env2 } : {} }).split("\n").filter((p) => p !== "");
43564
- if (listing.length === 0) return null;
43565
- const shown = listing.slice(0, GUARD_PATH_CAP);
43566
- const rest = listing.length - shown.length;
43567
- const [first = `${BORDER_STATE_DIR}/`] = shown;
43568
- const message = `repository tracks ${String(listing.length)} file(s) under ${BORDER_STATE_DIR}/ \u2014 border's state directory must stay untracked: ${shown.join(", ")}${rest > 0 ? ` (+${String(rest)} more)` : ""}. Remove with 'git rm -r --cached ${BORDER_STATE_DIR}/'.`;
43569
- return {
43570
- rule: TRACKED_BORDER_RULE,
43571
- severity: "CRITICAL",
43572
- target: "git",
43573
- path: first,
43574
- commit: headSha,
43575
- engine: "native",
43576
- message,
43577
- ...redact(`${headSha}:${BORDER_STATE_DIR}`),
43578
- snippet: `${BORDER_STATE_DIR}/ tracked`
43579
- };
43580
- }
43581
- function legOptions(o, sanitizer) {
43582
- return {
43583
- ...o.env !== void 0 ? { env: o.env } : {},
43584
- sanitizer
43585
- };
43586
- }
43587
- function historyRefRange(ctx) {
43588
- return ctx.refSet.length > 0 ? ctx.refSet.join(" ") : ctx.headSha;
43589
- }
43590
- async function executeCheck(o) {
43591
- const envOpt = o.env !== void 0 ? { env: o.env } : {};
43592
- const ctx = gatherContext(o.repoDir, envOpt);
43593
- const { handle, warning } = acquireLock(o.repoDir);
43594
- try {
43595
- return await runPipeline(o, ctx, warning);
43596
- } finally {
43597
- releaseLock(handle);
43598
- }
43599
- }
43600
- async function runPipeline(o, ctx, lockWarning) {
43601
- const repoDir = ctx.repoDir;
43602
- const envOpt = o.env !== void 0 ? { env: o.env } : {};
43603
- const findings = [];
43604
- const guard = trackedBorderStateFinding(repoDir, ctx.headSha, o.env);
43605
- const probe = await probeEngines(o.cfg, {
43606
- ...envOpt,
43607
- ...o.requireOverride !== void 0 ? { requireOverride: o.requireOverride } : {}
43608
- });
43609
- findings.push(...probe.findings);
43610
- if (guard !== null) findings.push(guard);
43611
- const broken = new Set(probe.findings.map((f) => f.engine));
43612
- const sanitizer = new TextSanitizer();
43613
- findings.push(...filterBorderStateFindings(detectHostileConfig({ repoDir, target: "git", ...envOpt }), repoDir));
43614
- if (!broken.has("gitleaks")) {
43615
- const eng = legOptions(o, sanitizer);
43616
- findings.push(...filterBorderStateFindings(scanGitHistory({ repoDir, refRange: historyRefRange(ctx), target: "git", ...eng }), repoDir));
43617
- findings.push(...filterBorderStateFindings(scanTree({ dir: repoDir, stateDir: join23(repoDir, BORDER_STATE_DIR), target: "tree", ...eng }), repoDir));
43618
- findings.push(...filterBorderStateFindings(scanTagMessages({ repoDir, target: "git", ...eng }), repoDir));
43619
- }
43620
- if (!broken.has("secretlint")) {
43621
- findings.push(...await scanGitTrackedFiles({ repoDir, target: "git", rules: o.cfg.rules, ...legOptions(o, sanitizer) }));
43622
- }
43623
- if (o.cfg.engines.trufflehog && !broken.has("trufflehog")) {
43624
- findings.push(...scanTrufflehog({ repoDir, target: "git", ...legOptions(o, sanitizer) }));
43625
- }
43626
- findings.push(...scanAiArtifacts({ repoDir, refSet: [...ctx.refSet], cfg: o.cfg.rules, ...envOpt }));
43627
- findings.push(...scanIdentity({ repoDir, refSet: [...ctx.refSet], cfg: o.cfg, ...envOpt }));
43628
- findings.push(...filterBorderStateFindings(scanExfilTree({ repoDir, hosts: o.cfg.rules.hosts, ...legOptions(o, sanitizer) }), repoDir));
43629
- findings.push(...filterBorderStateFindings(
43630
- scanCommitMessages({
43631
- repoDir,
43632
- refSet: ctx.refSet.length > 0 ? [...ctx.refSet] : [ctx.headSha],
43633
- remotes: o.cfg.targets.git.remotes,
43634
- hosts: o.cfg.rules.hosts,
43635
- ...legOptions(o, sanitizer)
43636
- }),
43637
- repoDir
43638
- ));
43639
- const ledgerArtifacts = [];
43640
- for (const channel of publishChannels()) {
43641
- if (!o.effectiveTargets.includes(channel.id) || !channel.configured(o.cfg)) continue;
43642
- const stage = await channel.stage({
43643
- repoDir,
43644
- cfg: o.cfg,
43645
- sanitizer,
43646
- ...envOpt,
43647
- skipGitleaks: broken.has("gitleaks"),
43648
- skipSecretlint: broken.has("secretlint")
43649
- });
43650
- findings.push(...stage.findings);
43651
- ledgerArtifacts.push(...stage.artifacts);
43652
- }
43653
- if ((o.cfg.release?.twin.length ?? 0) > 0) {
43654
- findings.push(
43655
- ...await twinCoherenceFindings({
43656
- pairs: o.cfg.release?.twin ?? [],
43657
- artifacts: ledgerArtifacts,
43658
- repoDir,
43659
- ...envOpt,
43660
- sanitizer
43661
- })
43662
- );
43663
- }
43664
- findings.push(...await runRegistryProbes({ repoDir, cfg: o.cfg, effectiveTargets: o.effectiveTargets, ...envOpt }));
43665
- if (o.cfg.residue?.enabled === false) {
43666
- for (let i = findings.length - 1; i >= 0; i -= 1) {
43667
- const f = findings[i];
43668
- if (f !== void 0 && RESIDUE_RULE_IDS.has(f.rule)) findings.splice(i, 1);
43669
- }
43670
- }
43671
- const rulesHash = await computeCheckRulesHash({
43672
- engineVersions: probe.engineVersions,
43673
- configDigest: o.configDigest,
43674
- ...o.env !== void 0 ? { env: o.env } : {}
43675
- });
43676
- if (o.cfg.residue?.requireProof === true && ledgerArtifacts.length > 0 && hasBlockingResidueCapability(findings)) {
43677
- findings.push(...proofFindings({ artifacts: ledgerArtifacts, records: readLedger(repoDir).records, rulesHash }));
43678
- }
43679
- const exposure = [...exposureSet(o.cfg, { cwd: repoDir })];
43680
- const allow = applyAllowList(findings, o.cfg.allow, repoDir);
43681
- const report = {
43682
- schemaVersion: 1,
43683
- key: computeCheckKey({
43684
- headSha: ctx.headSha,
43685
- porcelainDigest: ctx.porcelainDigest,
43686
- rulesHash,
43687
- exposureSet: exposure,
43688
- refSet: ctx.refSet,
43689
- effectiveTargets: o.effectiveTargets
43690
- }),
43691
- head: ctx.headSha,
43692
- dirty: ctx.dirty,
43693
- exposureSet: exposure,
43694
- refSet: ctx.refSet,
43695
- rulesHash,
43696
- verdict: computeVerdict(allow.kept),
43697
- counts: countFindings(allow.kept),
43698
- findings: allow.kept,
43699
- ...allow.allowHits.length > 0 ? { allowHits: allow.allowHits } : {},
43700
- ts: (/* @__PURE__ */ new Date()).toISOString()
43701
- };
43702
- return {
43703
- report,
43704
- ctx,
43705
- degraded: probe.degraded,
43706
- sanitizedSummary: sanitizeSummary(report, sanitizer),
43707
- lockWarning,
43708
- artifacts: ledgerArtifacts.length > 0 ? ledgerArtifacts : null
43709
- };
43710
- }
43711
- function sanitizeSummary(report, sanitizer) {
43712
- const lines = report.findings.map(
43713
- (f) => sanitizer.sanitize(`${f.severity} ${f.rule} ${f.engine} ${f.path ?? ""} ${f.commit ?? ""} ${f.message}`.replace(/\s+/g, " ").trim())
43714
- );
43715
- lines.unshift(sanitizer.sanitize(`border check ${report.verdict}: ${String(report.counts.total)} finding(s), ${String(report.counts.blocking)} blocking`));
43716
- return lines.join("\n");
43717
- }
43718
-
43719
- // src/commands/check.ts
43720
- async function runCheck(ctx) {
43721
- const env2 = ctx.env;
43722
- const load = loadConfig({
43723
- cwd: ctx.cwd,
43724
- ...ctx.flags.config !== void 0 ? { configPath: ctx.flags.config } : {},
43725
- ...env2 !== void 0 ? { env: env2 } : {}
43726
- });
43727
- for (const warning of load.warnings) ctx.stderr(`border: ${warning}`);
43728
- let effective;
43729
- if (load.kind === "loaded") {
43730
- effective = load;
43731
- } else if (load.explicit !== void 0) {
43732
- effective = { kind: "loaded", config: load.explicit.config, warnings: [], source: load.explicit.source };
43733
- } else {
43734
- if (ctx.flags.requireEngine !== void 0 && ctx.flags.requireEngine.length > 0) {
43735
- const probe = await probeEngines(NO_TARGETS_PROBE_CFG, {
43736
- requireOverride: ctx.flags.requireEngine,
43737
- ...env2 !== void 0 ? { env: env2 } : {}
43738
- });
43739
- if (probe.degraded) {
43740
- for (const finding of probe.findings) ctx.stderr(`border: ${finding.message}`);
43741
- return EXIT_ERROR;
43742
- }
43743
- }
43744
- ctx.stdout(`border: ${NO_OP_MESSAGE}`);
43745
- return EXIT_PASS;
43746
- }
43747
- const configDigest = computeConfigDigest(effective);
43748
- const repoDir = resolveRepoDir(ctx.cwd, { env: env2 });
43749
- const effectiveTargets = computeEffectiveTargets(effective.config, ctx.flags.targets);
43750
- if (!ctx.flags.force) {
43751
- const decision = await consultSkipLedger({
43752
- repoDir,
43753
- cfg: effective.config,
43754
- configDigest,
43755
- effectiveTargets,
43756
- llm: ctx.flags.llm,
43757
- ...env2 !== void 0 ? { env: env2 } : {},
43758
- ...ctx.flags.requireEngine !== void 0 && ctx.flags.requireEngine.length > 0 ? { requireOverride: ctx.flags.requireEngine } : {}
43759
- });
43760
- for (const warning of decision.warnings) ctx.stderr(`border: WARNING ${warning}`);
43761
- if (decision.skip !== null) {
43762
- ctx.stdout(formatSkipLine(decision.skip));
43763
- return exitCodeFromVerdict(decision.skip.verdict);
43764
- }
43765
- }
43766
- let outcome;
43767
- try {
43768
- outcome = await executeCheck({
43769
- repoDir,
43770
- cfg: effective.config,
43771
- configDigest,
43772
- effectiveTargets,
43773
- ...env2 !== void 0 ? { env: env2 } : {},
43774
- ...ctx.flags.requireEngine !== void 0 && ctx.flags.requireEngine.length > 0 ? { requireOverride: ctx.flags.requireEngine } : {}
43775
- });
43776
- } catch (err) {
43777
- if (err instanceof BorderLockHeldError) {
43778
- ctx.stderr(`border: ${err.message}`);
43779
- return EXIT_ERROR;
43780
- }
43781
- throw err;
43782
- }
43783
- if (outcome.lockWarning !== null) ctx.stderr(`border: WARNING ${outcome.lockWarning}`);
43784
- if (outcome.ctx.dirty) ctx.stderr("border: working tree is dirty \u2014 findings may reference uncommitted files");
43785
- if (ctx.flags.json) {
43786
- ctx.stdout(renderReportJson(outcome.report));
43787
- } else {
43788
- for (const line of outcome.sanitizedSummary.split("\n")) ctx.stdout(`border: ${line}`);
43789
- }
43790
- if (outcome.degraded) {
43791
- ctx.stderr("border: required engine(s) degraded \u2014 verdict is UNTRUSTWORTHY (exit 2 regardless of findings)");
43792
- return EXIT_ERROR;
43793
- }
43794
- recordCheckRun({
43795
- repoDir,
43796
- report: outcome.report,
43797
- ctx: outcome.ctx,
43798
- effectiveTargets,
43799
- llm: ctx.flags.llm,
43800
- artifacts: outcome.artifacts,
43801
- ...env2 !== void 0 ? { env: env2 } : {}
43802
- });
43803
- return exitCodeFromVerdict(outcome.report.verdict);
43804
- }
43805
- var NO_TARGETS_PROBE_CFG = {
43806
- version: 1,
43807
- targets: { git: { remotes: [] } },
43808
- rules: { authors: { emails: [], names: [] }, hosts: [], ips: [], pathPatterns: [], maxFileKB: 500 },
43809
- allow: [],
43810
- engines: { require: [], trufflehog: false }
43811
- };
43812
-
43813
- // src/commands/exfil.ts
43814
- import { createHash as createHash14 } from "node:crypto";
43815
- import { existsSync as existsSync15, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync4, readFileSync as readFileSync15, rmSync as rmSync11, writeFileSync as writeFileSync5 } from "node:fs";
43816
- import { tmpdir as tmpdir3 } from "node:os";
43817
- import { dirname as dirname12, join as join24 } from "node:path";
43818
-
43819
43568
  // src/commands/exfilGit.ts
43820
43569
  import { spawnSync as spawnSync15 } from "node:child_process";
43821
43570
  import { dirname as dirname11, resolve as resolve15 } from "node:path";
@@ -43933,7 +43682,7 @@ function scanBlobsNative(git, blobs) {
43933
43682
  }
43934
43683
  return findings;
43935
43684
  }
43936
- async function scanTipTree(git, treeRoot, rev, env2) {
43685
+ async function scanTipTree(git, treeRoot, rev, env2, opts) {
43937
43686
  const blobs = tipTree(git, rev);
43938
43687
  const texts = blobTexts(git, blobs);
43939
43688
  const native = [];
@@ -43941,16 +43690,23 @@ async function scanTipTree(git, treeRoot, rev, env2) {
43941
43690
  for (const b of blobs) {
43942
43691
  const text = texts.get(b.sha);
43943
43692
  if (text === void 0) continue;
43944
- for (const f of scanTreeText({ text, source: b.path })) native.push(toTreeFinding(f));
43693
+ for (const f of scanTreeText({
43694
+ text,
43695
+ source: b.path,
43696
+ ...opts?.sanitizer !== void 0 ? { onMatch: (rawValue, valueDigest) => opts.sanitizer?.register(valueDigest, rawValue) } : {}
43697
+ })) {
43698
+ native.push(toTreeFinding(f));
43699
+ }
43945
43700
  if (b.path.split("/").includes("..") || b.path === "") continue;
43946
- const abs = join24(treeRoot, b.path);
43701
+ const abs = join23(treeRoot, b.path);
43947
43702
  if (existsSync15(abs)) continue;
43948
43703
  mkdirSync10(dirname12(abs), { recursive: true });
43949
43704
  writeFileSync5(abs, text, "utf8");
43950
43705
  written.push(b.path);
43951
43706
  }
43952
- const lint = (await scanPaths({ dir: treeRoot, files: written, target: "tree", env: env2 })).filter((f) => isExfilId(f.rule));
43953
- const gl = scanTree({ dir: treeRoot, stateDir: join24(treeRoot, ".border-state"), target: "tree", env: env2 }).filter((f) => isExfilId(f.rule)).map((f) => f.path !== void 0 && f.path.startsWith(`${treeRoot}/`) ? { ...f, path: f.path.slice(treeRoot.length + 1) } : f);
43707
+ const eng = { ...opts?.sanitizer !== void 0 ? { sanitizer: opts.sanitizer } : {} };
43708
+ const lint = opts?.skipSecretlint === true ? [] : (await scanPaths({ dir: treeRoot, files: written, target: "tree", env: env2, ...eng })).filter((f) => isExfilId(f.rule));
43709
+ const gl = opts?.skipGitleaks === true ? [] : scanTree({ dir: treeRoot, stateDir: join23(treeRoot, ".border-state"), target: "tree", env: env2, ...eng }).filter((f) => isExfilId(f.rule)).map((f) => f.path !== void 0 && f.path.startsWith(`${treeRoot}/`) ? { ...f, path: f.path.slice(treeRoot.length + 1) } : f);
43954
43710
  return [...native, ...lint, ...gl];
43955
43711
  }
43956
43712
  function exfilRulesDigest() {
@@ -43983,7 +43739,7 @@ async function runExfilCore(ctx) {
43983
43739
  if (isUrl) {
43984
43740
  const url2 = first;
43985
43741
  exposure = [sanitizeUrl(url2)];
43986
- sandbox.dir = mkdtempSync4(join24(tmpdir3(), "border-exfil-"));
43742
+ sandbox.dir = mkdtempSync4(join23(tmpdir3(), "border-exfil-"));
43987
43743
  const git2 = makeGit(sandbox.dir, ctx.env);
43988
43744
  git2.run(["init", "-q"]);
43989
43745
  git2.run(["remote", "add", "origin", url2]);
@@ -44000,7 +43756,7 @@ async function runExfilCore(ctx) {
44000
43756
  units = positionals.map((ref) => ({ label: ref, rev: git2.run(["rev-parse", "--verify", ref]).trim() }));
44001
43757
  }
44002
43758
  const git = makeGit(repoDir, ctx.env);
44003
- sandbox.tree = mkdtempSync4(join24(tmpdir3(), "border-exfil-tree-"));
43759
+ sandbox.tree = mkdtempSync4(join23(tmpdir3(), "border-exfil-tree-"));
44004
43760
  const findings = [];
44005
43761
  const seenBlob = /* @__PURE__ */ new Set();
44006
43762
  for (const unit of units) {
@@ -44060,15 +43816,361 @@ async function runExfilCore(ctx) {
44060
43816
  }
44061
43817
  var runExfil = (ctx) => runExfilCore(ctx);
44062
43818
 
43819
+ // src/check/tipTreeLens.ts
43820
+ async function scanTipTreeLens(o) {
43821
+ const env2 = o.env ?? process.env;
43822
+ const git = makeGit(o.repoDir, env2);
43823
+ const treeRoot = mkdtempSync5(join24(tmpdir4(), "border-check-tip-tree-"));
43824
+ try {
43825
+ return await scanTipTree(git, treeRoot, o.rev, env2, {
43826
+ ...o.sanitizer !== void 0 ? { sanitizer: o.sanitizer } : {},
43827
+ ...o.skipGitleaks === true ? { skipGitleaks: true } : {},
43828
+ ...o.skipSecretlint === true ? { skipSecretlint: true } : {}
43829
+ });
43830
+ } finally {
43831
+ rmSync12(treeRoot, { recursive: true, force: true });
43832
+ }
43833
+ }
43834
+
43835
+ // src/check/proofValve.ts
43836
+ var ROUNDTRIP_PROOF_MISSING_RULE = "roundtrip-proof-missing";
43837
+ var ROUNDTRIP_PROOF_STALE_RULE = "roundtrip-proof-stale";
43838
+ var RESIDUE_RULE_IDS = new Set(Object.keys(RESIDUE_SEVERITIES));
43839
+ function hasBlockingResidueCapability(findings) {
43840
+ return findings.some((f) => RESIDUE_RULE_IDS.has(f.rule) && isBlocking(f.severity));
43841
+ }
43842
+ function proofFinding(rule, art, cause) {
43843
+ return {
43844
+ rule,
43845
+ severity: "CRITICAL",
43846
+ target: "artifact",
43847
+ path: art.file,
43848
+ engine: "native",
43849
+ message: `${art.file} (sha256 ${art.sha256.slice(0, 12)}\u2026) tripped the residue scan while residue.requireProof is on, but ${cause}. Run 'border roundtrip <spec>' for exactly these bytes to mint the ledger proof.`,
43850
+ ...redact(`${art.sha256}:${cause}`),
43851
+ snippet: `${art.file} ${art.sha256.slice(0, 12)}`
43852
+ };
43853
+ }
43854
+ function proofFindings(o) {
43855
+ const out = [];
43856
+ for (const art of o.artifacts) {
43857
+ const rec = latestRoundtripForSha(o.records, art.sha256);
43858
+ if (rec === null) {
43859
+ out.push(proofFinding(ROUNDTRIP_PROOF_MISSING_RULE, art, "no roundtrip proof record exists for its digest"));
43860
+ } else if (rec.rulesHash !== o.rulesHash) {
43861
+ out.push(
43862
+ proofFinding(
43863
+ ROUNDTRIP_PROOF_STALE_RULE,
43864
+ art,
43865
+ `its proof record predates the current rules policy (recorded ${rec.rulesHash.slice(0, 12)}\u2026, required ${o.rulesHash.slice(0, 12)}\u2026)`
43866
+ )
43867
+ );
43868
+ }
43869
+ }
43870
+ return out;
43871
+ }
43872
+
43873
+ // src/check.ts
43874
+ var TRACKED_BORDER_RULE = "repo-tracks-border-state";
43875
+ var GUARD_PATH_CAP = 50;
43876
+ function trackedBorderStateFinding(repoDir, headSha, env2) {
43877
+ const listing = runGitChecked(repoDir, ["ls-files", "--", `${BORDER_STATE_DIR}/`], { ...env2 !== void 0 ? { env: env2 } : {} }).split("\n").filter((p) => p !== "");
43878
+ if (listing.length === 0) return null;
43879
+ const shown = listing.slice(0, GUARD_PATH_CAP);
43880
+ const rest = listing.length - shown.length;
43881
+ const [first = `${BORDER_STATE_DIR}/`] = shown;
43882
+ const message = `repository tracks ${String(listing.length)} file(s) under ${BORDER_STATE_DIR}/ \u2014 border's state directory must stay untracked: ${shown.join(", ")}${rest > 0 ? ` (+${String(rest)} more)` : ""}. Remove with 'git rm -r --cached ${BORDER_STATE_DIR}/'.`;
43883
+ return {
43884
+ rule: TRACKED_BORDER_RULE,
43885
+ severity: "CRITICAL",
43886
+ target: "git",
43887
+ path: first,
43888
+ commit: headSha,
43889
+ engine: "native",
43890
+ message,
43891
+ ...redact(`${headSha}:${BORDER_STATE_DIR}`),
43892
+ snippet: `${BORDER_STATE_DIR}/ tracked`
43893
+ };
43894
+ }
43895
+ function legOptions(o, sanitizer) {
43896
+ return {
43897
+ ...o.env !== void 0 ? { env: o.env } : {},
43898
+ sanitizer
43899
+ };
43900
+ }
43901
+ function lensIdentity(f) {
43902
+ return `${f.rule}\0${f.engine}\0${f.path ?? ""}\0${String(f.line ?? -1)}\0${f.valueDigest}`;
43903
+ }
43904
+ function historyRefRange(ctx) {
43905
+ return ctx.refSet.length > 0 ? ctx.refSet.join(" ") : ctx.headSha;
43906
+ }
43907
+ async function executeCheck(o) {
43908
+ const envOpt = o.env !== void 0 ? { env: o.env } : {};
43909
+ const ctx = gatherContext(o.repoDir, envOpt);
43910
+ const { handle, warning } = acquireLock(o.repoDir);
43911
+ try {
43912
+ return await runPipeline(o, ctx, warning);
43913
+ } finally {
43914
+ releaseLock(handle);
43915
+ }
43916
+ }
43917
+ async function runPipeline(o, ctx, lockWarning) {
43918
+ const repoDir = ctx.repoDir;
43919
+ const envOpt = o.env !== void 0 ? { env: o.env } : {};
43920
+ const findings = [];
43921
+ const guard = trackedBorderStateFinding(repoDir, ctx.headSha, o.env);
43922
+ const probe = await probeEngines(o.cfg, {
43923
+ ...envOpt,
43924
+ ...o.requireOverride !== void 0 ? { requireOverride: o.requireOverride } : {}
43925
+ });
43926
+ findings.push(...probe.findings);
43927
+ if (guard !== null) findings.push(guard);
43928
+ const broken = new Set(probe.findings.map((f) => f.engine));
43929
+ const sanitizer = new TextSanitizer();
43930
+ findings.push(...filterBorderStateFindings(detectHostileConfig({ repoDir, target: "git", ...envOpt }), repoDir));
43931
+ if (!broken.has("gitleaks")) {
43932
+ const eng = legOptions(o, sanitizer);
43933
+ findings.push(...filterBorderStateFindings(scanGitHistory({ repoDir, refRange: historyRefRange(ctx), target: "git", ...eng }), repoDir));
43934
+ findings.push(...filterBorderStateFindings(scanTree({ dir: repoDir, stateDir: join25(repoDir, BORDER_STATE_DIR), target: "tree", ...eng }), repoDir));
43935
+ findings.push(...filterBorderStateFindings(scanTagMessages({ repoDir, target: "git", ...eng }), repoDir));
43936
+ }
43937
+ if (!broken.has("secretlint")) {
43938
+ findings.push(...await scanGitTrackedFiles({ repoDir, target: "git", rules: o.cfg.rules, ...legOptions(o, sanitizer) }));
43939
+ }
43940
+ if (o.cfg.engines.trufflehog && !broken.has("trufflehog")) {
43941
+ findings.push(...scanTrufflehog({ repoDir, target: "git", ...legOptions(o, sanitizer) }));
43942
+ }
43943
+ findings.push(...scanAiArtifacts({ repoDir, refSet: [...ctx.refSet], cfg: o.cfg.rules, ...envOpt }));
43944
+ findings.push(...scanIdentity({ repoDir, refSet: [...ctx.refSet], cfg: o.cfg, ...envOpt }));
43945
+ findings.push(...filterBorderStateFindings(scanExfilTree({ repoDir, hosts: o.cfg.rules.hosts, ...legOptions(o, sanitizer) }), repoDir));
43946
+ findings.push(...filterBorderStateFindings(
43947
+ scanCommitMessages({
43948
+ repoDir,
43949
+ refSet: ctx.refSet.length > 0 ? [...ctx.refSet] : [ctx.headSha],
43950
+ remotes: o.cfg.targets.git.remotes,
43951
+ hosts: o.cfg.rules.hosts,
43952
+ ...legOptions(o, sanitizer)
43953
+ }),
43954
+ repoDir
43955
+ ));
43956
+ if (o.effectiveTargets.includes("git")) {
43957
+ const tip = await scanTipTreeLens({
43958
+ repoDir,
43959
+ rev: ctx.headSha,
43960
+ ...envOpt,
43961
+ sanitizer,
43962
+ skipGitleaks: broken.has("gitleaks"),
43963
+ skipSecretlint: broken.has("secretlint")
43964
+ });
43965
+ const seen = new Set(findings.map(lensIdentity));
43966
+ for (const f of filterBorderStateFindings(tip, repoDir)) {
43967
+ const id = lensIdentity(f);
43968
+ if (seen.has(id)) continue;
43969
+ seen.add(id);
43970
+ findings.push(f);
43971
+ }
43972
+ }
43973
+ const ledgerArtifacts = [];
43974
+ for (const channel of publishChannels()) {
43975
+ if (!o.effectiveTargets.includes(channel.id) || !channel.configured(o.cfg)) continue;
43976
+ const stage = await channel.stage({
43977
+ repoDir,
43978
+ cfg: o.cfg,
43979
+ sanitizer,
43980
+ ...envOpt,
43981
+ skipGitleaks: broken.has("gitleaks"),
43982
+ skipSecretlint: broken.has("secretlint")
43983
+ });
43984
+ findings.push(...stage.findings);
43985
+ ledgerArtifacts.push(...stage.artifacts);
43986
+ }
43987
+ if ((o.cfg.release?.twin.length ?? 0) > 0) {
43988
+ findings.push(
43989
+ ...await twinCoherenceFindings({
43990
+ pairs: o.cfg.release?.twin ?? [],
43991
+ artifacts: ledgerArtifacts,
43992
+ repoDir,
43993
+ ...envOpt,
43994
+ sanitizer
43995
+ })
43996
+ );
43997
+ }
43998
+ findings.push(...await runRegistryProbes({ repoDir, cfg: o.cfg, effectiveTargets: o.effectiveTargets, ...envOpt }));
43999
+ if (o.cfg.residue?.enabled === false) {
44000
+ for (let i = findings.length - 1; i >= 0; i -= 1) {
44001
+ const f = findings[i];
44002
+ if (f !== void 0 && RESIDUE_RULE_IDS.has(f.rule)) findings.splice(i, 1);
44003
+ }
44004
+ }
44005
+ const rulesHash = await computeCheckRulesHash({
44006
+ engineVersions: probe.engineVersions,
44007
+ configDigest: o.configDigest,
44008
+ ...o.env !== void 0 ? { env: o.env } : {}
44009
+ });
44010
+ if (o.cfg.residue?.requireProof === true && ledgerArtifacts.length > 0 && hasBlockingResidueCapability(findings)) {
44011
+ findings.push(...proofFindings({ artifacts: ledgerArtifacts, records: readLedger(repoDir).records, rulesHash }));
44012
+ }
44013
+ const exposure = [...exposureSet(o.cfg, { cwd: repoDir })];
44014
+ const cfgExempt = suppressGateConfigPathPatterns(findings, repoDir, o.configSource);
44015
+ if (cfgExempt.suppressed > 0) {
44016
+ findings.length = 0;
44017
+ findings.push(...cfgExempt.kept);
44018
+ findings.push({
44019
+ rule: "gate-config-path-exempt",
44020
+ severity: "INFO",
44021
+ target: "config",
44022
+ ...o.configSource !== void 0 ? { path: o.configSource } : {},
44023
+ engine: "native",
44024
+ message: `${String(cfgExempt.suppressed)} path-pattern finding(s) suppressed for the gate's own config file (self-referential rule-ID bytes; credential engines still cover it)`,
44025
+ valueDigest: createHash15("sha256").update(`gate-config-exempt:${String(o.configSource)}`).digest("hex"),
44026
+ snippet: "gate-config-path-exempt"
44027
+ });
44028
+ }
44029
+ const allow = applyAllowList(findings, o.cfg.allow, repoDir);
44030
+ const report = {
44031
+ schemaVersion: 1,
44032
+ key: computeCheckKey({
44033
+ headSha: ctx.headSha,
44034
+ porcelainDigest: ctx.porcelainDigest,
44035
+ rulesHash,
44036
+ exposureSet: exposure,
44037
+ refSet: ctx.refSet,
44038
+ effectiveTargets: o.effectiveTargets
44039
+ }),
44040
+ head: ctx.headSha,
44041
+ dirty: ctx.dirty,
44042
+ exposureSet: exposure,
44043
+ refSet: ctx.refSet,
44044
+ rulesHash,
44045
+ verdict: computeVerdict(allow.kept),
44046
+ counts: countFindings(allow.kept),
44047
+ findings: allow.kept,
44048
+ ...allow.allowHits.length > 0 ? { allowHits: allow.allowHits } : {},
44049
+ ts: (/* @__PURE__ */ new Date()).toISOString()
44050
+ };
44051
+ return {
44052
+ report,
44053
+ ctx,
44054
+ degraded: probe.degraded,
44055
+ sanitizedSummary: sanitizeSummary(report, sanitizer),
44056
+ lockWarning,
44057
+ artifacts: ledgerArtifacts.length > 0 ? ledgerArtifacts : null
44058
+ };
44059
+ }
44060
+ function sanitizeSummary(report, sanitizer) {
44061
+ const lines = report.findings.map(
44062
+ (f) => sanitizer.sanitize(`${f.severity} ${f.rule} ${f.engine} ${f.path ?? ""} ${f.commit ?? ""} ${f.message}`.replace(/\s+/g, " ").trim())
44063
+ );
44064
+ lines.unshift(sanitizer.sanitize(`border check ${report.verdict}: ${String(report.counts.total)} finding(s), ${String(report.counts.blocking)} blocking`));
44065
+ return lines.join("\n");
44066
+ }
44067
+
44068
+ // src/commands/check.ts
44069
+ async function runCheck(ctx) {
44070
+ const env2 = ctx.env;
44071
+ const load = loadConfig({
44072
+ cwd: ctx.cwd,
44073
+ ...ctx.flags.config !== void 0 ? { configPath: ctx.flags.config } : {},
44074
+ ...env2 !== void 0 ? { env: env2 } : {}
44075
+ });
44076
+ for (const warning of load.warnings) ctx.stderr(`border: ${warning}`);
44077
+ let effective;
44078
+ if (load.kind === "loaded") {
44079
+ effective = load;
44080
+ } else if (load.explicit !== void 0) {
44081
+ effective = { kind: "loaded", config: load.explicit.config, warnings: [], source: load.explicit.source };
44082
+ } else {
44083
+ if (ctx.flags.requireEngine !== void 0 && ctx.flags.requireEngine.length > 0) {
44084
+ const probe = await probeEngines(NO_TARGETS_PROBE_CFG, {
44085
+ requireOverride: ctx.flags.requireEngine,
44086
+ ...env2 !== void 0 ? { env: env2 } : {}
44087
+ });
44088
+ if (probe.degraded) {
44089
+ for (const finding of probe.findings) ctx.stderr(`border: ${finding.message}`);
44090
+ return EXIT_ERROR;
44091
+ }
44092
+ }
44093
+ ctx.stdout(`border: ${NO_OP_MESSAGE}`);
44094
+ return EXIT_PASS;
44095
+ }
44096
+ const configDigest = computeConfigDigest(effective);
44097
+ const repoDir = resolveRepoDir(ctx.cwd, { env: env2 });
44098
+ const effectiveTargets = computeEffectiveTargets(effective.config, ctx.flags.targets);
44099
+ if (!ctx.flags.force) {
44100
+ const decision = await consultSkipLedger({
44101
+ repoDir,
44102
+ cfg: effective.config,
44103
+ configDigest,
44104
+ effectiveTargets,
44105
+ llm: ctx.flags.llm,
44106
+ ...env2 !== void 0 ? { env: env2 } : {},
44107
+ ...ctx.flags.requireEngine !== void 0 && ctx.flags.requireEngine.length > 0 ? { requireOverride: ctx.flags.requireEngine } : {}
44108
+ });
44109
+ for (const warning of decision.warnings) ctx.stderr(`border: WARNING ${warning}`);
44110
+ if (decision.skip !== null) {
44111
+ ctx.stdout(formatSkipLine(decision.skip));
44112
+ return exitCodeFromVerdict(decision.skip.verdict);
44113
+ }
44114
+ }
44115
+ let outcome;
44116
+ try {
44117
+ outcome = await executeCheck({
44118
+ repoDir,
44119
+ cfg: effective.config,
44120
+ configDigest,
44121
+ effectiveTargets,
44122
+ ...env2 !== void 0 ? { env: env2 } : {},
44123
+ ...ctx.flags.requireEngine !== void 0 && ctx.flags.requireEngine.length > 0 ? { requireOverride: ctx.flags.requireEngine } : {},
44124
+ // config self-exemption binds to a REAL file path only — the "git-remote"/
44125
+ // "<...>" source sentinels must never resolve onto a scanned content path.
44126
+ .../^\/.*$/.test(effective.source) && !effective.source.startsWith("<") ? { configSource: effective.source } : {}
44127
+ });
44128
+ } catch (err) {
44129
+ if (err instanceof BorderLockHeldError) {
44130
+ ctx.stderr(`border: ${err.message}`);
44131
+ return EXIT_ERROR;
44132
+ }
44133
+ throw err;
44134
+ }
44135
+ if (outcome.lockWarning !== null) ctx.stderr(`border: WARNING ${outcome.lockWarning}`);
44136
+ if (outcome.ctx.dirty) ctx.stderr("border: working tree is dirty \u2014 findings may reference uncommitted files");
44137
+ if (ctx.flags.json) {
44138
+ ctx.stdout(renderReportJson(outcome.report));
44139
+ } else {
44140
+ for (const line of outcome.sanitizedSummary.split("\n")) ctx.stdout(`border: ${line}`);
44141
+ }
44142
+ if (outcome.degraded) {
44143
+ ctx.stderr("border: required engine(s) degraded \u2014 verdict is UNTRUSTWORTHY (exit 2 regardless of findings)");
44144
+ return EXIT_ERROR;
44145
+ }
44146
+ recordCheckRun({
44147
+ repoDir,
44148
+ report: outcome.report,
44149
+ ctx: outcome.ctx,
44150
+ effectiveTargets,
44151
+ llm: ctx.flags.llm,
44152
+ artifacts: outcome.artifacts,
44153
+ ...env2 !== void 0 ? { env: env2 } : {}
44154
+ });
44155
+ return exitCodeFromVerdict(outcome.report.verdict);
44156
+ }
44157
+ var NO_TARGETS_PROBE_CFG = {
44158
+ version: 1,
44159
+ targets: { git: { remotes: [] } },
44160
+ rules: { authors: { emails: [], names: [] }, hosts: [], ips: [], pathPatterns: [], maxFileKB: 500 },
44161
+ allow: [],
44162
+ engines: { require: [], trufflehog: false }
44163
+ };
44164
+
44063
44165
  // src/llm/bundle.ts
44064
- import { createHash as createHash15 } from "node:crypto";
44166
+ import { createHash as createHash16 } from "node:crypto";
44065
44167
  import { existsSync as existsSync16, mkdirSync as mkdirSync11, readFileSync as readFileSync16, writeFileSync as writeFileSync7 } from "node:fs";
44066
- import { dirname as dirname14, join as join26 } from "node:path";
44168
+ import { dirname as dirname14, join as join27 } from "node:path";
44067
44169
 
44068
44170
  // src/llm/diff.ts
44069
44171
  import { spawnSync as spawnSync16 } from "node:child_process";
44070
- import { mkdtempSync as mkdtempSync5, rmSync as rmSync12, writeFileSync as writeFileSync6 } from "node:fs";
44071
- import { dirname as dirname13, join as join25, resolve as resolve16 } from "node:path";
44172
+ import { mkdtempSync as mkdtempSync6, rmSync as rmSync13, writeFileSync as writeFileSync6 } from "node:fs";
44173
+ import { dirname as dirname13, join as join26, resolve as resolve16 } from "node:path";
44072
44174
  var GIT_DIFF_MAX_BUFFER = 64 * 1024 * 1024;
44073
44175
  function gitOut(repoDir, args, o, allowFail = false) {
44074
44176
  const abs = resolve16(repoDir);
@@ -44165,24 +44267,24 @@ function collectRawDeltas(repoDir, baseSha, headSha, o = {}) {
44165
44267
  var MASK_CHUNK_CHARS = 2e6;
44166
44268
  function maskViaEngineDetection(repoDir, texts, o = {}) {
44167
44269
  const sanitizer = new TextSanitizer();
44168
- const sandbox = mkdtempSync5(join25(repoDir, BORDER_STATE_DIR, "llm-mask-"));
44270
+ const sandbox = mkdtempSync6(join26(repoDir, BORDER_STATE_DIR, "llm-mask-"));
44169
44271
  try {
44170
44272
  let idx = 0;
44171
44273
  for (const text of texts) {
44172
44274
  if (text === "") continue;
44173
44275
  for (let off = 0; off < text.length; off += MASK_CHUNK_CHARS, idx += 1) {
44174
- writeFileSync6(join25(sandbox, `detect-${String(idx)}.txt`), text.slice(off, off + MASK_CHUNK_CHARS), "utf8");
44276
+ writeFileSync6(join26(sandbox, `detect-${String(idx)}.txt`), text.slice(off, off + MASK_CHUNK_CHARS), "utf8");
44175
44277
  }
44176
44278
  }
44177
44279
  scanTree({
44178
44280
  dir: sandbox,
44179
- stateDir: join25(repoDir, BORDER_STATE_DIR),
44281
+ stateDir: join26(repoDir, BORDER_STATE_DIR),
44180
44282
  target: "llm-mask",
44181
44283
  sanitizer,
44182
44284
  ...engineEnv(o)
44183
44285
  });
44184
44286
  } finally {
44185
- rmSync12(sandbox, { recursive: true, force: true });
44287
+ rmSync13(sandbox, { recursive: true, force: true });
44186
44288
  }
44187
44289
  return (text) => sanitizer.sanitize(text);
44188
44290
  }
@@ -44234,7 +44336,7 @@ async function runLlmRequestCore(ctx) {
44234
44336
  ctx.stderr("border: llm-request: no check record for the current state \u2014 run 'border check' first (the bundle derives from the recorded ctx)");
44235
44337
  return EXIT_ERROR;
44236
44338
  }
44237
- const absReport = join26(repoDir, record2.reportPath);
44339
+ const absReport = join27(repoDir, record2.reportPath);
44238
44340
  if (!existsSync16(absReport)) {
44239
44341
  ctx.stderr(`border: llm-request: report archive missing (${record2.reportPath} pruned?) \u2014 run 'border check' again`);
44240
44342
  return EXIT_ERROR;
@@ -44291,9 +44393,9 @@ async function runLlmRequestCore(ctx) {
44291
44393
  fileDeltas,
44292
44394
  artifacts: record2.artifacts,
44293
44395
  deterministic: { verdict: report.verdict, counts: report.counts, findings: report.findings },
44294
- promptTemplate: { path: templatePath, sha256: createHash15("sha256").update(readFileSync16(templatePath)).digest("hex") }
44396
+ promptTemplate: { path: templatePath, sha256: createHash16("sha256").update(readFileSync16(templatePath)).digest("hex") }
44295
44397
  };
44296
- const outPath = join26(dirname14(absReport), "llm-request.json");
44398
+ const outPath = join27(dirname14(absReport), "llm-request.json");
44297
44399
  mkdirSync11(dirname14(outPath), { recursive: true });
44298
44400
  writeFileSync7(outPath, `${JSON.stringify(bundle, null, 2)}
44299
44401
  `, "utf8");
@@ -44303,14 +44405,14 @@ async function runLlmRequestCore(ctx) {
44303
44405
  }
44304
44406
 
44305
44407
  // src/llm/ingest.ts
44306
- import { createHash as createHash16 } from "node:crypto";
44408
+ import { createHash as createHash17 } from "node:crypto";
44307
44409
  import { existsSync as existsSync17, readFileSync as readFileSync17, readdirSync as readdirSync9 } from "node:fs";
44308
- import { isAbsolute, join as join27, resolve as resolve17 } from "node:path";
44410
+ import { isAbsolute, join as join28, resolve as resolve17 } from "node:path";
44309
44411
  var RULE_RE = /^[a-z0-9-]+$/;
44310
44412
  var MAX_TEXT = 4e3;
44311
44413
  var ALLOWED_KEYS = /* @__PURE__ */ new Set(["rule", "severity", "target", "path", "line", "commit", "message", "snippet", "engine", "valueDigest"]);
44312
44414
  function sha2562(text) {
44313
- return createHash16("sha256").update(text, "utf8").digest("hex");
44415
+ return createHash17("sha256").update(text, "utf8").digest("hex");
44314
44416
  }
44315
44417
  function usageError(ctx, why) {
44316
44418
  ctx.stderr(`border: llm-ingest: ${why}`);
@@ -44324,7 +44426,7 @@ function findLatestBundle(repoDir) {
44324
44426
  return "no llm-request bundle found \u2014 run 'border llm-request' first";
44325
44427
  }
44326
44428
  for (const d of dirs.sort().reverse()) {
44327
- const p = join27(runsDir(repoDir), d, "llm-request.json");
44429
+ const p = join28(runsDir(repoDir), d, "llm-request.json");
44328
44430
  if (!existsSync17(p)) continue;
44329
44431
  let parsed;
44330
44432
  try {
@@ -44337,7 +44439,7 @@ function findLatestBundle(repoDir) {
44337
44439
  if (b.schemaVersion !== 1 || typeof b.key !== "string" || !/^[0-9a-f]{64}$/.test(b.key) || typeof b.head !== "string" || !/^[0-9a-f]{40}$/.test(b.head) || !Array.isArray(b.fileDeltas) || b.deterministic === void 0) {
44338
44440
  return `bundle ${p} fails its own schema \u2014 re-run 'border llm-request'`;
44339
44441
  }
44340
- return { dir: join27(runsDir(repoDir), d), bundle: b };
44442
+ return { dir: join28(runsDir(repoDir), d), bundle: b };
44341
44443
  }
44342
44444
  return "no llm-request bundle found \u2014 run 'border llm-request' first";
44343
44445
  }
@@ -44482,43 +44584,551 @@ async function runLlmRequest(ctx) {
44482
44584
  }
44483
44585
 
44484
44586
  // src/commands/opencode.ts
44485
- import { createHash as createHash17 } from "node:crypto";
44486
- import { existsSync as existsSync18, lstatSync, mkdirSync as mkdirSync12, readFileSync as readFileSync18, rmSync as rmSync13, writeFileSync as writeFileSync8 } from "node:fs";
44587
+ import { existsSync as existsSync22, lstatSync, mkdirSync as mkdirSync12, readFileSync as readFileSync20, rmSync as rmSync14, writeFileSync as writeFileSync8 } from "node:fs";
44588
+ import { dirname as dirname16, join as join32 } from "node:path";
44589
+ import { fileURLToPath as fileURLToPath6 } from "node:url";
44590
+
44591
+ // src/opencode/inspect.ts
44592
+ import { existsSync as existsSync21, readFileSync as readFileSync19 } from "node:fs";
44593
+ import { join as join31 } from "node:path";
44594
+
44595
+ // src/opencode/jsonconfig.ts
44596
+ import { existsSync as existsSync19, readdirSync as readdirSync10, readFileSync as readFileSync18 } from "node:fs";
44597
+ import { join as join30 } from "node:path";
44598
+
44599
+ // src/opencode/contract.ts
44600
+ import { createHash as createHash18 } from "node:crypto";
44601
+ import { existsSync as existsSync18 } from "node:fs";
44487
44602
  import os3 from "node:os";
44488
- import { dirname as dirname15, join as join28 } from "node:path";
44603
+ import { dirname as dirname15, join as join29 } from "node:path";
44489
44604
  import { fileURLToPath as fileURLToPath5 } from "node:url";
44490
44605
  var PLUGIN_MARKER = "// border-opencode-plugin v";
44491
44606
  var COMMAND_MARKER = "<!-- border-opencode-command -->";
44607
+ var BORDER_PACKAGE = "border-customs";
44608
+ var DEFAULT_REGISTRY_BASE = "https://registry.npmjs.org";
44609
+ var REGISTRY_TIMEOUT_MS2 = 15e3;
44610
+ function sha256Hex3(bytes) {
44611
+ return createHash18("sha256").update(bytes).digest("hex");
44612
+ }
44613
+ function firstLine(bytes) {
44614
+ const text = bytes.toString("utf8");
44615
+ const newline = text.indexOf("\n");
44616
+ return newline < 0 ? text : text.slice(0, newline);
44617
+ }
44492
44618
  function opencodeConfigRoot(env2) {
44493
44619
  const xdg = env2["XDG_CONFIG_HOME"] ?? "";
44494
44620
  if (xdg.length > 0) return xdg;
44495
44621
  const home = env2["HOME"] ?? "";
44496
- return join28(home.length > 0 ? home : os3.homedir(), ".config");
44622
+ return join29(home.length > 0 ? home : os3.homedir(), ".config");
44497
44623
  }
44498
- function resolvePluginAsset(moduleUrl, fileName) {
44624
+ function opencodeCacheRoot(env2) {
44625
+ const xdg = env2["XDG_CACHE_HOME"] ?? "";
44626
+ const base = xdg.length > 0 ? xdg : join29(env2["HOME"] ?? os3.homedir(), ".cache");
44627
+ return join29(base, "opencode", "packages");
44628
+ }
44629
+ function routeAPluginPath(env2) {
44630
+ return join29(opencodeConfigRoot(env2), "opencode", "plugins", "border.ts");
44631
+ }
44632
+ function packagedAssetPath(moduleUrl, fileName) {
44499
44633
  const here = dirname15(fileURLToPath5(moduleUrl));
44500
44634
  const candidates = [
44501
- join28(here, "..", "plugin", fileName),
44502
- // dist mode (bundled): <root>/plugin/<f>
44503
- join28(here, "..", "..", "plugin", fileName)
44635
+ join29(here, "..", "plugin", fileName),
44636
+ // dist (bundled) mode: <root>/plugin/<f>
44637
+ join29(here, "..", "..", "plugin", fileName)
44504
44638
  // src mode: <root>/plugin/<f>
44505
44639
  ];
44506
44640
  return candidates.find((p) => existsSync18(p)) ?? candidates[1];
44507
44641
  }
44508
- function targetsFor(env2) {
44509
- const root = join28(opencodeConfigRoot(env2), "opencode");
44510
- return [
44511
- { fileName: "border.ts", destination: join28(root, "plugins", "border.ts"), marker: PLUGIN_MARKER },
44512
- { fileName: "border-command.md", destination: join28(root, "commands", "border.md"), marker: COMMAND_MARKER }
44642
+ function packagedDistEntry(moduleUrl) {
44643
+ const here = dirname15(fileURLToPath5(moduleUrl));
44644
+ const candidates = [
44645
+ join29(here, "index.js"),
44646
+ // dist (bundled) mode: <root>/dist/index.js
44647
+ join29(here, "..", "dist", "index.js"),
44648
+ // src/opencode mode one level under root
44649
+ join29(here, "..", "..", "dist", "index.js")
44650
+ // src mode: <root>/dist/index.js
44513
44651
  ];
44652
+ return candidates.find((p) => existsSync18(p)) ?? candidates[2];
44514
44653
  }
44515
- function sha2563(bytes) {
44516
- return createHash17("sha256").update(bytes).digest("hex");
44654
+
44655
+ // src/opencode/jsonconfig.ts
44656
+ function stripJsoncComments(text) {
44657
+ let out = "";
44658
+ let inString = false;
44659
+ let inLine = false;
44660
+ let inBlock = false;
44661
+ for (let i = 0; i < text.length; i += 1) {
44662
+ const ch = text[i];
44663
+ const next = text[i + 1] ?? "";
44664
+ if (inLine) {
44665
+ if (ch === "\n") {
44666
+ inLine = false;
44667
+ out += ch;
44668
+ }
44669
+ continue;
44670
+ }
44671
+ if (inBlock) {
44672
+ if (ch === "*" && next === "/") {
44673
+ inBlock = false;
44674
+ i += 1;
44675
+ out += " ";
44676
+ }
44677
+ continue;
44678
+ }
44679
+ if (inString) {
44680
+ if (ch === "\\") {
44681
+ out += ch + next;
44682
+ i += 1;
44683
+ continue;
44684
+ }
44685
+ if (ch === '"') inString = false;
44686
+ out += ch;
44687
+ continue;
44688
+ }
44689
+ if (ch === '"') {
44690
+ inString = true;
44691
+ out += ch;
44692
+ continue;
44693
+ }
44694
+ if (ch === "/" && next === "/") {
44695
+ inLine = true;
44696
+ i += 1;
44697
+ continue;
44698
+ }
44699
+ if (ch === "/" && next === "*") {
44700
+ inBlock = true;
44701
+ i += 1;
44702
+ continue;
44703
+ }
44704
+ out += ch;
44705
+ }
44706
+ return out;
44517
44707
  }
44518
- function firstLine(bytes) {
44519
- const text = bytes.toString("utf8");
44520
- const newline = text.indexOf("\n");
44521
- return newline < 0 ? text : text.slice(0, newline);
44708
+ function parseJsonc(text) {
44709
+ return JSON.parse(stripJsoncComments(text).replace(/,(\s*[}\]])/g, "$1"));
44710
+ }
44711
+ var isRecord2 = (v) => typeof v === "object" && v !== null;
44712
+ function splitNpmSpec(entry) {
44713
+ const at = entry.lastIndexOf("@");
44714
+ if (at <= 0) return { name: entry, spec: null };
44715
+ return { name: entry.slice(0, at), spec: entry.slice(at + 1) };
44716
+ }
44717
+ function readPluginDeclarations(path4, pkg) {
44718
+ const none = { path: path4, status: "absent", specs: [] };
44719
+ let text;
44720
+ try {
44721
+ if (!existsSync19(path4)) return none;
44722
+ text = readFileSync18(path4, "utf8");
44723
+ } catch {
44724
+ return { path: path4, status: "error", specs: [] };
44725
+ }
44726
+ let parsed;
44727
+ try {
44728
+ parsed = parseJsonc(text);
44729
+ } catch {
44730
+ return { path: path4, status: "error", specs: [] };
44731
+ }
44732
+ if (!isRecord2(parsed)) return { path: path4, status: "error", specs: [] };
44733
+ const plugin = Array.isArray(parsed["plugin"]) ? parsed["plugin"] : [];
44734
+ const specs = plugin.filter((e) => typeof e === "string" && splitNpmSpec(e).name === pkg);
44735
+ return { path: path4, status: "ok", specs };
44736
+ }
44737
+ function listCacheDirs(cacheRoot, pkg) {
44738
+ let names;
44739
+ try {
44740
+ names = readdirSync10(cacheRoot, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name.startsWith(`${pkg}@`)).map((e) => e.name).sort();
44741
+ } catch {
44742
+ return [];
44743
+ }
44744
+ return names.map((name) => {
44745
+ const pkgRoot = join30(cacheRoot, name, "node_modules", pkg);
44746
+ let packageVersion = null;
44747
+ try {
44748
+ const meta3 = parseJsonc(readFileSync18(join30(pkgRoot, "package.json"), "utf8"));
44749
+ if (isRecord2(meta3) && typeof meta3["version"] === "string") packageVersion = meta3["version"];
44750
+ } catch {
44751
+ packageVersion = null;
44752
+ }
44753
+ let markerLine = null;
44754
+ try {
44755
+ markerLine = firstLine(readFileSync18(join30(pkgRoot, "plugin", "border.ts")));
44756
+ } catch {
44757
+ markerLine = null;
44758
+ }
44759
+ const markerVersion = markerLine !== null && markerLine.startsWith(PLUGIN_MARKER) ? markerLine.slice(PLUGIN_MARKER.length).trim() : null;
44760
+ return { dir: join30(cacheRoot, name), tag: name.slice(pkg.length + 1), packageVersion, markerVersion, markerLine };
44761
+ });
44762
+ }
44763
+
44764
+ // src/opencode/aspects/cacheVersion.ts
44765
+ var isExactVersion = (spec) => /^\d+\.\d+\.\d+([-+].*)?$/.test(spec);
44766
+ function verifyCacheVersion(facts) {
44767
+ const id = "cache-version";
44768
+ const { cacheDirs, configs, cacheRoot, pkg } = facts;
44769
+ const errored = configs.filter((c) => c.status === "error").map((c) => c.path);
44770
+ const declared = configs.some((c) => c.specs.length > 0);
44771
+ const where = configs.map((c) => `${c.path} [${c.status}]`).join(", ");
44772
+ if (cacheDirs.length === 0) {
44773
+ if (errored.length > 0) {
44774
+ return { id, verdict: "CANNOT", detail: `no cache directory under ${cacheRoot} and the configuration is unreadable (${errored.join(", ")}) \u2014 cannot tell whether a Route-B load is claimed` };
44775
+ }
44776
+ if (declared) {
44777
+ return { id, verdict: "CANNOT", detail: `NOT-CACHED: ${pkg} is declared (${configs.flatMap((c) => [...c.specs]).join(", ")}) but no cache directory exists under ${cacheRoot} \u2014 the load claim has no bytes behind it` };
44778
+ }
44779
+ return { id, verdict: "PASS", detail: `no ${pkg} cache directory under ${cacheRoot} and none declared (${where}) \u2014 Route B not in use, nothing to be stale` };
44780
+ }
44781
+ const pins = new Set(
44782
+ configs.flatMap((c) => [...c.specs]).map((s) => splitNpmSpec(s).spec).filter((s) => s !== null && isExactVersion(s))
44783
+ );
44784
+ const problems = [];
44785
+ for (const d of cacheDirs) {
44786
+ if (d.packageVersion === null) {
44787
+ problems.push(`${d.dir}: package.json missing or unreadable`);
44788
+ }
44789
+ if (d.markerLine === null) {
44790
+ problems.push(`${d.dir}: plugin/border.ts missing or unreadable in the cached package`);
44791
+ } else if (d.markerVersion === null) {
44792
+ problems.push(`${d.dir}: plugin/border.ts first line lacks the marker '${PLUGIN_MARKER}'`);
44793
+ } else if (d.packageVersion !== null && d.markerVersion !== d.packageVersion) {
44794
+ problems.push(`${d.dir}: marker says ${d.markerVersion}, package.json says ${d.packageVersion}`);
44795
+ }
44796
+ if (pins.has(d.tag) && d.packageVersion !== null && d.packageVersion !== d.tag) {
44797
+ problems.push(`${d.dir}: cached under exact spec '${d.tag}' but the package reports ${d.packageVersion}`);
44798
+ }
44799
+ }
44800
+ if (problems.length > 0) {
44801
+ return { id, verdict: "FAIL", detail: problems.join("; ") };
44802
+ }
44803
+ return {
44804
+ id,
44805
+ verdict: "PASS",
44806
+ detail: `cache self-consistent: ${cacheDirs.map((d) => `${d.tag}->${d.packageVersion ?? "?"}`).join(", ")}`
44807
+ };
44808
+ }
44809
+
44810
+ // src/opencode/aspects/dualRoute.ts
44811
+ function verifyDualRoute(facts) {
44812
+ const id = "dual-route";
44813
+ const { configs, routeAInstalled, routeAPlugin, pkg } = facts;
44814
+ const errored = configs.filter((c) => c.status === "error").map((c) => c.path);
44815
+ if (errored.length > 0) {
44816
+ return { id, verdict: "CANNOT", detail: `configuration unreadable (${errored.join(", ")}) \u2014 Route B presence cannot be counted` };
44817
+ }
44818
+ const declared = configs.flatMap((c) => [...c.specs]);
44819
+ const hasB = declared.length > 0;
44820
+ if (routeAInstalled && hasB) {
44821
+ return {
44822
+ id,
44823
+ verdict: "FAIL",
44824
+ detail: `both routes registered: Route A drop at ${routeAPlugin} AND Route B declaration ${declared.map((d) => `'${d}'`).join(", ")} \u2014 pick exactly one route (the dual-registration window blueprint \xA77 forbids)`
44825
+ };
44826
+ }
44827
+ if (routeAInstalled) {
44828
+ return { id, verdict: "PASS", detail: `Route A only: drop at ${routeAPlugin}, no ${pkg} config declaration` };
44829
+ }
44830
+ if (hasB) {
44831
+ return { id, verdict: "PASS", detail: `Route B only: ${declared.map((d) => `'${d}'`).join(", ")}, no file drop at ${routeAPlugin}` };
44832
+ }
44833
+ return { id, verdict: "PASS", detail: "neither route registered \u2014 no border plugin load claimed on the V1 surface" };
44834
+ }
44835
+
44836
+ // src/opencode/aspects/identity.ts
44837
+ import { execFile } from "node:child_process";
44838
+ import { existsSync as existsSync20 } from "node:fs";
44839
+ var HANDSHAKE_ARGV = ["--help"];
44840
+ var HANDSHAKE_BANNER_PREFIX = "border";
44841
+ var HANDSHAKE_USAGE_NEEDLE = "usage: border";
44842
+ var HANDSHAKE_TIMEOUT_MS = 2e4;
44843
+ var MAX_OUTPUT_BYTES = 64 * 1024;
44844
+ var defaultInspectRunner = (target, argv) => new Promise((resolve20) => {
44845
+ execFile(
44846
+ target.bin,
44847
+ [...target.prefix, ...argv],
44848
+ { timeout: HANDSHAKE_TIMEOUT_MS, maxBuffer: MAX_OUTPUT_BYTES, shell: false },
44849
+ (error61, stdout, stderr) => {
44850
+ const out = stdout.slice(0, MAX_OUTPUT_BYTES);
44851
+ const err = stderr.slice(0, MAX_OUTPUT_BYTES);
44852
+ if (error61 === null) {
44853
+ resolve20({ status: 0, stdout: out, stderr: err });
44854
+ return;
44855
+ }
44856
+ const failure = error61;
44857
+ if (failure.code === "ENOENT" || failure.code === "EACCES" || failure.code === "ENOEXEC") {
44858
+ resolve20({ status: null, stdout: out, stderr: err });
44859
+ return;
44860
+ }
44861
+ const status = typeof failure.code === "number" ? failure.code : failure.killed === true || failure.signal != null ? 124 : -1;
44862
+ resolve20({ status, stdout: out, stderr: err });
44863
+ }
44864
+ );
44865
+ });
44866
+ function passesHandshake(outcome) {
44867
+ if (outcome.status !== 0) return false;
44868
+ const firstLine2 = (outcome.stdout.match(/^\s*(.*)/) ?? ["", ""])[1] ?? "";
44869
+ return firstLine2.startsWith(HANDSHAKE_BANNER_PREFIX) && outcome.stdout.includes(HANDSHAKE_USAGE_NEEDLE);
44870
+ }
44871
+ function identityCandidates(env2, distEntry) {
44872
+ const configured = env2["BORDER_BIN"];
44873
+ if (configured !== void 0 && configured.length > 0) {
44874
+ return [{ bin: configured, prefix: [], label: `BORDER_BIN=${configured}` }];
44875
+ }
44876
+ const candidates = [];
44877
+ if (existsSync20(distEntry)) {
44878
+ candidates.push({ bin: distEntry, prefix: [], label: "packaged dist/index.js (shebang exec)" });
44879
+ candidates.push({ bin: "node", prefix: [distEntry], label: "packaged dist/index.js under PATH node" });
44880
+ }
44881
+ candidates.push({ bin: "border", prefix: [], label: "border on PATH" });
44882
+ return candidates;
44883
+ }
44884
+ async function verifyIdentity(deps) {
44885
+ const id = "identity-handshake";
44886
+ const runner = deps.runner ?? defaultInspectRunner;
44887
+ const candidates = identityCandidates(deps.env, deps.distEntry);
44888
+ const reasons = [];
44889
+ let anySpawned = false;
44890
+ for (const candidate of candidates) {
44891
+ const probe = await runner(candidate, HANDSHAKE_ARGV);
44892
+ if (passesHandshake(probe)) {
44893
+ return { id, verdict: "PASS", detail: `${candidate.label} passed the identity handshake` };
44894
+ }
44895
+ if (probe.status !== null) {
44896
+ anySpawned = true;
44897
+ reasons.push(`${candidate.label}: spawned but --help did not answer as border (impostor?)`);
44898
+ } else {
44899
+ reasons.push(`${candidate.label}: unspawnable (ENOENT/EACCES/ENOEXEC)`);
44900
+ }
44901
+ }
44902
+ if (anySpawned) {
44903
+ return { id, verdict: "FAIL", detail: `a border binary was reachable but failed the identity handshake \u2014 impersonation shape: ${reasons.join("; ")}` };
44904
+ }
44905
+ return { id, verdict: "CANNOT", detail: `no border binary reachable \u2014 tried: ${reasons.join("; ")}` };
44906
+ }
44907
+
44908
+ // src/opencode/aspects/routeA.ts
44909
+ function verifyRouteAParity(facts) {
44910
+ const id = "route-a-parity";
44911
+ const { routeAPlugin, routeAInstalled } = facts;
44912
+ if (!routeAInstalled) {
44913
+ return { id, verdict: "PASS", detail: `${routeAPlugin}: absent \u2014 Route A not installed, nothing to be stale` };
44914
+ }
44915
+ if (facts.packagedPlugin === null) {
44916
+ return { id, verdict: "CANNOT", detail: "the packaged plugin asset is unreadable \u2014 the border install itself looks broken, parity cannot be judged" };
44917
+ }
44918
+ const installed = facts.routeABytes;
44919
+ if (installed === null) {
44920
+ return { id, verdict: "CANNOT", detail: `${routeAPlugin}: present but unreadable \u2014 parity cannot be judged` };
44921
+ }
44922
+ const installedSha = sha256Hex3(installed);
44923
+ const packagedSha = sha256Hex3(facts.packagedPlugin);
44924
+ if (installedSha === packagedSha) {
44925
+ return { id, verdict: "PASS", detail: `${routeAPlugin}: up-to-date installed=${installedSha} packaged=${packagedSha}` };
44926
+ }
44927
+ const ours = firstLine(installed).startsWith(PLUGIN_MARKER);
44928
+ const shape = ours ? "outdated (marker ours, bytes differ)" : "foreign (first line lacks the marker)";
44929
+ return { id, verdict: "FAIL", detail: `${routeAPlugin}: ${shape} installed=${installedSha} packaged=${packagedSha}` };
44930
+ }
44931
+
44932
+ // src/opencode/aspects/scope.ts
44933
+ var SCOPE_ID = "scope";
44934
+ var SCOPE_NAME = "v1-load-surface";
44935
+ var SCOPE_UNCOVERED = [
44936
+ "V2 project-local .opencode/plugins/",
44937
+ "V2 npm-prefix/node_modules installs",
44938
+ "V2 lazy activation state"
44939
+ ];
44940
+ function verifyScope() {
44941
+ return {
44942
+ id: SCOPE_ID,
44943
+ verdict: "PASS",
44944
+ detail: `verdict scope = ${SCOPE_NAME}; NOT covered (declared blind, separate ledger item): ${SCOPE_UNCOVERED.join(", ")}`
44945
+ };
44946
+ }
44947
+
44948
+ // src/opencode/registry.ts
44949
+ var isRecord3 = (v) => typeof v === "object" && v !== null;
44950
+ var defaultRegistryFetcher = async (url2, init) => {
44951
+ if (!/^https?:\/\//.test(url2)) throw new Error(`border opencode inspect refuses non-http(s) URL: ${url2}`);
44952
+ const res = await fetch(url2, {
44953
+ redirect: "follow",
44954
+ signal: init.signal,
44955
+ headers: { "user-agent": "border-customs (+https://github.com/TachikomaGundam/Border-Customs; border opencode inspect)" }
44956
+ });
44957
+ const raw = res.headers.get("content-length");
44958
+ const parsed = raw === null ? Number.NaN : Number(raw);
44959
+ return {
44960
+ status: res.status,
44961
+ contentLength: Number.isFinite(parsed) && parsed >= 0 ? parsed : null,
44962
+ chunks: () => {
44963
+ if (res.body === null) {
44964
+ return {
44965
+ async *[Symbol.asyncIterator]() {
44966
+ }
44967
+ };
44968
+ }
44969
+ return res.body;
44970
+ }
44971
+ };
44972
+ };
44973
+ function npmTagUrl(pkg, tag, base = DEFAULT_REGISTRY_BASE) {
44974
+ const enc = pkg.startsWith("@") ? pkg.replace("/", "%2F") : encodeURIComponent(pkg);
44975
+ return `${base}/${enc}/${encodeURIComponent(tag)}`;
44976
+ }
44977
+ var REGISTRY_BODY_CAP = 8 * 1024 * 1024;
44978
+ async function fetchRegistryVersion(fetcher, url2, timeoutMs) {
44979
+ const res = await fetcher(url2, { signal: AbortSignal.timeout(timeoutMs) });
44980
+ if (res.status !== 200) throw new Error(`HTTP ${String(res.status)} from ${url2}`);
44981
+ const parts = [];
44982
+ let total = 0;
44983
+ for await (const chunk of res.chunks()) {
44984
+ total += chunk.byteLength;
44985
+ if (total > REGISTRY_BODY_CAP) throw new Error(`${url2} exceeds the ${String(REGISTRY_BODY_CAP)} B metadata cap`);
44986
+ parts.push(Buffer.from(chunk));
44987
+ }
44988
+ let parsed;
44989
+ try {
44990
+ parsed = JSON.parse(Buffer.concat(parts).toString("utf8"));
44991
+ } catch {
44992
+ throw new Error(`metadata response from ${url2} is not valid JSON`);
44993
+ }
44994
+ if (!isRecord3(parsed) || typeof parsed["version"] !== "string" || parsed["version"].length === 0) {
44995
+ throw new Error(`metadata response from ${url2} carries no "version" string`);
44996
+ }
44997
+ return parsed["version"];
44998
+ }
44999
+
45000
+ // src/opencode/aspects/specFreshness.ts
45001
+ var isExactVersion2 = (spec) => /^\d+\.\d+\.\d+([-+].*)?$/.test(spec);
45002
+ async function verifySpecFreshness(facts, deps = {}) {
45003
+ const id = "spec-freshness";
45004
+ const { configs, cacheDirs, pkg } = facts;
45005
+ const errored = configs.filter((c) => c.status === "error").map((c) => c.path);
45006
+ if (errored.length > 0) {
45007
+ return { id, verdict: "CANNOT", detail: `configuration unreadable (${errored.join(", ")}) \u2014 the expected version cannot be determined` };
45008
+ }
45009
+ const specs = [...new Set(configs.flatMap((c) => [...c.specs]).map((s) => splitNpmSpec(s).spec).filter((s) => s !== null))];
45010
+ if (specs.length === 0) {
45011
+ return { id, verdict: "PASS", detail: `no ${pkg} spec declared in opencode config \u2014 nothing to be fresh` };
45012
+ }
45013
+ const expected = /* @__PURE__ */ new Map();
45014
+ const fetcher = deps.fetcher ?? defaultRegistryFetcher;
45015
+ const timeoutMs = deps.timeoutMs ?? REGISTRY_TIMEOUT_MS2;
45016
+ for (const spec of specs) {
45017
+ if (isExactVersion2(spec)) {
45018
+ expected.set(spec, spec);
45019
+ continue;
45020
+ }
45021
+ try {
45022
+ expected.set(spec, await fetchRegistryVersion(fetcher, npmTagUrl(pkg, spec, deps.registryBase), timeoutMs));
45023
+ } catch (err) {
45024
+ const message = err instanceof Error ? err.message : String(err);
45025
+ return { id, verdict: "CANNOT", detail: `registry unreachable for spec '${pkg}@${spec}': ${message} \u2014 border never reads silence as fresh` };
45026
+ }
45027
+ }
45028
+ if (cacheDirs.length === 0) {
45029
+ return { id, verdict: "PASS", detail: `nothing cached to compare (see cache-version); spec resolves to ${[...new Set(expected.values())].join(", ")}` };
45030
+ }
45031
+ const wanted = new Set(expected.values());
45032
+ const judged = cacheDirs.filter((d) => d.packageVersion !== null);
45033
+ const stale = judged.filter((d) => !wanted.has(d.packageVersion));
45034
+ if (judged.length > 0 && stale.length > 0) {
45035
+ return {
45036
+ id,
45037
+ verdict: "FAIL",
45038
+ detail: `cache holds ${stale.map((d) => `${d.tag}->${d.packageVersion}`).join(",")}, spec expects ${[...wanted].join(",")}`
45039
+ };
45040
+ }
45041
+ return { id, verdict: "PASS", detail: `cache matches spec: ${[...wanted].join(",")}` };
45042
+ }
45043
+
45044
+ // src/opencode/inspect.ts
45045
+ function aggregateVerdict(aspects) {
45046
+ if (aspects.some((a) => a.verdict === "FAIL")) return "FAIL";
45047
+ if (aspects.some((a) => a.verdict === "CANNOT")) return "CANNOT";
45048
+ return "PASS";
45049
+ }
45050
+ function inspectExit(verdict) {
45051
+ switch (verdict) {
45052
+ case "FAIL":
45053
+ return EXIT_BLOCKED;
45054
+ case "CANNOT":
45055
+ return EXIT_ERROR;
45056
+ case "PASS":
45057
+ return EXIT_PASS;
45058
+ }
45059
+ }
45060
+ function readPackagedPlugin(path4) {
45061
+ try {
45062
+ return readFileSync19(path4);
45063
+ } catch {
45064
+ return null;
45065
+ }
45066
+ }
45067
+ function gatherFacts(env2, cwd, deps) {
45068
+ const pkg = deps.package ?? BORDER_PACKAGE;
45069
+ const pluginDrop = routeAPluginPath(env2);
45070
+ const cacheRoot = deps.cacheRoot ?? opencodeCacheRoot(env2);
45071
+ const globalPath = deps.globalConfigPath ?? join31(opencodeConfigRoot(env2), "opencode", "opencode.jsonc");
45072
+ const routeAInstalled = existsSync21(pluginDrop);
45073
+ return {
45074
+ pkg,
45075
+ env: env2,
45076
+ cacheRoot,
45077
+ cacheDirs: listCacheDirs(cacheRoot, pkg),
45078
+ configs: [readPluginDeclarations(globalPath, pkg), readPluginDeclarations(join31(cwd, "opencode.jsonc"), pkg)],
45079
+ packagedPlugin: readPackagedPlugin(packagedAssetPath(import.meta.url, "border.ts")),
45080
+ routeAPlugin: pluginDrop,
45081
+ routeAInstalled,
45082
+ routeABytes: routeAInstalled ? readPackagedPlugin(pluginDrop) : null
45083
+ };
45084
+ }
45085
+ async function runInspectCore(ctx, deps = {}) {
45086
+ const facts = gatherFacts(ctx.env, ctx.cwd, deps);
45087
+ const aspects = [
45088
+ verifyCacheVersion(facts),
45089
+ await verifySpecFreshness(facts, {
45090
+ ...deps.registryFetcher !== void 0 ? { fetcher: deps.registryFetcher } : {},
45091
+ ...deps.registryBase !== void 0 ? { registryBase: deps.registryBase } : {}
45092
+ }),
45093
+ await verifyIdentity({
45094
+ ...deps.runner !== void 0 ? { runner: deps.runner } : {},
45095
+ distEntry: deps.distEntry ?? packagedDistEntry(import.meta.url),
45096
+ env: facts.env
45097
+ }),
45098
+ verifyRouteAParity(facts),
45099
+ verifyDualRoute(facts),
45100
+ verifyScope()
45101
+ ];
45102
+ const verdict = aggregateVerdict(aspects);
45103
+ const report = { schemaVersion: 1, scope: "v1", verdict, aspects };
45104
+ if (ctx.flags.json) {
45105
+ ctx.stdout(JSON.stringify(report));
45106
+ } else {
45107
+ ctx.stdout(`border opencode inspect [${report.scope}] ${verdict}`);
45108
+ for (const a of aspects) {
45109
+ ctx.stdout(` ${a.verdict.padEnd(6)} ${a.id}: ${a.detail}`);
45110
+ }
45111
+ }
45112
+ return inspectExit(verdict);
45113
+ }
45114
+
45115
+ // src/commands/opencode.ts
45116
+ function resolvePluginAsset(moduleUrl, fileName) {
45117
+ const here = dirname16(fileURLToPath6(moduleUrl));
45118
+ const candidates = [
45119
+ join32(here, "..", "plugin", fileName),
45120
+ // dist mode (bundled): <root>/plugin/<f>
45121
+ join32(here, "..", "..", "plugin", fileName)
45122
+ // src mode: <root>/plugin/<f>
45123
+ ];
45124
+ return candidates.find((p) => existsSync22(p)) ?? candidates[1];
45125
+ }
45126
+ function targetsFor(env2) {
45127
+ const root = join32(opencodeConfigRoot(env2), "opencode");
45128
+ return [
45129
+ { fileName: "border.ts", destination: join32(root, "plugins", "border.ts"), marker: PLUGIN_MARKER },
45130
+ { fileName: "border-command.md", destination: join32(root, "commands", "border.md"), marker: COMMAND_MARKER }
45131
+ ];
44522
45132
  }
44523
45133
  function carriesMarker(bytes, marker) {
44524
45134
  return firstLine(bytes).startsWith(marker);
@@ -44530,7 +45140,7 @@ function fail(ctx, message) {
44530
45140
  function readPackagedAsset(ctx, fileName) {
44531
45141
  const source = resolvePluginAsset(import.meta.url, fileName);
44532
45142
  try {
44533
- return readFileSync18(source);
45143
+ return readFileSync20(source);
44534
45144
  } catch {
44535
45145
  ctx.stderr(`border: opencode: packaged asset is missing (${source})`);
44536
45146
  ctx.stderr("border: opencode: the border install looks broken \u2014 `npm i -g border-customs` or a fresh checkout should carry plugin/.");
@@ -44539,7 +45149,7 @@ function readPackagedAsset(ctx, fileName) {
44539
45149
  }
44540
45150
  function readTarget(destination) {
44541
45151
  try {
44542
- return readFileSync18(destination);
45152
+ return readFileSync20(destination);
44543
45153
  } catch {
44544
45154
  return null;
44545
45155
  }
@@ -44606,7 +45216,7 @@ function opencodeInstall(ctx) {
44606
45216
  ctx.stdout(`${target.destination}: up to date`);
44607
45217
  continue;
44608
45218
  }
44609
- mkdirSync12(dirname15(target.destination), { recursive: true });
45219
+ mkdirSync12(dirname16(target.destination), { recursive: true });
44610
45220
  writeFileSync8(target.destination, packaged);
44611
45221
  ctx.stdout(`${target.destination}: ${state === "outdated" ? "updated" : "installed"}`);
44612
45222
  }
@@ -44620,8 +45230,8 @@ function opencodeStatus(ctx) {
44620
45230
  for (const { target, packaged } of prepared) {
44621
45231
  const current = readTarget(target.destination);
44622
45232
  const state = classify(target, current, packaged);
44623
- const installedSha = current === null ? "-" : sha2563(current);
44624
- ctx.stdout(`${target.destination}: ${state} installed=${installedSha} packaged=${sha2563(packaged)}`);
45233
+ const installedSha = current === null ? "-" : sha256Hex3(current);
45234
+ ctx.stdout(`${target.destination}: ${state} installed=${installedSha} packaged=${sha256Hex3(packaged)}`);
44625
45235
  }
44626
45236
  return EXIT_PASS;
44627
45237
  }
@@ -44641,30 +45251,34 @@ function opencodeUninstall(ctx) {
44641
45251
  `refusing to remove ${target.destination} \u2014 the file is not ours (its first line lacks the marker '${target.marker}'); nothing was removed anywhere`
44642
45252
  );
44643
45253
  }
44644
- rmSync13(target.destination);
45254
+ rmSync14(target.destination);
44645
45255
  ctx.stdout(`${target.destination}: removed`);
44646
45256
  }
44647
45257
  ctx.stdout("note: restart opencode for the tool and command to disappear.");
44648
45258
  return EXIT_PASS;
44649
45259
  }
44650
45260
  function runOpencode(ctx) {
44651
- const [sub, ...rest] = ctx.positionals;
44652
- if (rest.length > 0) {
44653
- throw new UnknownArgError(
44654
- `opencode ${sub ?? "<none>"}: unexpected argument '${rest[0] ?? ""}' \u2014 usage: border opencode install | status | uninstall`
44655
- );
44656
- }
45261
+ const [sub, ...restAll] = ctx.positionals;
45262
+ const rest = restAll.filter((arg) => arg !== "--json");
45263
+ const USAGE = "usage: border opencode install | status | uninstall | inspect";
44657
45264
  switch (sub) {
44658
45265
  case "install":
44659
- return opencodeInstall(ctx);
44660
45266
  case "status":
44661
- return opencodeStatus(ctx);
44662
45267
  case "uninstall":
44663
- return opencodeUninstall(ctx);
45268
+ case "inspect": {
45269
+ if (rest.length > 0) {
45270
+ throw new UnknownArgError(`opencode ${sub}: unexpected argument '${rest[0] ?? ""}' \u2014 ${USAGE}`);
45271
+ }
45272
+ const table2 = {
45273
+ install: opencodeInstall,
45274
+ status: opencodeStatus,
45275
+ uninstall: opencodeUninstall,
45276
+ inspect: runInspectCore
45277
+ };
45278
+ return table2[sub](ctx);
45279
+ }
44664
45280
  default:
44665
- throw new UnknownArgError(
44666
- `opencode: unknown subcommand '${sub ?? "<none>"}' \u2014 usage: border opencode install | status | uninstall`
44667
- );
45281
+ throw new UnknownArgError(`opencode: unknown subcommand '${sub ?? "<none>"}' \u2014 ${USAGE}`);
44668
45282
  }
44669
45283
  }
44670
45284
 
@@ -44766,9 +45380,9 @@ function confirmRemoteBranch(i) {
44766
45380
 
44767
45381
  // src/push/landing.ts
44768
45382
  import { spawnSync as spawnSync18 } from "node:child_process";
44769
- import { mkdtempSync as mkdtempSync6, rmSync as rmSync14 } from "node:fs";
44770
- import { tmpdir as tmpdir4 } from "node:os";
44771
- import { dirname as dirname16, join as join29, resolve as resolve18 } from "node:path";
45383
+ import { mkdtempSync as mkdtempSync7, rmSync as rmSync15 } from "node:fs";
45384
+ import { tmpdir as tmpdir5 } from "node:os";
45385
+ import { dirname as dirname17, join as join33, resolve as resolve18 } from "node:path";
44772
45386
  var LANDINGS_REF_PREFIX = "refs/border-landings/";
44773
45387
  async function runLandingVerification(o) {
44774
45388
  if (o.legs.length === 0) return null;
@@ -44791,6 +45405,12 @@ async function runLandingVerification(o) {
44791
45405
  );
44792
45406
  return EXIT_ERROR;
44793
45407
  }
45408
+ const allow = applyAllowList(findings, o.allow ?? [], o.repoDir);
45409
+ findings = allow.kept;
45410
+ if (allow.allowHits.length > 0) {
45411
+ const hits = allow.allowHits.map((h) => `${h.rule}#entry${String(h.entryIndex)}:${String(h.count)}`).join(", ");
45412
+ o.err(`border: ${leg.target.target} landing: ${String(allow.allowHits.reduce((n, h) => n + h.count, 0))} tip finding(s) exempted by config allow pins (${hits}) \u2014 same entries the check verdict honored, echoed loud`);
45413
+ }
44794
45414
  const blocking = findings.filter((f) => isBlocking(f.severity)).length;
44795
45415
  const verdict = blocking > 0 ? "blocked" : "clean";
44796
45416
  sink(buildLandingRecord({ key: o.key, target: leg.target.target, ref: `refs/heads/${leg.branch}`, remoteSha: sha, verdict, blocking, rulesHash }));
@@ -44818,7 +45438,7 @@ function gitPlain(repoDir, env2, args) {
44818
45438
  for (const [name, value] of Object.entries(env2)) {
44819
45439
  if (!name.startsWith("GIT_")) clean[name] = value;
44820
45440
  }
44821
- clean.GIT_CEILING_DIRECTORIES = dirname16(resolve18(repoDir));
45441
+ clean.GIT_CEILING_DIRECTORIES = dirname17(resolve18(repoDir));
44822
45442
  clean.GIT_OPTIONAL_LOCKS = "0";
44823
45443
  clean.GIT_TERMINAL_PROMPT = "0";
44824
45444
  const r = spawnSync18("git", ["-C", resolve18(repoDir), ...args], { encoding: "utf8", env: clean, timeout: 55e3, maxBuffer: 32 * 1024 * 1024 });
@@ -44843,11 +45463,11 @@ async function defaultScanRemoteTip(o, remote, branch, remoteSha) {
44843
45463
  ownedTempRef = landingRef;
44844
45464
  rev = git.run(["rev-parse", landingRef]).trim();
44845
45465
  }
44846
- const treeRoot = mkdtempSync6(join29(tmpdir4(), "border-landing-tree-"));
45466
+ const treeRoot = mkdtempSync7(join33(tmpdir5(), "border-landing-tree-"));
44847
45467
  try {
44848
45468
  return await scanTipTree(git, treeRoot, rev, o.env);
44849
45469
  } finally {
44850
- rmSync14(treeRoot, { recursive: true, force: true });
45470
+ rmSync15(treeRoot, { recursive: true, force: true });
44851
45471
  }
44852
45472
  } finally {
44853
45473
  if (ownedTempRef !== null) {
@@ -45027,6 +45647,9 @@ async function executeYesPush(ctx, loaded) {
45027
45647
  key: state.key,
45028
45648
  legs: legs.map((leg) => ({ target: leg, branch })),
45029
45649
  env: env2,
45650
+ // the SAME allow entries the certifying check honored — one standard
45651
+ // across faces (2026-10-04 incident fix; see push/landing.ts doctrine).
45652
+ allow: loaded.config.allow,
45030
45653
  out: ctx.stdout,
45031
45654
  err: ctx.stderr
45032
45655
  });
@@ -45049,17 +45672,17 @@ async function executeYesPush(ctx, loaded) {
45049
45672
  }
45050
45673
 
45051
45674
  // src/roundtrip/orchestrate.ts
45052
- import { mkdtempSync as mkdtempSync7, rmSync as rmSync15, writeFileSync as writeFileSync9 } from "node:fs";
45675
+ import { mkdtempSync as mkdtempSync8, rmSync as rmSync16, writeFileSync as writeFileSync9 } from "node:fs";
45053
45676
  import { randomBytes } from "node:crypto";
45054
- import { tmpdir as tmpdir5 } from "node:os";
45055
- import { join as join30 } from "node:path";
45677
+ import { tmpdir as tmpdir6 } from "node:os";
45678
+ import { join as join34 } from "node:path";
45056
45679
 
45057
45680
  // src/scan/fetch.ts
45058
- import { createHash as createHash18 } from "node:crypto";
45681
+ import { createHash as createHash19 } from "node:crypto";
45059
45682
  import { basename as basename5 } from "node:path";
45060
45683
  var SCAN_MAX_ARTIFACT_BYTES = 200 * 1024 * 1024;
45061
45684
  var SCAN_REQUEST_TIMEOUT_MS = 6e4;
45062
- var SCAN_USER_AGENT = "border-customs/0.7.1 (+https://github.com/sumteclab/border; border scan)";
45685
+ var SCAN_USER_AGENT = "border-customs/0.8.1 (+https://github.com/gate-corp/border; border scan)";
45063
45686
  var CRATES_DOWNLOAD_HOST = "https://static.crates.io";
45064
45687
  var defaultScanFetcher = async (url2, init) => {
45065
45688
  if (!/^https?:\/\//.test(url2)) throw new EngineRunError(`border scan refuses non-http(s) URL: ${url2}`, null);
@@ -45113,7 +45736,7 @@ async function fetchJson(fetcher, url2, timeoutMs) {
45113
45736
  fail2(`metadata response from ${url2} is not valid JSON`);
45114
45737
  }
45115
45738
  }
45116
- var isRecord2 = (v) => typeof v === "object" && v !== null;
45739
+ var isRecord4 = (v) => typeof v === "object" && v !== null;
45117
45740
  function channelBaseUrl(eco) {
45118
45741
  const ch = publishChannels().find((c) => c.id === eco);
45119
45742
  if (ch === void 0 || ch.defaultUrl.length === 0) {
@@ -45144,7 +45767,7 @@ async function fetchArtifact(spec, o) {
45144
45767
  switch (spec.ecosystem) {
45145
45768
  case "npm": {
45146
45769
  const meta3 = await fetchJson(o.fetcher, npmMetadataUrl(spec.name, spec.version), timeoutMs);
45147
- const dist = isRecord2(meta3) && isRecord2(meta3["dist"]) ? meta3["dist"] : {};
45770
+ const dist = isRecord4(meta3) && isRecord4(meta3["dist"]) ? meta3["dist"] : {};
45148
45771
  const tarball = dist["tarball"];
45149
45772
  if (typeof tarball !== "string" || tarball.length === 0) fail2(`npm metadata for ${label} has no dist.tarball`);
45150
45773
  if (!/^https?:\/\//.test(tarball)) fail2(`npm dist.tarball for ${label} is not an http(s) URL`);
@@ -45155,8 +45778,8 @@ async function fetchArtifact(spec, o) {
45155
45778
  }
45156
45779
  case "pypi": {
45157
45780
  const meta3 = await fetchJson(o.fetcher, pypiMetadataUrl(spec.name, spec.version), timeoutMs);
45158
- const urls = isRecord2(meta3) && Array.isArray(meta3["urls"]) ? meta3["urls"] : [];
45159
- const files = urls.filter(isRecord2);
45781
+ const urls = isRecord4(meta3) && Array.isArray(meta3["urls"]) ? meta3["urls"] : [];
45782
+ const files = urls.filter(isRecord4);
45160
45783
  const sdists = files.filter((f) => f["packagetype"] === "sdist");
45161
45784
  const sdist = sdists.find((f) => typeof f["filename"] === "string" && f["filename"].endsWith(".tar.gz"));
45162
45785
  if (sdist === void 0) {
@@ -45184,8 +45807,8 @@ async function fetchArtifact(spec, o) {
45184
45807
  }
45185
45808
  }
45186
45809
  }
45187
- function sha256Hex3(data) {
45188
- return createHash18("sha256").update(data).digest("hex");
45810
+ function sha256Hex4(data) {
45811
+ return createHash19("sha256").update(data).digest("hex");
45189
45812
  }
45190
45813
 
45191
45814
  // src/scan/spec.ts
@@ -45228,8 +45851,8 @@ function parseScanSpec(raw) {
45228
45851
  }
45229
45852
 
45230
45853
  // src/roundtrip/localArtifact.ts
45231
- import { createReadStream, existsSync as existsSync19, statSync as statSync3 } from "node:fs";
45232
- import { createHash as createHash19 } from "node:crypto";
45854
+ import { createReadStream, existsSync as existsSync23, statSync as statSync3 } from "node:fs";
45855
+ import { createHash as createHash20 } from "node:crypto";
45233
45856
  import { basename as basename6, resolve as resolve19 } from "node:path";
45234
45857
  var EXT_TABLE = /* @__PURE__ */ new Map([
45235
45858
  [".whl", "pypi"],
@@ -45277,7 +45900,7 @@ var GRAMMAR_HINT = {
45277
45900
  };
45278
45901
  function classifyLocalInput(raw, cwd, parsesAsRegistrySpec) {
45279
45902
  const abs = resolve19(cwd, raw);
45280
- if (existsSync19(abs)) {
45903
+ if (existsSync23(abs)) {
45281
45904
  const st = statSync3(abs);
45282
45905
  if (st.isDirectory()) {
45283
45906
  bad3(`'${raw}' resolves to a directory (${abs}) \u2014 local mode needs a single artifact FILE, not a directory`);
@@ -45312,7 +45935,7 @@ function classifyLocalInput(raw, cwd, parsesAsRegistrySpec) {
45312
45935
  return null;
45313
45936
  }
45314
45937
  async function readLocalArtifact(absPath, cap = SCAN_MAX_ARTIFACT_BYTES) {
45315
- const hash2 = createHash19("sha256");
45938
+ const hash2 = createHash20("sha256");
45316
45939
  const parts = [];
45317
45940
  let total = 0;
45318
45941
  for await (const chunk of createReadStream(absPath)) {
@@ -45538,7 +46161,7 @@ var CLAIM_SCANNER_PY = [
45538
46161
  ].join("\n");
45539
46162
 
45540
46163
  // src/roundtrip/manifest.ts
45541
- import { createHash as createHash20 } from "node:crypto";
46164
+ import { createHash as createHash21 } from "node:crypto";
45542
46165
  var RT_ENGINE = "roundtrip";
45543
46166
  var RT_RESIDUE_RULE = "roundtrip-residue-file";
45544
46167
  var RT_MODIFY_RULE = "roundtrip-modified-file";
@@ -45589,7 +46212,7 @@ var PERSISTENCE_PATTERNS = [
45589
46212
  function isPersistenceSurface(path4) {
45590
46213
  return PERSISTENCE_PATTERNS.some((re) => re.test(path4));
45591
46214
  }
45592
- var digestOf = (what) => createHash20("sha256").update(what).digest("hex");
46215
+ var digestOf = (what) => createHash21("sha256").update(what).digest("hex");
45593
46216
  function classifyResidue(label, diff, attribution = null) {
45594
46217
  const findings = [];
45595
46218
  for (const e of diff.added) {
@@ -45636,7 +46259,7 @@ function classifyResidue(label, diff, attribution = null) {
45636
46259
 
45637
46260
  // src/roundtrip/orchestrate.ts
45638
46261
  function containerNameFor(label, rand = randomBytes(3).toString("hex")) {
45639
- return `rt-${sha256Hex3(label).slice(0, 8)}-${rand}`;
46262
+ return `rt-${sha256Hex4(label).slice(0, 8)}-${rand}`;
45640
46263
  }
45641
46264
  var shArgv = (name) => {
45642
46265
  if (!/^[A-Za-z0-9@._+/-]+$/.test(name)) {
@@ -45757,7 +46380,7 @@ function runPipeline2(exec, profile, spec, label, hostPath, container, closure,
45757
46380
  return {
45758
46381
  findings: classifyResidue(label, diffManifests(m1, m3), attribution),
45759
46382
  installDelta,
45760
- baselineDigest: sha256Hex3([...m1.keys()].join("\n"))
46383
+ baselineDigest: sha256Hex4([...m1.keys()].join("\n"))
45761
46384
  };
45762
46385
  } finally {
45763
46386
  try {
@@ -45791,12 +46414,12 @@ async function runRoundtripCore(ctx, deps = {}) {
45791
46414
  ctx.stderr("roundtrip: docker unavailable \u2014 cannot verify");
45792
46415
  return EXIT_ERROR;
45793
46416
  }
45794
- const baseDir = mkdtempSync7(join30(tmpdir5(), "border-roundtrip-"));
46417
+ const baseDir = mkdtempSync8(join34(tmpdir6(), "border-roundtrip-"));
45795
46418
  try {
45796
46419
  const localRead = local !== null ? await readLocalArtifact(local.absPath) : null;
45797
46420
  const bytes = localRead?.bytes ?? (await fetchArtifact(spec, { fetcher: deps.fetcher ?? defaultScanFetcher })).bytes;
45798
- const artifactSha256 = localRead !== null ? localRead.sha256 : sha256Hex3(bytes);
45799
- const hostPath = join30(baseDir, "artifact");
46421
+ const artifactSha256 = localRead !== null ? localRead.sha256 : sha256Hex4(bytes);
46422
+ const hostPath = join34(baseDir, "artifact");
45800
46423
  writeFileSync9(hostPath, bytes);
45801
46424
  const container = containerNameFor(label);
45802
46425
  const closure = spec.ecosystem === "pypi" ? resolvePipClosure(exec, profile, hostPath, label, spec) : null;
@@ -45804,12 +46427,12 @@ async function runRoundtripCore(ctx, deps = {}) {
45804
46427
  const verdict = computeVerdict(findings);
45805
46428
  const report = {
45806
46429
  schemaVersion: 1,
45807
- key: sha256Hex3(`roundtrip:${label}:${baselineDigest}:${verdict}`),
46430
+ key: sha256Hex4(`roundtrip:${label}:${baselineDigest}:${verdict}`),
45808
46431
  head: baselineDigest.slice(0, 40),
45809
46432
  dirty: false,
45810
46433
  exposureSet: [label],
45811
46434
  refSet: [],
45812
- rulesHash: sha256Hex3(`${profile.image}|${profile.install(profile.artifactPath, spec).join(" ")}|${profile.uninstall(spec).join(" ")}`),
46435
+ rulesHash: sha256Hex4(`${profile.image}|${profile.install(profile.artifactPath, spec).join(" ")}|${profile.uninstall(spec).join(" ")}`),
45813
46436
  verdict,
45814
46437
  counts: countFindings(findings),
45815
46438
  findings,
@@ -45841,7 +46464,7 @@ async function runRoundtripCore(ctx, deps = {}) {
45841
46464
  }
45842
46465
  return exitCodeFromVerdict(verdict);
45843
46466
  } finally {
45844
- rmSync15(baseDir, { recursive: true, force: true });
46467
+ rmSync16(baseDir, { recursive: true, force: true });
45845
46468
  }
45846
46469
  }
45847
46470
  function parsesRegistrySpec(raw) {
@@ -45897,9 +46520,9 @@ function dockerAvailableGuard(exec) {
45897
46520
  var runRoundtrip = (ctx) => runRoundtripCore(ctx);
45898
46521
 
45899
46522
  // src/scan/scan.ts
45900
- import { mkdtempSync as mkdtempSync8 } from "node:fs";
45901
- import { tmpdir as tmpdir6 } from "node:os";
45902
- import { join as join32 } from "node:path";
46523
+ import { mkdtempSync as mkdtempSync9 } from "node:fs";
46524
+ import { tmpdir as tmpdir7 } from "node:os";
46525
+ import { join as join36 } from "node:path";
45903
46526
 
45904
46527
  // src/scan/config.ts
45905
46528
  function buildScanConfigYaml(eco) {
@@ -45926,8 +46549,8 @@ function synthesizeScanConfig(eco) {
45926
46549
  }
45927
46550
 
45928
46551
  // src/scan/materialize.ts
45929
- import { existsSync as existsSync20, mkdirSync as mkdirSync13, readdirSync as readdirSync10, readFileSync as readFileSync19, rmSync as rmSync16, writeFileSync as writeFileSync10 } from "node:fs";
45930
- import { join as join31 } from "node:path";
46552
+ import { existsSync as existsSync24, mkdirSync as mkdirSync13, readdirSync as readdirSync11, readFileSync as readFileSync21, rmSync as rmSync17, writeFileSync as writeFileSync10 } from "node:fs";
46553
+ import { join as join35 } from "node:path";
45931
46554
  var CRATES_ENVELOPE_FILES = ["Cargo.toml.orig", ".cargo-ok", ".cargo_vcs_info.json"];
45932
46555
  var fail3 = (why) => {
45933
46556
  throw new Error(`border scan cannot materialize the artifact (${why}) \u2014 refusing to stage an unusable tree (fail-closed)`);
@@ -45941,15 +46564,15 @@ function extractFlat(archive, destDir) {
45941
46564
  }
45942
46565
  }
45943
46566
  function unwrapSingleDir(dir) {
45944
- const entries = readdirSync10(dir, { withFileTypes: true });
46567
+ const entries = readdirSync11(dir, { withFileTypes: true });
45945
46568
  const dirs = entries.filter((e) => e.isDirectory());
45946
46569
  if (entries.length === 1 && dirs.length === 1 && dirs[0] !== void 0) {
45947
- return join31(dir, dirs[0].name);
46570
+ return join35(dir, dirs[0].name);
45948
46571
  }
45949
46572
  return dir;
45950
46573
  }
45951
46574
  function requireManifest(repoDir, ecosystem, candidates) {
45952
- if (!candidates.some((rel) => existsSync20(join31(repoDir, rel)))) {
46575
+ if (!candidates.some((rel) => existsSync24(join35(repoDir, rel)))) {
45953
46576
  fail3(`${ecosystem} package tree has none of [${candidates.join(", ")}] at its root`);
45954
46577
  }
45955
46578
  }
@@ -45959,18 +46582,18 @@ function materializePackage(o) {
45959
46582
  `);
45960
46583
  });
45961
46584
  const safe = safeArtifactName(o.filename, `${o.ecosystem}-artifact`);
45962
- const archive = join31(o.baseDir, safe);
46585
+ const archive = join35(o.baseDir, safe);
45963
46586
  writeFileSync10(archive, o.bytes);
45964
- const extractDir = join31(o.baseDir, "extract");
46587
+ const extractDir = join35(o.baseDir, "extract");
45965
46588
  mkdirSync13(extractDir, { recursive: true });
45966
46589
  extractFlat(archive, extractDir);
45967
46590
  let repoDir = unwrapSingleDir(extractDir);
45968
46591
  if (o.ecosystem === "rubygems") {
45969
46592
  const outer = repoDir;
45970
46593
  const dataCandidates = findNativeMissArchives(outer).filter((f) => f.endsWith("data.tar.gz"));
45971
- const inner = dataCandidates[0] ?? join31(outer, "data.tar.gz");
45972
- if (!existsSync20(inner)) fail3(".gem archive contains no data.tar.gz");
45973
- const gemTree = join31(o.baseDir, "gem-tree");
46594
+ const inner = dataCandidates[0] ?? join35(outer, "data.tar.gz");
46595
+ if (!existsSync24(inner)) fail3(".gem archive contains no data.tar.gz");
46596
+ const gemTree = join35(o.baseDir, "gem-tree");
45974
46597
  mkdirSync13(gemTree, { recursive: true });
45975
46598
  extractFlat(inner, gemTree);
45976
46599
  repoDir = unwrapSingleDir(gemTree);
@@ -45981,11 +46604,11 @@ function materializePackage(o) {
45981
46604
  } else {
45982
46605
  requireManifest(repoDir, o.ecosystem, ["Cargo.toml"]);
45983
46606
  for (const file2 of CRATES_ENVELOPE_FILES) {
45984
- const path4 = join31(repoDir, file2);
45985
- if (!existsSync20(path4)) continue;
45986
- const original = readFileSync19(path4);
45987
- rmSync16(path4, { force: true });
45988
- note(`border scan: crates envelope normalized: ${file2} sha256=${sha256Hex3(original)}`);
46607
+ const path4 = join35(repoDir, file2);
46608
+ if (!existsSync24(path4)) continue;
46609
+ const original = readFileSync21(path4);
46610
+ rmSync17(path4, { force: true });
46611
+ note(`border scan: crates envelope normalized: ${file2} sha256=${sha256Hex4(original)}`);
45989
46612
  }
45990
46613
  }
45991
46614
  const env2 = o.env;
@@ -46011,7 +46634,7 @@ async function runScanCore(ctx, deps = {}) {
46011
46634
  }
46012
46635
  const cfg = synthesizeScanConfig(spec.ecosystem);
46013
46636
  const fetcher = deps.fetcher ?? defaultScanFetcher;
46014
- const baseDir = mkdtempSync8(join32(tmpdir6(), "border-scan-"));
46637
+ const baseDir = mkdtempSync9(join36(tmpdir7(), "border-scan-"));
46015
46638
  try {
46016
46639
  const { bytes, filename } = await fetchArtifact(spec, { fetcher });
46017
46640
  const env2 = { ...ctx.env };
@@ -46022,12 +46645,12 @@ async function runScanCore(ctx, deps = {}) {
46022
46645
  const verdict = computeVerdict(findings);
46023
46646
  const report = {
46024
46647
  schemaVersion: 1,
46025
- key: sha256Hex3(`scan:${spec.ecosystem}:${spec.name}@${spec.version}:${head}`),
46648
+ key: sha256Hex4(`scan:${spec.ecosystem}:${spec.name}@${spec.version}:${head}`),
46026
46649
  head,
46027
46650
  dirty: false,
46028
46651
  exposureSet: [`${spec.ecosystem}:${spec.name}@${spec.version}`],
46029
46652
  refSet: [],
46030
- rulesHash: sha256Hex3(buildScanConfigYaml(spec.ecosystem)),
46653
+ rulesHash: sha256Hex4(buildScanConfigYaml(spec.ecosystem)),
46031
46654
  verdict,
46032
46655
  counts: countFindings(findings),
46033
46656
  findings,
@@ -46168,7 +46791,7 @@ function usage() {
46168
46791
  " llm-ingest record provenance captured by the harness",
46169
46792
  " scan inspect a third-party package ([ecosystem:]name@version) for residue",
46170
46793
  " roundtrip install+uninstall a package (registry spec or local artifact file) in a throwaway container, report uninstall residue",
46171
- " opencode install|status|uninstall the official opencode plugin adapter (files under $XDG_CONFIG_HOME/opencode)",
46794
+ " opencode install|status|uninstall|inspect the official opencode plugin adapter (files under $XDG_CONFIG_HOME/opencode; inspect = read-only V1 load-surface audit)",
46172
46795
  " exfil read-only exfil-lens scan of <ref|url> [ref...]: tip tree + tag notes (--deep adds reachable-history blobs + commit messages)",
46173
46796
  "",
46174
46797
  "flags:",
@@ -46311,7 +46934,7 @@ function isMainModule({ argv1, moduleUrl, realpath }) {
46311
46934
  return p;
46312
46935
  }
46313
46936
  };
46314
- return pathToFileURL(canonical(argv1)).href === pathToFileURL(canonical(fileURLToPath6(moduleUrl))).href;
46937
+ return pathToFileURL(canonical(argv1)).href === pathToFileURL(canonical(fileURLToPath7(moduleUrl))).href;
46315
46938
  }
46316
46939
  if (isMainModule({ argv1: process.argv[1], moduleUrl: import.meta.url, realpath: realpathSync.native })) {
46317
46940
  const outcome = run(process.argv.slice(2));