@codyswann/lisa 4.71.1 → 4.71.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/all/copy-overwrite/scripts/lib/history-secret-scanner.mjs +46 -37
- package/all/copy-overwrite/scripts/lib/npm-update-gate.mjs +52 -35
- package/all/copy-overwrite/scripts/lib/npm-update-hosted-gate.mjs +48 -26
- package/all/copy-overwrite/scripts/lib/npm-update-invariants.mjs +97 -0
- package/all/copy-overwrite/scripts/lib/npm-update-native-process.mjs +24 -6
- package/all/copy-overwrite/scripts/lisa-npm-updater.mjs +37 -16
- package/all/copy-overwrite/scripts/npm-updater-helper-graph.json +10 -6
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +28 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
- package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +11 -8
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/package.json +4 -4
- 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/rails/copy-overwrite/ast-grep/rules/ruby/no-unsafe-send.yml +17 -0
|
@@ -52,6 +52,18 @@ export const PINS = Object.freeze({
|
|
|
52
52
|
const digest = bytes => createHash("sha256").update(bytes).digest("hex");
|
|
53
53
|
const shellQuote = value => `'${value.replaceAll("'", "'\\''")}'`;
|
|
54
54
|
|
|
55
|
+
/** Keep vendor recreation private without changing the calling process's mask. */
|
|
56
|
+
export const scannerInvocation = (binary, argv) => ({
|
|
57
|
+
binary: "/bin/sh",
|
|
58
|
+
argv: [
|
|
59
|
+
"-c",
|
|
60
|
+
'umask 077 || exit 1; exec "$@"',
|
|
61
|
+
"lisa-private-scanner",
|
|
62
|
+
binary,
|
|
63
|
+
...argv,
|
|
64
|
+
],
|
|
65
|
+
});
|
|
66
|
+
|
|
55
67
|
/** Audit the actual vendor Git children: Gitleaks can swallow their failures. */
|
|
56
68
|
const auditedGit = scratch => {
|
|
57
69
|
const environment = gitEnvironment();
|
|
@@ -244,8 +256,8 @@ export const scanCommits = (commits, cwd, requested, heads = []) => {
|
|
|
244
256
|
const report = join(scratch, "report.json");
|
|
245
257
|
const ignore = join(scratch, "ignore");
|
|
246
258
|
writeFileSync(config, "[extend]\nuseDefault = true\n", { mode: 0o600 });
|
|
247
|
-
// Gitleaks
|
|
248
|
-
//
|
|
259
|
+
// Gitleaks removes and recreates this file; its dedicated child sets umask
|
|
260
|
+
// before vendor creation, while the caller's mask remains unchanged.
|
|
249
261
|
writeFileSync(report, "[]", { mode: 0o600 });
|
|
250
262
|
writeFileSync(ignore, "", { mode: 0o600 });
|
|
251
263
|
// An isolated bare view excludes caller ignore files even in Git metadata.
|
|
@@ -272,41 +284,38 @@ export const scanCommits = (commits, cwd, requested, heads = []) => {
|
|
|
272
284
|
for (let offset = 0; offset < commits.length; offset += 100) {
|
|
273
285
|
const group = commits.slice(offset, offset + 100);
|
|
274
286
|
audit.begin();
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
maxBuffer: 16 * 1024 * 1024,
|
|
308
|
-
}
|
|
309
|
-
);
|
|
287
|
+
const invocation = scannerInvocation(scanner, [
|
|
288
|
+
"git",
|
|
289
|
+
source,
|
|
290
|
+
"--config",
|
|
291
|
+
config,
|
|
292
|
+
"--gitleaks-ignore-path",
|
|
293
|
+
ignore,
|
|
294
|
+
"--ignore-gitleaks-allow",
|
|
295
|
+
"--redact=100",
|
|
296
|
+
"--no-banner",
|
|
297
|
+
"--no-color",
|
|
298
|
+
"--log-level",
|
|
299
|
+
"error",
|
|
300
|
+
"--platform",
|
|
301
|
+
"none",
|
|
302
|
+
"--exit-code",
|
|
303
|
+
"42",
|
|
304
|
+
"--timeout",
|
|
305
|
+
"120",
|
|
306
|
+
"--report-format",
|
|
307
|
+
"json",
|
|
308
|
+
"--report-path",
|
|
309
|
+
report,
|
|
310
|
+
"--log-opts",
|
|
311
|
+
`--no-walk=unsorted --root --diff-merges=separate --no-ext-diff --no-textconv --no-renames ${group.join(" ")}`,
|
|
312
|
+
]);
|
|
313
|
+
const result = spawnSync(invocation.binary, invocation.argv, {
|
|
314
|
+
cwd: scratch,
|
|
315
|
+
env: audit.environment,
|
|
316
|
+
timeout: 130000,
|
|
317
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
318
|
+
});
|
|
310
319
|
if (
|
|
311
320
|
result.error ||
|
|
312
321
|
result.signal ||
|
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
ordinaryGateReceipt,
|
|
43
43
|
} from "./npm-update-publication.mjs";
|
|
44
44
|
import { executeCanonicalHelper } from "./npm-update-controller-factory.mjs";
|
|
45
|
+
import { withStage } from "./npm-update-invariants.mjs";
|
|
45
46
|
|
|
46
47
|
const BOT = "github-actions[bot]";
|
|
47
48
|
const MAIL = "41898282+github-actions[bot]@users.noreply.github.com";
|
|
@@ -143,7 +144,7 @@ export async function descriptorFor({
|
|
|
143
144
|
async function stageProposal(context, env) {
|
|
144
145
|
const { cwd, proposal } = context;
|
|
145
146
|
const command = args => git(cwd, env, args, undefined, context.deadline);
|
|
146
|
-
await baseline(cwd, env, proposal);
|
|
147
|
+
await withStage("gate-baseline", () => baseline(cwd, env, proposal));
|
|
147
148
|
const parent = (await command(["rev-parse", "HEAD"])).stdout
|
|
148
149
|
.toString()
|
|
149
150
|
.trim();
|
|
@@ -154,8 +155,12 @@ async function stageProposal(context, env) {
|
|
|
154
155
|
);
|
|
155
156
|
const branch = `lisa/npm-${proposal.key}`;
|
|
156
157
|
await command(["checkout", "-b", branch]);
|
|
157
|
-
await
|
|
158
|
-
|
|
158
|
+
await withStage("gate-link", () =>
|
|
159
|
+
executeCanonicalHelper(context, "stage-read", "link")
|
|
160
|
+
);
|
|
161
|
+
await withStage("gate-attach", () =>
|
|
162
|
+
executeCanonicalHelper(context, "stage-read", "attach-branch")
|
|
163
|
+
);
|
|
159
164
|
for (const file of FILES)
|
|
160
165
|
writeFileSync(join(cwd, file), proposal.files[file]);
|
|
161
166
|
await command(["add", "--", ...FILES]);
|
|
@@ -263,38 +268,50 @@ async function pushProposal(context, env, branch, object) {
|
|
|
263
268
|
export async function gateProposal(context) {
|
|
264
269
|
const scoped = { ...context, deadline: Date.now() + 1_800_000 };
|
|
265
270
|
const { proposal, policy, token, preview } = context;
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
return withPrivateRoot(async root => {
|
|
274
|
-
const env = {
|
|
275
|
-
...candidateEnvironment(root),
|
|
276
|
-
GIT_AUTHOR_NAME: BOT,
|
|
277
|
-
GIT_AUTHOR_EMAIL: MAIL,
|
|
278
|
-
GIT_COMMITTER_NAME: BOT,
|
|
279
|
-
GIT_COMMITTER_EMAIL: MAIL,
|
|
280
|
-
GIT_AUTHOR_DATE: `${preview.epoch} +0000`,
|
|
281
|
-
GIT_COMMITTER_DATE: `${preview.epoch} +0000`,
|
|
282
|
-
};
|
|
283
|
-
const branch = await stageProposal(scoped, env);
|
|
284
|
-
const message = await installGateProof(context, root, args =>
|
|
285
|
-
git(context.cwd, env, args, undefined, scoped.deadline)
|
|
271
|
+
await withStage("gate-validate", () => {
|
|
272
|
+
validateProposal(proposal, policy);
|
|
273
|
+
assertHostedGate(context);
|
|
274
|
+
validateGateProof(context);
|
|
275
|
+
required(
|
|
276
|
+
typeof token === "string" && token.length > 0,
|
|
277
|
+
"readonly gate token is absent"
|
|
286
278
|
);
|
|
287
|
-
const hosted = await createHostedGate(scoped, root, env);
|
|
288
|
-
try {
|
|
289
|
-
const gated = { ...scoped, hookInstallation: hosted.installation };
|
|
290
|
-
const object = await committedProposal(
|
|
291
|
-
gated,
|
|
292
|
-
{ ...hosted.env, LISA_NPM_HOOK_ROLE: "commit" },
|
|
293
|
-
message
|
|
294
|
-
);
|
|
295
|
-
return await pushProposal(gated, hosted.env, branch, object);
|
|
296
|
-
} finally {
|
|
297
|
-
await hosted.close();
|
|
298
|
-
}
|
|
299
279
|
});
|
|
280
|
+
return withStage("gate-scratch", () =>
|
|
281
|
+
withPrivateRoot(async root => {
|
|
282
|
+
const env = {
|
|
283
|
+
...candidateEnvironment(root),
|
|
284
|
+
GIT_AUTHOR_NAME: BOT,
|
|
285
|
+
GIT_AUTHOR_EMAIL: MAIL,
|
|
286
|
+
GIT_COMMITTER_NAME: BOT,
|
|
287
|
+
GIT_COMMITTER_EMAIL: MAIL,
|
|
288
|
+
GIT_AUTHOR_DATE: `${preview.epoch} +0000`,
|
|
289
|
+
GIT_COMMITTER_DATE: `${preview.epoch} +0000`,
|
|
290
|
+
};
|
|
291
|
+
const branch = await withStage("gate-stage", () =>
|
|
292
|
+
stageProposal(scoped, env)
|
|
293
|
+
);
|
|
294
|
+
const proofGit = args =>
|
|
295
|
+
git(context.cwd, env, args, undefined, scoped.deadline);
|
|
296
|
+
const message = await withStage("gate-proof", () =>
|
|
297
|
+
installGateProof(context, root, proofGit)
|
|
298
|
+
);
|
|
299
|
+
const hosted = await createHostedGate(scoped, root, env);
|
|
300
|
+
try {
|
|
301
|
+
const gated = { ...scoped, hookInstallation: hosted.installation };
|
|
302
|
+
const object = await withStage("gate-commit", () =>
|
|
303
|
+
committedProposal(
|
|
304
|
+
gated,
|
|
305
|
+
{ ...hosted.env, LISA_NPM_HOOK_ROLE: "commit" },
|
|
306
|
+
message
|
|
307
|
+
)
|
|
308
|
+
);
|
|
309
|
+
return await withStage("gate-push", () =>
|
|
310
|
+
pushProposal(gated, hosted.env, branch, object)
|
|
311
|
+
);
|
|
312
|
+
} finally {
|
|
313
|
+
await withStage("gate-close", () => hosted.close());
|
|
314
|
+
}
|
|
315
|
+
})
|
|
316
|
+
);
|
|
300
317
|
}
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
} from "./npm-update-controller-factory.mjs";
|
|
22
22
|
import { startHookReadBroker } from "./npm-update-hook-provider.mjs";
|
|
23
23
|
import { originalHookInstallation } from "./npm-update-hook-installation.mjs";
|
|
24
|
+
import { withStage } from "./npm-update-invariants.mjs";
|
|
24
25
|
import {
|
|
25
26
|
sha256,
|
|
26
27
|
PROPOSAL_PREDICATE,
|
|
@@ -234,22 +235,9 @@ function nodeGateway(root, context) {
|
|
|
234
235
|
return bin;
|
|
235
236
|
}
|
|
236
237
|
|
|
237
|
-
/**
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const native = controllerTools(context.config.automationProvenance);
|
|
241
|
-
const graph = await qualifiedControllerGraph(context.cwd, context.config, [
|
|
242
|
-
"lisa-work-item.mjs",
|
|
243
|
-
"lisa-automation-provenance.mjs",
|
|
244
|
-
"lisa-rails-prepush.mjs",
|
|
245
|
-
"lib/npm-update-hosted-hook.mjs",
|
|
246
|
-
"lib/npm-update-hook-preload.mjs",
|
|
247
|
-
]);
|
|
248
|
-
const installed = await installHostedDependencies(context, root, env);
|
|
249
|
-
const installation = await installOriginalManager(context, installed);
|
|
250
|
-
const scope = await proofScope(context, installed);
|
|
251
|
-
mkdirSync(join(root, "gh-config"), { mode: 0o700 });
|
|
252
|
-
const profile = {
|
|
238
|
+
/** The unchanged read-only subject is constructed separately so diagnostic wrapping stays within function budgets. */
|
|
239
|
+
function hookProfile(context, root, native, scope) {
|
|
240
|
+
return {
|
|
253
241
|
version: 1,
|
|
254
242
|
deadline: context.deadline,
|
|
255
243
|
cwd: context.cwd,
|
|
@@ -267,16 +255,50 @@ export async function createHostedGate(context, root, env) {
|
|
|
267
255
|
scope.proofs
|
|
268
256
|
),
|
|
269
257
|
};
|
|
270
|
-
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** A separate read-only capability is available during original gates; it cannot acquire publisher/issuer permissions. */
|
|
261
|
+
export async function createHostedGate(context, root, env) {
|
|
262
|
+
await withStage("gate-validate", () => assertHostedGate(context));
|
|
263
|
+
const native = await withStage("gate-tools", () =>
|
|
264
|
+
controllerTools(context.config.automationProvenance)
|
|
265
|
+
);
|
|
266
|
+
const graph = await withStage("gate-graph", () =>
|
|
267
|
+
qualifiedControllerGraph(context.cwd, context.config, [
|
|
268
|
+
"lisa-work-item.mjs",
|
|
269
|
+
"lisa-automation-provenance.mjs",
|
|
270
|
+
"lisa-rails-prepush.mjs",
|
|
271
|
+
"lib/npm-update-hosted-hook.mjs",
|
|
272
|
+
"lib/npm-update-hook-preload.mjs",
|
|
273
|
+
])
|
|
274
|
+
);
|
|
275
|
+
const installed = await withStage("gate-install", () =>
|
|
276
|
+
installHostedDependencies(context, root, env)
|
|
277
|
+
);
|
|
278
|
+
const installation = await withStage("gate-hooks", () =>
|
|
279
|
+
installOriginalManager(context, installed)
|
|
280
|
+
);
|
|
281
|
+
const scope = await withStage("gate-scope", () =>
|
|
282
|
+
proofScope(context, installed)
|
|
283
|
+
);
|
|
284
|
+
const profile = await withStage("gate-scope", () => {
|
|
285
|
+
mkdirSync(join(root, "gh-config"), { mode: 0o700 });
|
|
286
|
+
return hookProfile(context, root, native, scope);
|
|
287
|
+
});
|
|
288
|
+
const broker = await withStage("gate-broker", () =>
|
|
289
|
+
startHookReadBroker(profile, context.token)
|
|
290
|
+
);
|
|
271
291
|
try {
|
|
272
|
-
const bin =
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
292
|
+
const bin = await withStage("gate-gateway", () =>
|
|
293
|
+
nodeGateway(root, {
|
|
294
|
+
version: 1,
|
|
295
|
+
root,
|
|
296
|
+
cwd: context.cwd,
|
|
297
|
+
graph,
|
|
298
|
+
native,
|
|
299
|
+
reader: { root, path: broker.path, deadline: context.deadline },
|
|
300
|
+
})
|
|
301
|
+
);
|
|
280
302
|
return {
|
|
281
303
|
installation,
|
|
282
304
|
env: {
|
|
@@ -294,7 +316,7 @@ export async function createHostedGate(context, root, env) {
|
|
|
294
316
|
close: broker.close,
|
|
295
317
|
};
|
|
296
318
|
} catch (error) {
|
|
297
|
-
await broker.close();
|
|
319
|
+
await withStage("gate-close", () => broker.close());
|
|
298
320
|
throw error;
|
|
299
321
|
}
|
|
300
322
|
}
|
|
@@ -2,6 +2,103 @@
|
|
|
2
2
|
// Do not edit directly — durable changes belong upstream in Lisa.
|
|
3
3
|
|
|
4
4
|
/** Pure shared diagnostics retain one error identity without importing producer orchestration. */
|
|
5
|
+
const stages = new Set([
|
|
6
|
+
"configuration",
|
|
7
|
+
"gate-input",
|
|
8
|
+
"gate-validate",
|
|
9
|
+
"gate-scratch",
|
|
10
|
+
"gate-stage",
|
|
11
|
+
"gate-baseline",
|
|
12
|
+
"gate-link",
|
|
13
|
+
"gate-attach",
|
|
14
|
+
"gate-proof",
|
|
15
|
+
"gate-tools",
|
|
16
|
+
"gate-graph",
|
|
17
|
+
"gate-install",
|
|
18
|
+
"gate-hooks",
|
|
19
|
+
"gate-scope",
|
|
20
|
+
"gate-broker",
|
|
21
|
+
"gate-gateway",
|
|
22
|
+
"gate-commit",
|
|
23
|
+
"gate-push",
|
|
24
|
+
"gate-close",
|
|
25
|
+
"gate-output",
|
|
26
|
+
]);
|
|
27
|
+
const diagnostics = new WeakMap();
|
|
28
|
+
const signals = new Set([
|
|
29
|
+
"SIGTERM",
|
|
30
|
+
"SIGINT",
|
|
31
|
+
"SIGKILL",
|
|
32
|
+
"SIGHUP",
|
|
33
|
+
"SIGQUIT",
|
|
34
|
+
"SIGABRT",
|
|
35
|
+
"SIGPIPE",
|
|
36
|
+
"SIGSEGV",
|
|
37
|
+
"SIGBUS",
|
|
38
|
+
"SIGILL",
|
|
39
|
+
"SIGTRAP",
|
|
40
|
+
"SIGFPE",
|
|
41
|
+
]);
|
|
42
|
+
const errnos = new Set([
|
|
43
|
+
"EACCES",
|
|
44
|
+
"ENOENT",
|
|
45
|
+
"ENOEXEC",
|
|
46
|
+
"EMFILE",
|
|
47
|
+
"ENFILE",
|
|
48
|
+
"EAGAIN",
|
|
49
|
+
"EIO",
|
|
50
|
+
"EPIPE",
|
|
51
|
+
]);
|
|
52
|
+
const categories = new Set([
|
|
53
|
+
"exit",
|
|
54
|
+
"signal",
|
|
55
|
+
"cancelled",
|
|
56
|
+
"deadline",
|
|
57
|
+
"output-bound",
|
|
58
|
+
"input-failed",
|
|
59
|
+
"spawn-error",
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
/** Nested stages preserve the innermost observed boundary and the exact original thrown value. */
|
|
63
|
+
export async function withStage(stage, operation) {
|
|
64
|
+
required(stages.has(stage), "invalid updater diagnostic stage");
|
|
65
|
+
try {
|
|
66
|
+
return await operation();
|
|
67
|
+
} catch (error) {
|
|
68
|
+
if (
|
|
69
|
+
error !== null &&
|
|
70
|
+
(typeof error === "object" || typeof error === "function")
|
|
71
|
+
) {
|
|
72
|
+
const prior = diagnostics.get(error) ?? {};
|
|
73
|
+
diagnostics.set(error, { ...prior, stage: prior.stage ?? stage });
|
|
74
|
+
}
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Only native capture registers observed close facts; exception properties never establish provenance. */
|
|
80
|
+
export function recordNativeFailure(error, category, status, signal, errno) {
|
|
81
|
+
diagnostics.set(error, {
|
|
82
|
+
...diagnostics.get(error),
|
|
83
|
+
native: categories.has(category) ? category : "unknown",
|
|
84
|
+
status:
|
|
85
|
+
Number.isInteger(status) && status >= 0 && status <= 255 ? status : null,
|
|
86
|
+
signal: signals.has(signal) ? signal : null,
|
|
87
|
+
errno: errnos.has(errno) ? errno : null,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Never inspect arbitrary messages, stacks, getters, commands, paths or captured child output. */
|
|
92
|
+
export function publicFailure(error) {
|
|
93
|
+
const facts = diagnostics.get(error);
|
|
94
|
+
const parts = [`stage=${facts?.stage ?? "unknown"}`];
|
|
95
|
+
if (facts?.native) {
|
|
96
|
+
parts.push(`native=${facts.native}`, `status=${facts.status ?? "null"}`);
|
|
97
|
+
if (facts.signal) parts.push(`signal=${facts.signal}`);
|
|
98
|
+
if (facts.errno) parts.push(`errno=${facts.errno}`);
|
|
99
|
+
}
|
|
100
|
+
return `npm updater failed: required policy, authorization, installation, gate or exact publication evidence was unavailable (${parts.join(" ")})`;
|
|
101
|
+
}
|
|
5
102
|
|
|
6
103
|
/** Only trusted static boundary reasons may leave a phase as a public diagnostic. */
|
|
7
104
|
export class UpdaterError extends Error {
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
import { required } from "./npm-update-contract.mjs";
|
|
8
|
+
import { recordNativeFailure } from "./npm-update-invariants.mjs";
|
|
8
9
|
|
|
9
10
|
/** The complete supervisor vector, including its control overhead, is bounded literal data. */
|
|
10
11
|
function supervisedArguments(vector) {
|
|
@@ -104,27 +105,37 @@ function captureProcess(
|
|
|
104
105
|
const errors = [];
|
|
105
106
|
let size = 0;
|
|
106
107
|
let failure;
|
|
108
|
+
let category;
|
|
109
|
+
let errno;
|
|
107
110
|
let closed = false;
|
|
108
|
-
const stop = reason => {
|
|
109
|
-
|
|
111
|
+
const stop = (reason, kind) => {
|
|
112
|
+
if (!failure) {
|
|
113
|
+
failure = new Error(`npm updater: ${reason}`);
|
|
114
|
+
category = kind;
|
|
115
|
+
}
|
|
110
116
|
if (!closed && child.pid) child.kill("SIGTERM");
|
|
111
117
|
};
|
|
112
|
-
const abort = () => stop("child was cancelled");
|
|
118
|
+
const abort = () => stop("child was cancelled", "cancelled");
|
|
113
119
|
abortSignal?.addEventListener("abort", abort, { once: true });
|
|
114
120
|
if (abortSignal?.aborted) abort();
|
|
115
|
-
const timer = setTimeout(
|
|
121
|
+
const timer = setTimeout(
|
|
122
|
+
() => stop("child exceeded deadline", "deadline"),
|
|
123
|
+
timeout
|
|
124
|
+
);
|
|
116
125
|
const collect = target => data => {
|
|
117
126
|
size += data.length;
|
|
118
|
-
if (size > maximum) stop("child output exceeded bound");
|
|
127
|
+
if (size > maximum) stop("child output exceeded bound", "output-bound");
|
|
119
128
|
else target.push(data);
|
|
120
129
|
};
|
|
121
130
|
child.stdout.on("data", collect(chunks));
|
|
122
131
|
child.stderr.on("data", collect(errors));
|
|
123
132
|
child.on("error", error => {
|
|
124
133
|
failure = error;
|
|
134
|
+
category = "spawn-error";
|
|
135
|
+
errno = error.code;
|
|
125
136
|
});
|
|
126
137
|
child.stdin.on("error", error => {
|
|
127
|
-
if (error.code !== "EPIPE") stop("child input failed");
|
|
138
|
+
if (error.code !== "EPIPE") stop("child input failed", "input-failed");
|
|
128
139
|
});
|
|
129
140
|
child.stdin.end(input);
|
|
130
141
|
child.on("close", (code, signal) => {
|
|
@@ -134,6 +145,13 @@ function captureProcess(
|
|
|
134
145
|
if (failure || signal || !allowed.includes(code)) {
|
|
135
146
|
const error =
|
|
136
147
|
failure ?? new Error(`npm updater: child failed (${code ?? signal})`);
|
|
148
|
+
recordNativeFailure(
|
|
149
|
+
error,
|
|
150
|
+
category ?? (signal ? "signal" : "exit"),
|
|
151
|
+
code,
|
|
152
|
+
signal,
|
|
153
|
+
errno
|
|
154
|
+
);
|
|
137
155
|
reject(
|
|
138
156
|
Object.assign(error, {
|
|
139
157
|
stdout: Buffer.concat(chunks),
|
|
@@ -11,11 +11,11 @@ import { join, resolve } from "node:path";
|
|
|
11
11
|
import { invokedAsScript } from "./lib/invoked-as-script.mjs";
|
|
12
12
|
import {
|
|
13
13
|
required,
|
|
14
|
-
UpdaterError,
|
|
15
14
|
keys,
|
|
16
15
|
validatePolicy,
|
|
17
16
|
validateProposal,
|
|
18
17
|
} from "./lib/npm-update-contract.mjs";
|
|
18
|
+
import { publicFailure, withStage } from "./lib/npm-update-invariants.mjs";
|
|
19
19
|
import {
|
|
20
20
|
readJson,
|
|
21
21
|
writeJson,
|
|
@@ -119,6 +119,32 @@ async function publishPhase(
|
|
|
119
119
|
process.stdout.write(`${result.status} ${result.url}\n`);
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
/** Gate input/output classification preserves the original orchestration and authority order. */
|
|
123
|
+
async function gatePhase(
|
|
124
|
+
cwd,
|
|
125
|
+
output,
|
|
126
|
+
proposal,
|
|
127
|
+
policy,
|
|
128
|
+
config,
|
|
129
|
+
allocation,
|
|
130
|
+
preview
|
|
131
|
+
) {
|
|
132
|
+
const result = await gateProposal({
|
|
133
|
+
cwd,
|
|
134
|
+
proposal,
|
|
135
|
+
policy,
|
|
136
|
+
allocation,
|
|
137
|
+
preview,
|
|
138
|
+
...(await withStage("gate-input", () => readGateProof(output))),
|
|
139
|
+
token: process.env.GH_TOKEN,
|
|
140
|
+
config,
|
|
141
|
+
});
|
|
142
|
+
await withStage("gate-output", () =>
|
|
143
|
+
writeJson(join(output, "gated.json"), result)
|
|
144
|
+
);
|
|
145
|
+
process.stdout.write(`gated ${result.receipt.commit}\n`);
|
|
146
|
+
}
|
|
147
|
+
|
|
122
148
|
/** Strict phase and fixed directory arguments are data, never a caller recipe. */
|
|
123
149
|
export async function main(argv = process.argv.slice(2)) {
|
|
124
150
|
required(
|
|
@@ -131,7 +157,9 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
131
157
|
const [phase, checkout, directory] = argv;
|
|
132
158
|
const cwd = resolve(checkout);
|
|
133
159
|
const output = resolve(directory);
|
|
134
|
-
const { config, policy } = await configuration(
|
|
160
|
+
const { config, policy } = await withStage("configuration", () =>
|
|
161
|
+
configuration(cwd)
|
|
162
|
+
);
|
|
135
163
|
phaseDirectory(output);
|
|
136
164
|
if (phase === "prepare") {
|
|
137
165
|
const result = await prepareUpdate({ cwd, policy, config });
|
|
@@ -168,21 +196,16 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
168
196
|
process.stdout.write(`${result.mode} checkpoint complete\n`);
|
|
169
197
|
return;
|
|
170
198
|
}
|
|
171
|
-
if (phase === "gate")
|
|
172
|
-
|
|
199
|
+
if (phase === "gate")
|
|
200
|
+
return gatePhase(
|
|
173
201
|
cwd,
|
|
202
|
+
output,
|
|
174
203
|
proposal,
|
|
175
204
|
policy,
|
|
176
|
-
allocation,
|
|
177
|
-
preview,
|
|
178
|
-
...readGateProof(output),
|
|
179
|
-
token: process.env.GH_TOKEN,
|
|
180
205
|
config,
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
206
|
+
allocation,
|
|
207
|
+
preview
|
|
208
|
+
);
|
|
186
209
|
return publishPhase(
|
|
187
210
|
cwd,
|
|
188
211
|
output,
|
|
@@ -197,8 +220,6 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
197
220
|
if (invokedAsScript(import.meta.url))
|
|
198
221
|
main().catch(error => {
|
|
199
222
|
// Never print candidate/provider payloads or child output that may contain credentials.
|
|
200
|
-
process.stderr.write(
|
|
201
|
-
`${error instanceof UpdaterError ? error.message : "npm updater failed: required policy, authorization, installation, gate or exact publication evidence was unavailable"}\n`
|
|
202
|
-
);
|
|
223
|
+
process.stderr.write(`${publicFailure(error)}\n`);
|
|
203
224
|
process.exitCode = 1;
|
|
204
225
|
});
|
|
@@ -142,7 +142,7 @@
|
|
|
142
142
|
"children": []
|
|
143
143
|
},
|
|
144
144
|
"lib/history-secret-scanner.mjs": {
|
|
145
|
-
"sha256": "
|
|
145
|
+
"sha256": "07b639188c44ed5db817fc47bcdedfdd58e700024af19d464d78497b1ee236b3",
|
|
146
146
|
"staticImports": [
|
|
147
147
|
"lib/history-secret-evidence.mjs",
|
|
148
148
|
"lib/history-secret-git.mjs",
|
|
@@ -353,7 +353,7 @@
|
|
|
353
353
|
"children": []
|
|
354
354
|
},
|
|
355
355
|
"lib/npm-update-gate.mjs": {
|
|
356
|
-
"sha256": "
|
|
356
|
+
"sha256": "bb6b6b8ea1e3620ee0b1b620e50331788bc99b44f431057e12a60cd138e56bc4",
|
|
357
357
|
"staticImports": [
|
|
358
358
|
"lib/github-attestation-verifier.mjs",
|
|
359
359
|
"lib/npm-update-contract.mjs",
|
|
@@ -362,6 +362,7 @@
|
|
|
362
362
|
"lib/npm-update-gate-proof.mjs",
|
|
363
363
|
"lib/npm-update-github.mjs",
|
|
364
364
|
"lib/npm-update-hosted-gate.mjs",
|
|
365
|
+
"lib/npm-update-invariants.mjs",
|
|
365
366
|
"lib/npm-update-prepare.mjs",
|
|
366
367
|
"lib/npm-update-process.mjs",
|
|
367
368
|
"lib/npm-update-publication.mjs",
|
|
@@ -499,7 +500,7 @@
|
|
|
499
500
|
"children": []
|
|
500
501
|
},
|
|
501
502
|
"lib/npm-update-hosted-gate.mjs": {
|
|
502
|
-
"sha256": "
|
|
503
|
+
"sha256": "b6adf8af72067f883c83e11b7465a3f4c219a6e78d98b029b1af489967ccbaa8",
|
|
503
504
|
"staticImports": [
|
|
504
505
|
"lib/github-attestation-verifier.mjs",
|
|
505
506
|
"lib/npm-update-contract.mjs",
|
|
@@ -507,6 +508,7 @@
|
|
|
507
508
|
"lib/npm-update-helper.mjs",
|
|
508
509
|
"lib/npm-update-hook-installation.mjs",
|
|
509
510
|
"lib/npm-update-hook-provider.mjs",
|
|
511
|
+
"lib/npm-update-invariants.mjs",
|
|
510
512
|
"lib/npm-update-process.mjs",
|
|
511
513
|
"node:fs",
|
|
512
514
|
"node:path",
|
|
@@ -534,7 +536,7 @@
|
|
|
534
536
|
]
|
|
535
537
|
},
|
|
536
538
|
"lib/npm-update-invariants.mjs": {
|
|
537
|
-
"sha256": "
|
|
539
|
+
"sha256": "e7a093ceeaca34b6e0cf2ea2eccd3b5e1882e295ec2baeeaec9da0373e669687",
|
|
538
540
|
"staticImports": [],
|
|
539
541
|
"dynamicImports": [],
|
|
540
542
|
"children": []
|
|
@@ -573,9 +575,10 @@
|
|
|
573
575
|
"children": []
|
|
574
576
|
},
|
|
575
577
|
"lib/npm-update-native-process.mjs": {
|
|
576
|
-
"sha256": "
|
|
578
|
+
"sha256": "295d69d90f32aad9d757060ea6d3f66787a00e24c19e01e5beaf2ba752fec8da",
|
|
577
579
|
"staticImports": [
|
|
578
580
|
"lib/npm-update-contract.mjs",
|
|
581
|
+
"lib/npm-update-invariants.mjs",
|
|
579
582
|
"node:child_process",
|
|
580
583
|
"node:url"
|
|
581
584
|
],
|
|
@@ -950,7 +953,7 @@
|
|
|
950
953
|
"children": []
|
|
951
954
|
},
|
|
952
955
|
"lisa-npm-updater.mjs": {
|
|
953
|
-
"sha256": "
|
|
956
|
+
"sha256": "0bfa51b90df7ef2e076d35312ece4b6b550e586f2f343a85d94e7dca52156809",
|
|
954
957
|
"staticImports": [
|
|
955
958
|
"lib/github-attestation-verifier.mjs",
|
|
956
959
|
"lib/invoked-as-script.mjs",
|
|
@@ -960,6 +963,7 @@
|
|
|
960
963
|
"lib/npm-update-gate-proof.mjs",
|
|
961
964
|
"lib/npm-update-gate.mjs",
|
|
962
965
|
"lib/npm-update-github.mjs",
|
|
966
|
+
"lib/npm-update-invariants.mjs",
|
|
963
967
|
"lib/npm-update-prepare.mjs",
|
|
964
968
|
"lib/npm-update-process.mjs",
|
|
965
969
|
"lib/npm-update-publish.mjs",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lisa-owned-hash-ledger.d.ts","sourceRoot":"","sources":["../../src/core/lisa-owned-hash-ledger.ts"],"names":[],"mappings":"AACA,6EAA6E;AAE7E;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAC3C,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"lisa-owned-hash-ledger.d.ts","sourceRoot":"","sources":["../../src/core/lisa-owned-hash-ledger.ts"],"names":[],"mappings":"AACA,6EAA6E;AAE7E;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAC3C,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAgwDjC,CAAC;AAEH;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,+BAA+B,EAAE,QAAQ,CACpD,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAmqDjC,CAAC"}
|