@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.
- package/dist/cli/doctor-nightly-e2e-guard-command-files.d.ts +19 -0
- package/dist/cli/doctor-nightly-e2e-guard-command-files.d.ts.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-command-files.js +221 -0
- package/dist/cli/doctor-nightly-e2e-guard-command-files.js.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-contract.d.ts +113 -0
- package/dist/cli/doctor-nightly-e2e-guard-contract.d.ts.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-contract.js +87 -0
- package/dist/cli/doctor-nightly-e2e-guard-contract.js.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-deadline.d.ts +61 -0
- package/dist/cli/doctor-nightly-e2e-guard-deadline.d.ts.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-deadline.js +97 -0
- package/dist/cli/doctor-nightly-e2e-guard-deadline.js.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-evidence.d.ts +52 -0
- package/dist/cli/doctor-nightly-e2e-guard-evidence.d.ts.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-evidence.js +68 -0
- package/dist/cli/doctor-nightly-e2e-guard-evidence.js.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-graph.d.ts +14 -0
- package/dist/cli/doctor-nightly-e2e-guard-graph.d.ts.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-graph.js +130 -0
- package/dist/cli/doctor-nightly-e2e-guard-graph.js.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-io.d.ts +41 -0
- package/dist/cli/doctor-nightly-e2e-guard-io.d.ts.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-io.js +239 -0
- package/dist/cli/doctor-nightly-e2e-guard-io.js.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-job.d.ts +31 -0
- package/dist/cli/doctor-nightly-e2e-guard-job.d.ts.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-job.js +156 -0
- package/dist/cli/doctor-nightly-e2e-guard-job.js.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-proof.d.ts +42 -0
- package/dist/cli/doctor-nightly-e2e-guard-proof.d.ts.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-proof.js +57 -0
- package/dist/cli/doctor-nightly-e2e-guard-proof.js.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-remediation.d.ts +32 -0
- package/dist/cli/doctor-nightly-e2e-guard-remediation.d.ts.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-remediation.js +55 -0
- package/dist/cli/doctor-nightly-e2e-guard-remediation.js.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-runtime.d.ts +34 -0
- package/dist/cli/doctor-nightly-e2e-guard-runtime.d.ts.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-runtime.js +93 -0
- package/dist/cli/doctor-nightly-e2e-guard-runtime.js.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-scan.d.ts +17 -0
- package/dist/cli/doctor-nightly-e2e-guard-scan.d.ts.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-scan.js +86 -0
- package/dist/cli/doctor-nightly-e2e-guard-scan.js.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-shell-lexer.d.ts +38 -0
- package/dist/cli/doctor-nightly-e2e-guard-shell-lexer.d.ts.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-shell-lexer.js +160 -0
- package/dist/cli/doctor-nightly-e2e-guard-shell-lexer.js.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-shell.d.ts +40 -0
- package/dist/cli/doctor-nightly-e2e-guard-shell.d.ts.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard-shell.js +201 -0
- package/dist/cli/doctor-nightly-e2e-guard-shell.js.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard.d.ts +36 -0
- package/dist/cli/doctor-nightly-e2e-guard.d.ts.map +1 -0
- package/dist/cli/doctor-nightly-e2e-guard.js +186 -0
- package/dist/cli/doctor-nightly-e2e-guard.js.map +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +7 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/core/nightly-e2e-guard-behavior-certificate.d.ts +25 -0
- package/dist/core/nightly-e2e-guard-behavior-certificate.d.ts.map +1 -0
- package/dist/core/nightly-e2e-guard-behavior-certificate.js +30 -0
- package/dist/core/nightly-e2e-guard-behavior-certificate.js.map +1 -0
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +29 -2
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/package.json +5 -3
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/scripts/check-derived-artifacts.mjs +32 -5
- package/scripts/generate-nightly-e2e-guard-certificate.mjs +370 -0
- 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"}
|