hammerkit 1.26.0 → 1.27.0-next.10

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 (128) hide show
  1. package/build.schema.json +62 -1
  2. package/dist/cache/backends/local-cache-backend.js +10 -2
  3. package/dist/cache/backends/registry-cache-backend.js +2 -2
  4. package/dist/cache/explain.js +13 -11
  5. package/dist/cli.js +3 -0
  6. package/dist/docker/item-network.js +471 -0
  7. package/dist/docker/pull.js +4 -2
  8. package/dist/docker/remove-orphaned-containers.js +13 -6
  9. package/dist/environment/replace-env-variables.js +8 -6
  10. package/dist/executer/await-completed-dependencies.js +2 -1
  11. package/dist/executer/check-readiness.js +2 -2
  12. package/dist/executer/docker-service.js +24 -13
  13. package/dist/executer/docker-task.js +18 -29
  14. package/dist/executer/event-cache.js +24 -2
  15. package/dist/executer/execute-command.js +18 -5
  16. package/dist/executer/execute-docker.js +4 -1
  17. package/dist/executer/execution-steps.js +33 -7
  18. package/dist/executer/get-docker-executor.js +14 -7
  19. package/dist/executer/scheduler/enqueue-next.js +17 -3
  20. package/dist/executer/watch-loop.js +2 -2
  21. package/dist/executer/watch-state-key.js +1 -1
  22. package/dist/file/within-root.js +42 -0
  23. package/dist/harness/connect.js +99 -0
  24. package/dist/harness/format.js +73 -0
  25. package/dist/harness/mcp-command.js +59 -0
  26. package/dist/harness/mcp.js +432 -0
  27. package/dist/harness/opencode.js +492 -0
  28. package/dist/harness/pi.js +217 -0
  29. package/dist/harness/sandbox-client.js +411 -0
  30. package/dist/index.js +33 -36
  31. package/dist/kubernetes/apply.js +42 -1
  32. package/dist/kubernetes/await-running-state.js +33 -1
  33. package/dist/kubernetes/claim-layout.js +71 -0
  34. package/dist/kubernetes/ensure-http-route.js +1 -1
  35. package/dist/kubernetes/ensure-kubernetes-deployment-exists.js +46 -28
  36. package/dist/kubernetes/ensure-kubernetes-persistent-volume-claim-exists.js +132 -5
  37. package/dist/kubernetes/ensure-kubernetes-service-exists.js +27 -11
  38. package/dist/kubernetes/ensure-persistent-data.js +75 -24
  39. package/dist/kubernetes/get-service-ip.js +16 -2
  40. package/dist/kubernetes/job-placement.js +99 -0
  41. package/dist/kubernetes/job-secrets.js +320 -0
  42. package/dist/kubernetes/kept-claims.js +203 -0
  43. package/dist/kubernetes/kubernetes-instance.js +10 -2
  44. package/dist/kubernetes/network-gate.js +71 -0
  45. package/dist/kubernetes/network-policy.js +583 -0
  46. package/dist/kubernetes/remove-persistent-data.js +3 -1
  47. package/dist/kubernetes/resources.js +37 -4
  48. package/dist/kubernetes/restore-kubernetes-data.js +28 -7
  49. package/dist/kubernetes/secrets.js +7 -9
  50. package/dist/kubernetes/store-kubernetes-data.js +1 -1
  51. package/dist/kubernetes/volumes.js +104 -12
  52. package/dist/log.js +1 -1
  53. package/dist/main.js +41 -0
  54. package/dist/network/egress-proxy.js +407 -0
  55. package/dist/network/port-relay.js +35 -0
  56. package/dist/optimizer/get-work-cache-stats.js +16 -0
  57. package/dist/optimizer/work-task-cache-description.js +5 -2
  58. package/dist/planner/service-definition.js +5 -0
  59. package/dist/planner/utils/append-work-dependencies.js +5 -2
  60. package/dist/planner/utils/append-work-environment.js +2 -0
  61. package/dist/planner/utils/append-work-service.js +5 -0
  62. package/dist/planner/utils/append-work-task.js +20 -1
  63. package/dist/planner/utils/assert-item-paths.js +50 -0
  64. package/dist/planner/utils/hosted-volumes.js +35 -0
  65. package/dist/planner/utils/task-arguments.js +3 -0
  66. package/dist/planner/work-network.js +193 -0
  67. package/dist/planner/work-runtime-docker.js +43 -1
  68. package/dist/planner/work-runtime-kubernetes.js +370 -111
  69. package/dist/planner/work-runtime-local.js +2 -1
  70. package/dist/program.js +33 -5
  71. package/dist/remote/annotations.js +115 -0
  72. package/dist/remote/bundle-text.js +24 -0
  73. package/dist/remote/bundle.js +9 -1
  74. package/dist/remote/remote-commands.js +15 -3
  75. package/dist/remote/remote-work-commands.js +272 -71
  76. package/dist/remote/server-client.js +18 -5
  77. package/dist/remote/source-manifest.js +15 -2
  78. package/dist/remote/token-source.js +67 -0
  79. package/dist/schema/build-file-base-task-schema.js +7 -0
  80. package/dist/schema/build-file-container-service-schema.js +8 -0
  81. package/dist/schema/build-file-container-task-schema.js +3 -0
  82. package/dist/schema/build-file-environment-schema.js +9 -0
  83. package/dist/schema/network-schema.js +78 -0
  84. package/dist/schema/reference-parser.js +2 -0
  85. package/dist/schema/schema-parser.js +16 -3
  86. package/dist/schema/work-scope-parser.js +5 -0
  87. package/dist/secrets/command-secret-provider.js +73 -10
  88. package/dist/secrets/github-app-token-command.js +26 -0
  89. package/dist/secrets/github-app-token.js +191 -0
  90. package/dist/server/accounts-api.js +9 -2
  91. package/dist/server/definitions-api.js +69 -47
  92. package/dist/server/definitions.js +76 -51
  93. package/dist/server/executor.js +156 -41
  94. package/dist/server/git-checkout.js +72 -8
  95. package/dist/server/kubernetes-backend.js +603 -0
  96. package/dist/server/kubernetes-sandbox-storage.js +997 -0
  97. package/dist/server/oauth.js +12 -0
  98. package/dist/server/plan.js +88 -2
  99. package/dist/server/policy.js +104 -15
  100. package/dist/server/proposals-api.js +24 -40
  101. package/dist/server/proposals.js +12 -25
  102. package/dist/server/repo-access.js +37 -6
  103. package/dist/server/run-logs.js +217 -0
  104. package/dist/server/run-plan.js +48 -2
  105. package/dist/server/run-request.js +29 -10
  106. package/dist/server/run-store.js +5 -0
  107. package/dist/server/run-worker-command.js +13 -1
  108. package/dist/server/run-worker.js +121 -24
  109. package/dist/server/runs.js +191 -10
  110. package/dist/server/sandbox-docker.js +62 -0
  111. package/dist/server/sandbox-files-api.js +269 -0
  112. package/dist/server/sandbox-files.js +1054 -0
  113. package/dist/server/sandbox-patch.js +481 -0
  114. package/dist/server/sandbox-pod-command.js +15 -0
  115. package/dist/server/sandbox-pod.js +146 -0
  116. package/dist/server/sandbox-storage.js +462 -0
  117. package/dist/server/sandboxes-api.js +216 -0
  118. package/dist/server/sandboxes.js +519 -0
  119. package/dist/server/server-command.js +39 -20
  120. package/dist/server/server-config.js +443 -22
  121. package/dist/server/server.js +219 -40
  122. package/dist/utils/abort-on-signals.js +46 -6
  123. package/dist/utils/run-id.js +12 -0
  124. package/dist/utils/tar.js +25 -0
  125. package/harness/opencode.ts +11 -0
  126. package/harness/pi.ts +7 -0
  127. package/package.json +8 -2
  128. package/dist/remote/text-diff.js +0 -89
