@vela-science/canopus 0.4.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +249 -0
- package/LICENSE-APACHE +176 -0
- package/LICENSE-MIT +21 -0
- package/README.md +124 -0
- package/SECURITY.md +35 -0
- package/capsules/erdos1056-k15/README.md +35 -0
- package/capsules/erdos1056-k15/bin/linux-arm64/10428401-10428600/verifier +0 -0
- package/capsules/erdos1056-k15/bin/linux-x86_64/10428401-10428600/verifier +0 -0
- package/capsules/formal-erdos-505-test-dim-one/README.md +20 -0
- package/capsules/formal-erdos-505-test-dim-one/verifier +105 -0
- package/dist/src/activity/events.d.ts +15 -0
- package/dist/src/activity/events.js +24 -0
- package/dist/src/activity/store.d.ts +10 -0
- package/dist/src/activity/store.js +165 -0
- package/dist/src/artifact/freeze.d.ts +21 -0
- package/dist/src/artifact/freeze.js +177 -0
- package/dist/src/artifact/materialize.d.ts +6 -0
- package/dist/src/artifact/materialize.js +29 -0
- package/dist/src/budget/enforce.d.ts +30 -0
- package/dist/src/budget/enforce.js +98 -0
- package/dist/src/candidate/validate.d.ts +3 -0
- package/dist/src/candidate/validate.js +32 -0
- package/dist/src/capability/withdrawal.d.ts +47 -0
- package/dist/src/capability/withdrawal.js +487 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +503 -0
- package/dist/src/contracts/candidate.d.ts +50 -0
- package/dist/src/contracts/candidate.js +93 -0
- package/dist/src/contracts/mission.d.ts +139 -0
- package/dist/src/contracts/mission.js +401 -0
- package/dist/src/contracts/validation.d.ts +25 -0
- package/dist/src/contracts/validation.js +95 -0
- package/dist/src/engines/codex-events.d.ts +25 -0
- package/dist/src/engines/codex-events.js +219 -0
- package/dist/src/engines/codex-exec.d.ts +17 -0
- package/dist/src/engines/codex-exec.js +136 -0
- package/dist/src/engines/codex-home.d.ts +7 -0
- package/dist/src/engines/codex-home.js +50 -0
- package/dist/src/engines/codex-tool-free.d.ts +26 -0
- package/dist/src/engines/codex-tool-free.js +213 -0
- package/dist/src/engines/codex-tools-native.d.ts +30 -0
- package/dist/src/engines/codex-tools-native.js +405 -0
- package/dist/src/engines/engine.d.ts +55 -0
- package/dist/src/engines/engine.js +4 -0
- package/dist/src/engines/fake.d.ts +7 -0
- package/dist/src/engines/fake.js +37 -0
- package/dist/src/evidence/manifests.d.ts +9 -0
- package/dist/src/evidence/manifests.js +56 -0
- package/dist/src/index.d.ts +32 -0
- package/dist/src/index.js +32 -0
- package/dist/src/mission/prepare.d.ts +33 -0
- package/dist/src/mission/prepare.js +375 -0
- package/dist/src/product/custody.d.ts +27 -0
- package/dist/src/product/custody.js +131 -0
- package/dist/src/product/doctor.d.ts +61 -0
- package/dist/src/product/doctor.js +278 -0
- package/dist/src/product/profile-bundle.d.ts +21 -0
- package/dist/src/product/profile-bundle.js +78 -0
- package/dist/src/product/profile.d.ts +67 -0
- package/dist/src/product/profile.js +251 -0
- package/dist/src/product/replay.d.ts +10 -0
- package/dist/src/product/replay.js +71 -0
- package/dist/src/product/run.d.ts +31 -0
- package/dist/src/product/run.js +264 -0
- package/dist/src/product/runtime.d.ts +18 -0
- package/dist/src/product/runtime.js +64 -0
- package/dist/src/product/version.d.ts +1 -0
- package/dist/src/product/version.js +6 -0
- package/dist/src/product/withdraw.d.ts +8 -0
- package/dist/src/product/withdraw.js +255 -0
- package/dist/src/projection/diagnostic.d.ts +12 -0
- package/dist/src/projection/diagnostic.js +61 -0
- package/dist/src/projection/failure.d.ts +26 -0
- package/dist/src/projection/failure.js +63 -0
- package/dist/src/projection/run.d.ts +89 -0
- package/dist/src/projection/run.js +159 -0
- package/dist/src/receipt/map.d.ts +25 -0
- package/dist/src/receipt/map.js +162 -0
- package/dist/src/repair/plan.d.ts +2 -0
- package/dist/src/repair/plan.js +22 -0
- package/dist/src/roles.d.ts +2 -0
- package/dist/src/roles.js +9 -0
- package/dist/src/run.d.ts +94 -0
- package/dist/src/run.js +654 -0
- package/dist/src/util/canonical.d.ts +5 -0
- package/dist/src/util/canonical.js +53 -0
- package/dist/src/util/command.d.ts +26 -0
- package/dist/src/util/command.js +161 -0
- package/dist/src/util/files.d.ts +3 -0
- package/dist/src/util/files.js +65 -0
- package/dist/src/vela/cli.d.ts +71 -0
- package/dist/src/vela/cli.js +718 -0
- package/dist/src/vela/types.d.ts +27 -0
- package/dist/src/vela/types.js +1 -0
- package/dist/src/verifier/run.d.ts +24 -0
- package/dist/src/verifier/run.js +315 -0
- package/dist/src/workspace/prepare.d.ts +30 -0
- package/dist/src/workspace/prepare.js +183 -0
- package/docs/MISSIONS.md +78 -0
- package/docs/RELEASES.md +1036 -0
- package/docs/RUN_RECORD.md +70 -0
- package/missions/erdos1056-k15-next/mission.draft.json +40 -0
- package/missions/formal-erdos-505-test-dim-one/mission.draft.json +40 -0
- package/package.json +89 -0
- package/profiles/erdos1056-k15-10428401-10428600.json +33 -0
- package/profiles/formal-erdos-505-test-dim-one.json +35 -0
- package/runtime/native-worker/config-linux.toml +20 -0
- package/runtime/native-worker/config.toml +17 -0
- package/schemas/candidate.v0.json +125 -0
- package/schemas/engine-manifest.v0.json +45 -0
- package/schemas/engine-output.v0.json +41 -0
- package/schemas/mission.v0.json +175 -0
- package/schemas/mission.v1.json +224 -0
- package/schemas/verifier-manifest.v0.json +48 -0
- package/schemas/verifier-manifest.v1.json +59 -0
- package/scripts/run-hostile-native-custody-fixture.mjs +382 -0
- package/scripts/run-hostile-verifier-fixture.mjs +63 -0
- package/tests/fixtures/hostile-verifier/probe.py +35 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
function normalize(value, at) {
|
|
3
|
+
if (value === null ||
|
|
4
|
+
typeof value === "string" ||
|
|
5
|
+
typeof value === "boolean") {
|
|
6
|
+
return value;
|
|
7
|
+
}
|
|
8
|
+
if (typeof value === "number") {
|
|
9
|
+
if (!Number.isFinite(value)) {
|
|
10
|
+
throw new TypeError(`${at} contains a non-finite number`);
|
|
11
|
+
}
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
if (Array.isArray(value)) {
|
|
15
|
+
return value.map((item, index) => normalize(item, `${at}[${index}]`));
|
|
16
|
+
}
|
|
17
|
+
if (typeof value === "object") {
|
|
18
|
+
const prototype = Object.getPrototypeOf(value);
|
|
19
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
20
|
+
throw new TypeError(`${at} must contain plain JSON objects`);
|
|
21
|
+
}
|
|
22
|
+
const input = value;
|
|
23
|
+
const output = {};
|
|
24
|
+
for (const key of Object.keys(input).sort()) {
|
|
25
|
+
const item = input[key];
|
|
26
|
+
if (item === undefined) {
|
|
27
|
+
throw new TypeError(`${at}.${key} is undefined`);
|
|
28
|
+
}
|
|
29
|
+
output[key] = normalize(item, `${at}.${key}`);
|
|
30
|
+
}
|
|
31
|
+
return output;
|
|
32
|
+
}
|
|
33
|
+
throw new TypeError(`${at} contains a non-JSON value`);
|
|
34
|
+
}
|
|
35
|
+
export function canonicalJson(value) {
|
|
36
|
+
return `${JSON.stringify(normalize(value, "$"))}\n`;
|
|
37
|
+
}
|
|
38
|
+
// RFC 8785 uses ECMAScript JSON serialization over recursively sorted object
|
|
39
|
+
// keys and does not append a record newline. Vela Receipt v1 uses these bytes.
|
|
40
|
+
export function canonicalJcs(value) {
|
|
41
|
+
return JSON.stringify(normalize(value, "$"));
|
|
42
|
+
}
|
|
43
|
+
export function sha256Bytes(value) {
|
|
44
|
+
return `sha256:${createHash("sha256").update(value).digest("hex")}`;
|
|
45
|
+
}
|
|
46
|
+
export function contentDigest(value) {
|
|
47
|
+
return sha256Bytes(canonicalJson(value));
|
|
48
|
+
}
|
|
49
|
+
// Vela protocol objects use compact canonical JSON bytes, without the record
|
|
50
|
+
// newline used by Canopus-owned manifests and activity records.
|
|
51
|
+
export function protocolDigest(value) {
|
|
52
|
+
return sha256Bytes(canonicalJcs(value));
|
|
53
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type CommandFailureKind = "invalid_argv" | "spawn" | "timeout" | "output_limit" | "aborted";
|
|
2
|
+
export declare class CommandFailure extends Error {
|
|
3
|
+
readonly kind: CommandFailureKind;
|
|
4
|
+
constructor(kind: CommandFailureKind, message: string);
|
|
5
|
+
}
|
|
6
|
+
export interface CommandResult {
|
|
7
|
+
argv: string[];
|
|
8
|
+
exitCode: number;
|
|
9
|
+
signal: NodeJS.Signals | null;
|
|
10
|
+
stdout: Buffer;
|
|
11
|
+
stderr: Buffer;
|
|
12
|
+
durationMs: number;
|
|
13
|
+
}
|
|
14
|
+
export interface CommandOptions {
|
|
15
|
+
argv: readonly string[];
|
|
16
|
+
cwd: string;
|
|
17
|
+
env: NodeJS.ProcessEnv;
|
|
18
|
+
timeoutMs: number;
|
|
19
|
+
maxOutputBytes: number;
|
|
20
|
+
stdin?: Uint8Array | string;
|
|
21
|
+
signal?: AbortSignal;
|
|
22
|
+
}
|
|
23
|
+
export type CommandRunner = (options: CommandOptions) => Promise<CommandResult>;
|
|
24
|
+
export declare const MAX_COMMAND_ARGV = 128;
|
|
25
|
+
export declare function isolatedEnvironment(home: string, platform?: NodeJS.Platform): NodeJS.ProcessEnv;
|
|
26
|
+
export declare function runCommand(options: CommandOptions): Promise<CommandResult>;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
export class CommandFailure extends Error {
|
|
4
|
+
kind;
|
|
5
|
+
constructor(kind, message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "CommandFailure";
|
|
8
|
+
this.kind = kind;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export const MAX_COMMAND_ARGV = 128;
|
|
12
|
+
function validateArgv(argv) {
|
|
13
|
+
if (argv.length === 0 || argv.length > MAX_COMMAND_ARGV) {
|
|
14
|
+
throw new CommandFailure("invalid_argv", `argv must contain 1..${MAX_COMMAND_ARGV} entries`);
|
|
15
|
+
}
|
|
16
|
+
for (const [index, item] of argv.entries()) {
|
|
17
|
+
if (item.length === 0 || item.length > 16_384 || item.includes("\0")) {
|
|
18
|
+
throw new CommandFailure("invalid_argv", `argv[${index}] is invalid`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function terminateTree(pid, signal) {
|
|
23
|
+
if (pid === undefined) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
if (process.platform === "win32") {
|
|
28
|
+
process.kill(pid, signal);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
process.kill(-pid, signal);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// The process may already have exited.
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export function isolatedEnvironment(home, platform = process.platform) {
|
|
39
|
+
const path = process.env.PATH;
|
|
40
|
+
const common = {
|
|
41
|
+
...(path === undefined ? {} : { PATH: path }),
|
|
42
|
+
HOME: home,
|
|
43
|
+
XDG_CONFIG_HOME: `${home}/.config`,
|
|
44
|
+
XDG_CACHE_HOME: `${home}/.cache`,
|
|
45
|
+
XDG_DATA_HOME: `${home}/.local/share`,
|
|
46
|
+
GIT_CONFIG_NOSYSTEM: "1",
|
|
47
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
48
|
+
VELA_NO_KEY_ACCESS: "1",
|
|
49
|
+
NO_PROXY: "*",
|
|
50
|
+
no_proxy: "*",
|
|
51
|
+
};
|
|
52
|
+
if (platform === "win32") {
|
|
53
|
+
return {
|
|
54
|
+
...common,
|
|
55
|
+
USERPROFILE: home,
|
|
56
|
+
APPDATA: `${home}\\AppData\\Roaming`,
|
|
57
|
+
LOCALAPPDATA: `${home}\\AppData\\Local`,
|
|
58
|
+
GIT_CONFIG_GLOBAL: "NUL",
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
...common,
|
|
63
|
+
LANG: "C.UTF-8",
|
|
64
|
+
LC_ALL: "C.UTF-8",
|
|
65
|
+
// rustls-native-certs checks this before macOS keychains. Pinning the
|
|
66
|
+
// system PEM bundle keeps TLS functional without exposing user keychains.
|
|
67
|
+
SSL_CERT_FILE: "/etc/ssl/cert.pem",
|
|
68
|
+
GIT_CONFIG_GLOBAL: "/dev/null",
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export async function runCommand(options) {
|
|
72
|
+
validateArgv(options.argv);
|
|
73
|
+
if (!Number.isInteger(options.timeoutMs) || options.timeoutMs < 1) {
|
|
74
|
+
throw new CommandFailure("invalid_argv", "timeoutMs must be a positive integer");
|
|
75
|
+
}
|
|
76
|
+
if (!Number.isInteger(options.maxOutputBytes) || options.maxOutputBytes < 1) {
|
|
77
|
+
throw new CommandFailure("invalid_argv", "maxOutputBytes must be a positive integer");
|
|
78
|
+
}
|
|
79
|
+
if (options.signal?.aborted === true) {
|
|
80
|
+
throw new CommandFailure("aborted", "command was aborted before spawn");
|
|
81
|
+
}
|
|
82
|
+
const executable = options.argv[0];
|
|
83
|
+
if (executable === undefined) {
|
|
84
|
+
throw new CommandFailure("invalid_argv", "argv must name an executable");
|
|
85
|
+
}
|
|
86
|
+
const started = performance.now();
|
|
87
|
+
return await new Promise((resolve, reject) => {
|
|
88
|
+
const child = spawn(executable, options.argv.slice(1), {
|
|
89
|
+
cwd: options.cwd,
|
|
90
|
+
env: options.env,
|
|
91
|
+
detached: process.platform !== "win32",
|
|
92
|
+
shell: false,
|
|
93
|
+
stdio: "pipe",
|
|
94
|
+
windowsHide: true,
|
|
95
|
+
});
|
|
96
|
+
const stdout = [];
|
|
97
|
+
const stderr = [];
|
|
98
|
+
let bytes = 0;
|
|
99
|
+
let failure;
|
|
100
|
+
let killTimer;
|
|
101
|
+
const terminate = (nextFailure) => {
|
|
102
|
+
if (failure !== undefined) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
failure = nextFailure;
|
|
106
|
+
terminateTree(child.pid, "SIGTERM");
|
|
107
|
+
killTimer = setTimeout(() => terminateTree(child.pid, "SIGKILL"), 250);
|
|
108
|
+
killTimer.unref();
|
|
109
|
+
};
|
|
110
|
+
const collect = (target, chunk) => {
|
|
111
|
+
bytes += chunk.length;
|
|
112
|
+
if (bytes > options.maxOutputBytes) {
|
|
113
|
+
terminate(new CommandFailure("output_limit", `command output exceeded ${options.maxOutputBytes} bytes`));
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
target.push(chunk);
|
|
117
|
+
};
|
|
118
|
+
child.stdout.on("data", (chunk) => collect(stdout, chunk));
|
|
119
|
+
child.stderr.on("data", (chunk) => collect(stderr, chunk));
|
|
120
|
+
const timeout = setTimeout(() => terminate(new CommandFailure("timeout", `command exceeded ${options.timeoutMs} milliseconds`)), options.timeoutMs);
|
|
121
|
+
timeout.unref();
|
|
122
|
+
const abort = () => terminate(new CommandFailure("aborted", "command was aborted"));
|
|
123
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
124
|
+
child.once("error", (error) => {
|
|
125
|
+
clearTimeout(timeout);
|
|
126
|
+
if (killTimer !== undefined)
|
|
127
|
+
clearTimeout(killTimer);
|
|
128
|
+
options.signal?.removeEventListener("abort", abort);
|
|
129
|
+
reject(new CommandFailure("spawn", `could not spawn ${executable}: ${error.message}`));
|
|
130
|
+
});
|
|
131
|
+
child.once("close", (code, signal) => {
|
|
132
|
+
clearTimeout(timeout);
|
|
133
|
+
if (killTimer !== undefined)
|
|
134
|
+
clearTimeout(killTimer);
|
|
135
|
+
options.signal?.removeEventListener("abort", abort);
|
|
136
|
+
// A verifier may fork, close inherited stdio, and let its parent exit.
|
|
137
|
+
// The wrapper's successful exit is therefore not sufficient: terminate
|
|
138
|
+
// the entire detached process group before returning in every outcome.
|
|
139
|
+
terminateTree(child.pid, "SIGTERM");
|
|
140
|
+
terminateTree(child.pid, "SIGKILL");
|
|
141
|
+
if (failure !== undefined) {
|
|
142
|
+
reject(failure);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
resolve({
|
|
146
|
+
argv: [...options.argv],
|
|
147
|
+
exitCode: code ?? -1,
|
|
148
|
+
signal,
|
|
149
|
+
stdout: Buffer.concat(stdout),
|
|
150
|
+
stderr: Buffer.concat(stderr),
|
|
151
|
+
durationMs: Math.round(performance.now() - started),
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
if (options.stdin === undefined) {
|
|
155
|
+
child.stdin.end();
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
child.stdin.end(options.stdin);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { constants } from "node:fs";
|
|
3
|
+
import { open } from "node:fs/promises";
|
|
4
|
+
export const MAX_EXECUTABLE_BYTES = 1024 * 1024 * 1024;
|
|
5
|
+
function assertStableRegularFile(file, before, after) {
|
|
6
|
+
if (before.dev !== after.dev ||
|
|
7
|
+
before.ino !== after.ino ||
|
|
8
|
+
before.size !== after.size ||
|
|
9
|
+
before.mtimeMs !== after.mtimeMs) {
|
|
10
|
+
throw new Error(`${file} changed while it was being read`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export async function readBoundedRegularFile(file, maxBytes) {
|
|
14
|
+
const noFollow = "O_NOFOLLOW" in constants ? constants.O_NOFOLLOW : 0;
|
|
15
|
+
const handle = await open(file, constants.O_RDONLY | noFollow);
|
|
16
|
+
try {
|
|
17
|
+
const before = await handle.stat();
|
|
18
|
+
if (!before.isFile() || before.nlink !== 1) {
|
|
19
|
+
throw new Error(`${file} is not one singly linked regular file`);
|
|
20
|
+
}
|
|
21
|
+
if (before.size > maxBytes)
|
|
22
|
+
throw new Error(`${file} exceeds ${maxBytes} bytes`);
|
|
23
|
+
const value = Buffer.alloc(before.size);
|
|
24
|
+
let offset = 0;
|
|
25
|
+
while (offset < value.length) {
|
|
26
|
+
const { bytesRead } = await handle.read(value, offset, value.length - offset, offset);
|
|
27
|
+
if (bytesRead === 0)
|
|
28
|
+
throw new Error(`${file} ended before its declared size`);
|
|
29
|
+
offset += bytesRead;
|
|
30
|
+
}
|
|
31
|
+
assertStableRegularFile(file, before, await handle.stat());
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
await handle.close();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export async function sha256RegularFile(file, maxBytes) {
|
|
39
|
+
const noFollow = "O_NOFOLLOW" in constants ? constants.O_NOFOLLOW : 0;
|
|
40
|
+
const handle = await open(file, constants.O_RDONLY | noFollow);
|
|
41
|
+
try {
|
|
42
|
+
const before = await handle.stat();
|
|
43
|
+
if (!before.isFile() || before.nlink !== 1) {
|
|
44
|
+
throw new Error(`${file} is not one singly linked regular file`);
|
|
45
|
+
}
|
|
46
|
+
if (before.size > maxBytes)
|
|
47
|
+
throw new Error(`${file} exceeds ${maxBytes} bytes`);
|
|
48
|
+
const hash = createHash("sha256");
|
|
49
|
+
const buffer = Buffer.allocUnsafe(1024 * 1024);
|
|
50
|
+
let offset = 0;
|
|
51
|
+
while (offset < before.size) {
|
|
52
|
+
const length = Math.min(buffer.length, before.size - offset);
|
|
53
|
+
const { bytesRead } = await handle.read(buffer, 0, length, offset);
|
|
54
|
+
if (bytesRead === 0)
|
|
55
|
+
throw new Error(`${file} ended before its declared size`);
|
|
56
|
+
hash.update(buffer.subarray(0, bytesRead));
|
|
57
|
+
offset += bytesRead;
|
|
58
|
+
}
|
|
59
|
+
assertStableRegularFile(file, before, await handle.stat());
|
|
60
|
+
return `sha256:${hash.digest("hex")}`;
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
await handle.close();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { FrozenArtifact } from "../contracts/candidate.js";
|
|
2
|
+
import type { ExecutionBindingV1, Mission, MissionRoots, StrictBaseline } from "../contracts/mission.js";
|
|
3
|
+
import { type CommandRunner } from "../util/command.js";
|
|
4
|
+
import type { LandResult, VelaCommandResponse, VelaInspection } from "./types.js";
|
|
5
|
+
export type { CommandRunner } from "../util/command.js";
|
|
6
|
+
export declare function retainedArtifactPath(repoRoot: string, frontier: string, digest: string): string;
|
|
7
|
+
export declare class VelaClientError extends Error {
|
|
8
|
+
readonly code: "command_failed" | "malformed_output" | "version_mismatch" | "root_mismatch" | "unexpected_route";
|
|
9
|
+
constructor(code: VelaClientError["code"], message: string);
|
|
10
|
+
}
|
|
11
|
+
export interface VelaClientOptions {
|
|
12
|
+
binary: string;
|
|
13
|
+
expectedVersion: string;
|
|
14
|
+
expectedSha256: string;
|
|
15
|
+
home: string;
|
|
16
|
+
maxOutputBytes?: number;
|
|
17
|
+
timeoutMs?: number;
|
|
18
|
+
runner?: CommandRunner;
|
|
19
|
+
}
|
|
20
|
+
export interface AuthoredReceiptInput {
|
|
21
|
+
claim: string;
|
|
22
|
+
claimType: Mission["claim_type"];
|
|
23
|
+
replayability: Mission["replayability"];
|
|
24
|
+
artifacts: Array<{
|
|
25
|
+
path: string;
|
|
26
|
+
kind: string;
|
|
27
|
+
}>;
|
|
28
|
+
caveats: string[];
|
|
29
|
+
predictedObservable?: string;
|
|
30
|
+
notApplicable?: true;
|
|
31
|
+
performedTest: string;
|
|
32
|
+
result: string;
|
|
33
|
+
evidence: string[];
|
|
34
|
+
counterevidence: string[];
|
|
35
|
+
executionBinding?: ExecutionBindingV1;
|
|
36
|
+
work?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface VelaLandCommandObservation {
|
|
39
|
+
argv: string[];
|
|
40
|
+
exit_code: number;
|
|
41
|
+
stdout: string;
|
|
42
|
+
stderr: string;
|
|
43
|
+
stdout_digest: string;
|
|
44
|
+
stderr_digest: string;
|
|
45
|
+
}
|
|
46
|
+
export interface VelaWithdrawalResult {
|
|
47
|
+
proposal_id: string;
|
|
48
|
+
withdrawal_event_id: string;
|
|
49
|
+
withdrawn_at: string;
|
|
50
|
+
state_root_before: string;
|
|
51
|
+
state_root_after: string;
|
|
52
|
+
publication_commit: string;
|
|
53
|
+
}
|
|
54
|
+
export declare function strictBaselineFromCheck(check: Record<string, unknown>): StrictBaseline;
|
|
55
|
+
export declare function validateLandResult(mission: Mission, raw: Record<string, unknown>): LandResult;
|
|
56
|
+
export declare class VelaClient {
|
|
57
|
+
#private;
|
|
58
|
+
constructor(options: VelaClientOptions);
|
|
59
|
+
observeStrictBaseline(repoRoot: string, frontier: string): Promise<StrictBaseline>;
|
|
60
|
+
assertVersion(cwd: string): Promise<string>;
|
|
61
|
+
inspect(repoRoot: string, frontier: string, strictBaseline?: StrictBaseline): Promise<VelaInspection>;
|
|
62
|
+
assertRoots(repoRoot: string, frontier: string, expected: MissionRoots, strictBaseline?: StrictBaseline): Promise<VelaInspection>;
|
|
63
|
+
next(mission: Mission, repoRoot: string): Promise<VelaCommandResponse>;
|
|
64
|
+
offer(repoRoot: string, frontier: string, roots: MissionRoots, strictBaseline?: StrictBaseline, limit?: number): Promise<VelaCommandResponse>;
|
|
65
|
+
work(mission: Mission, repoRoot: string, target: string, expected: MissionRoots): Promise<VelaCommandResponse>;
|
|
66
|
+
withdraw(repoRoot: string, frontier: string, proposalId: string, actor: string, reason: string): Promise<VelaWithdrawalResult>;
|
|
67
|
+
landAuthoredCommand(mission: Mission, repoRoot: string, input: AuthoredReceiptInput, _expected: MissionRoots): Promise<VelaLandCommandObservation>;
|
|
68
|
+
parseLandCommand(observation: VelaLandCommandObservation): Record<string, unknown>;
|
|
69
|
+
validateLandResult(mission: Mission, raw: Record<string, unknown>): LandResult;
|
|
70
|
+
verifyReceiptBinding(mission: Mission, repoRoot: string, landing: LandResult, input: AuthoredReceiptInput, artifacts: readonly FrozenArtifact[]): Promise<void>;
|
|
71
|
+
}
|