@orchestraworks/worker-darwin-arm64 0.0.140 → 0.0.142
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 +59 -23
- 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 on each harness process, refuses a bare claim: with no token there the harness makes no call at
|
|
9
|
+
// 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.142";
|
|
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) {
|
|
@@ -269,22 +267,58 @@ function agentApiBaseUrl() {
|
|
|
269
267
|
|
|
270
268
|
// The worker declares this on a machine the customer enrolled, and on no machine the platform launched.
|
|
271
269
|
// Presence is the declaration. The worker answers it from that machine's own bootstrap rather than
|
|
272
|
-
// passing a value through, so nothing running inside the machine can declare it of itself.
|
|
273
|
-
|
|
270
|
+
// passing a value through, so nothing running inside the machine can declare it of itself. A worker built
|
|
271
|
+
// before the rename declares it under the former name alone, which is read second.
|
|
272
|
+
const MACHINE_ENROLLED = ["ORCHESTRA_MACHINE_ENROLLED", "SFDK_MACHINE_ENROLLED"];
|
|
273
|
+
|
|
274
|
+
/** The name the worker declared this machine enrolled under, or undefined on a machine the platform launched. */
|
|
275
|
+
function enrolledDeclaration() {
|
|
276
|
+
return MACHINE_ENROLLED.find((name) => (process.env[name] || "").trim() !== "");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// The worker renews the file in place, so it is read on every call. Behind our edge the edge replaces
|
|
280
|
+
// this bearer with one for the same agent.
|
|
281
|
+
function agentToken() {
|
|
282
|
+
const variable = (process.env.ORCHESTRA_API_TOKEN || "").trim();
|
|
283
|
+
if (variable) return variable;
|
|
284
|
+
const file = (process.env.ORCHESTRA_API_TOKEN_FILE || "").trim();
|
|
285
|
+
if (!file) return undefined;
|
|
286
|
+
try {
|
|
287
|
+
return readFileSync(file, "utf8").trim() || undefined;
|
|
288
|
+
} catch {
|
|
289
|
+
return undefined;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// The CLI's transport rule: a bearer goes over https, or over plain http only to this machine itself.
|
|
294
|
+
const LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "::1"]);
|
|
274
295
|
|
|
275
|
-
function
|
|
276
|
-
|
|
296
|
+
function carriesBearer(baseUrl) {
|
|
297
|
+
let url;
|
|
298
|
+
try {
|
|
299
|
+
url = new URL(baseUrl);
|
|
300
|
+
} catch {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
if (url.protocol === "https:") return true;
|
|
304
|
+
return url.protocol === "http:" && LOOPBACK_HOSTS.has(url.hostname.replace(/^\[|\]$/g, ""));
|
|
277
305
|
}
|
|
278
306
|
|
|
279
|
-
async function platformRequest(method, path, organizationId, body) {
|
|
307
|
+
async function platformRequest(method, path, organizationId, body, token = agentToken()) {
|
|
280
308
|
let response;
|
|
281
309
|
try {
|
|
282
|
-
|
|
310
|
+
const baseUrl = agentApiBaseUrl();
|
|
311
|
+
if (token && !carriesBearer(baseUrl)) {
|
|
312
|
+
logDiagnostic("PLATFORM_BASE_URL is neither https nor this machine, so the agent token is not sent to it");
|
|
313
|
+
token = undefined;
|
|
314
|
+
}
|
|
315
|
+
response = await fetch(`${baseUrl}${path}`, {
|
|
283
316
|
method,
|
|
284
317
|
headers: {
|
|
285
318
|
"Content-Type": "application/json",
|
|
286
319
|
Accept: "application/json",
|
|
287
320
|
"X-Organization-Id": organizationId,
|
|
321
|
+
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
288
322
|
},
|
|
289
323
|
body: body === undefined ? undefined : JSON.stringify(body),
|
|
290
324
|
signal: AbortSignal.timeout(PLATFORM_REQUEST_TIMEOUT_MS),
|
|
@@ -660,16 +694,18 @@ async function claimPlatformState({
|
|
|
660
694
|
}) {
|
|
661
695
|
const { succeed, fail } = turnResponder(id, errorData, settlement);
|
|
662
696
|
|
|
663
|
-
// On a machine
|
|
664
|
-
//
|
|
665
|
-
//
|
|
666
|
-
//
|
|
667
|
-
//
|
|
668
|
-
//
|
|
669
|
-
|
|
697
|
+
// On a machine with no edge of ours and no agent token, nothing authorizes a call to the platform's
|
|
698
|
+
// API and every claim would come back refused — failing a turn whose script succeeded and whose answer
|
|
699
|
+
// is already on the session. The answer is then the whole of what the turn reports. Read off the
|
|
700
|
+
// worker's declaration and not off a missing edge stamp: a machine the platform launched can be missing
|
|
701
|
+
// that stamp too, and there the refusal is a deployment fault to surface rather than a turn to settle
|
|
702
|
+
// quietly.
|
|
703
|
+
const token = agentToken();
|
|
704
|
+
const declaration = enrolledDeclaration();
|
|
705
|
+
if (declaration !== undefined && !token) {
|
|
670
706
|
logDiagnostic(
|
|
671
|
-
`${
|
|
672
|
-
`
|
|
707
|
+
`${declaration} is set and no agent token is readable, so nothing authorizes this machine's ` +
|
|
708
|
+
`calls to the platform: this turn claims no session state and settles on its answer`,
|
|
673
709
|
);
|
|
674
710
|
succeed(answerText);
|
|
675
711
|
return;
|
|
@@ -680,7 +716,7 @@ async function claimPlatformState({
|
|
|
680
716
|
? { outcome: "ACHIEVED", summary: "exit 0" }
|
|
681
717
|
: { outcome: "FAILED", summary: `exit ${exitCode}: ${tail(stderrTail, STDERR_TAIL_SUMMARY)}` };
|
|
682
718
|
const sessionPath = `/sessions/${encodeURIComponent(platformSessionId)}`;
|
|
683
|
-
const response = await platformRequest("PATCH", sessionPath, organizationId, body);
|
|
719
|
+
const response = await platformRequest("PATCH", sessionPath, organizationId, body, token);
|
|
684
720
|
if (!response.ok && response.status !== 409) {
|
|
685
721
|
fail(`claim rejected: ${response.status}`);
|
|
686
722
|
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: 46512002 bytes
|
|
4
|
+
sha256: 7cbdd29779395d8ea71bb971f6810ebc09ec453f17388419b4c2a7f13f7b6e61
|