agent-hitch 0.2.13 → 0.2.14

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 (126) hide show
  1. package/benchmark-packages/automationbench/RESOURCES.md +27 -0
  2. package/benchmark-packages/automationbench/resources.mjs +86 -0
  3. package/benchmark-packages/shared-tree/README.md +14 -0
  4. package/benchmark-packages/shared-tree/import.mjs +39 -0
  5. package/dist/scripts/canary-automation-resources.js +86 -0
  6. package/dist/scripts/canary-automation-resources.js.map +1 -0
  7. package/dist/scripts/canary-resource-empty-daemon.js +195 -0
  8. package/dist/scripts/canary-resource-empty-daemon.js.map +1 -0
  9. package/dist/scripts/canary-resources.js +89 -0
  10. package/dist/scripts/canary-resources.js.map +1 -0
  11. package/dist/scripts/check-architecture.js +6 -5
  12. package/dist/scripts/check-architecture.js.map +1 -1
  13. package/dist/scripts/resource-space-sampler.js +83 -0
  14. package/dist/scripts/resource-space-sampler.js.map +1 -0
  15. package/dist/src/backends/harbor/backend.js +5 -1
  16. package/dist/src/backends/harbor/backend.js.map +1 -1
  17. package/dist/src/backends/harbor/resource-admission.js +23 -0
  18. package/dist/src/backends/harbor/resource-admission.js.map +1 -0
  19. package/dist/src/cli/commands/resources.js +23 -0
  20. package/dist/src/cli/commands/resources.js.map +1 -0
  21. package/dist/src/cli/main.js +2 -0
  22. package/dist/src/cli/main.js.map +1 -1
  23. package/dist/src/control-plane/remote-offer-contract.js +11 -2
  24. package/dist/src/control-plane/remote-offer-contract.js.map +1 -1
  25. package/dist/src/control-plane/remote-result-transport.js +10 -0
  26. package/dist/src/control-plane/remote-result-transport.js.map +1 -1
  27. package/dist/src/control-plane/remote-work-coordinator.js +4 -1
  28. package/dist/src/control-plane/remote-work-coordinator.js.map +1 -1
  29. package/dist/src/control-plane/remote-work-inputs.js +16 -4
  30. package/dist/src/control-plane/remote-work-inputs.js.map +1 -1
  31. package/dist/src/control-plane/remote-worker-client.js +22 -0
  32. package/dist/src/control-plane/remote-worker-client.js.map +1 -1
  33. package/dist/src/control-plane/remote-worker-codecs.js +1 -1
  34. package/dist/src/control-plane/remote-worker-codecs.js.map +1 -1
  35. package/dist/src/control-plane/remote-worker-protocol.js +12 -2
  36. package/dist/src/control-plane/remote-worker-protocol.js.map +1 -1
  37. package/dist/src/control-plane/remote-worker-runner.js +1 -1
  38. package/dist/src/control-plane/remote-worker-runner.js.map +1 -1
  39. package/dist/src/control-plane/remote-workers.js +2 -1
  40. package/dist/src/control-plane/remote-workers.js.map +1 -1
  41. package/dist/src/evals/benchmark-adapter-manifest.js +4 -0
  42. package/dist/src/evals/benchmark-adapter-manifest.js.map +1 -1
  43. package/dist/src/evals/benchmark-candidate.js +11 -3
  44. package/dist/src/evals/benchmark-candidate.js.map +1 -1
  45. package/dist/src/evals/eval-result-builder.js +22 -1
  46. package/dist/src/evals/eval-result-builder.js.map +1 -1
  47. package/dist/src/evals/index.js +1 -0
  48. package/dist/src/evals/index.js.map +1 -1
  49. package/dist/src/evals/planned-execution.js +5 -14
  50. package/dist/src/evals/planned-execution.js.map +1 -1
  51. package/dist/src/evals/request.js +9 -0
  52. package/dist/src/evals/request.js.map +1 -1
  53. package/dist/src/evals/resource-eval-lifecycle.js +31 -0
  54. package/dist/src/evals/resource-eval-lifecycle.js.map +1 -0
  55. package/dist/src/evals/resource-legacy-export.js +57 -0
  56. package/dist/src/evals/resource-legacy-export.js.map +1 -0
  57. package/dist/src/evals/service.js +5 -20
  58. package/dist/src/evals/service.js.map +1 -1
  59. package/dist/src/evals/task-resources.js +12 -4
  60. package/dist/src/evals/task-resources.js.map +1 -1
  61. package/dist/src/evals/trial-bundle-files.js +81 -0
  62. package/dist/src/evals/trial-bundle-files.js.map +1 -0
  63. package/dist/src/evals/trial-import.js +7 -78
  64. package/dist/src/evals/trial-import.js.map +1 -1
  65. package/dist/src/foundation/durable-json.js +33 -0
  66. package/dist/src/foundation/durable-json.js.map +1 -0
  67. package/dist/src/foundation/index.js +2 -0
  68. package/dist/src/foundation/index.js.map +1 -1
  69. package/dist/src/foundation/resource-image-references.js +52 -0
  70. package/dist/src/foundation/resource-image-references.js.map +1 -0
  71. package/dist/src/images/gc.js +2 -2
  72. package/dist/src/images/gc.js.map +1 -1
  73. package/dist/src/images/registry.js +27 -2
  74. package/dist/src/images/registry.js.map +1 -1
  75. package/dist/src/resources/api.js +207 -0
  76. package/dist/src/resources/api.js.map +1 -0
  77. package/dist/src/resources/bundle.js +117 -0
  78. package/dist/src/resources/bundle.js.map +1 -0
  79. package/dist/src/resources/evidence.js +93 -0
  80. package/dist/src/resources/evidence.js.map +1 -0
  81. package/dist/src/resources/gc.js +123 -0
  82. package/dist/src/resources/gc.js.map +1 -0
  83. package/dist/src/resources/index.js +14 -0
  84. package/dist/src/resources/index.js.map +1 -0
  85. package/dist/src/resources/materialize.js +143 -0
  86. package/dist/src/resources/materialize.js.map +1 -0
  87. package/dist/src/resources/object-store.js +191 -0
  88. package/dist/src/resources/object-store.js.map +1 -0
  89. package/dist/src/resources/oci-layer-validation.js +202 -0
  90. package/dist/src/resources/oci-layer-validation.js.map +1 -0
  91. package/dist/src/resources/oci-provider.js +101 -0
  92. package/dist/src/resources/oci-provider.js.map +1 -0
  93. package/dist/src/resources/oci-registry-bundle.js +253 -0
  94. package/dist/src/resources/oci-registry-bundle.js.map +1 -0
  95. package/dist/src/resources/protocol.js +222 -0
  96. package/dist/src/resources/protocol.js.map +1 -0
  97. package/dist/src/resources/result-retention.js +93 -0
  98. package/dist/src/resources/result-retention.js.map +1 -0
  99. package/dist/src/resources/role-context.js +54 -0
  100. package/dist/src/resources/role-context.js.map +1 -0
  101. package/dist/src/resources/stats.js +36 -0
  102. package/dist/src/resources/stats.js.map +1 -0
  103. package/dist/src/resources/store.js +310 -0
  104. package/dist/src/resources/store.js.map +1 -0
  105. package/dist/src/resources/tasks.js +153 -0
  106. package/dist/src/resources/tasks.js.map +1 -0
  107. package/dist/src/resources/transfer.js +162 -0
  108. package/dist/src/resources/transfer.js.map +1 -0
  109. package/dist/src/resources/views.js +130 -0
  110. package/dist/src/resources/views.js.map +1 -0
  111. package/dist/src/workers/remote-harbor-work-spec.js +9 -3
  112. package/dist/src/workers/remote-harbor-work-spec.js.map +1 -1
  113. package/dist/src/workers/remote-harbor-worker.js +24 -9
  114. package/dist/src/workers/remote-harbor-worker.js.map +1 -1
  115. package/docs/resource-storage.zh-CN.md +95 -0
  116. package/docs/schemas/execution-provider-status.schema.json +20 -0
  117. package/docs/schemas/hitch-resource-dataset-v2.schema.json +590 -0
  118. package/docs/schemas/hitch-resource-lock-v1.schema.json +341 -0
  119. package/docs/schemas/hitch-resource-plan-v1.schema.json +423 -0
  120. package/docs/schemas/hitch-resource-selection-v1.schema.json +608 -0
  121. package/docs/schemas/hitch-tree-v1.schema.json +75 -0
  122. package/docs/schemas/remote-harbor-work-spec.schema.json +47 -3
  123. package/docs/schemas/remote-work-offer.schema.json +2 -1
  124. package/docs/schemas/remote-worker-registration.schema.json +20 -0
  125. package/package.json +9 -3
  126. package/test-contracts/hitch-resources-v1.json +197 -0