package/build.schema.json CHANGED
@@ -261,6 +261,37 @@
261
261
  "additionalProperties": false,
262
262
  "description": "cpu and memory requests and limits"
263
263
  },
264
+ "network": {
265
+ "anyOf": [
266
+ {
267
+ "type": "string",
268
+ "const": "open"
269
+ },
270
+ {
271
+ "type": "string",
272
+ "const": "none"
273
+ },
274
+ {
275
+ "type": "object",
276
+ "properties": {
277
+ "allow": {
278
+ "type": "array",
279
+ "items": {
280
+ "type": "string"
281
+ }
282
+ }
283
+ },
284
+ "required": [
285
+ "allow"
286
+ ],
287
+ "additionalProperties": false
288
+ }
289
+ ],
290
+ "description": "network the task or service reaches besides its needs: open (default), none or { allow: [hosts or host:port] }"
291
+ },
292
+ "args": {
293
+ "type": "boolean"
294
+ },
264
295
  "runner": {
265
296
  "type": "string",
266
297
  "minLength": 1
@@ -273,6 +304,10 @@
273
304
  "items": {
274
305
  "type": "string"
275
306
  }
307
+ },
308
+ "volumeSize": {
309
+ "type": "string",
310
+ "description": "size of its claim on Kubernetes, e.g. 10Gi"
276
311
  }
