@mettlelabs/mettle 0.0.0-beta.1 → 0.0.0-beta.1-linux-x64

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/THIRD_PARTY_NOTICES.md +11479 -0
  2. package/bin/mettle +4 -0
  3. package/harness/audit-investigation.mjs +203 -0
  4. package/harness/chunk-13tgmdey.mjs +33761 -0
  5. package/harness/chunk-1sygmp11.mjs +18142 -0
  6. package/harness/chunk-1ykxpmaz.mjs +7887 -0
  7. package/harness/chunk-2gt4cy7x.mjs +2290 -0
  8. package/harness/chunk-2pm2sayw.mjs +248 -0
  9. package/harness/chunk-32y07kkp.mjs +3747 -0
  10. package/harness/chunk-3m7jn5ac.mjs +16242 -0
  11. package/harness/chunk-3wvjs93w.mjs +538 -0
  12. package/harness/chunk-4bepyxmq.mjs +113 -0
  13. package/harness/chunk-4jtnt9k5.mjs +95 -0
  14. package/harness/chunk-50sbrf09.mjs +18972 -0
  15. package/harness/chunk-56csr8sw.mjs +322 -0
  16. package/harness/chunk-5cvb1jnb.mjs +41 -0
  17. package/harness/chunk-5wgmv4np.mjs +585 -0
  18. package/harness/chunk-65eyq32y.mjs +225 -0
  19. package/harness/chunk-6fnh6qhk.mjs +195 -0
  20. package/harness/chunk-6kgqw9ny.mjs +32303 -0
  21. package/harness/chunk-7b242j0n.mjs +14 -0
  22. package/harness/chunk-7bg2gnv2.mjs +7540 -0
  23. package/harness/chunk-ageqxj9v.mjs +63008 -0
  24. package/harness/chunk-b0qbt5jd.mjs +14 -0
  25. package/harness/chunk-b5g1r3fz.mjs +4785 -0
  26. package/harness/chunk-b71gpkxg.mjs +1514 -0
  27. package/harness/chunk-bdv1rx4a.mjs +20364 -0
  28. package/harness/chunk-c1631s2x.mjs +12241 -0
  29. package/harness/chunk-d5xgxsnp.mjs +74 -0
  30. package/harness/chunk-erg1fbh0.mjs +0 -0
  31. package/harness/chunk-fh78v9vn.mjs +19366 -0
  32. package/harness/chunk-fjx29qvp.mjs +50 -0
  33. package/harness/chunk-gryka6kg.mjs +39 -0
  34. package/harness/chunk-jb0r19et.mjs +180 -0
  35. package/harness/chunk-mfn574ss.mjs +179 -0
  36. package/harness/chunk-msg872ea.mjs +334 -0
  37. package/harness/chunk-nz5sv9as.mjs +1642 -0
  38. package/harness/chunk-p9d3cgvq.mjs +452 -0
  39. package/harness/chunk-pq6wvwxr.mjs +12 -0
  40. package/harness/chunk-qcm9arf8.mjs +7736 -0
  41. package/harness/chunk-qr8zfqjd.mjs +24 -0
  42. package/harness/chunk-rz2tz6jp.mjs +26 -0
  43. package/harness/chunk-sbkgc3kn.mjs +8 -0
  44. package/harness/chunk-v66qvpnb.mjs +169 -0
  45. package/harness/chunk-vjaxzab3.mjs +136 -0
  46. package/harness/chunk-vr1n5nza.mjs +1045 -0
  47. package/harness/chunk-vsf2zajv.mjs +3867 -0
  48. package/harness/chunk-wq253fj4.mjs +19041 -0
  49. package/harness/chunk-wyv7ceq4.mjs +0 -0
  50. package/harness/chunk-xnqknk2r.mjs +198 -0
  51. package/harness/chunk-xqyc4ca2.mjs +1890 -0
  52. package/harness/chunk-z6n9thea.mjs +45146 -0
  53. package/harness/chunk-zty0d3bw.mjs +0 -0
  54. package/harness/chunk-zvkxtj82.mjs +42 -0
  55. package/harness/issue-api-token.mjs +35 -0
  56. package/harness/launcher.mjs +159 -0
  57. package/harness/sandbox.mjs +132 -0
  58. package/harness/server.mjs +66322 -0
  59. package/package.json +13 -15
  60. package/bin/mettle.js +0 -51
