@orchestraworks/worker-darwin-arm64 0.0.139 → 0.0.141

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orchestraworks/worker-darwin-arm64",
3
- "version": "0.0.139",
3
+ "version": "0.0.141",
4
4
  "description": "Orchestra worker for darwin arm64.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Living Computers",
@@ -3,10 +3,10 @@
3
3
  // line-delimited stdio JSON-RPC. One process per bridge multiplexes every session over one stdio pipe,
4
4
  // so the read loop must never block on an in-flight command.
5
5
  //
6
- // Each turn ends by setting the session's outcome claim from the command's exit code. A machine the
7
- // customer enrolled, which the worker declares by setting `SFDK_MACHINE_ENROLLED`, has no edge of ours in
8
- // front of it, so every claim there would be refused: the harness makes no call at all and ends the turn
9
- // on the script's own answer.
6
+ // Each turn ends by setting the session's outcome claim from the command's exit code, sent with the agent's
7
+ // own token when the harness has one. A machine with no edge of ours in front of it, which the worker
8
+ // declares by setting `SFDK_MACHINE_ENROLLED`, refuses a bare claim: with no token there the harness makes
9
+ // no call at all and ends the turn on the script's own answer.
10
10
 
11
11
  import { spawn } from "node:child_process";
12
12
  import { randomUUID } from "node:crypto";
@@ -18,7 +18,7 @@ import { createInterface } from "node:readline";
18
18
  import { describeFetchFailure } from "./fetch-failure.js";
19
19
 
20
20
  const HARNESS_NAME = "software-factory-script-harness";
21
- const HARNESS_VERSION = "0.0.139";
21
+ const HARNESS_VERSION = "0.0.141";
22
22
 
23
23
  const IS_WINDOWS = process.platform === "win32";
24
24
 
@@ -257,8 +257,6 @@ try {
257
257
  programReadError = `cannot read instructions file: ${error.message}`;
258
258
  }
259
259
 
260
- // NO Authorization header is ever attached — the egress broker mints and injects the short-lived agent
261
- // bearer for the agent-API destination (the agent runtime must never hold credentials).
262
260
  function agentApiBaseUrl() {
263
261
  const configured = (process.env.PLATFORM_BASE_URL || "").trim().replace(/\/+$/, "");
264
262
  if (!configured) {
@@ -276,15 +274,49 @@ function machineIsEnrolled() {
276
274
  return (process.env[MACHINE_ENROLLED] || "").trim() !== "";
277
275
  }
278
276
 
279
- async function platformRequest(method, path, organizationId, body) {
277
+ // The worker renews the file in place, so it is read on every call. Behind our edge the edge replaces
278
+ // this bearer with one for the same agent.
279
+ function agentToken() {
280
+ const variable = (process.env.ORCHESTRA_API_TOKEN || "").trim();
281
+ if (variable) return variable;
282
+ const file = (process.env.ORCHESTRA_API_TOKEN_FILE || "").trim();
283
+ if (!file) return undefined;
284
+ try {
285
+ return readFileSync(file, "utf8").trim() || undefined;
286
+ } catch {
287
+ return undefined;
288
+ }
289
+ }
290
+
291
+ // The CLI's transport rule: a bearer goes over https, or over plain http only to this machine itself.
292
+ const LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "::1"]);
293
+
294
+ function carriesBearer(baseUrl) {
295
+ let url;
296
+ try {
297
+ url = new URL(baseUrl);
298
+ } catch {
299
+ return false;
300
+ }
301
+ if (url.protocol === "https:") return true;
302
+ return url.protocol === "http:" && LOOPBACK_HOSTS.has(url.hostname.replace(/^\[|\]$/g, ""));
303
+ }
304
+
305
+ async function platformRequest(method, path, organizationId, body, token = agentToken()) {
280
306
  let response;
281
307
  try {
282
- response = await fetch(`${agentApiBaseUrl()}${path}`, {
308
+ const baseUrl = agentApiBaseUrl();
309
+ if (token && !carriesBearer(baseUrl)) {
310
+ logDiagnostic("PLATFORM_BASE_URL is neither https nor this machine, so the agent token is not sent to it");
311
+ token = undefined;
312
+ }
313
+ response = await fetch(`${baseUrl}${path}`, {
283
314
  method,
284
315
  headers: {
285
316
  "Content-Type": "application/json",
286
317
  Accept: "application/json",
287
318
  "X-Organization-Id": organizationId,
319
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
288
320
  },
289
321
  body: body === undefined ? undefined : JSON.stringify(body),
290
322
  signal: AbortSignal.timeout(PLATFORM_REQUEST_TIMEOUT_MS),
@@ -660,16 +692,17 @@ async function claimPlatformState({
660
692
  }) {
661
693
  const { succeed, fail } = turnResponder(id, errorData, settlement);
662
694
 
663
- // On a machine the customer enrolled there is no edge of ours, so nothing authorizes a call to the
664
- // platform's API and every claim here would come back refused — failing a turn whose script succeeded
665
- // and whose answer is already on the session. The answer is then the whole of what the turn reports.
666
- // Read off the worker's declaration and not off a missing edge stamp: a machine the platform launched
667
- // can be missing that stamp too, and there the refusal is a deployment fault to surface rather than a
668
- // turn to settle quietly.
669
- if (machineIsEnrolled()) {
695
+ // On a machine with no edge of ours and no agent token, nothing authorizes a call to the platform's
696
+ // API and every claim would come back refused — failing a turn whose script succeeded and whose answer
697
+ // is already on the session. The answer is then the whole of what the turn reports. Read off the
698
+ // worker's declaration and not off a missing edge stamp: a machine the platform launched can be missing
699
+ // that stamp too, and there the refusal is a deployment fault to surface rather than a turn to settle
700
+ // quietly.
701
+ const token = agentToken();
702
+ if (machineIsEnrolled() && !token) {
670
703
  logDiagnostic(
671
- `${MACHINE_ENROLLED} is set, so this machine is one the platform did not launch and nothing ` +
672
- `authorizes its calls to the platform: this turn claims no session state and settles on its answer`,
704
+ `${MACHINE_ENROLLED} is set and no agent token is readable, so nothing authorizes this machine's ` +
705
+ `calls to the platform: this turn claims no session state and settles on its answer`,
673
706
  );
674
707
  succeed(answerText);
675
708
  return;
@@ -680,7 +713,7 @@ async function claimPlatformState({
680
713
  ? { outcome: "ACHIEVED", summary: "exit 0" }
681
714
  : { outcome: "FAILED", summary: `exit ${exitCode}: ${tail(stderrTail, STDERR_TAIL_SUMMARY)}` };
682
715
  const sessionPath = `/sessions/${encodeURIComponent(platformSessionId)}`;
683
- const response = await platformRequest("PATCH", sessionPath, organizationId, body);
716
+ const response = await platformRequest("PATCH", sessionPath, organizationId, body, token);
684
717
  if (!response.ok && response.status !== 409) {
685
718
  fail(`claim rejected: ${response.status}`);
686
719
  return;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "software-factory-script-harness",
3
3
  "type": "module",
4
- "version": "0.0.139",
4
+ "version": "0.0.141",
5
5
  "scripts": {
6
6
  "test": "node --test test/*.test.js"
7
7
  }
package/worker CHANGED
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: package/worker
3
- size: 45904994 bytes
4
- sha256: b606ae4e3f3b555aec71f2f8c39f1b87e612241a36e0a21d939f2cdc0456a347
3
+ size: 46402946 bytes
4
+ sha256: 9ec494f672f281a0b883ff7146ff5aa286e5382732198139822d748f247959f2