277
312
  },
278
313
  "required": [
@@ -335,6 +370,12 @@
335
370
  "resources": {
336
371
  "$ref": "#/definitions/hammerkit/properties/tasks/additionalProperties/anyOf/0/properties/resources"
337
372
  },
373
+ "network": {
374
+ "$ref": "#/definitions/hammerkit/properties/tasks/additionalProperties/anyOf/0/properties/network"
375
+ },
376
+ "args": {
377
+ "$ref": "#/definitions/hammerkit/properties/tasks/additionalProperties/anyOf/0/properties/args"
378
+ },
338
379
  "runner": {
339
380
  "$ref": "#/definitions/hammerkit/properties/tasks/additionalProperties/anyOf/0/properties/runner"
340
381
  },
@@ -468,6 +509,17 @@
468
509
  "resources": {
469
510
  "$ref": "#/definitions/hammerkit/properties/tasks/additionalProperties/anyOf/0/properties/resources",
470
511
  "description": "cpu and memory requests and limits"
512
+ },
513
+ "volumeSize": {
514
+ "$ref": "#/definitions/hammerkit/properties/tasks/additionalProperties/anyOf/0/properties/volumeSize",
515
+ "description": "size of its claim on Kubernetes, e.g. 10Gi"
516
+ },
517
+ "network": {
518
+ "$ref": "#/definitions/hammerkit/properties/tasks/additionalProperties/anyOf/0/properties/network",
519
+ "description": "network the task or service reaches besides its needs: open (default), none or { allow: [hosts or host:port] }"
520
+ },
521
+ "args": {
522
+ "type": "boolean"
471
523
  }
472
524
  },
473
525
  "required": [
@@ -630,6 +682,15 @@
630
682
  "additionalProperties": false
631
683
  }
632
684
  },
685
+ "networkPolicy": {
686
+ "type": "string",
687
+ "const": "enforced",
688
+ "description": "the cluster enforces NetworkPolicy, which limited networks need"
689
+ },
690
+ "volumeSize": {
691
+ "$ref": "#/definitions/hammerkit/properties/tasks/additionalProperties/anyOf/0/properties/volumeSize",
692
+ "description": "size of the claim of each task and service, 1Gi by default"
693
+ },
633
694
  "ingresses": {
634
695
  "not": {}
635
696
  }
@@ -750,7 +811,7 @@
750
811
  "$ref": "#/definitions/hammerkit/properties/tasks/additionalProperties/anyOf/0/properties/timeout"
751
812
  },
752
813
  "maxSize": {
753
- "type": "string"
814
+ "$ref": "#/definitions/hammerkit/properties/tasks/additionalProperties/anyOf/0/properties/volumeSize"
754
815
  },
755
816
  "keepPerTask": {
756
817
  "type": "integer",
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createLocalCacheBackend = void 0;
3
+ exports.createLocalCacheBackend = exports.getDefaultLocalCachePath = void 0;
4
4
  const path_1 = require("path");
5
5
  const os_1 = require("os");
6
6
  const promises_1 = require("fs/promises");
@@ -16,8 +16,16 @@ async function directories(path) {
16
16
  return [];
17
17
  }
18
18
  }