File without changes
@@ -0,0 +1,42 @@
1
+ import {
2
+ string,
3
+ number,
4
+ array,
5
+ strictObject,
6
+ _enum
7
+ } from "./chunk-1sygmp11.mjs";
8
+
9
+ // apps/harness/src/access.ts
10
+ var identity = string().min(1).max(256);
11
+ var RunAuthoritySchema = strictObject({
12
+ tenantId: identity,
13
+ actorId: identity,
14
+ engagementId: identity,
15
+ policyRevision: identity
16
+ });
17
+ var ApiPrincipalSchema = RunAuthoritySchema.extend({
18
+ permissions: array(_enum([
19
+ "run:create",
20
+ "engagement:create",
21
+ "run:read",
22
+ "run:control",
23
+ "run:recover",
24
+ "run:delete"
25
+ ])).min(1).refine((permissions) => new Set(permissions).size === permissions.length),
26
+ expiresAt: number().int().positive()
27
+ });
28
+ var ApiTokenRecordSchema = strictObject({
29
+ tokenSha256: string().regex(/^[a-f0-9]{64}$/),
30
+ principal: ApiPrincipalSchema
31
+ });
32
+ var BEARER_TOKEN_PATTERN = /^Bearer ([A-Za-z0-9_-]{43})$/;
33
+ function authorityFor(principal) {
34
+ return RunAuthoritySchema.parse({
35
+ tenantId: principal.tenantId,
36
+ actorId: principal.actorId,
37
+ engagementId: principal.engagementId,
38
+ policyRevision: principal.policyRevision
39
+ });
40
+ }
41
+
42
+ export { RunAuthoritySchema, ApiPrincipalSchema, ApiTokenRecordSchema, BEARER_TOKEN_PATTERN, authorityFor };
@@ -0,0 +1,35 @@
1
+ import"./chunk-2gt4cy7x.mjs";
2
+ import"./chunk-zvkxtj82.mjs";
3
+ import {
4
+ writeApiTokenFiles
5
+ } from "./chunk-4jtnt9k5.mjs";
6
+
7
+ // apps/harness/scripts/issue-api-token.ts
8
+ import { readFile } from "node:fs/promises";
9
+ import { parseArgs } from "node:util";
10
+ try {
11
+ const { values } = parseArgs({
12
+ options: {
13
+ request: { type: "string" },
14
+ "output-dir": { type: "string" },
15
+ help: { type: "boolean" }
16
+ },
17
+ strict: true,
18
+ allowPositionals: false
19
+ });
20
+ if (values.help) {
21
+ process.stdout.write(`Usage: issue-api-token --request <request.json> --output-dir <new-private-directory>
22
+ `);
23
+ } else {
24
+ if (!values.request || !values["output-dir"])
25
+ throw new Error("Explicit request and output directory required.");
26
+ const request = JSON.parse(await readFile(values.request, "utf8"));
27
+ const result = await writeApiTokenFiles(request, values["output-dir"]);
28
+ process.stdout.write(`${JSON.stringify(result)}
29
+ `);
30
+ }
31
+ } catch {
32
+ process.stderr.write(`API token issuance failed. Check the request, existing parent directory, and unused output path; no credentials printed.
33
+ `);
34
+ process.exitCode = 1;
35
+ }
@@ -0,0 +1,159 @@
1
+ import {
2
+ CONTRACT_VERSION,
3
+ RunConfigSchema,
4
+ HarnessError,
5
+ publicError,
6
+ COORDINATOR_TARGET
7
+ } from "./chunk-2gt4cy7x.mjs";
8
+ import {
9
+ RunAuthoritySchema
10
+ } from "./chunk-zvkxtj82.mjs";
11
+ import {
12
+ SandboxConfigSchema,
13
+ DockerEngine,
14
+ checkSandbox
15
+ } from "./chunk-xqyc4ca2.mjs";
16
+ import {
17
+ liveRoute,
18
+ liveProfiles,
19
+ loadInvestigationGrant,
20
+ SOURCE_TOTAL_BYTES,
21
+ SOURCE_FILES_MAX,
22
+ InvestigationProfilesSchema
23
+ } from "./chunk-32y07kkp.mjs";
24
+ import {
25
+ privateFile,
26
+ ownedDirectory
27
+ } from "./chunk-7bg2gnv2.mjs";
28
+
29
+ // apps/harness/scripts/launcher.ts
30
+ import { parseArgs } from "node:util";
31
+
32
+ // apps/harness/src/runtime/launcher.ts
33
+ import { join } from "node:path";
34
+ function launchTokenRequest() {
35
+ return {
36
+ tenantId: "local-team",
37
+ actorId: "operator",
38
+ engagementId: "counter-development",
39
+ policyRevision: "v1",
40
+ permissions: [
41
+ "run:create",
42
+ "run:read",
43
+ "run:control",
44
+ "run:recover",
45
+ "engagement:create"
46
+ ],
47
+ ttlSeconds: 86400
48
+ };
49
+ }
50
+ function launchRunConfig(environment) {
51
+ return RunConfigSchema.parse({
52
+ contractVersion: CONTRACT_VERSION,
53
+ model: liveRoute(environment).model
54
+ });
55
+ }
56
+ async function investigationProfiles(setup) {
57
+ const { environment, location = "local", engineId } = setup;
58
+ const { tenantId, actorId, engagementId, policyRevision } = launchTokenRequest();
59
+ const base = {
60
+ authority: setup.authority ?? RunAuthoritySchema.parse({
61
+ tenantId,
62
+ actorId,
63
+ engagementId,
64
+ policyRevision
65
+ }),
66
+ models: liveProfiles(environment).map((model) => ({
67
+ id: model.route.model,
68
+ provider: model.route.provider
69
+ })),
70
+ expiresAt: setup.expiresAt ?? new Date(Date.now() + launchTokenRequest().ttlSeconds * 1000).toISOString(),
71
+ stages: { maxWorkers: 2, huntPartitions: 2 }
72
+ };
73
+ const pinned = async (input) => {
74
+ const config = SandboxConfigSchema.parse(input);
75
+ if (location === "vm" && !engineId)
76
+ throw new HarnessError("investigation_config", "VM setup requires --engine-id from the designated VM, independently of the forwarded socket.");
77
+ const engine = await checkSandbox({ ...config, ...engineId ? { engineId } : {} }, setup.engine ?? new DockerEngine(config.socket));
78
+ return SandboxConfigSchema.parse({ ...config, engineId: engine, location });
79
+ };
80
+ const profiles = [];
81
+ if (setup.review) {
82
+ if (setup.githubTokenFile)
83
+ await privateFile(setup.githubTokenFile, 4096);
84
+ const localRoot = setup.localRoot ? await ownedDirectory(setup.localRoot, new HarnessError("investigation_config", "The local review root must be a directory owned by this operator.")) : undefined;
85
+ profiles.push({
86
+ ...base,
87
+ id: `${location}-review`,
88
+ mode: "codereview",
89
+ sandbox: await pinned({
90
+ image: environment.HARNESS_SANDBOX_IMAGE,
91
+ socket: environment.HARNESS_SANDBOX_SOCKET,
92
+ runtime: environment.HARNESS_SANDBOX_RUNTIME
93
+ }),
94
+ workspaceRoot: join(setup.directory, "snapshots"),
95
+ ...localRoot ? { localRoot } : {},
96
+ maxFiles: SOURCE_FILES_MAX,
97
+ maxSourceBytes: SOURCE_TOTAL_BYTES,
98
+ allowPatchProposals: true,
99
+ ...setup.githubTokenFile ? { githubTokenFile: setup.githubTokenFile } : {}
100
+ });
101
+ }
102
+ if (setup.pentestGrant) {
103
+ const grant = await loadInvestigationGrant(setup.pentestGrant);
104
+ if (grant.mode !== "pentest")
105
+ throw new HarnessError("investigation_config", "The pentest profile requires a pentest grant.");
106
+ if (location === "vm" && !grant.sandbox)
107
+ throw new HarnessError("investigation_config", "VM profiles require an isolated live target grant.");
108
+ profiles.push({
109
+ ...base,
110
+ id: `${location}-pentest`,
111
+ mode: "pentest",
112
+ grant: {
113
+ ...grant,
114
+ ...grant.sandbox ? { sandbox: await pinned(grant.sandbox) } : {}
115
+ }
116
+ });
117
+ }
118
+ return InvestigationProfilesSchema.parse(profiles);
119
+ }
120
+
121
+ // apps/harness/scripts/launcher.ts
122
+ var USAGE = "Usage: launcher.ts token-request | run-config | investigation-profiles --directory <path> [--github-token-file <path>]";
123
+ try {
124
+ const { positionals, values } = parseArgs({
125
+ strict: true,
126
+ allowPositionals: true,
127
+ options: {
128
+ directory: { type: "string" },
129
+ "github-token-file": { type: "string" }
130
+ }
131
+ });
132
+ const [command] = positionals;
133
+ if (positionals.length !== 1 || command !== "investigation-profiles" && Object.keys(values).length > 0)
134
+ throw new Error(USAGE);
135
+ if (command === "token-request")
136
+ process.stdout.write(`${JSON.stringify(launchTokenRequest())}
137
+ `);
138
+ else if (command === "run-config")
139
+ process.stdout.write(`${JSON.stringify({
140
+ target: COORDINATOR_TARGET,
141
+ config: launchRunConfig(process.env)
142
+ })}
143
+ `);
144
+ else if (command === "investigation-profiles" && values.directory) {
145
+ const profiles = await investigationProfiles({
146
+ environment: process.env,
147
+ directory: values.directory,
148
+ review: true,
149
+ ...values["github-token-file"] ? { githubTokenFile: values["github-token-file"] } : {}
150
+ });
151
+ process.stdout.write(`${JSON.stringify(profiles, null, 2)}
152
+ `);
153
+ } else
154
+ throw new Error(USAGE);
155
+ } catch (error) {
156
+ process.stderr.write(`${error instanceof Error && error.message === USAGE ? USAGE : publicError(error)}
157
+ `);
158
+ process.exitCode = 1;
159
+ }
@@ -0,0 +1,132 @@
1
+ import {
2
+ HarnessError,
3
+ publicError,
4
+ FIXTURE_TARGET,
5
+ fixtureConfig
6
+ } from "./chunk-2gt4cy7x.mjs";
7
+ import {
8
+ ToolExecutor,
9
+ SandboxProbeJournal,
10
+ SandboxJournal,
11
+ reapSandboxes
12
+ } from "./chunk-msg872ea.mjs";
13
+ import {
14
+ sandboxRuntime,
15
+ PROBE_TOOL,
16
+ ToolRegistry,
17
+ DockerEngine,
18
+ sandboxConfig,
19
+ checkSandbox,
20
+ SandboxWorker
21
+ } from "./chunk-xqyc4ca2.mjs";
22
+ import"./chunk-7bg2gnv2.mjs";
23
+ import"./chunk-zvkxtj82.mjs";
24
+ import {
25
+ databaseConfig
26
+ } from "./chunk-5cvb1jnb.mjs";
27
+ import {
28
+ uuid
29
+ } from "./chunk-1sygmp11.mjs";
30
+
31
+ // apps/harness/src/sandbox/probe.ts
32
+ import { randomUUID } from "node:crypto";
33
+ async function sandboxProbe(args) {
34
+ const [command, argument] = args;
35
+ if (!["check", "run", "cleanup", "reap"].includes(command ?? "") || args.length !== (command === "cleanup" ? 2 : 1) || command === "cleanup" && !uuid().safeParse(argument).success)
36
+ throw new HarnessError("sandbox_command", "Use sandbox check, run, reap, or cleanup <runId>.");
37
+ const config = sandboxConfig();
38
+ const engine = new DockerEngine(config.socket);
39
+ if (command === "check") {
40
+ const workerId = await checkSandbox(config, engine);
41
+ console.log(JSON.stringify({
42
+ configured: true,
43
+ runtime: sandboxRuntime(config),
44
+ workerId,
45
+ image: config.image,
46
+ executed: false,
47
+ productionApproved: false
48
+ }));
49
+ return;
50
+ }
51
+ const journal = new SandboxProbeJournal(databaseConfig());
52
+ const controller = new AbortController;
53
+ let lease;
54
+ let heartbeat;
55
+ let heartbeatTask;
56
+ const stop = () => controller.abort();
57
+ process.on("SIGINT", stop);
58
+ process.on("SIGTERM", stop);
59
+ try {
60
+ if (command === "reap") {
61
+ const report = await reapSandboxes(config, engine, journal, controller.signal);
62
+ console.log(JSON.stringify(report));
63
+ if (report.interrupted || report.outcomes.some((outcome) => outcome.status === "blocked"))
64
+ process.exitCode = 1;
65
+ return;
66
+ }
67
+ if (command === "run")
68
+ await checkSandbox(config, engine);
69
+ const runId = argument ?? randomUUID();
70
+ if (command === "run")
71
+ await journal.createRun(runId, FIXTURE_TARGET, fixtureConfig());
72
+ lease = await journal.acquire(runId);
73
+ const owned = lease;
74
+ heartbeat = setInterval(() => {
75
+ if (heartbeatTask)
76
+ return;
77
+ heartbeatTask = journal.heartbeat(owned).then(async () => {
78
+ if ((await journal.read(runId)).stopRequested)
79
+ controller.abort();
80
+ }).catch(() => controller.abort()).finally(() => {
81
+ heartbeatTask = undefined;
82
+ });
83
+ }, 1000);
84
+ const worker = new SandboxWorker(config, engine, new SandboxJournal(journal, lease));
85
+ if (command === "cleanup") {
86
+ const removed = await worker.reap();
87
+ console.log(JSON.stringify({
88
+ runId,
89
+ removed,
90
+ actionReplayed: false,
91
+ actionReconciled: false
92
+ }));
93
+ return;
94
+ }
95
+ console.log(JSON.stringify({
96
+ runId,
97
+ diagnostic: "offline-sandbox-probe",
98
+ providerCalls: 0
99
+ }));
100
+ const callId = "sandbox-probe-1";
101
+ await journal.beginModel(lease, "sandbox-diagnostic", {
102
+ diagnostic: "offline-sandbox-probe"
103
+ });
104
+ await journal.completeModel(lease, "sandbox-diagnostic", {
105
+ tool_calls: [{ id: callId, name: PROBE_TOOL, args: {} }]
106
+ });
107
+ const executor = new ToolExecutor(journal, lease, controller.signal, new ToolRegistry([worker.tool()]));
108
+ const result = JSON.parse(await executor.execute(callId, PROBE_TOOL, {}));
109
+ await journal.finish(lease, "completed");
110
+ console.log(JSON.stringify({ runId, ...result, productionApproved: false }));
111
+ } finally {
112
+ controller.abort();
113
+ if (heartbeat)
114
+ clearInterval(heartbeat);
115
+ await heartbeatTask;
116
+ if (lease)
117
+ await journal.release(lease).catch(() => {
118
+ return;
119
+ });
120
+ await journal.close();
121
+ process.off("SIGINT", stop);
122
+ process.off("SIGTERM", stop);
123
+ }
124
+ }
125
+
126
+ // apps/harness/scripts/sandbox.ts
127
+ try {
128
+ await sandboxProbe(process.argv.slice(2));
129
+ } catch (error) {
130
+ console.error(publicError(error));
131
+ process.exitCode = 1;
132
+ }