@@ -0,0 +1,207 @@
1
+ import { lstat, readFile, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { DockerRegistryResolver } from "../images/index.js";
4
+ import { durableWriteJSON as atomicWriteJSON } from "../foundation/index.js";
5
+ import { auditResources } from "./gc.js";
6
+ import { materializeResourceTask, finishResourceWorkspace } from "./materialize.js";
7
+ import { DockerResourceImageProvider } from "./oci-provider.js";
8
+ import { localRegistry } from "./oci-registry-bundle.js";
9
+ import { identity, object, parseStrictJson, resourceId } from "./protocol.js";
10
+ import { limits } from "./object-store.js";
11
+ import { ResourceStore } from "./store.js";
12
+ import { exportResourceBundle, importResourceBundle } from "./bundle.js";
13
+ import { resourceStorageStats } from "./stats.js";
14
+ import { parseResourceDataset, preflightResourceTask, readResourceInput, sealResourceTask, selectResources, RESOURCE_EXECUTION_CAPABILITIES } from "./tasks.js";
15
+ export async function configuredResourceStore(root) {
16
+ let config = { protocol: "hitch-resource-host@1", transport: {}, imagePolicy: "cache-first", platform: "linux/amd64", workspace: {} };
17
+ try {
18
+ config = parseHostConfig(parseStrictJson(await readFile(path.join(root, "resource-config.json"), "utf8")));
19
+ }
20
+ catch (error) {
21
+ if (error.code !== "ENOENT")
22
+ throw error;
23
+ }
24
+ return { store: new ResourceStore(root, { ...(config.limits ? { limits: config.limits } : {}), images: new DockerResourceImageProvider(root, config.transport, new DockerRegistryResolver({ policy: config.imagePolicy }), config.offline, config.imagePolicy, limits(config.limits)) }), config };
25
+ }
26
+ export async function preflightResourceInput(store, ref, options) {
27
+ return store.admission(() => preflightInput(store, ref, options));
28
+ }
29
+ async function preflightInput(store, ref, options) {
30
+ const source = await readResourceInput(ref);
31
+ if (!source)
32
+ return undefined;
33
+ const execution = "schema_version" in source ? source.execution : source.manifest.execution;
34
+ if (execution.platform !== options.platform)
35
+ throw new Error("resource execution platform differs from the frozen plan");
36
+ const capabilities = "schema_version" in source ? source.required_capabilities : source.manifest.required_capabilities;
37
+ for (const c of capabilities)
38
+ if (!RESOURCE_EXECUTION_CAPABILITIES.includes(c))
39
+ throw new Error(`unsupported required resource capability: ${c}`);
40
+ const isDirectory = (await lstat(ref)).isDirectory(), plans = [];
41
+ for (const task of source.tasks) {
42
+ if (isDirectory) {
43
+ const actual = await store.import(path.join(ref, task.task_id), "tree", `${options.owner}:source-check`, options.signal);
44
+ await store.finishLease(actual.leaseId, "ended");
45
+ if (identity("hitch-source-task@1", actual.resource) !== task.source_task_digest)
46
+ throw new Error("local task descriptor changed since sealing");
47
+ }
48
+ plans.push((await preflightResourceTask(store, task, { ...options, owner: `${options.owner}:${task.task_id}` })).plan);
49
+ }
50
+ const inputDigest = "schema_version" in source ? source.dataset_digest : source.digest;
51
+ return { protocol: "hitch-resource-preflight@1", inputDigest, plans, planDigest: identity("hitch-resource-preflight@1", { inputDigest, plans: plans.map(p => ({ taskId: p.task.task_id, digest: p.digest })) }) };
52
+ }
53
+ export async function resourceRequest(root, operation, value) {
54
+ if (operation === "capabilities")
55
+ return { protocol: "hitch-resources-api@1", capabilities: RESOURCE_EXECUTION_CAPABILITIES, selections: "hitch-resource-selection@1" };
56
+ if (operation === "configure") {
57
+ const config = parseHostConfig(value);
58
+ await atomicWriteJSON(path.join(root, "resource-config.json"), config);
59
+ return config;
60
+ }
61
+ const { store, config } = await configuredResourceStore(root);
62
+ switch (operation) {
63
+ case "inspect": {
64
+ object(value, []);
65
+ return resourceStorageStats(store);
66
+ }
67
+ case "import": {
68
+ const input = object(value, ["source", "kind", "owner"]);
69
+ if (typeof input.source !== "string" || typeof input.owner !== "string" || input.kind !== "blob" && input.kind !== "tree")
70
+ throw new TypeError("invalid resource import request");
71
+ return store.import(path.resolve(input.source), input.kind, input.owner);
72
+ }
73
+ case "pin": {
74
+ const input = object(value, ["owner", "generation", "purpose", "lock"]);
75
+ return store.pin(input);
76
+ }
77
+ case "release": {
78
+ const input = object(value, ["owner", "generation"]);
79
+ await store.release(input.owner, input.generation);
80
+ return { released: true };
81
+ }
82
+ case "lease-end": {
83
+ const input = object(value, ["leaseId", "confirmation"]);
84
+ if (typeof input.leaseId !== "string" || !["ended", "unknown"].includes(String(input.confirmation)))
85
+ throw new TypeError("invalid lease confirmation");
86
+ await store.finishLease(input.leaseId, input.confirmation);
87
+ return { acknowledged: true };
88
+ }
89
+ case "audit": {
90
+ const input = object(value, ["apply", "graceMs"]);
91
+ if (input.apply !== undefined && typeof input.apply !== "boolean")
92
+ throw new TypeError("apply must be explicit boolean");
93
+ return auditResources(store, input);
94
+ }
95
+ case "bundle-export": {
96
+ const input = object(value, ["ref", "output", "owner"]);
97
+ if (typeof input.ref !== "string" || typeof input.output !== "string" || typeof input.owner !== "string")
98
+ throw new TypeError("invalid bundle export request");
99
+ const source = await readResourceInput(input.ref);
100
+ if (!source)
101
+ throw new Error("resource input required");
102
+ const selection = "schema_version" in source ? selectResources(source, source.tasks.map(t => t.task_id)) : source;
103
+ return exportResourceBundle(store, selection, input.output, input.owner);
104
+ }
105
+ case "bundle-import": {
106
+ const input = object(value, ["directory", "owner", "output"]);
107
+ if (typeof input.directory !== "string" || typeof input.owner !== "string" || typeof input.output !== "string")
108
+ throw new TypeError("invalid bundle import request");
109
+ if (config.imagePolicy !== "cache-only")
110
+ throw new Error("offline bundle import requires cache-only image policy");
111
+ const result = await importResourceBundle(store, input.directory, input.owner);
112
+ await writeFile(input.output, JSON.stringify(result.selection), { flag: "wx", mode: 0o600 });
113
+ return result;
114
+ }
115
+ case "seal-dataset": {
116
+ const input = object(value, ["directory", "owner", "manifest", "taskIds"]);
117
+ if (typeof input.directory !== "string" || typeof input.owner !== "string" || !Array.isArray(input.taskIds) || input.taskIds.some(id => typeof id !== "string"))
118
+ throw new TypeError("invalid dataset seal request");
119
+ const directory = input.directory, owner = input.owner, taskIds = input.taskIds;
120
+ return store.admission(async () => {
121
+ const metadata = object(input.manifest, ["benchmark", "adapter", "scoring", "raw_metrics", "required_capabilities", "execution"]);
122
+ const tasks = [];
123
+ for (const id of [...taskIds].sort()) {
124
+ resourceId(id);
125
+ tasks.push(await sealResourceTask(store, path.join(directory, id), id, `${owner}:${id}`));
126
+ }
127
+ const body = { schema_version: "2", kind: "gear-harbor-benchmark", resource_protocol: "hitch-resource-lock@1", ...metadata, tasks };
128
+ const manifest = parseResourceDataset({ ...body, dataset_digest: identity("hitch-resource-dataset@2", body) });
129
+ if (manifest.execution.platform !== config.platform)
130
+ throw new Error("resource execution platform differs from host");
131
+ for (const capability of manifest.required_capabilities)
132
+ if (!RESOURCE_EXECUTION_CAPABILITIES.includes(capability))
133
+ throw new Error(`unsupported required resource capability: ${capability}`);
134
+ for (const task of tasks)
135
+ await preflightResourceTask(store, task, { owner: `${owner}:admission:${task.task_id}`, generation: 1, platform: config.platform });
136
+ await writeFile(path.join(directory, "benchmark.adapter.json"), `${JSON.stringify(manifest, null, 2)}\n`, { flag: "wx", mode: 0o600 });
137
+ return manifest;
138
+ });
139
+ }
140
+ case "seal-task": {
141
+ const input = object(value, ["directory", "taskId", "owner"]);
142
+ if ([input.directory, input.taskId, input.owner].some(v => typeof v !== "string"))
143
+ throw new TypeError("invalid task seal request");
144
+ return sealResourceTask(store, input.directory, input.taskId, input.owner);
145
+ }
146
+ case "preflight": {
147
+ const input = object(value, ["ref", "owner", "generation", "platform"]);
148
+ if (typeof input.ref !== "string" || typeof input.owner !== "string")
149
+ throw new TypeError("invalid preflight request");
150
+ return preflightResourceInput(store, input.ref, { owner: input.owner, generation: input.generation, platform: input.platform ?? config.platform });
151
+ }
152
+ case "selection": {
153
+ const input = object(value, ["manifest", "taskIds", "output"]), selection = selectResources(parseResourceDataset(input.manifest), input.taskIds);
154
+ if (input.output !== undefined) {
155
+ if (typeof input.output !== "string")
156
+ throw new TypeError("invalid selection output");
157
+ await writeFile(input.output, `${JSON.stringify(selection)}\n`, { flag: "wx" });
158
+ }
159
+ return selection;
160
+ }
161
+ case "materialize": {
162
+ const input = object(value, ["plan", "owner", "generation"]);
163
+ return materializeResourceTask(store, input.plan, { owner: input.owner, generation: input.generation, policy: config.workspace });
164
+ }
165
+ case "workspace-end": {
166
+ const input = object(value, ["id", "executionEnded", "resultSealed"]);
167
+ await finishResourceWorkspace(store, input.id, input);
168
+ return { removed: true };
169
+ }
170
+ default: throw new TypeError(`unsupported resource API operation: ${operation}`);
171
+ }
172
+ }
173
+ export async function resourceFileRequest(root, operation, file) {
174
+ if ((await lstat(file)).size > 16 * 1024 ** 2)
175
+ throw new Error("resource request size limit exceeded");
176
+ return resourceRequest(root, operation, parseStrictJson(await readFile(file, "utf8")));
177
+ }
178
+ function parseHostConfig(value) {
179
+ const raw = object(value, ["protocol", "transport", "imagePolicy", "platform", "workspace", "limits", "offline"]);
180
+ if (raw.protocol !== "hitch-resource-host@1" || !["registry", "cache-first", "cache-only"].includes(String(raw.imagePolicy)) || typeof raw.platform !== "string" || !/^linux\/(amd64|arm64)(\/v[0-9]+)?$/.test(raw.platform))
181
+ throw new TypeError("invalid resource host configuration");
182
+ if (!raw.transport || typeof raw.transport !== "object" || Array.isArray(raw.transport))
183
+ throw new TypeError("resource transport must be a map");
184
+ for (const [key, ref] of Object.entries(raw.transport))
185
+ if (!/^sha256:[a-f0-9]{64}$/.test(key) || typeof ref !== "string" || !ref.endsWith(`@${key}`) || /[\s\0]/.test(ref))
186
+ throw new TypeError("invalid immutable image transport");
187
+ if (raw.limits !== undefined)
188
+ limits(raw.limits);
189
+ if (raw.offline !== undefined) {
190
+ const offline = object(raw.offline, ["exportFormat", "registry"]);
191
+ if (offline.exportFormat !== undefined && !["docker-archive", "registry-bundle"].includes(String(offline.exportFormat)))
192
+ throw new Error("invalid offline image format");
193
+ if (offline.registry !== undefined) {
194
+ if (typeof offline.registry !== "string")
195
+ throw new Error("invalid offline registry");
196
+ localRegistry(offline.registry);
197
+ }
198
+ }
199
+ const policy = object(raw.workspace, ["mode", "maxCopyBytes", "maxWorkspaces"]);
200
+ if (policy.mode !== undefined && !["auto", "copy", "require-clone"].includes(String(policy.mode)))
201
+ throw new TypeError("invalid workspace mode");
202
+ for (const key of ["maxCopyBytes", "maxWorkspaces"])
203
+ if (policy[key] !== undefined && (!Number.isSafeInteger(policy[key]) || policy[key] < (key === "maxWorkspaces" ? 1 : 0)))
204
+ throw new TypeError("invalid workspace budget");
205
+ return raw;
206
+ }
207
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/resources/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ import { createReadStream } from "node:fs";
2
+ import { copyFile, lstat, mkdir, readFile, readdir, rename, rm, statfs } from "node:fs/promises";
3
+ import { createHash, randomUUID } from "node:crypto";
4
+ import path from "node:path";
5
+ import { durableWriteJSON as atomicWriteJSON } from "../foundation/index.js";
6
+ import { canonical, identity, natural, object, parseStrictJson, sha } from "./protocol.js";
7
+ import { createResourceDelivery, parseResourceDelivery, receiveResourceDelivery } from "./transfer.js";
8
+ import { parseResourceSelection } from "./tasks.js";
9
+ export async function exportResourceBundle(store, selection, destination, owner, signal) {
10
+ destination = path.resolve(destination);
11
+ if (await lstat(destination).catch(e => { if (e.code !== "ENOENT")
12
+ throw e; return undefined; }))
13
+ throw new Error("bundle output already exists");
14
+ const delivery = await createResourceDelivery(store, selection, owner, 1, signal), temp = `${destination}.${randomUUID()}.tmp`, archives = [];
15
+ await mkdir(path.join(temp, "objects"), { recursive: true, mode: 0o700 });
16
+ await mkdir(path.join(temp, "oci"));
17
+ try {
18
+ let total = 0;
19
+ for (const item of delivery.objects) {
20
+ signal?.throwIfAborted();
21
+ total += item.size;
22
+ if (total > store.objects.budget.maxTotalBytes)
23
+ throw new Error("bundle export budget exceeded");
24
+ await store.objects.verify(item.digest, item.size);
25
+ const file = path.join(temp, "objects", item.digest.slice(7));
26
+ const space = await statfs(temp, { bigint: true });
27
+ if (space.bavail * space.bsize < BigInt(item.size) + BigInt(store.objects.budget.minFreeBytes))
28
+ throw new Error("bundle export free-space reserve exceeded");
29
+ await copyFile(store.objects.objectPath(item.digest), file);
30
+ await store.objects.verify(item.digest, item.size, file);
31
+ }
32
+ for (const image of delivery.images) {
33
+ if (!store.options.images?.exportArchive)
34
+ throw new Error("OCI provider does not support offline export");
35
+ const file = path.join(temp, "oci", image.resource.manifestDigest.slice(7));
36
+ await store.options.images.exportArchive(image.resource, file, signal, { maxBytes: Math.min(store.objects.budget.maxObjectBytes, store.objects.budget.maxTotalBytes - total), minFreeBytes: store.objects.budget.minFreeBytes });
37
+ const info = await lstat(file);
38
+ if (!info.isFile() || info.size > store.objects.budget.maxObjectBytes)
39
+ throw new Error("OCI archive object budget exceeded");
40
+ const hash = createHash("sha256");
41
+ let size = 0;
42
+ for await (const chunk of createReadStream(file)) {
43
+ signal?.throwIfAborted();
44
+ size += chunk.length;
45
+ if (size > store.objects.budget.maxObjectBytes)
46
+ throw new Error("OCI archive object budget exceeded");
47
+ hash.update(chunk);
48
+ }
49
+ const digest = sha(`sha256:${hash.digest("hex")}`);
50
+ await store.objects.verify(digest, size, file);
51
+ total += size;
52
+ if (total > store.objects.budget.maxTotalBytes)
53
+ throw new Error("bundle export budget exceeded");
54
+ archives.push({ manifestDigest: image.resource.manifestDigest, digest, size });
55
+ }
56
+ const body = { protocol: "hitch-resource-bundle@1", delivery, archives }, index = { ...body, digest: identity(body.protocol, body) };
57
+ await atomicWriteJSON(path.join(temp, "index.json"), index);
58
+ signal?.throwIfAborted();
59
+ await rename(temp, destination);
60
+ return index;
61
+ }
62
+ finally {
63
+ await rm(temp, { recursive: true, force: true });
64
+ }
65
+ }
66
+ /** A directory bundle has no archive paths to extract. OCI archives go only to the OCI provider. */
67
+ export async function importResourceBundle(store, directory, owner, signal) {
68
+ const indexFile = path.join(directory, "index.json");
69
+ if (!(await lstat(directory)).isDirectory() || !(await lstat(indexFile)).isFile() || (await lstat(indexFile)).size > 16 * 1024 ** 2)
70
+ throw new Error("invalid resource bundle");
71
+ const raw = object(parseStrictJson(await readFile(indexFile, "utf8")), ["protocol", "delivery", "archives", "digest"]), { digest, ...body } = raw;
72
+ if (raw.protocol !== "hitch-resource-bundle@1" || digest !== identity(raw.protocol, body) || !Array.isArray(raw.archives))
73
+ throw new Error("invalid resource bundle index");
74
+ const delivery = parseResourceDelivery(raw.delivery), archives = raw.archives.map(a => {
75
+ const entry = object(a, ["manifestDigest", "digest", "size"]);
76
+ sha(entry.manifestDigest);
77
+ sha(entry.digest);
78
+ if (!Number.isSafeInteger(entry.size) || entry.size < 0)
79
+ throw new TypeError("invalid OCI archive size");
80
+ return entry;
81
+ });
82
+ if (canonical(archives.map(a => a.manifestDigest).sort()) !== canonical(delivery.images.map(i => i.resource.manifestDigest).sort()))
83
+ throw new Error("offline image archives are incomplete or duplicate");
84
+ for (const sub of ["objects", "oci"])
85
+ if (!(await lstat(path.join(directory, sub))).isDirectory())
86
+ throw new Error("bundle paths must be directories without links");
87
+ if (canonical((await readdir(path.join(directory, "objects"))).sort()) !== canonical(delivery.objects.map(o => o.digest.slice(7)).sort()) || canonical((await readdir(path.join(directory, "oci"))).sort()) !== canonical(archives.map(a => a.manifestDigest.slice(7)).sort()))
88
+ throw new Error("bundle object inventory mismatch");
89
+ const total = delivery.objects.reduce((n, o) => n + o.size, 0) + archives.reduce((n, a) => n + a.size, 0);
90
+ if (total > store.objects.budget.maxTotalBytes)
91
+ throw new Error("offline bundle total byte budget exceeded");
92
+ // Verify the entire bundle before any provider mutation.
93
+ for (const item of delivery.objects)
94
+ await store.objects.verify(item.digest, item.size, path.join(directory, "objects", item.digest.slice(7)));
95
+ for (const item of archives)
96
+ await store.objects.verify(item.digest, item.size, path.join(directory, "oci", item.manifestDigest.slice(7)));
97
+ let expandedBytes = 0, imageFiles = 0;
98
+ for (const archive of archives) {
99
+ if (!store.options.images?.validateArchive)
100
+ throw new Error("OCI provider does not support bounded offline validation");
101
+ const usage = await store.options.images.validateArchive(delivery.images.find(i => i.resource.manifestDigest === archive.manifestDigest).resource, path.join(directory, "oci", archive.manifestDigest.slice(7)), signal, { maxExpandedBytes: store.objects.budget.maxTotalBytes - expandedBytes, maxFiles: store.objects.budget.maxFiles - imageFiles });
102
+ expandedBytes += natural(usage.expandedBytes);
103
+ imageFiles += natural(usage.files);
104
+ if (expandedBytes > store.objects.budget.maxTotalBytes || imageFiles > store.objects.budget.maxFiles)
105
+ throw new Error("offline OCI expanded budget exceeded");
106
+ }
107
+ const lease = await store.locked(() => store.beginLease(owner, "import"));
108
+ for (const archive of archives) {
109
+ if (!store.options.images?.importArchive)
110
+ throw new Error("OCI provider does not support cache-only offline import");
111
+ await store.importImageArchive(lease, delivery.images.find(i => i.resource.manifestDigest === archive.manifestDigest).resource, path.join(directory, "oci", archive.manifestDigest.slice(7)), signal);
112
+ }
113
+ const result = await receiveResourceDelivery(store, delivery, async (item) => createReadStream(path.join(directory, "objects", item.digest.slice(7))), owner, 1, signal);
114
+ await store.finishLease(lease.id, "ended");
115
+ return { selection: parseResourceSelection(delivery.selection), transferredBytes: result.transferredBytes, missingObjects: result.missingObjects };
116
+ }
117
+ //# sourceMappingURL=bundle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle.js","sourceRoot":"","sources":["../../../src/resources/bundle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ import { lstat, readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { durableWriteJSON as atomicWriteJSON, runCommand } from "../foundation/index.js";
4
+ import { canonical, identity, parseStrictJson, sha } from "./protocol.js";
5
+ import { finishResourceWorkspace } from "./materialize.js";
6
+ import { parseResourceTask, taskClosureLock } from "./tasks.js";
7
+ import { exportResourceResultProof } from "./result-retention.js";
8
+ export async function readResourceEvidence(file) {
9
+ const info = await lstat(file).catch(e => { if (e.code !== "ENOENT")
10
+ throw e; return undefined; });
11
+ if (!info)
12
+ return undefined;
13
+ if (!info.isFile() || info.size > 16 * 1024 ** 2)
14
+ throw new Error("invalid resource execution evidence");
15
+ const evidence = parseStrictJson(await readFile(file, "utf8"));
16
+ const { digest, ...body } = evidence.plan;
17
+ parseResourceTask(evidence.plan.task);
18
+ if (evidence.protocol !== "hitch-resource-workspace@1" || digest !== identity("hitch-resource-plan@1", body) || !/^[a-f0-9-]{36}$/.test(evidence.id) || typeof evidence.executionEnded !== "boolean")
19
+ throw new Error("resource execution evidence identity mismatch");
20
+ sha(evidence.materialized_task_digest);
21
+ if (!evidence.materializedTree || identity("hitch-materialized-task@1", evidence.materializedTree) !== evidence.materialized_task_digest)
22
+ throw new Error("materialized tree proof missing");
23
+ return evidence;
24
+ }
25
+ /** Run evidence is sealed before the execution lease can be released. */
26
+ export async function sealResourceEvidence(input) {
27
+ const evidence = await readResourceEvidence(input.file);
28
+ if (!evidence)
29
+ return;
30
+ if (evidence.plan.task.task_id !== input.taskId)
31
+ throw new Error("resource execution task mismatch");
32
+ const observed = [];
33
+ const docker = process.env.HITCH_DOCKER_PATH || "docker", cache = new Map();
34
+ const inspect = async (digest) => {
35
+ sha(digest);
36
+ let value = cache.get(digest);
37
+ if (value)
38
+ return value;
39
+ value = JSON.parse((await runCommand(docker, ["image", "inspect", "--format", "{{json .}}", digest], { timeoutMs: 30_000 })).stdout);
40
+ if (value.Id !== digest || !Array.isArray(value.RootFS?.Layers))
41
+ throw new Error("observed OCI config identity mismatch");
42
+ cache.set(digest, value);
43
+ return value;
44
+ };
45
+ for (const container of input.execution?.observed.containers ?? []) {
46
+ if (!container.image_config_digest)
47
+ continue;
48
+ const image = await inspect(container.image_config_digest), labels = image.Config?.Labels ?? {};
49
+ if (labels["dev.hitch.resource.plan"] !== evidence.plan.digest)
50
+ continue;
51
+ const role = labels["dev.hitch.resource.consumer"], consumer = parseStrictJson(role);
52
+ const bindings = evidence.plan.task.lock.bindings.filter(b => canonical(b.consumer) === canonical(consumer) && b.use === "environment-image");
53
+ if (!bindings.length)
54
+ throw new Error("observed resource consumer is undeclared");
55
+ const platform = `${image.Os}/${image.Architecture}${image.Variant ? `/${image.Variant}` : ""}`;
56
+ if (platform !== evidence.plan.platform)
57
+ throw new Error("observed resource platform changed");
58
+ const baseConfigs = [];
59
+ for (const binding of bindings) {
60
+ const expected = evidence.images.find(i => i.resource === binding.resource);
61
+ if (!expected)
62
+ throw new Error("OCI base evidence missing");
63
+ const base = await inspect(expected.configDigest);
64
+ if (canonical(image.RootFS.Layers.slice(0, base.RootFS.Layers.length)) !== canonical(base.RootFS.Layers))
65
+ throw new Error("observed image does not descend from declared resource base");
66
+ baseConfigs.push(expected.configDigest);
67
+ }
68
+ observed.push({ consumer, configDigest: container.image_config_digest, platform, baseConfigs });
69
+ }
70
+ if (input.requireObserved)
71
+ for (const binding of evidence.plan.task.lock.bindings.filter(b => b.use === "environment-image"))
72
+ if (!observed.some(i => canonical(i.consumer) === canonical(binding.consumer)))
73
+ throw new Error("successful resource trial lacks observed role/image evidence");
74
+ const lock = taskClosureLock(evidence.plan.task);
75
+ if ("hitch-materialized-task" in lock.resources)
76
+ throw new Error("reserved materialization resource ID");
77
+ const root = await input.store.pin({ owner: input.owner, generation: 1, purpose: "sealed-run", lock: { ...lock, resources: { ...lock.resources, "hitch-materialized-task": evidence.materializedTree } } });
78
+ const proofObjects = await exportResourceResultProof(input.store, evidence.plan, root.closure.objectDigests, input.runDirectory);
79
+ await atomicWriteJSON(path.join(input.runDirectory, "resource.execution.json"), { protocol: "hitch-resource-execution@1", plan: evidence.plan, materialized_task_digest: evidence.materialized_task_digest, materializedTree: evidence.materializedTree, images: evidence.images, observed, proofObjects, materialization: { clonedBytes: evidence.clonedBytes, copiedBytes: evidence.copiedBytes, fallbackReasons: evidence.fallbackReasons } });
80
+ }
81
+ export async function confirmResourceResultSealed(file) {
82
+ const evidence = await readResourceEvidence(file);
83
+ if (evidence)
84
+ await atomicWriteJSON(file, { ...evidence, resultSealed: true });
85
+ }
86
+ export async function reclaimResourceExecution(store, file, cleanupConfirmed) {
87
+ const evidence = await readResourceEvidence(file);
88
+ if (!evidence || !cleanupConfirmed || !evidence.executionEnded || !evidence.resultSealed)
89
+ return false;
90
+ await finishResourceWorkspace(store, evidence.id, { executionEnded: true, resultSealed: true });
91
+ return true;
92
+ }
93
+ //# sourceMappingURL=evidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evidence.js","sourceRoot":"","sources":["../../../src/resources/evidence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,gBAAgB,IAAI,eAAe,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzF,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,uBAAuB,EAA0B,MAAM,kBAAkB,CAAC;AAEnF,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAGlE,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,IAAY;IACrD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ;QAAE,MAAM,CAAC,CAAC,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAAC,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAChI,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzG,MAAM,QAAQ,GAAG,eAAe,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAA8B,CAAC;IAC5F,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC;IAAC,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjF,IAAI,QAAQ,CAAC,QAAQ,KAAK,4BAA4B,IAAI,MAAM,KAAK,QAAQ,CAAC,uBAAuB,EAAE,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,OAAO,QAAQ,CAAC,cAAc,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACvQ,GAAG,CAAC,QAAQ,CAAC,wBAAwB,CAAC,CAAC;IACvC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,IAAI,QAAQ,CAAC,2BAA2B,EAAE,QAAQ,CAAC,gBAAgB,CAAC,KAAK,QAAQ,CAAC,wBAAwB;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IAC7L,OAAO,QAAQ,CAAC;AAClB,CAAC;AACD,yEAAyE;AACzE,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,KAA6J;IACtM,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAAC,IAAI,CAAC,QAAQ;QAAE,OAAO;IAC/E,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,KAAK,KAAK,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACrG,MAAM,QAAQ,GAAgG,EAAE,CAAC;IACjH,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,QAAQ,EAAE,KAAK,GAAG,IAAI,GAAG,EAA+B,CAAC;IACzG,MAAM,OAAO,GAAG,KAAK,EAAE,MAAc,EAAE,EAAE;QACvC,GAAG,CAAC,MAAM,CAAC,CAAC;QAAC,IAAI,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAAC,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;QACpE,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,UAAU,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACrI,IAAI,KAAM,CAAC,EAAE,KAAK,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAM,CAAC,MAAM,EAAE,MAAM,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,KAAM,CAAC,CAAC;QAAC,OAAO,KAAM,CAAC;IACxK,CAAC,CAAC;IACF,KAAK,MAAM,SAAS,IAAI,KAAK,CAAC,SAAS,EAAE,QAAQ,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC;QACnE,IAAI,CAAC,SAAS,CAAC,mBAAmB;YAAE,SAAS;QAC7C,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,mBAAmB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,MAAM,IAAI,EAAE,CAAC;QAChG,IAAI,MAAM,CAAC,yBAAyB,CAAC,KAAK,QAAQ,CAAC,IAAI,CAAC,MAAM;YAAE,SAAS;QACzE,MAAM,IAAI,GAAG,MAAM,CAAC,6BAA6B,CAAC,EAAE,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;QACrF,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,mBAAmB,CAAC,CAAC;QAC9I,IAAI,CAAC,QAAQ,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAClF,MAAM,QAAQ,GAAG,GAAG,KAAK,CAAC,EAAE,IAAI,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QAChG,IAAI,QAAQ,KAAK,QAAQ,CAAC,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QAC/F,MAAM,WAAW,GAAa,EAAE,CAAC;QACjC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;YAAC,IAAI,CAAC,QAAQ;gBAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;YACzI,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;YAClD,IAAI,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;YACzL,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAC1C,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,CAAC,mBAAmB,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC;IAClG,CAAC;IACD,IAAI,KAAK,CAAC,eAAe;QAAE,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,mBAAmB,CAAC;YAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAC9R,MAAM,IAAI,GAAG,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjD,IAAI,yBAAyB,IAAI,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IACzG,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,yBAAyB,EAAE,QAAQ,CAAC,gBAAiB,EAAE,EAAE,EAAE,CAAC,CAAC;IAC7M,MAAM,YAAY,GAAG,MAAM,yBAAyB,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IACjI,MAAM,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,yBAAyB,CAAC,EAAE,EAAE,QAAQ,EAAE,4BAA4B,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,wBAAwB,EAAE,QAAQ,CAAC,wBAAwB,EAAE,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,eAAe,EAAE,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,eAAe,EAAE,QAAQ,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;AACpb,CAAC;AACD,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,IAAY;IAC5D,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAAC,IAAI,QAAQ;QAAE,MAAM,eAAe,CAAC,IAAI,EAAE,EAAE,GAAG,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;AACpI,CAAC;AACD,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,KAAoB,EAAE,IAAY,EAAE,gBAAyB;IAC1G,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,gBAAgB,IAAI,CAAC,QAAQ,CAAC,cAAc,IAAI,CAAC,QAAQ,CAAC,YAAY;QAAE,OAAO,KAAK,CAAC;IAC1J,MAAM,uBAAuB,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;IAAC,OAAO,IAAI,CAAC;AAC/G,CAAC"}
@@ -0,0 +1,123 @@
1
+ import { mkdir, readdir, rename, rm } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { durableWriteJSON as atomicWriteJSON, readJSON } from "../foundation/index.js";
4
+ import { canonical, natural, object } from "./protocol.js";
5
+ import { validateLease, validateRoot } from "./store.js";
6
+ import { planViewGc } from "./views.js";
7
+ export async function auditResources(store, options = {}) {
8
+ const graceMs = options.graceMs ?? 24 * 60 * 60 * 1000;
9
+ natural(graceMs);
10
+ return store.locked(async () => {
11
+ const roots = await store.records("roots"), leases = await store.records("leases"), marked = new Map();
12
+ const mark = (digest, reason) => { const reasons = marked.get(digest) ?? new Set(); reasons.add(reason); marked.set(digest, reasons); };
13
+ for (const root of roots) {
14
+ validateRoot(root);
15
+ if (root.state !== "active")
16
+ continue;
17
+ const actual = await fileClosure(store, Object.values(root.lock.resources));
18
+ if (canonical(actual) !== canonical(root.closure.objectDigests))
19
+ throw new Error("durable resource closure is incomplete; GC stopped");
20
+ for (const digest of actual)
21
+ mark(digest, `owner:${root.owner}:${root.generation}`);
22
+ }
23
+ for (const lease of leases) {
24
+ validateLease(lease);
25
+ if (lease.state === "released")
26
+ continue;
27
+ // No PID or expiry test: unknown remote execution keeps its protection.
28
+ for (const digest of lease.objectDigests)
29
+ mark(digest, `${lease.state}-lease:${lease.id}`);
30
+ }
31
+ const report = { protocol: "hitch-resource-gc@1", dryRun: !options.apply, objects: 0, logicalBytes: 0, retained: [], eligible: [], quarantined: [], deleted: [] };
32
+ const directory = path.join(store.directory, "objects", "sha256"), quarantine = path.join(store.directory, "quarantine");
33
+ const names = async (dir) => readdir(dir).catch((e) => { if (e.code !== "ENOENT")
34
+ throw e; return []; });
35
+ // Verify every present object before any mutation. A partial producer may
36
+ // protect its next not-yet-published digest; active roots may never do so.
37
+ const files = await names(directory), quarantined = await names(quarantine);
38
+ for (const name of [...files, ...quarantined])
39
+ if (!/^[a-f0-9]{64}$/.test(name))
40
+ throw new Error("unknown object store entry; GC stopped");
41
+ const quarantineTimes = new Map();
42
+ for (const name of quarantined) {
43
+ const digest = `sha256:${name}`;
44
+ if (files.includes(name) || marked.has(digest))
45
+ throw new Error("duplicate or referenced quarantine object; GC stopped");
46
+ const index = object(await readJSON(path.join(store.directory, "quarantine-index", `${name}.json`)), ["protocol", "digest", "quarantinedAt"]);
47
+ if (index.protocol !== "hitch-resource-quarantine@1" || index.digest !== digest || !Number.isSafeInteger(index.quarantinedAt) || index.quarantinedAt < 0)
48
+ throw new Error("invalid quarantine record; GC stopped");
49
+ await store.objects.verify(digest, undefined, path.join(quarantine, name));
50
+ quarantineTimes.set(name, index.quarantinedAt);
51
+ }
52
+ for (const lease of leases)
53
+ if (lease.state !== "released" && lease.purpose !== "import") {
54
+ for (const digest of lease.objectDigests)
55
+ if (!files.includes(digest.slice(7)))
56
+ throw new Error("active resource lease has missing content; GC stopped");
57
+ }
58
+ for (const name of files) {
59
+ options.signal?.throwIfAborted();
60
+ report.logicalBytes += await store.objects.verify(`sha256:${name}`);
61
+ report.objects++;
62
+ }
63
+ const collectViews = await planViewGc(store, marked, graceMs);
64
+ if (options.apply)
65
+ await collectViews();
66
+ for (const name of files) {
67
+ const digest = `sha256:${name}`, reasons = marked.get(digest);
68
+ if (reasons) {
69
+ report.retained.push({ digest, reasons: [...reasons].sort() });
70
+ continue;
71
+ }
72
+ report.eligible.push(digest);
73
+ if (!options.apply)
74
+ continue;
75
+ options.signal?.throwIfAborted();
76
+ await mkdir(quarantine, { recursive: true });
77
+ await atomicWriteJSON(path.join(store.directory, "quarantine-index", `${name}.json`), { protocol: "hitch-resource-quarantine@1", digest, quarantinedAt: Date.now() });
78
+ await rename(path.join(directory, name), path.join(quarantine, name));
79
+ report.quarantined.push(digest);
80
+ }
81
+ for (const name of quarantined) {
82
+ const digest = `sha256:${name}`;
83
+ if (marked.has(digest))
84
+ throw new Error("referenced object is quarantined; acquire must restore it before GC");
85
+ if (!options.apply || Date.now() - quarantineTimes.get(name) < graceMs)
86
+ continue;
87
+ options.signal?.throwIfAborted();
88
+ await rm(path.join(quarantine, name));
89
+ await rm(path.join(store.directory, "quarantine-index", `${name}.json`));
90
+ report.deleted.push(digest);
91
+ }
92
+ return report;
93
+ }, options.signal);
94
+ }
95
+ export async function fileClosure(store, resources) {
96
+ const found = new Set();
97
+ let bytes = 0, files = 0;
98
+ for (const resource of resources) {
99
+ if (resource.kind === "oci-image")
100
+ continue;
101
+ const digest = resource.kind === "blob" ? resource.digest : resource.manifestDigest;
102
+ await store.objects.verify(digest, resource.kind === "blob" ? resource.size : undefined);
103
+ found.add(digest);
104
+ if (resource.kind === "tree") {
105
+ const tree = await store.objects.readTree(digest);
106
+ files += tree.entries.length;
107
+ for (const entry of tree.entries)
108
+ if (entry.kind === "file") {
109
+ await store.objects.verify(entry.digest, entry.size);
110
+ found.add(entry.digest);
111
+ bytes += entry.size;
112
+ }
113
+ }
114
+ else {
115
+ bytes += resource.size;
116
+ files++;
117
+ }
118
+ if (bytes > store.objects.budget.maxTotalBytes || files > store.objects.budget.maxFiles)
119
+ throw new Error("resource closure budget exceeded");
120
+ }
121
+ return [...found].sort();
122
+ }
123
+ //# sourceMappingURL=gc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gc.js","sourceRoot":"","sources":["../../../src/resources/gc.ts"],"names":[],"mappings":"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"}