19
+ // Below the home directory, or below `HAMMERKIT_DIR` when that is set: a server sets
20
+ // it per source trust, so the runs of one repository share their cache and nobody
21
+ // else's run finds it (a run's home directory is its own and goes with it).
22
+ function getDefaultLocalCachePath() {
23
+ const directory = process.env.HAMMERKIT_DIR;
24
+ return directory ? (0, path_1.join)(directory, 'remote-cache') : (0, path_1.join)((0, os_1.homedir)(), '.hammerkit', 'remote-cache');
25
+ }
26
+ exports.getDefaultLocalCachePath = getDefaultLocalCachePath;
19
27
  function createLocalCacheBackend(spec) {
20
- const root = spec.path ?? (0, path_1.join)((0, os_1.homedir)(), '.hammerkit', 'remote-cache');
28
+ const root = spec.path ?? getDefaultLocalCachePath();
21
29
  async function readEntry(taskId, stateKey) {
22
30
  const dir = (0, path_1.join)(root, taskId, stateKey);
23
31
  let created;
@@ -5,6 +5,7 @@ const crypto_1 = require("crypto");
5
5
  const os_1 = require("os");
6
6
  const path_1 = require("path");
7
7
  const tar_1 = require("tar");
8
+ const tar_2 = require("../../utils/tar");
8
9
  const registry_reference_1 = require("./registry/registry-reference");
9
10
  const registry_client_1 = require("./registry/registry-client");
10
11
  const MAX_TAG_LENGTH = 128;
@@ -74,8 +75,7 @@ function createRegistryCacheBackend(spec) {
74
75
  const layerFile = (0, path_1.join)(dir, 'layer.tar');
75
76
  const files = (await environment.file.listFiles(from)).sort();
76
77
  // portable + mtime-free so identical entries produce identical digests
77
- // `noMtime` is supported by tar 6 but missing from its type definitions
78
- await (0, tar_1.create)({ file: layerFile, cwd: from, portable: true, noMtime: true }, files);
78
+ await (0, tar_2.packArchive)({ file: layerFile, cwd: from, portable: true, noMtime: true }, files);
79
79
  const layer = await (0, registry_client_1.digestFile)(layerFile);
80
80
  const config = Buffer.from(JSON.stringify({
81
81
  architecture: 'amd64',
@@ -121,6 +121,19 @@ async function explainTask(item, defaultCacheMethod, environment, memo = new Map
121
121
  return { taskId: item.id(), taskName: item.name, status: 'miss', causes: [{ kind: 'never-cached' }] };
122
122
  }
123
123
  visiting.add(item.id());
124
+ // Like the scheduler, a task whose cache is off is never looked up, so its
125
+ // sources aren't hashed for it.
126
+ if ((0, state_key_1.resolveEffective)(item, defaultCacheMethod).method === 'none') {
127
+ const explanation = {
128
+ taskId: item.id(),
129
+ taskName: item.name,
130
+ status: 'uncacheable',
131
+ causes: [{ kind: 'caching-disabled' }],
132
+ };
133
+ memo.set(item.id(), explanation);
134
+ visiting.delete(item.id());
135
+ return explanation;
136
+ }
124
137
  const { stateKey, stats, resolved, provable, unmatched } = await (0, state_key_1.computeStateKey)(item, defaultCacheMethod, environment);
125
138
  // Mirrors the scheduler: a task that cannot be proven up to date always runs
126
139
  // (see computeStateKey), whatever a cache holds for it.
@@ -144,17 +157,6 @@ async function explainTask(item, defaultCacheMethod, environment, memo = new Map
144
157
  visiting.delete(item.id());
145
158
  return explanation;
146
159
  }
147
- if (resolved.method === 'none') {
148
- const explanation = {
149
- taskId: item.id(),
150
- taskName: item.name,
151
- status: 'uncacheable',
152
- causes: [{ kind: 'caching-disabled' }],
153
- };
154
- memo.set(item.id(), explanation);
155
- visiting.delete(item.id());
156
- return explanation;
157
- }
158
160
  const runtimeStateKey = await safeCurrentStateKey(item, environment);
159
161
  const hasEntry = await safeHas(item, stateKey, environment);
160
162
  const predictedHit = runtimeStateKey === stateKey || hasEntry;
package/dist/cli.js CHANGED
@@ -23,6 +23,7 @@ const dry_run_1 = require("./executer/dry-run");
23
23
  const cache_sync_1 = require("./cache/cache-sync");
24
24
  const cache_inventory_1 = require("./cache/cache-inventory");
25
25
  const prefetch_secrets_1 = require("./secrets/prefetch-secrets");
26
+ const work_network_1 = require("./planner/work-network");
26
27
  const isCliTask = (val) => val.type === 'task';
27
28
  exports.isCliTask = isCliTask;
28
29
  const isCliService = (val) => val.type === 'service';
@@ -50,6 +51,7 @@ class Cli {
50
51
  return {
51
52
  state: processWorkTree,
52
53
  start: async () => {
54
+ (0, work_network_1.applyNetworkCeiling)(workTree, type === 'down' ? null : options?.network ?? null);
53
55
  if (type !== 'down') {
54
56
  await this.prepareSecrets(true);
55
57
  }
@@ -80,6 +82,7 @@ class Cli {
80
82
  skipDeps: options?.skipDeps ?? true,
81
83
  wait: options?.wait ?? 'ready',
82
84
  resourceCheck: options?.resourceCheck ?? true,
85
+ network: options?.network ?? null,
83
86
  });
84
87
  }
85
88
  const result = (0, get_scheduler_execute_result_1.getSchedulerExecuteResult)(workTree);