@codyswann/lisa 4.21.5 → 4.21.6

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.
Files changed (120) hide show
  1. package/dist/cli/doctor-nightly-e2e-guard-command-files.d.ts +19 -0
  2. package/dist/cli/doctor-nightly-e2e-guard-command-files.d.ts.map +1 -0
  3. package/dist/cli/doctor-nightly-e2e-guard-command-files.js +221 -0
  4. package/dist/cli/doctor-nightly-e2e-guard-command-files.js.map +1 -0
  5. package/dist/cli/doctor-nightly-e2e-guard-contract.d.ts +113 -0
  6. package/dist/cli/doctor-nightly-e2e-guard-contract.d.ts.map +1 -0
  7. package/dist/cli/doctor-nightly-e2e-guard-contract.js +87 -0
  8. package/dist/cli/doctor-nightly-e2e-guard-contract.js.map +1 -0
  9. package/dist/cli/doctor-nightly-e2e-guard-deadline.d.ts +61 -0
  10. package/dist/cli/doctor-nightly-e2e-guard-deadline.d.ts.map +1 -0
  11. package/dist/cli/doctor-nightly-e2e-guard-deadline.js +97 -0
  12. package/dist/cli/doctor-nightly-e2e-guard-deadline.js.map +1 -0
  13. package/dist/cli/doctor-nightly-e2e-guard-evidence.d.ts +52 -0
  14. package/dist/cli/doctor-nightly-e2e-guard-evidence.d.ts.map +1 -0
  15. package/dist/cli/doctor-nightly-e2e-guard-evidence.js +68 -0
  16. package/dist/cli/doctor-nightly-e2e-guard-evidence.js.map +1 -0
  17. package/dist/cli/doctor-nightly-e2e-guard-graph.d.ts +14 -0
  18. package/dist/cli/doctor-nightly-e2e-guard-graph.d.ts.map +1 -0
  19. package/dist/cli/doctor-nightly-e2e-guard-graph.js +130 -0
  20. package/dist/cli/doctor-nightly-e2e-guard-graph.js.map +1 -0
  21. package/dist/cli/doctor-nightly-e2e-guard-io.d.ts +41 -0
  22. package/dist/cli/doctor-nightly-e2e-guard-io.d.ts.map +1 -0
  23. package/dist/cli/doctor-nightly-e2e-guard-io.js +239 -0
  24. package/dist/cli/doctor-nightly-e2e-guard-io.js.map +1 -0
  25. package/dist/cli/doctor-nightly-e2e-guard-job.d.ts +31 -0
  26. package/dist/cli/doctor-nightly-e2e-guard-job.d.ts.map +1 -0
  27. package/dist/cli/doctor-nightly-e2e-guard-job.js +156 -0
  28. package/dist/cli/doctor-nightly-e2e-guard-job.js.map +1 -0
  29. package/dist/cli/doctor-nightly-e2e-guard-proof.d.ts +42 -0
  30. package/dist/cli/doctor-nightly-e2e-guard-proof.d.ts.map +1 -0
  31. package/dist/cli/doctor-nightly-e2e-guard-proof.js +57 -0
  32. package/dist/cli/doctor-nightly-e2e-guard-proof.js.map +1 -0
  33. package/dist/cli/doctor-nightly-e2e-guard-remediation.d.ts +32 -0
  34. package/dist/cli/doctor-nightly-e2e-guard-remediation.d.ts.map +1 -0
  35. package/dist/cli/doctor-nightly-e2e-guard-remediation.js +55 -0
  36. package/dist/cli/doctor-nightly-e2e-guard-remediation.js.map +1 -0
  37. package/dist/cli/doctor-nightly-e2e-guard-runtime.d.ts +34 -0
  38. package/dist/cli/doctor-nightly-e2e-guard-runtime.d.ts.map +1 -0
  39. package/dist/cli/doctor-nightly-e2e-guard-runtime.js +93 -0
  40. package/dist/cli/doctor-nightly-e2e-guard-runtime.js.map +1 -0
  41. package/dist/cli/doctor-nightly-e2e-guard-scan.d.ts +17 -0
  42. package/dist/cli/doctor-nightly-e2e-guard-scan.d.ts.map +1 -0
  43. package/dist/cli/doctor-nightly-e2e-guard-scan.js +86 -0
  44. package/dist/cli/doctor-nightly-e2e-guard-scan.js.map +1 -0
  45. package/dist/cli/doctor-nightly-e2e-guard-shell-lexer.d.ts +38 -0
  46. package/dist/cli/doctor-nightly-e2e-guard-shell-lexer.d.ts.map +1 -0
  47. package/dist/cli/doctor-nightly-e2e-guard-shell-lexer.js +160 -0
  48. package/dist/cli/doctor-nightly-e2e-guard-shell-lexer.js.map +1 -0
  49. package/dist/cli/doctor-nightly-e2e-guard-shell.d.ts +40 -0
  50. package/dist/cli/doctor-nightly-e2e-guard-shell.d.ts.map +1 -0
  51. package/dist/cli/doctor-nightly-e2e-guard-shell.js +201 -0
  52. package/dist/cli/doctor-nightly-e2e-guard-shell.js.map +1 -0
  53. package/dist/cli/doctor-nightly-e2e-guard.d.ts +36 -0
  54. package/dist/cli/doctor-nightly-e2e-guard.d.ts.map +1 -0
  55. package/dist/cli/doctor-nightly-e2e-guard.js +186 -0
  56. package/dist/cli/doctor-nightly-e2e-guard.js.map +1 -0
  57. package/dist/cli/doctor.d.ts.map +1 -1
  58. package/dist/cli/doctor.js +7 -0
  59. package/dist/cli/doctor.js.map +1 -1
  60. package/dist/core/nightly-e2e-guard-behavior-certificate.d.ts +25 -0
  61. package/dist/core/nightly-e2e-guard-behavior-certificate.d.ts.map +1 -0
  62. package/dist/core/nightly-e2e-guard-behavior-certificate.js +30 -0
  63. package/dist/core/nightly-e2e-guard-behavior-certificate.js.map +1 -0
  64. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  65. package/dist/core/upstream-evidence-manifest.js +29 -2
  66. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  67. package/package.json +5 -3
  68. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  70. package/plugins/lisa-agy/plugin.json +1 -1
  71. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  72. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  73. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  74. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  75. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  77. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  78. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  79. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  80. package/plugins/lisa-expo-agy/plugin.json +1 -1
  81. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  82. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  83. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  84. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  85. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  86. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  87. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  88. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  89. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  90. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  91. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  92. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  93. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  94. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  95. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  96. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  97. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  98. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  99. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  100. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  101. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  102. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  103. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  104. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  105. package/plugins/lisa-rails-agy/plugin.json +1 -1
  106. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  107. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  108. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  109. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  110. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  111. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  112. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  113. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  114. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  115. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  116. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  117. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  118. package/scripts/check-derived-artifacts.mjs +32 -5
  119. package/scripts/generate-nightly-e2e-guard-certificate.mjs +370 -0
  120. package/scripts/two-channel-couplings.json +16 -4
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @file doctor-nightly-e2e-guard-evidence.ts
3
+ * @description Preclassification evidence pass for one reachable workflow job
4
+ * @module cli/doctor-nightly-e2e-guard-evidence
5
+ */
6
+ import { type NightlyGuardWorkflowRecord } from "./doctor-nightly-e2e-guard-contract.js";
7
+ import { type NightlyGuardRunInspection } from "./doctor-nightly-e2e-guard-shell.js";
8
+ /** Evidence gathered before deciding which supported job grammar applies. */
9
+ export interface NightlyGuardJobEvidence {
10
+ /** YAML-decoded steps retained for per-step environment attribution. */
11
+ readonly steps: readonly Readonly<Record<string, unknown>>[];
12
+ /** Comment-stripped POSIX run interpretations for those steps. */
13
+ readonly analyses: readonly NightlyGuardRunInspection[];
14
+ /** Workflow/job environment carries recognized bypass semantics. */
15
+ readonly inheritedEnvironment: boolean;
16
+ /** At least one step environment carries recognized bypass semantics. */
17
+ readonly stepEnvironment: boolean;
18
+ /** Job or step condition carries recognized bypass semantics. */
19
+ readonly condition: boolean;
20
+ /** Reusable input mapping carries recognized bypass semantics. */
21
+ readonly withMapping: boolean;
22
+ /** Comment-stripped run tokens construct recognized bypass state. */
23
+ readonly run: boolean;
24
+ /** At least one supported or refused run contains a Node command. */
25
+ readonly hasNode: boolean;
26
+ }
27
+ /**
28
+ * Recognize only operational bypass keys or values with nightly-E2E semantics.
29
+ * @param levels - YAML mappings at increasing precedence
30
+ * @returns Whether a mapping participates in this guard's bypass contract
31
+ */
32
+ export declare const bypassBearingMapping: (...levels: readonly unknown[]) => boolean;
33
+ /**
34
+ * Conditions are executable evidence only when their value has guard semantics.
35
+ * @param value - Parsed job/step `if` value
36
+ * @returns Whether the condition can participate in nightly bypass behavior
37
+ */
38
+ export declare const conditionalBypass: (value: unknown) => boolean;
39
+ /**
40
+ * Inspect all executable fields before official/local/direct classification.
41
+ * @param workflow - Parsed owner of the job and workflow defaults
42
+ * @param job - Parsed job mapping with runner and step metadata
43
+ * @returns Evidence shared by every classification branch
44
+ */
45
+ export declare const inspectNightlyGuardJobEvidence: (workflow: NightlyGuardWorkflowRecord, job: Readonly<Record<string, unknown>>) => NightlyGuardJobEvidence;
46
+ /**
47
+ * Collapse evidence only after every executable field has been inspected.
48
+ * @param evidence - Complete preclassification evidence record
49
+ * @returns Whether any field places the job in the nightly bypass contract
50
+ */
51
+ export declare const hasAnyNightlyGuardBypassEvidence: (evidence: NightlyGuardJobEvidence) => boolean;
52
+ //# sourceMappingURL=doctor-nightly-e2e-guard-evidence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-nightly-e2e-guard-evidence.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-nightly-e2e-guard-evidence.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,KAAK,0BAA0B,EAGhC,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAIL,KAAK,yBAAyB,EAC/B,MAAM,qCAAqC,CAAC;AAE7C,6EAA6E;AAC7E,MAAM,WAAW,uBAAuB;IACtC,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;IAC7D,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,SAAS,yBAAyB,EAAE,CAAC;IACxD,oEAAoE;IACpE,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAC;IACvC,yEAAyE;IACzE,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,iEAAiE;IACjE,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,kEAAkE;IAClE,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,qEAAqE;IACrE,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAmBD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,GAAG,QAAQ,SAAS,OAAO,EAAE,KAAG,OAOlE,CAAC;AAEJ;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,OAAO,KAAG,OACY,CAAC;AAYhE;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,GACzC,UAAU,0BAA0B,EACpC,KAAK,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,KACrC,uBAmCF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gCAAgC,GAC3C,UAAU,uBAAuB,KAChC,OAKW,CAAC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @file doctor-nightly-e2e-guard-evidence.ts
3
+ * @description Preclassification evidence pass for one reachable workflow job
4
+ * @module cli/doctor-nightly-e2e-guard-evidence
5
+ */
6
+ import { nightlyGuardObject, nightlyGuardText, } from "./doctor-nightly-e2e-guard-contract.js";
7
+ import { hasNightlyBypassReference, inspectNightlyGuardRun, isNightlyBypassEnvironmentName, } from "./doctor-nightly-e2e-guard-shell.js";
8
+ const mergedEnvironment = (...levels) => Object.assign({}, ...levels.map(level => nightlyGuardObject(level) ?? {}));
9
+ const literalEnvironment = (environment) => Object.fromEntries(Object.entries(environment).filter((entry) => typeof entry[1] === "string"));
10
+ const bypassKey = (key) => isNightlyBypassEnvironmentName(key) || hasNightlyBypassReference(key);
11
+ /**
12
+ * Recognize only operational bypass keys or values with nightly-E2E semantics.
13
+ * @param levels - YAML mappings at increasing precedence
14
+ * @returns Whether a mapping participates in this guard's bypass contract
15
+ */
16
+ export const bypassBearingMapping = (...levels) => levels.some(level => Object.entries(nightlyGuardObject(level) ?? {}).some(([key, value]) => bypassKey(key) ||
17
+ (typeof value === "string" && hasNightlyBypassReference(value))));
18
+ /**
19
+ * Conditions are executable evidence only when their value has guard semantics.
20
+ * @param value - Parsed job/step `if` value
21
+ * @returns Whether the condition can participate in nightly bypass behavior
22
+ */
23
+ export const conditionalBypass = (value) => typeof value === "string" && hasNightlyBypassReference(value);
24
+ const workflowShell = (workflow) => nightlyGuardObject(nightlyGuardObject(workflow.document.defaults)?.run)
25
+ ?.shell;
26
+ const jobShell = (job) => nightlyGuardObject(nightlyGuardObject(job.defaults)?.run)?.shell;
27
+ const firstDefined = (...values) => values.find(value => value !== undefined);
28
+ /**
29
+ * Inspect all executable fields before official/local/direct classification.
30
+ * @param workflow - Parsed owner of the job and workflow defaults
31
+ * @param job - Parsed job mapping with runner and step metadata
32
+ * @returns Evidence shared by every classification branch
33
+ */
34
+ export const inspectNightlyGuardJobEvidence = (workflow, job) => {
35
+ const rawSteps = Array.isArray(job.steps) ? job.steps : [];
36
+ const steps = rawSteps.map(step => nightlyGuardObject(step) ?? {});
37
+ const inheritedEnvironment = bypassBearingMapping(workflow.document.env, job.env);
38
+ const analyses = steps.map(step => {
39
+ const environment = mergedEnvironment(workflow.document.env, job.env, step.env);
40
+ return inspectNightlyGuardRun(nightlyGuardText(step.run), literalEnvironment(environment), {
41
+ shell: firstDefined(step.shell, jobShell(job), workflowShell(workflow)),
42
+ runsOn: job["runs-on"],
43
+ environment,
44
+ });
45
+ });
46
+ return {
47
+ steps,
48
+ analyses,
49
+ inheritedEnvironment,
50
+ stepEnvironment: steps.some(step => bypassBearingMapping(step.env)),
51
+ condition: conditionalBypass(job.if) ||
52
+ steps.some(step => conditionalBypass(step.if)),
53
+ withMapping: bypassBearingMapping(job.with),
54
+ run: analyses.some(analysis => analysis.bypassEvidence),
55
+ hasNode: analyses.some(analysis => analysis.containsNode),
56
+ };
57
+ };
58
+ /**
59
+ * Collapse evidence only after every executable field has been inspected.
60
+ * @param evidence - Complete preclassification evidence record
61
+ * @returns Whether any field places the job in the nightly bypass contract
62
+ */
63
+ export const hasAnyNightlyGuardBypassEvidence = (evidence) => evidence.inheritedEnvironment ||
64
+ evidence.stepEnvironment ||
65
+ evidence.condition ||
66
+ evidence.withMapping ||
67
+ evidence.run;
68
+ //# sourceMappingURL=doctor-nightly-e2e-guard-evidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-nightly-e2e-guard-evidence.js","sourceRoot":"","sources":["../../src/cli/doctor-nightly-e2e-guard-evidence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @file doctor-nightly-e2e-guard-graph.ts
3
+ * @description Root-preserving traversal of reachable local reusable workflows
4
+ * @module cli/doctor-nightly-e2e-guard-graph
5
+ */
6
+ import { type NightlyGuardScanResult, type NightlyGuardWorkflowRecord } from "./doctor-nightly-e2e-guard-contract.js";
7
+ /**
8
+ * Traverse each root independently so shared reusables retain every active
9
+ * root-to-job attribution while static target proof remains deduplicated.
10
+ * @param records - Parsed bounded workflow inventory
11
+ * @returns Deterministic active callers or the first graph refusal
12
+ */
13
+ export declare function traceNightlyGuardCallers(records: readonly NightlyGuardWorkflowRecord[]): NightlyGuardScanResult;
14
+ //# sourceMappingURL=doctor-nightly-e2e-guard-graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-nightly-e2e-guard-graph.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-nightly-e2e-guard-graph.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EASL,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,EAKhC,MAAM,wCAAwC,CAAC;AA2KhD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,SAAS,0BAA0B,EAAE,GAC7C,sBAAsB,CA2BxB"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * @file doctor-nightly-e2e-guard-graph.ts
3
+ * @description Root-preserving traversal of reachable local reusable workflows
4
+ * @module cli/doctor-nightly-e2e-guard-graph
5
+ */
6
+ import { MAX_NIGHTLY_GUARD_ATTRIBUTION_BYTES, MAX_NIGHTLY_GUARD_CALLERS, MAX_NIGHTLY_GUARD_JOB_ID_BYTES, MAX_NIGHTLY_GUARD_LOCAL_DEPTH, MAX_NIGHTLY_GUARD_TARGETS, NIGHTLY_GUARD_WORKFLOWS, isNightlyGuardJobId, nightlyGuardCallerAttributionBytes, nightlyGuardObject, orderNightlyGuardStrings, } from "./doctor-nightly-e2e-guard-contract.js";
7
+ import { inspectNightlyGuardJob } from "./doctor-nightly-e2e-guard-job.js";
8
+ const failure = (workflow, reason) => ({ failure: { workflow: workflow.file, reason } });
9
+ const isFailure = (result) => "failure" in result;
10
+ const triggerNames = (value) => {
11
+ if (typeof value === "string")
12
+ return [value];
13
+ if (Array.isArray(value)) {
14
+ return value.filter(item => typeof item === "string");
15
+ }
16
+ return Object.keys(nightlyGuardObject(value) ?? {});
17
+ };
18
+ const isRoot = (record) => triggerNames(record.document.on).some(event => event !== "workflow_call");
19
+ const pathPart = (workflow, jobId) => `${workflow.file}#${jobId}`;
20
+ const validateBounds = (workflow, callers) => {
21
+ if (callers.length > MAX_NIGHTLY_GUARD_CALLERS) {
22
+ return failure(workflow, `bypass caller limit ${MAX_NIGHTLY_GUARD_CALLERS} exceeded`);
23
+ }
24
+ const targets = new Set(callers.map(caller => caller.target));
25
+ if (targets.size > MAX_NIGHTLY_GUARD_TARGETS) {
26
+ return failure(workflow, `guard target limit ${MAX_NIGHTLY_GUARD_TARGETS} exceeded`);
27
+ }
28
+ const attributionBytes = callers.reduce((total, caller) => total + nightlyGuardCallerAttributionBytes(caller), 0);
29
+ return attributionBytes > MAX_NIGHTLY_GUARD_ATTRIBUTION_BYTES
30
+ ? {
31
+ failure: {
32
+ workflow: NIGHTLY_GUARD_WORKFLOWS,
33
+ reason: `caller attribution exceeds the ${MAX_NIGHTLY_GUARD_ATTRIBUTION_BYTES}-byte limit`,
34
+ },
35
+ }
36
+ : { callers };
37
+ };
38
+ const callerFor = (workflow, jobId, context, caller) => ({
39
+ workflow: workflow.file,
40
+ job: jobId,
41
+ callPath: [...context.parents, pathPart(workflow, jobId)].join(" -> "),
42
+ kind: caller.kind,
43
+ target: caller.target,
44
+ });
45
+ const childContext = (workflow, jobId, context) => ({
46
+ depth: context.depth + 1,
47
+ stack: [...context.stack, workflow.name],
48
+ parents: [...context.parents, pathPart(workflow, jobId)],
49
+ });
50
+ /**
51
+ * Traverse one workflow and every local edge below it.
52
+ * @param workflow - Current parsed workflow
53
+ * @param byName - Bounded inventory keyed by basename
54
+ * @param context - Root-path recursion state
55
+ * @returns Callers below this workflow or an explicit graph refusal
56
+ */
57
+ const walkWorkflow = (workflow, byName, context) => {
58
+ if (context.stack.includes(workflow.name)) {
59
+ return failure(workflow, `reachable local workflow cycle: ${[...context.stack, workflow.name].join(" -> ")}`);
60
+ }
61
+ const jobs = nightlyGuardObject(workflow.document.jobs) ?? {};
62
+ const jobIds = orderNightlyGuardStrings(Object.keys(jobs));
63
+ const walkJobs = (index, accumulated) => {
64
+ const jobId = jobIds[index];
65
+ if (jobId === undefined)
66
+ return validateBounds(workflow, accumulated);
67
+ if (!isNightlyGuardJobId(jobId)) {
68
+ return failure(workflow, `job identifier exceeds the ${MAX_NIGHTLY_GUARD_JOB_ID_BYTES}-byte GitHub identifier limit or uses unsupported characters`);
69
+ }
70
+ const job = nightlyGuardObject(jobs[jobId]);
71
+ if (!job)
72
+ return walkJobs(index + 1, accumulated);
73
+ const inspection = inspectNightlyGuardJob(workflow, jobId, job);
74
+ if (inspection.failure)
75
+ return { failure: inspection.failure };
76
+ const own = inspection.caller
77
+ ? [callerFor(workflow, jobId, context, inspection.caller)]
78
+ : [];
79
+ if (!inspection.local)
80
+ return walkJobs(index + 1, [...accumulated, ...own]);
81
+ const child = byName.get(inspection.local);
82
+ if (!child) {
83
+ return failure(workflow, `${jobId}: local reusable ${inspection.local} is missing or unresolved`);
84
+ }
85
+ if (context.depth >= MAX_NIGHTLY_GUARD_LOCAL_DEPTH) {
86
+ return failure(workflow, `reachable local workflow depth exceeds ${MAX_NIGHTLY_GUARD_LOCAL_DEPTH}`);
87
+ }
88
+ const nested = walkWorkflow(child, byName, childContext(workflow, jobId, context));
89
+ return isFailure(nested)
90
+ ? nested
91
+ : walkJobs(index + 1, [...accumulated, ...own, ...nested.callers]);
92
+ };
93
+ return walkJobs(0, []);
94
+ };
95
+ /**
96
+ * Traverse each root independently so shared reusables retain every active
97
+ * root-to-job attribution while static target proof remains deduplicated.
98
+ * @param records - Parsed bounded workflow inventory
99
+ * @returns Deterministic active callers or the first graph refusal
100
+ */
101
+ export function traceNightlyGuardCallers(records) {
102
+ const byName = new Map(records.map(record => [record.name, record]));
103
+ const roots = records.filter(isRoot);
104
+ const walkRoots = (index, accumulated) => {
105
+ const root = roots[index];
106
+ if (root === undefined)
107
+ return validateBounds(records[0] ?? emptyRecord, accumulated);
108
+ const result = walkWorkflow(root, byName, {
109
+ depth: 0,
110
+ stack: [],
111
+ parents: [],
112
+ });
113
+ return isFailure(result)
114
+ ? result
115
+ : walkRoots(index + 1, [...accumulated, ...result.callers]);
116
+ };
117
+ const result = walkRoots(0, []);
118
+ if (isFailure(result)) {
119
+ return { state: "unavailable", failures: [result.failure] };
120
+ }
121
+ const callers = [...result.callers].sort((left, right) => left.callPath < right.callPath ? -1 : left.callPath > right.callPath ? 1 : 0);
122
+ return { state: "ok", callers };
123
+ }
124
+ /** Synthetic owner for bounds when an inventory contains no records. */
125
+ const emptyRecord = {
126
+ file: ".github/workflows",
127
+ name: "",
128
+ document: {},
129
+ };
130
+ //# sourceMappingURL=doctor-nightly-e2e-guard-graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-nightly-e2e-guard-graph.js","sourceRoot":"","sources":["../../src/cli/doctor-nightly-e2e-guard-graph.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import { type NightlyGuardDeadline } from "./doctor-nightly-e2e-guard-deadline.js";
2
+ /** Successful bytes or the precise availability class of a safe read. */
3
+ export type NightlyGuardReadResult = {
4
+ readonly state: "ok";
5
+ readonly bytes: Buffer;
6
+ } | {
7
+ readonly state: "missing";
8
+ readonly reason: string;
9
+ } | {
10
+ readonly state: "unavailable";
11
+ readonly reason: string;
12
+ };
13
+ /** Deterministic directory entries or an explicit availability refusal. */
14
+ export type NightlyGuardDirectoryResult = {
15
+ readonly state: "ok";
16
+ readonly names: readonly string[];
17
+ } | {
18
+ readonly state: "missing";
19
+ readonly reason: string;
20
+ } | {
21
+ readonly state: "unavailable";
22
+ readonly reason: string;
23
+ };
24
+ /**
25
+ * Read one regular file without following any path component.
26
+ * @param projectRoot - Containment root
27
+ * @param relativePath - Project-relative path
28
+ * @param maxBytes - Hard byte ceiling
29
+ * @param deadline - Shared deadline
30
+ * @returns Bounded bytes or a precise availability class
31
+ */
32
+ export declare function readNightlyGuardFile(projectRoot: string, relativePath: string, maxBytes: number, deadline: NightlyGuardDeadline): Promise<NightlyGuardReadResult>;
33
+ /**
34
+ * List a directory only when every component and its identity remain safe.
35
+ * @param projectRoot - Containment root
36
+ * @param relativePath - Project-relative directory
37
+ * @param deadline - Shared deadline
38
+ * @returns Directory entries or an availability refusal
39
+ */
40
+ export declare function readNightlyGuardDirectory(projectRoot: string, relativePath: string, deadline: NightlyGuardDeadline): Promise<NightlyGuardDirectoryResult>;
41
+ //# sourceMappingURL=doctor-nightly-e2e-guard-io.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-nightly-e2e-guard-io.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-nightly-e2e-guard-io.ts"],"names":[],"mappings":"AASA,OAAO,EAGL,KAAK,oBAAoB,EAE1B,MAAM,wCAAwC,CAAC;AAEhD,yEAAyE;AACzE,MAAM,MAAM,sBAAsB,GAC9B;IAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/D,2EAA2E;AAC3E,MAAM,MAAM,2BAA2B,GACnC;IAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAC3D;IAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAwM/D;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,oBAAoB,GAC7B,OAAO,CAAC,sBAAsB,CAAC,CA6DjC;AAED;;;;;;GAMG;AACH,wBAAsB,yBAAyB,CAC7C,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,oBAAoB,GAC7B,OAAO,CAAC,2BAA2B,CAAC,CA+BtC"}
@@ -0,0 +1,239 @@
1
+ /**
2
+ * @file doctor-nightly-e2e-guard-io.ts
3
+ * @description Bounded no-follow reads for hostile workflow and target paths
4
+ * @module cli/doctor-nightly-e2e-guard-io
5
+ */
6
+ import { constants } from "node:fs";
7
+ import { lstat, open, readdir, realpath } from "node:fs/promises";
8
+ import * as path from "node:path";
9
+ import { NightlyGuardDeadlineError, nightlyGuardRemaining, withinNightlyGuardDeadline, } from "./doctor-nightly-e2e-guard-deadline.js";
10
+ const errorCode = (error) => error.code;
11
+ const displayError = (error) => error instanceof Error ? error.message : String(error);
12
+ const rethrowDeadline = (error) => {
13
+ if (error instanceof NightlyGuardDeadlineError)
14
+ throw error;
15
+ };
16
+ const identity = (stats) => ({
17
+ device: stats.dev,
18
+ inode: stats.ino,
19
+ });
20
+ const sameIdentity = (left, right) => left.device === right.device && left.inode === right.inode;
21
+ const byteLimit = (bytes) => bytes === 1024 * 1024 ? "1 MiB" : `${bytes} byte`;
22
+ const safeParts = (relativePath) => {
23
+ if (path.isAbsolute(relativePath))
24
+ return undefined;
25
+ const parts = relativePath.split(/[\\/]/u);
26
+ return parts.length > 0 &&
27
+ parts.every(part => part !== "" && part !== "." && part !== "..")
28
+ ? parts
29
+ : undefined;
30
+ };
31
+ const unavailable = (reason) => ({
32
+ state: "unavailable",
33
+ reason,
34
+ });
35
+ /**
36
+ * Walk every project-relative component with lstat, rejecting symlinks before
37
+ * any directory or file operation can follow them.
38
+ * @param projectRoot - Logical project containment root
39
+ * @param relativePath - Validated relative path
40
+ * @param deadline - Shared whole-operation deadline
41
+ * @returns Final component identity or an exact refusal
42
+ */
43
+ async function inspectComponents(projectRoot, relativePath, deadline) {
44
+ const parts = safeParts(relativePath);
45
+ if (!parts)
46
+ return unavailable("path escapes the project root");
47
+ const inspect = async (index) => {
48
+ const current = path.join(projectRoot, ...parts.slice(0, index + 1));
49
+ if (nightlyGuardRemaining(deadline) <= 0) {
50
+ throw new NightlyGuardDeadlineError(deadline.reason);
51
+ }
52
+ const inspected = await withinNightlyGuardDeadline(deadline, () => lstat(current)).catch(error => {
53
+ rethrowDeadline(error);
54
+ const code = errorCode(error);
55
+ return code === "ENOENT"
56
+ ? { state: "missing", reason: `${relativePath} is missing` }
57
+ : unavailable(`${relativePath} is unreadable (${code ?? displayError(error)})`);
58
+ });
59
+ if ("state" in inspected)
60
+ return inspected;
61
+ const stats = inspected;
62
+ if (stats.isSymbolicLink()) {
63
+ return unavailable(`${parts.slice(0, index + 1).join("/")} is a symlink`);
64
+ }
65
+ if (index < parts.length - 1 && !stats.isDirectory()) {
66
+ return unavailable(`${parts.slice(0, index + 1).join("/")} is not a directory`);
67
+ }
68
+ return index === parts.length - 1
69
+ ? { state: "ok", final: stats }
70
+ : await inspect(index + 1);
71
+ };
72
+ return await inspect(0);
73
+ }
74
+ const isContained = (root, target) => {
75
+ const relative = path.relative(root, target);
76
+ return (relative !== "" &&
77
+ relative !== ".." &&
78
+ !relative.startsWith(`..${path.sep}`) &&
79
+ !path.isAbsolute(relative));
80
+ };
81
+ /**
82
+ * Verify the opened inode is still the contained, non-symlink path immediately
83
+ * before its bytes become proof evidence.
84
+ * @param projectRoot - Logical containment root
85
+ * @param relativePath - Path whose components are rechecked
86
+ * @param opened - Inode identity captured from the file descriptor
87
+ * @param deadline - Shared deadline
88
+ * @returns Reverified component result
89
+ */
90
+ async function verifyIdentity(projectRoot, relativePath, opened, deadline) {
91
+ const inspected = await inspectComponents(projectRoot, relativePath, deadline);
92
+ if (inspected.state !== "ok")
93
+ return inspected;
94
+ if (!sameIdentity(opened, identity(inspected.final))) {
95
+ return unavailable(`${relativePath} changed identity while it was read`);
96
+ }
97
+ try {
98
+ const [physicalRoot, physicalTarget] = await withinNightlyGuardDeadline(deadline, () => Promise.all([
99
+ realpath(projectRoot),
100
+ realpath(path.join(projectRoot, relativePath)),
101
+ ]));
102
+ return isContained(physicalRoot, physicalTarget)
103
+ ? inspected
104
+ : unavailable(`${relativePath} is not contained by the project root`);
105
+ }
106
+ catch (error) {
107
+ rethrowDeadline(error);
108
+ return unavailable(`${relativePath} containment is unreadable (${errorCode(error) ?? displayError(error)})`);
109
+ }
110
+ }
111
+ /**
112
+ * Read at most `maxBytes + 1` through an already no-follow file descriptor.
113
+ * @param handle - Open no-follow file descriptor
114
+ * @param maxBytes - Hard content ceiling
115
+ * @param deadline - Shared deadline
116
+ * @returns Bounded bytes, including one overflow sentinel byte when present
117
+ */
118
+ async function readBounded(handle, maxBytes, deadline) {
119
+ const buffer = Buffer.alloc(maxBytes + 1);
120
+ const readAt = async (offset) => {
121
+ if (offset >= buffer.length)
122
+ return offset;
123
+ if (nightlyGuardRemaining(deadline) <= 0) {
124
+ throw new NightlyGuardDeadlineError(deadline.reason);
125
+ }
126
+ const { bytesRead } = await withinNightlyGuardDeadline(deadline, () => handle.read(buffer, offset, buffer.length - offset, offset));
127
+ return bytesRead === 0 ? offset : await readAt(offset + bytesRead);
128
+ };
129
+ const used = await readAt(0);
130
+ return buffer.subarray(0, used);
131
+ }
132
+ const openNightlyGuardFile = async (projectRoot, relativePath, deadline) => await withinNightlyGuardDeadline(deadline, () => open(path.join(projectRoot, relativePath), constants.O_RDONLY | constants.O_NOFOLLOW)).then(handle => ({ state: "ok", handle }), error => {
133
+ rethrowDeadline(error);
134
+ const code = errorCode(error);
135
+ return code === "ENOENT"
136
+ ? { state: "missing", reason: `${relativePath} is missing` }
137
+ : {
138
+ state: "unavailable",
139
+ reason: `${relativePath} is unreadable (${code ?? displayError(error)})`,
140
+ };
141
+ });
142
+ /**
143
+ * Read one regular file without following any path component.
144
+ * @param projectRoot - Containment root
145
+ * @param relativePath - Project-relative path
146
+ * @param maxBytes - Hard byte ceiling
147
+ * @param deadline - Shared deadline
148
+ * @returns Bounded bytes or a precise availability class
149
+ */
150
+ export async function readNightlyGuardFile(projectRoot, relativePath, maxBytes, deadline) {
151
+ const inspected = await inspectComponents(projectRoot, relativePath, deadline);
152
+ if (inspected.state !== "ok")
153
+ return inspected;
154
+ if (!inspected.final.isFile()) {
155
+ return {
156
+ state: "unavailable",
157
+ reason: `${relativePath} is not a regular file`,
158
+ };
159
+ }
160
+ if (inspected.final.size > maxBytes) {
161
+ return {
162
+ state: "unavailable",
163
+ reason: `${relativePath} exceeds the ${byteLimit(maxBytes)} file limit`,
164
+ };
165
+ }
166
+ const opened = await openNightlyGuardFile(projectRoot, relativePath, deadline);
167
+ if (opened.state !== "ok")
168
+ return opened;
169
+ const handle = opened.handle;
170
+ try {
171
+ const stats = await withinNightlyGuardDeadline(deadline, () => handle.stat());
172
+ if (!stats.isFile()) {
173
+ return {
174
+ state: "unavailable",
175
+ reason: `${relativePath} is not a regular file`,
176
+ };
177
+ }
178
+ const bytes = await readBounded(handle, maxBytes, deadline);
179
+ if (bytes.length > maxBytes) {
180
+ return {
181
+ state: "unavailable",
182
+ reason: `${relativePath} exceeds the ${byteLimit(maxBytes)} file limit`,
183
+ };
184
+ }
185
+ const verified = await verifyIdentity(projectRoot, relativePath, identity(stats), deadline);
186
+ return verified.state === "ok" ? { state: "ok", bytes } : verified;
187
+ }
188
+ catch (error) {
189
+ rethrowDeadline(error);
190
+ return {
191
+ state: "unavailable",
192
+ reason: `${relativePath} is unreadable (${errorCode(error) ?? displayError(error)})`,
193
+ };
194
+ }
195
+ finally {
196
+ await handle.close();
197
+ }
198
+ }
199
+ /**
200
+ * List a directory only when every component and its identity remain safe.
201
+ * @param projectRoot - Containment root
202
+ * @param relativePath - Project-relative directory
203
+ * @param deadline - Shared deadline
204
+ * @returns Directory entries or an availability refusal
205
+ */
206
+ export async function readNightlyGuardDirectory(projectRoot, relativePath, deadline) {
207
+ const before = await inspectComponents(projectRoot, relativePath, deadline);
208
+ if (before.state !== "ok")
209
+ return before;
210
+ if (!before.final.isDirectory()) {
211
+ return {
212
+ state: "unavailable",
213
+ reason: `${relativePath} is not a directory`,
214
+ };
215
+ }
216
+ try {
217
+ const names = await withinNightlyGuardDeadline(deadline, () => readdir(path.join(projectRoot, relativePath)));
218
+ const after = await inspectComponents(projectRoot, relativePath, deadline);
219
+ if (after.state !== "ok")
220
+ return after;
221
+ return sameIdentity(identity(before.final), identity(after.final))
222
+ ? { state: "ok", names }
223
+ : {
224
+ state: "unavailable",
225
+ reason: `${relativePath} changed identity while it was listed`,
226
+ };
227
+ }
228
+ catch (error) {
229
+ rethrowDeadline(error);
230
+ const code = errorCode(error);
231
+ return code === "ENOENT"
232
+ ? { state: "missing", reason: `${relativePath} is missing` }
233
+ : {
234
+ state: "unavailable",
235
+ reason: `${relativePath} is unreadable (${code ?? displayError(error)})`,
236
+ };
237
+ }
238
+ }
239
+ //# sourceMappingURL=doctor-nightly-e2e-guard-io.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-nightly-e2e-guard-io.js","sourceRoot":"","sources":["../../src/cli/doctor-nightly-e2e-guard-io.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @file doctor-nightly-e2e-guard-job.ts
3
+ * @description Executable-field parsing for one reachable workflow job
4
+ * @module cli/doctor-nightly-e2e-guard-job
5
+ */
6
+ import { type NightlyGuardScanFailure, type NightlyGuardWorkflowRecord } from "./doctor-nightly-e2e-guard-contract.js";
7
+ /** Supported active target resolved from one job. */
8
+ export interface NightlyGuardJobCaller {
9
+ /** Direct Node invocation or Lisa's exact official reusable endpoint. */
10
+ readonly kind: "official-reusable" | "direct";
11
+ /** Literal normalized target path. */
12
+ readonly target: string;
13
+ }
14
+ /** Executable interpretation of one reachable job. */
15
+ export interface NightlyGuardJobInspection {
16
+ /** Guard caller when this job directly invokes one. */
17
+ readonly caller?: NightlyGuardJobCaller;
18
+ /** Local reusable basename when this job calls one. */
19
+ readonly local?: string;
20
+ /** Fail-closed ambiguity or unsupported syntax. */
21
+ readonly failure?: NightlyGuardScanFailure;
22
+ }
23
+ /**
24
+ * Interpret one reachable executable job without scanning prose or comments.
25
+ * @param workflow - Parsed workflow containing the job
26
+ * @param jobId - Stable job mapping key
27
+ * @param job - Parsed job mapping
28
+ * @returns Direct caller, local edge, or an explicit refusal
29
+ */
30
+ export declare function inspectNightlyGuardJob(workflow: NightlyGuardWorkflowRecord, jobId: string, job: Readonly<Record<string, unknown>>): NightlyGuardJobInspection;
31
+ //# sourceMappingURL=doctor-nightly-e2e-guard-job.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-nightly-e2e-guard-job.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-nightly-e2e-guard-job.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAEL,KAAK,uBAAuB,EAC5B,KAAK,0BAA0B,EAIhC,MAAM,wCAAwC,CAAC;AAchD,qDAAqD;AACrD,MAAM,WAAW,qBAAqB;IACpC,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,mBAAmB,GAAG,QAAQ,CAAC;IAC9C,sCAAsC;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,sDAAsD;AACtD,MAAM,WAAW,yBAAyB;IACxC,uDAAuD;IACvD,QAAQ,CAAC,MAAM,CAAC,EAAE,qBAAqB,CAAC;IACxC,uDAAuD;IACvD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,mDAAmD;IACnD,QAAQ,CAAC,OAAO,CAAC,EAAE,uBAAuB,CAAC;CAC5C;AA4MD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,0BAA0B,EACpC,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACrC,yBAAyB,CAmB3B"}