@orchestraworks/worker-darwin-x64 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 +1 -1
- package/script-harness/index.js +52 -19
- package/script-harness/package.json +1 -1
- package/worker +2 -2
package/package.json
CHANGED
package/script-harness/index.js
CHANGED
|
@@ -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
|
|
7
|
-
//
|
|
8
|
-
//
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
664
|
-
//
|
|
665
|
-
//
|
|
666
|
-
//
|
|
667
|
-
//
|
|
668
|
-
//
|
|
669
|
-
|
|
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
|
|
672
|
-
`
|
|
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;
|
package/worker
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
2
|
name: package/worker
|
|
3
|
-
size:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 48748624 bytes
|
|
4
|
+
sha256: 2028cacd0695f667c5586019b486663a2801bae65acb9d9186e04d6c4c7359a7
|