@deeeed/metamask-harness 0.79.0 → 0.81.0
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/CHANGELOG.md +73 -0
- package/README.md +1 -1
- package/adapters/extension/ensure-browser.sh +2 -2
- package/adapters/extension/inject.mjs +0 -1
- package/adapters/extension/launch-browser.cjs +39 -613
- package/adapters/extension/readiness.mjs +2 -5
- package/adapters/extension/reattach.sh +2 -2
- package/adapters/extension/stamp-runtime-title.cjs +1 -1
- package/adapters/manifest.json +16 -64
- package/adapters/mobile/bridge-runtime/cdp-bridge.cjs +57 -1358
- package/adapters/mobile/bridge-runtime/teaching.cjs +20 -0
- package/adapters/mobile/inject.sh +16 -0
- package/adapters/mobile/launch-console-forwarder.cjs +1 -2
- package/adapters/mobile/open-device.sh +2 -2
- package/adapters/mobile/reload-app.mjs +4 -4
- package/adapters/mobile/reset-app-data.sh +1 -1
- package/adapters/mobile/start-console-forwarder.sh +3 -2
- package/adapters/mobile/start-metro.sh +17 -12
- package/adapters/mobile/wait-for-bridge.cjs +2 -2
- package/adapters/shared/harness-source-fingerprint.mjs +13 -8
- package/adapters/shared/open-debug.mjs +2 -2
- package/adapters/shared/sync-wallet-fixture.sh +8 -5
- package/adapters/terminal/cleanup.mjs +2 -1
- package/adapters/terminal/inject.mjs +2 -1
- package/adapters/terminal/launch.mjs +17 -13
- package/adapters/terminal/lib/mainnet-guard.mjs +9 -0
- package/adapters/terminal/lib/readiness.mjs +20 -12
- package/adapters/terminal/policy.mjs +35 -0
- package/adapters/terminal/verify.mjs +10 -3
- package/adapters/terminal/wallet-host.mjs +43 -225
- package/bin/mm-harness +9 -28
- package/dist/adapters/checkout-files.js +16 -0
- package/dist/adapters/console-capture.js +14 -1
- package/dist/adapters/core/actions.js +8 -4
- package/dist/adapters/core/overlay.js +1 -1
- package/dist/adapters/core/readiness.js +28 -1
- package/dist/adapters/core/run.js +2 -2
- package/dist/adapters/core/surface.js +16 -1
- package/dist/adapters/extension/actions.js +6 -2
- package/dist/adapters/extension/browser-pid.js +56 -0
- package/dist/adapters/extension/console-capture.js +1 -1
- package/dist/adapters/extension/doctor-checks.js +1 -1
- package/dist/adapters/extension/ensure-ready.js +5 -4
- package/dist/adapters/extension/extension-id.js +1 -1
- package/dist/adapters/extension/feature-flags.js +1 -1
- package/dist/adapters/extension/fixtures.js +1 -2
- package/dist/adapters/extension/launch.js +4 -5
- package/dist/adapters/extension/launched-browser.js +1 -2
- package/dist/adapters/extension/network-observer.js +14 -1
- package/dist/adapters/extension/overlay.js +1 -1
- package/dist/adapters/extension/product-config.js +1 -1
- package/dist/adapters/extension/readiness.js +1 -1
- package/dist/adapters/extension/reload.js +1 -1
- package/dist/adapters/extension/run.js +135 -14
- package/dist/adapters/extension/runtime-decision.js +2 -1
- package/dist/adapters/extension/runtime.js +9 -5
- package/dist/adapters/extension/surface.js +15 -2
- package/dist/adapters/extension/verify.js +2 -2
- package/dist/adapters/harness-freshness.js +2 -1
- package/dist/adapters/mobile/actions.js +4 -1
- package/dist/adapters/mobile/android-gfxinfo-performance.js +1 -3
- package/dist/adapters/mobile/app-identity.js +10 -0
- package/dist/adapters/mobile/doctor-checks.js +1 -1
- package/dist/adapters/mobile/fixtures.js +1 -1
- package/dist/adapters/mobile/launch.js +27 -28
- package/dist/adapters/mobile/lifecycle.js +1 -1
- package/dist/adapters/mobile/metro-env.js +9 -59
- package/dist/adapters/mobile/network-observer.js +68 -0
- package/dist/adapters/mobile/performance-observer.js +2 -4
- package/dist/adapters/mobile/prepare-target.js +1 -1
- package/dist/adapters/mobile/prepare.js +3 -4
- package/dist/adapters/mobile/provision.js +1 -1
- package/dist/adapters/mobile/readiness.js +1 -1
- package/dist/adapters/mobile/recording-target.js +15 -0
- package/dist/adapters/mobile/release-artifact-state.js +1 -1
- package/dist/adapters/mobile/reload.js +1 -1
- package/dist/adapters/mobile/run.js +39 -15
- package/dist/adapters/mobile/runtime-decision.js +2 -4
- package/dist/adapters/mobile/source-freshness.js +22 -126
- package/dist/adapters/mobile/surface.js +26 -3
- package/dist/adapters/mobile/ui.js +16 -5
- package/dist/adapters/mobile/verify.js +2 -3
- package/dist/adapters/performance/cdp-trace.js +1 -1
- package/dist/adapters/performance/device-platform.js +1 -1
- package/dist/adapters/perps-order-inputs.js +36 -0
- package/dist/adapters/proof-failure.js +11 -0
- package/dist/adapters/slot-ports.js +1 -1
- package/dist/adapters/surface.js +1 -0
- package/dist/adapters/terminal/actions.js +4 -1
- package/dist/adapters/terminal/console-capture.js +1 -1
- package/dist/adapters/terminal/doctor-checks.js +2 -0
- package/dist/adapters/terminal/launch.js +4 -1
- package/dist/adapters/terminal/overlay.js +8 -1
- package/dist/adapters/terminal/run.js +33 -5
- package/dist/adapters/terminal/surface.js +9 -1
- package/dist/adapters.js +27 -7
- package/dist/advisor-policy.js +1 -1
- package/dist/checkout-view.js +1 -2
- package/dist/cli.js +59 -21
- package/dist/command-contract.js +1 -26
- package/dist/commands/check.js +33 -10
- package/dist/commands/checklist.js +1 -1
- package/dist/commands/completion-candidates.js +6 -14
- package/dist/commands/config.js +2 -2
- package/dist/commands/core-readiness.js +12 -7
- package/dist/commands/debug.js +3 -3
- package/dist/commands/device-target.js +5 -5
- package/dist/commands/doctor.js +2 -14
- package/dist/commands/domain.js +2 -2
- package/dist/commands/ensure-ready.js +1 -7
- package/dist/commands/fixtures.js +5 -6
- package/dist/commands/help.js +3 -4
- package/dist/commands/launch/device.js +10 -17
- package/dist/commands/launch/extension.js +2 -8
- package/dist/commands/launch/mobile.js +1 -1
- package/dist/commands/logs.js +3 -3
- package/dist/commands/mobile-device-view.js +4 -2
- package/dist/commands/overlay.js +110 -0
- package/dist/commands/pin.js +1 -1
- package/dist/commands/pr-body.js +2 -2
- package/dist/commands/prepare.js +4 -9
- package/dist/commands/provision.js +3 -12
- package/dist/commands/recipe-advice.js +1 -2
- package/dist/commands/recipe-quality.js +2 -3
- package/dist/commands/resolve-extension.js +1 -7
- package/dist/commands/review.js +4 -4
- package/dist/commands/runtime-decision.js +1 -6
- package/dist/commands/runtime-health.js +1 -7
- package/dist/commands/runtime-launch.js +1 -13
- package/dist/commands/self-test.js +5 -8
- package/dist/commands/status-watch.js +1 -2
- package/dist/commands/status.js +2 -5
- package/dist/commands/task-init.js +2 -3
- package/dist/commands/tutorial.js +2 -2
- package/dist/commands/update.js +1 -1
- package/dist/completions-cache.js +1 -1
- package/dist/console-classifier.js +19 -0
- package/dist/doctor.js +2 -3
- package/dist/engine.js +57 -0
- package/dist/funding-execution-context.js +96 -1
- package/dist/host.js +32 -0
- package/dist/index.js +1 -6
- package/dist/live-tsx.js +49 -0
- package/dist/mm-harness-cli.js +4 -6
- package/dist/paths.js +34 -64
- package/dist/performance-observation.js +3 -5
- package/dist/progress.js +1 -1
- package/dist/recipe-assistance-context.js +6 -9
- package/dist/recipe-security.js +2 -59
- package/dist/review/knowledge.js +2 -2
- package/dist/runner.js +7 -4
- package/dist/runtime-context.js +1 -1
- package/dist/task-view.js +2 -3
- package/docs/CONTRIBUTING.md +5 -3
- package/docs/RECIPES.md +31 -3
- package/docs/cli-contract.md +2 -2
- package/docs/feature-guard.md +90 -0
- package/library/README.md +3 -1
- package/library/actions/core/perps/_controller.mjs +153 -134
- package/library/actions/core/perps/_rewards.mjs +186 -0
- package/library/actions/core/perps/close_positions.mjs +1 -1
- package/library/actions/core/perps/place_order.mjs +167 -45
- package/library/actions/core/perps/quote_fees.mjs +61 -0
- package/library/actions/core/wallet/list_accounts.mjs +14 -57
- package/library/actions/extension/feature_flags/state.mjs +1 -1
- package/library/actions/extension/perps/close_visible_position.mjs +5 -0
- package/library/actions/extension/perps/edit_margin.mjs +4 -0
- package/library/actions/extension/perps/mutation-receipt.mjs +95 -3
- package/library/actions/extension/perps/perps.mjs +320 -3
- package/library/actions/extension/perps/place_order.mjs +3 -1
- package/library/actions/extension/perps/update_position_tpsl.mjs +4 -0
- package/library/actions/extension/platform/cdp.mjs +73 -11
- package/library/actions/harness-exports.mjs +1 -6
- package/library/actions/mobile/app/network-control.mjs +6 -8
- package/library/actions/mobile/perps/perps.mjs +216 -11
- package/library/actions/mobile/perps/place_order.mjs +3 -1
- package/library/actions/mobile/perps/prepare_local_snapshot_endpoint.mjs +1 -1
- package/library/actions/mobile/platform/bridge.mjs +8 -8
- package/library/actions/mobile/platform/native-session-name.mjs +21 -1
- package/library/actions/mobile/platform/native-session.mjs +3 -4
- package/library/actions/mobile/platform/observe-ui.mjs +12 -6
- package/library/actions/mobile/ui/native-navigation.mjs +4 -3
- package/library/actions/mobile/wallet/native-ui.mjs +3 -2
- package/library/actions/shared/analytics/_adapter.mjs +1 -1
- package/library/actions/shared/console-findings.mjs +1 -1
- package/library/actions/shared/perps/order-policy.mjs +177 -0
- package/library/actions/shared/wallet/fixture-accounts.mjs +84 -0
- package/library/actions/terminal/app/launch.mjs +3 -2
- package/library/actions/terminal/platform/hud.mjs +2 -1
- package/library/actions/terminal/platform/page.mjs +2 -1
- package/library/actions/terminal/platform/runtime.mjs +2 -1
- package/library/actions/terminal/wallet/_signature-log.mjs +40 -161
- package/library/actions/terminal/wallet/assert_signatures.mjs +6 -12
- package/library/actions/terminal/wallet/read_signatures.mjs +10 -9
- package/library/manifests/core.action-manifest.json +87 -13
- package/library/manifests/extension.action-manifest.json +4 -0
- package/library/manifests/mobile.action-manifest.json +12 -0
- package/package.json +8 -9
- package/site/assets/help-recipes.json +1 -0
- package/adapters/extension/lib/slot-title.cjs +0 -292
- package/adapters/mobile/bridge-runtime/console-forwarder.cjs +0 -472
- package/adapters/mobile/bridge-runtime/lib/bridge-errors.cjs +0 -125
- package/adapters/mobile/bridge-runtime/lib/cdp-broker.cjs +0 -1055
- package/adapters/mobile/bridge-runtime/lib/cdp-eval.cjs +0 -110
- package/adapters/mobile/bridge-runtime/lib/config.cjs +0 -61
- package/adapters/mobile/bridge-runtime/lib/console-format.cjs +0 -53
- package/adapters/mobile/bridge-runtime/lib/devtools-proxy.cjs +0 -177
- package/adapters/mobile/bridge-runtime/lib/issue-capture.cjs +0 -446
- package/adapters/mobile/bridge-runtime/lib/match-bridge-target.cjs +0 -84
- package/adapters/mobile/bridge-runtime/lib/target-discovery.cjs +0 -403
- package/adapters/mobile/bridge-runtime/lib/ws-client.cjs +0 -116
- package/adapters/mobile/coalesce-metro-log.cjs +0 -24
- package/adapters/mobile/launch-metro.cjs +0 -77
- package/adapters/mobile/metro-config.cjs +0 -98
- package/adapters/mobile/metro-log-generation.cjs +0 -106
- package/adapters/terminal/lib/origin.mjs +0 -30
- package/adapters/terminal/lib/page-script.mjs +0 -246
- package/adapters/terminal/lib/strict-wallet.mjs +0 -138
- package/dist/adapters/mobile/frame-metrics.js +0 -118
- package/dist/adapters/mobile/video-recorder.js +0 -289
- package/dist/artifact-files.js +0 -92
- package/dist/checkout-lock.js +0 -149
- package/dist/cli-color.js +0 -98
- package/dist/command-journal.js +0 -308
- package/dist/commands/call.js +0 -685
- package/dist/commands/last.js +0 -60
- package/dist/commands/launch/index.js +0 -109
- package/dist/commands/list-executables.js +0 -247
- package/dist/commands/manifest.js +0 -488
- package/dist/commands/parse-args.js +0 -279
- package/dist/commands/reload.js +0 -41
- package/dist/commands/run-engine.js +0 -1340
- package/dist/commands/run-report.js +0 -241
- package/dist/commands/run.js +0 -751
- package/dist/commands/shared.js +0 -323
- package/dist/commands/stop.js +0 -60
- package/dist/devices.js +0 -100
- package/dist/discovery.js +0 -15
- package/dist/execution-provenance.js +0 -332
- package/dist/harness.js +0 -451
- package/dist/heal-bounds.js +0 -137
- package/dist/json-stream.js +0 -60
- package/dist/leaf-invoke.js +0 -19
- package/dist/library-provenance.js +0 -33
- package/dist/live-adapter-contract.js +0 -380
- package/dist/metamask-action-validation.js +0 -68
- package/dist/network-observation.js +0 -290
- package/dist/recording-target.js +0 -120
- package/dist/run-diagnostics.js +0 -364
- package/dist/run-recording.js +0 -481
- package/dist/runtime-proof.js +0 -90
- package/library/actions/mobile/platform/tool-paths.mjs +0 -123
|
@@ -1,332 +0,0 @@
|
|
|
1
|
-
import { execFileSync } from "node:child_process";
|
|
2
|
-
import { createHash } from "node:crypto";
|
|
3
|
-
import fs, { constants as fsConstants } from "node:fs";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { getAdapterSurface } from "./adapters/surface.js";
|
|
6
|
-
import { indexArtifactManifest } from "./artifact-files.js";
|
|
7
|
-
import { importRecipeProtocol, runnerDir } from "./paths.js";
|
|
8
|
-
const gitContexts = /* @__PURE__ */ new Map();
|
|
9
|
-
let protocolPromise;
|
|
10
|
-
class ProvenanceDriftError extends Error {
|
|
11
|
-
code = "PROVENANCE_DRIFT";
|
|
12
|
-
exitCode = 5;
|
|
13
|
-
userAction;
|
|
14
|
-
provenancePath;
|
|
15
|
-
drift;
|
|
16
|
-
constructor(provenancePath, drift, cause) {
|
|
17
|
-
const fields = [...new Set(drift.map((entry) => entry.field))].join(", ");
|
|
18
|
-
super(
|
|
19
|
-
`Execution inputs changed after preparation (${fields}); evidence is invalid.`,
|
|
20
|
-
cause === void 0 ? void 0 : { cause }
|
|
21
|
-
);
|
|
22
|
-
this.name = "ProvenanceDriftError";
|
|
23
|
-
this.provenancePath = provenancePath;
|
|
24
|
-
this.drift = drift;
|
|
25
|
-
this.userAction = `restore the prepared recipe, library, and product source, then rerun; inspect ${provenancePath}`;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
async function captureExecutionProvenance(input, phase) {
|
|
29
|
-
const protocol = await (protocolPromise ??= importRecipeProtocol());
|
|
30
|
-
const recipeDigest = input.recipePath ? recipeFileDigest(protocol, input.recipePath) : protocol.digestRecipeDocument(input.recipeDocument);
|
|
31
|
-
const libraries = (input.librarySources ?? []).map((source, index) => ({
|
|
32
|
-
name: source.name ?? `library-${index + 1}`,
|
|
33
|
-
...sourceSnapshot(source.root)
|
|
34
|
-
}));
|
|
35
|
-
const runnerRoot = input.runnerRoot ?? runnerDir;
|
|
36
|
-
return {
|
|
37
|
-
phase,
|
|
38
|
-
capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
39
|
-
recipeDigest,
|
|
40
|
-
product: sourceSnapshot(
|
|
41
|
-
input.projectRoot,
|
|
42
|
-
input.adapter,
|
|
43
|
-
input.excludedProductRoots
|
|
44
|
-
),
|
|
45
|
-
runner: sourceSnapshot(runnerRoot, void 0, [], [
|
|
46
|
-
"src",
|
|
47
|
-
"adapters",
|
|
48
|
-
"library",
|
|
49
|
-
"bin",
|
|
50
|
-
"dist",
|
|
51
|
-
"package.json"
|
|
52
|
-
]),
|
|
53
|
-
libraries,
|
|
54
|
-
helpers: (input.helperPaths ?? []).map((helperPath) => ({
|
|
55
|
-
path: displayPath(input.projectRoot, helperPath),
|
|
56
|
-
sourceFingerprint: fileFingerprint(helperPath)
|
|
57
|
-
}))
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
function executionProvenanceDrift(start, current) {
|
|
61
|
-
const drift = [];
|
|
62
|
-
if (current.phase === "start") return drift;
|
|
63
|
-
const phase = current.phase;
|
|
64
|
-
compare(drift, phase, "recipeDigest", start.recipeDigest, current.recipeDigest);
|
|
65
|
-
compareSource(drift, phase, "product", start.product, current.product);
|
|
66
|
-
compareSource(drift, phase, "runner", start.runner, current.runner);
|
|
67
|
-
if (start.libraries.length !== current.libraries.length) {
|
|
68
|
-
compare(
|
|
69
|
-
drift,
|
|
70
|
-
phase,
|
|
71
|
-
"libraries.length",
|
|
72
|
-
String(start.libraries.length),
|
|
73
|
-
String(current.libraries.length)
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
const count = Math.min(start.libraries.length, current.libraries.length);
|
|
77
|
-
for (let index = 0; index < count; index += 1) {
|
|
78
|
-
const expected = start.libraries[index];
|
|
79
|
-
const actual = current.libraries[index];
|
|
80
|
-
const prefix = `libraries[${index}]`;
|
|
81
|
-
compare(drift, phase, `${prefix}.name`, expected.name, actual.name);
|
|
82
|
-
compareSource(drift, phase, prefix, expected, actual);
|
|
83
|
-
}
|
|
84
|
-
if (start.helpers.length !== current.helpers.length) {
|
|
85
|
-
compare(
|
|
86
|
-
drift,
|
|
87
|
-
phase,
|
|
88
|
-
"helpers.length",
|
|
89
|
-
String(start.helpers.length),
|
|
90
|
-
String(current.helpers.length)
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
const helperCount = Math.min(start.helpers.length, current.helpers.length);
|
|
94
|
-
for (let index = 0; index < helperCount; index += 1) {
|
|
95
|
-
compare(drift, phase, `helpers[${index}].path`, start.helpers[index].path, current.helpers[index].path);
|
|
96
|
-
compare(
|
|
97
|
-
drift,
|
|
98
|
-
phase,
|
|
99
|
-
`helpers[${index}].sourceFingerprint`,
|
|
100
|
-
start.helpers[index].sourceFingerprint,
|
|
101
|
-
current.helpers[index].sourceFingerprint
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
return drift;
|
|
105
|
-
}
|
|
106
|
-
async function writeExecutionProvenance(artifactsDir, snapshots, drift, artifactManifestPath) {
|
|
107
|
-
const provenancePath = path.join(path.resolve(artifactsDir), "execution-provenance.json");
|
|
108
|
-
const record = {
|
|
109
|
-
schemaVersion: 1,
|
|
110
|
-
valid: drift.length === 0,
|
|
111
|
-
snapshots,
|
|
112
|
-
drift
|
|
113
|
-
};
|
|
114
|
-
fs.mkdirSync(path.dirname(provenancePath), { recursive: true });
|
|
115
|
-
fs.writeFileSync(provenancePath, `${JSON.stringify(record, null, 2)}
|
|
116
|
-
`);
|
|
117
|
-
if (artifactManifestPath) {
|
|
118
|
-
await indexArtifactManifest(artifactManifestPath, [
|
|
119
|
-
{
|
|
120
|
-
path: "execution-provenance.json",
|
|
121
|
-
type: "json",
|
|
122
|
-
label: "Execution provenance",
|
|
123
|
-
category: "system",
|
|
124
|
-
metadata: {
|
|
125
|
-
valid: record.valid,
|
|
126
|
-
errorCode: record.valid ? null : "PROVENANCE_DRIFT"
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
]);
|
|
130
|
-
}
|
|
131
|
-
return provenancePath;
|
|
132
|
-
}
|
|
133
|
-
function recipeFileDigest(protocol, recipePath) {
|
|
134
|
-
const source = readRegularFileNoFollow(recipePath);
|
|
135
|
-
try {
|
|
136
|
-
return protocol.digestRecipeDocument(JSON.parse(source.toString("utf8")));
|
|
137
|
-
} catch {
|
|
138
|
-
return `invalid:sha256:${createHash("sha256").update(source).digest("hex")}`;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
function sourceSnapshot(root, adapter, excludedRoots = [], includedRoots = []) {
|
|
142
|
-
const git = gitContext(root);
|
|
143
|
-
if (!git) {
|
|
144
|
-
return {
|
|
145
|
-
head: null,
|
|
146
|
-
status: "not-a-git-checkout",
|
|
147
|
-
sourceFingerprint: directoryFingerprint(root, excludedRoots, includedRoots)
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
const pathspecs = sourcePathspecs(git, excludedRoots, includedRoots);
|
|
151
|
-
const status = gitText(git.topLevel, [
|
|
152
|
-
"status",
|
|
153
|
-
"--porcelain=v1",
|
|
154
|
-
"--untracked-files=normal",
|
|
155
|
-
"--",
|
|
156
|
-
...pathspecs
|
|
157
|
-
]);
|
|
158
|
-
const head = gitBuffer(git.topLevel, ["rev-parse", "HEAD"]);
|
|
159
|
-
const platformFingerprint = adapter ? getAdapterSurface(adapter).sourceFingerprint : void 0;
|
|
160
|
-
return {
|
|
161
|
-
head: head.toString("utf8").trim() || null,
|
|
162
|
-
status,
|
|
163
|
-
sourceFingerprint: platformFingerprint && path.resolve(root) === git.topLevel ? platformFingerprint(root) : nestedGitSourceFingerprint(root, git, pathspecs, excludedRoots, includedRoots, head)
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
function nestedGitSourceFingerprint(root, git, pathspecs, excludedRoots, includedRoots, head) {
|
|
167
|
-
const gitFingerprint = gitSourceFingerprint(git.topLevel, pathspecs, head);
|
|
168
|
-
if (git.pathspec === "." && includedRoots.length === 0) return gitFingerprint;
|
|
169
|
-
return createHash("sha256").update(gitFingerprint).update("\0nested-source\0").update(directoryFingerprint(root, excludedRoots, includedRoots)).digest("hex");
|
|
170
|
-
}
|
|
171
|
-
function gitContext(root) {
|
|
172
|
-
const cacheKey = path.resolve(root);
|
|
173
|
-
if (gitContexts.has(cacheKey)) return gitContexts.get(cacheKey) ?? null;
|
|
174
|
-
try {
|
|
175
|
-
const resolved = cacheKey;
|
|
176
|
-
const topLevel = fs.realpathSync(
|
|
177
|
-
gitText(resolved, ["rev-parse", "--show-toplevel"]).trim()
|
|
178
|
-
);
|
|
179
|
-
const relative = path.relative(topLevel, fs.realpathSync(resolved));
|
|
180
|
-
const context = relative === ".." || relative.startsWith(`..${path.sep}`) ? null : { topLevel, pathspec: relative || "." };
|
|
181
|
-
gitContexts.set(cacheKey, context);
|
|
182
|
-
return context;
|
|
183
|
-
} catch {
|
|
184
|
-
gitContexts.set(cacheKey, null);
|
|
185
|
-
return null;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
function gitSourceFingerprint(topLevel, pathspecs, head) {
|
|
189
|
-
const hash = createHash("sha256");
|
|
190
|
-
hash.update(head);
|
|
191
|
-
hash.update("\0diff\0");
|
|
192
|
-
hash.update(
|
|
193
|
-
gitBuffer(topLevel, [
|
|
194
|
-
"diff",
|
|
195
|
-
"--no-ext-diff",
|
|
196
|
-
"--binary",
|
|
197
|
-
head.toString("utf8").trim(),
|
|
198
|
-
"--",
|
|
199
|
-
...pathspecs
|
|
200
|
-
])
|
|
201
|
-
);
|
|
202
|
-
const untracked = gitText(topLevel, [
|
|
203
|
-
"ls-files",
|
|
204
|
-
"--others",
|
|
205
|
-
"--exclude-standard",
|
|
206
|
-
"-z",
|
|
207
|
-
"--",
|
|
208
|
-
...pathspecs
|
|
209
|
-
]).split("\0").filter(Boolean).sort();
|
|
210
|
-
for (const relative of untracked) {
|
|
211
|
-
hash.update(`\0untracked\0${relative}\0`);
|
|
212
|
-
const absolute = path.join(topLevel, relative);
|
|
213
|
-
hash.update(readPathIdentity(absolute));
|
|
214
|
-
}
|
|
215
|
-
return hash.digest("hex");
|
|
216
|
-
}
|
|
217
|
-
function sourcePathspecs(git, excludedRoots, includedRoots) {
|
|
218
|
-
const exclusions = excludedRoots.flatMap((root) => {
|
|
219
|
-
const relative = path.relative(git.topLevel, fs.existsSync(root) ? fs.realpathSync(root) : path.resolve(root));
|
|
220
|
-
return relative !== ".." && !relative.startsWith(`..${path.sep}`) ? [`:(exclude)${relative}`] : [];
|
|
221
|
-
});
|
|
222
|
-
const inclusions = includedRoots.length > 0 ? includedRoots.map((root) => path.join(git.pathspec === "." ? "" : git.pathspec, root)) : [git.pathspec];
|
|
223
|
-
return [...inclusions, ...exclusions];
|
|
224
|
-
}
|
|
225
|
-
function directoryFingerprint(root, excludedRoots, includedRoots) {
|
|
226
|
-
const hash = createHash("sha256");
|
|
227
|
-
const resolvedRoot = path.resolve(root);
|
|
228
|
-
const roots = includedRoots.length > 0 ? includedRoots : [""];
|
|
229
|
-
for (const included of roots) {
|
|
230
|
-
hashDirectory(
|
|
231
|
-
hash,
|
|
232
|
-
resolvedRoot,
|
|
233
|
-
included,
|
|
234
|
-
new Set(excludedRoots.map((entry) => path.resolve(entry)))
|
|
235
|
-
);
|
|
236
|
-
}
|
|
237
|
-
return hash.digest("hex");
|
|
238
|
-
}
|
|
239
|
-
function hashDirectory(hash, root, relative, excludedRoots) {
|
|
240
|
-
const absolute = path.join(root, relative);
|
|
241
|
-
if ([...excludedRoots].some(
|
|
242
|
-
(excluded) => absolute === excluded || absolute.startsWith(`${excluded}${path.sep}`)
|
|
243
|
-
)) return;
|
|
244
|
-
let stat;
|
|
245
|
-
try {
|
|
246
|
-
stat = fs.lstatSync(absolute);
|
|
247
|
-
} catch (error) {
|
|
248
|
-
if (error.code === "ENOENT") {
|
|
249
|
-
hash.update(`absent\0${relative}\0`);
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
throw error;
|
|
253
|
-
}
|
|
254
|
-
if (stat.isDirectory()) {
|
|
255
|
-
hash.update(`directory\0${relative}\0`);
|
|
256
|
-
for (const name of fs.readdirSync(absolute).sort()) {
|
|
257
|
-
if (relative === "" && (name === ".git" || name === "node_modules" || name === "temp")) continue;
|
|
258
|
-
hashDirectory(hash, root, path.join(relative, name), excludedRoots);
|
|
259
|
-
}
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
if (stat.isSymbolicLink()) {
|
|
263
|
-
throw new Error(`Execution provenance source must not be a symbolic link: ${absolute}`);
|
|
264
|
-
}
|
|
265
|
-
hash.update(`file\0${relative}\0`);
|
|
266
|
-
hash.update(readRegularFileNoFollow(absolute));
|
|
267
|
-
hash.update("\0");
|
|
268
|
-
}
|
|
269
|
-
function fileFingerprint(filePath) {
|
|
270
|
-
return createHash("sha256").update(readRegularFileNoFollow(filePath)).digest("hex");
|
|
271
|
-
}
|
|
272
|
-
function readPathIdentity(filePath) {
|
|
273
|
-
const stat = fs.lstatSync(filePath);
|
|
274
|
-
if (stat.isSymbolicLink()) {
|
|
275
|
-
throw new Error(`Execution provenance source must not be a symbolic link: ${filePath}`);
|
|
276
|
-
}
|
|
277
|
-
return readRegularFileNoFollow(filePath);
|
|
278
|
-
}
|
|
279
|
-
function readRegularFileNoFollow(filePath) {
|
|
280
|
-
let fd;
|
|
281
|
-
try {
|
|
282
|
-
fd = fs.openSync(filePath, fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW);
|
|
283
|
-
} catch (error) {
|
|
284
|
-
if (error.code === "ELOOP") {
|
|
285
|
-
throw new Error(`Execution provenance source must not be a symbolic link: ${filePath}`);
|
|
286
|
-
}
|
|
287
|
-
throw error;
|
|
288
|
-
}
|
|
289
|
-
try {
|
|
290
|
-
if (!fs.fstatSync(fd).isFile()) {
|
|
291
|
-
throw new Error(`Execution provenance source is not a regular file: ${filePath}`);
|
|
292
|
-
}
|
|
293
|
-
return fs.readFileSync(fd);
|
|
294
|
-
} finally {
|
|
295
|
-
fs.closeSync(fd);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
function displayPath(projectRoot, filePath) {
|
|
299
|
-
const relative = path.relative(path.resolve(projectRoot), path.resolve(filePath));
|
|
300
|
-
return relative !== ".." && !relative.startsWith(`..${path.sep}`) ? relative || "." : path.resolve(filePath);
|
|
301
|
-
}
|
|
302
|
-
function gitText(cwd, args) {
|
|
303
|
-
return gitBuffer(cwd, args).toString("utf8");
|
|
304
|
-
}
|
|
305
|
-
function gitBuffer(cwd, args) {
|
|
306
|
-
return execFileSync("git", args, {
|
|
307
|
-
cwd,
|
|
308
|
-
encoding: "buffer",
|
|
309
|
-
maxBuffer: 128 * 1024 * 1024,
|
|
310
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
function compareSource(drift, phase, prefix, start, current) {
|
|
314
|
-
compare(drift, phase, `${prefix}.head`, start.head, current.head);
|
|
315
|
-
compare(drift, phase, `${prefix}.status`, start.status, current.status);
|
|
316
|
-
compare(
|
|
317
|
-
drift,
|
|
318
|
-
phase,
|
|
319
|
-
`${prefix}.sourceFingerprint`,
|
|
320
|
-
start.sourceFingerprint,
|
|
321
|
-
current.sourceFingerprint
|
|
322
|
-
);
|
|
323
|
-
}
|
|
324
|
-
function compare(drift, phase, field, start, current) {
|
|
325
|
-
if (start !== current) drift.push({ phase, field, start, current });
|
|
326
|
-
}
|
|
327
|
-
export {
|
|
328
|
-
ProvenanceDriftError,
|
|
329
|
-
captureExecutionProvenance,
|
|
330
|
-
executionProvenanceDrift,
|
|
331
|
-
writeExecutionProvenance
|
|
332
|
-
};
|