@orchestraworks/worker 0.0.138 → 0.0.140

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/README.md CHANGED
@@ -27,6 +27,192 @@ docker run --rm --entrypoint worker <image> check --harness claude
27
27
 
28
28
  `worker version` prints the version and the protocol versions this build speaks.
29
29
 
30
+ ## Make a machine image
31
+
32
+ `worker install-machine` makes the host it runs on into a machine image that a cloud starts machines from.
33
+ Use it for your own image under a Launcher on Azure, the program you run in your own cloud. A machine you
34
+ enroll yourself is not an image: run `orchestra install`, or `worker install --role worker`.
35
+
36
+ ```
37
+ worker install-machine --cloud azure|aws [--harness <families>|none] [--egress-redirect] [--docker] [--node]
38
+ ```
39
+
40
+ Run it once, as root on Linux or as an administrator on Windows, on a host that has never run the worker.
41
+ Each step reads what is there, changes only what is different, and prints `ok: <step>` or
42
+ `changed: <step>`. The first failure stops the run and names the step. You can run it again.
43
+
44
+ `<root>` is the machine-wide root: `/var/lib/sfdk/worker` on Linux, `%ProgramData%\sfdk\worker` on Windows.
45
+
46
+ | Step | When | What it does |
47
+ |---|---|---|
48
+ | preconditions | always | Refuses a host it is not written for. Refuses a host that has booted as a machine: a boot file or `<root>/state` is there. Refuses a running worker service. |
49
+ | directories | Windows | Creates `<root>`, `C:\software-factory` and its `etc` folder for SYSTEM and Administrators only. Users can also read and run `C:\software-factory`, which holds the programs on the machine path. A folder that is already there is kept as it is. |
50
+ | package | always | Copies this release package to `<root>/package`. The service runs from there, because a self-update replaces the package directory. |
51
+ | agent account | Linux | Creates the `agent` account, uid and gid 1000, home `/home`, and gives `/home` to it. Another account at uid 1000 is kept. |
52
+ | harnesses | `--harness` | Installs the named harness families and their Node under the root. `none` or no flag installs none: a family installs itself on its first turn, in about a minute. |
53
+ | service | always | Defines the service, `SfdkWorker` on Windows and `sfdk-worker.service` on Linux. It restarts after a failure. The step does not start it. |
54
+ | cloud | always | `azure`: at each boot, the start-up task runs `worker boot-files --cloud azure`, which writes the boot files from the VM's userData, and then the worker starts. `aws`: the worker starts at each boot, after the platform's user data, and an Azure start-up task or unit from an earlier run is removed. |
55
+ | egress redirect | `--egress-redirect` | WinDivert and its inbound firewall rule on Windows, `iptables` on Linux. A Launcher machine does not need it. |
56
+ | Docker | `--docker` | Windows containers, or rootless Docker for the `agent` account. |
57
+ | Node | `--node` | The agent's own Node, on the machine path. On Windows a new Node keeps the packages that `npm install -g` put in its folder. |
58
+ | check | always | Runs `worker check --profile launcher` for `azure`, and `--profile enrolled` for `aws`. |
59
+
60
+ The hosts:
61
+
62
+ - Windows Server 2025 x64, Core or Desktop, Generation 2, and Ubuntu 22.04 and 24.04, amd64 and arm64:
63
+ every step.
64
+ - Another Windows Server, or another Linux with systemd and glibc: the required steps, `--harness` and
65
+ `--node`. `--docker` and `--egress-redirect` are refused, and on Linux `--cloud azure` is refused too.
66
+ - Windows 11, another client edition of Windows, and a Linux without systemd: refused.
67
+
68
+ The machine must reach these hosts. The command does not test them:
69
+
70
+ - the platform, and its object store;
71
+ - while you build the image: `registry.npmjs.org` and `nodejs.org`, and with `--docker`,
72
+ `download.docker.com`; on Windows with `--egress-redirect`, `github.com`; on Linux, the Ubuntu package
73
+ mirror.
74
+
75
+ ### Windows Server 2025 for a Launcher on Azure
76
+
77
+ 1. Create the build VM from Microsoft's Windows Server 2025 image, Generation 2, with
78
+ `--security-type Standard`. A Trusted Launch VM cannot be captured into the image definition of step 7.
79
+ 2. Install your toolchain.
80
+ 3. Download the worker package and check it against the digest npm publishes. In PowerShell, as an
81
+ administrator:
82
+
83
+ ```powershell
84
+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
85
+ $version = '<worker version>'
86
+ $meta = Invoke-RestMethod "https://registry.npmjs.org/@orchestraworks%2Fworker-win32-x64/$version"
87
+ $tarball = Join-Path $env:TEMP 'worker.tgz'
88
+ Invoke-WebRequest -UseBasicParsing -Uri $meta.dist.tarball -OutFile $tarball
89
+ $digest = [Security.Cryptography.SHA512]::Create().ComputeHash([IO.File]::ReadAllBytes($tarball))
90
+ if (('sha512-' + [Convert]::ToBase64String($digest)) -ne $meta.dist.integrity) { throw 'the download does not match the digest npm publishes' }
91
+ $unpacked = Join-Path $env:TEMP 'worker'
92
+ New-Item -ItemType Directory -Force -Path $unpacked | Out-Null
93
+ tar.exe -xzf $tarball -C $unpacked
94
+ ```
95
+
96
+ 4. Make the machine. Add `--harness claude` or another family to preinstall it:
97
+
98
+ ```powershell
99
+ & "$unpacked\package\worker.exe" install-machine --cloud azure
100
+ if ($LASTEXITCODE -ne 0) { throw "install-machine exited $LASTEXITCODE; the line above names the step that failed" }
101
+ ```
102
+
103
+ 5. Restart the VM until no restart is pending. Sysprep refuses to run, or stops, while one is pending.
104
+ This command shows `"restartPending":false` when none is:
105
+
106
+ ```powershell
107
+ & "$env:ProgramData\sfdk\worker\package\worker.exe" check --profile launcher --output json
108
+ ```
109
+
110
+ 6. Generalize with Sysprep:
111
+
112
+ ```powershell
113
+ & "$env:SystemRoot\System32\Sysprep\Sysprep.exe" /oobe /generalize /mode:vm /shutdown
114
+ ```
115
+
116
+ - Do not remove the built-in Administrator account. Azure renames it, so `Remove-LocalUser` fails, and
117
+ Sysprep resets it.
118
+ - An installed SQL Server is generalized only through SQL Server's own image preparation, as Microsoft
119
+ documents for SQL Server and Sysprep.
120
+
121
+ 7. Capture the VM into an image definition in your Azure Compute Gallery. The Launcher creates Standard
122
+ security VMs, and on the `Dsv6` sizes it uses the NVMe disk controller, so the definition declares both:
123
+
124
+ ```bash
125
+ az vm deallocate --resource-group <rg> --name <vm>
126
+ az vm generalize --resource-group <rg> --name <vm>
127
+ az sig image-definition create --resource-group <rg> --gallery-name <gallery> \
128
+ --gallery-image-definition <definition> --publisher <publisher> --offer <offer> --sku <sku> \
129
+ --os-type Windows --os-state Generalized --hyper-v-generation V2 \
130
+ --features "SecurityType=TrustedLaunchSupported DiskControllerTypes=SCSI,NVMe"
131
+ az sig image-version create --resource-group <rg> --gallery-name <gallery> \
132
+ --gallery-image-definition <definition> --gallery-image-version 1.0.0 \
133
+ --virtual-machine "$(az vm show --resource-group <rg> --name <vm> --query id --output tsv)"
134
+ ```
135
+
136
+ Keep the quotes around `--features`: without them the Azure CLI refuses the second feature as an
137
+ unrecognized argument.
138
+
139
+ 8. Name the image version's resource id in the environment's `image`.
140
+
141
+ ### Ubuntu for a Launcher on Azure
142
+
143
+ 1. Create the build VM from Canonical's Ubuntu 22.04 or 24.04 image, Generation 2, with
144
+ `--security-type Standard`.
145
+ 2. Install your toolchain.
146
+ 3. Download the worker package and check it against the digest npm publishes. On arm64 the package is
147
+ `worker-linux-arm64`:
148
+
149
+ ```bash
150
+ version='<worker version>'
151
+ curl -fsSL "https://registry.npmjs.org/@orchestraworks%2Fworker-linux-x64/${version}" -o worker.json
152
+ tarball="$(python3 -c 'import json; print(json.load(open("worker.json"))["dist"]["tarball"])')"
153
+ integrity="$(python3 -c 'import json; print(json.load(open("worker.json"))["dist"]["integrity"])')"
154
+ curl -fsSL "${tarball}" -o worker.tgz
155
+ [ "sha512-$(openssl dgst -sha512 -binary worker.tgz | base64 -w0)" = "${integrity}" ] ||
156
+ { echo "the download does not match the digest npm publishes" >&2; exit 1; }
157
+ mkdir -p worker && tar -xzf worker.tgz -C worker
158
+ ```
159
+
160
+ 4. Make the machine:
161
+
162
+ ```bash
163
+ sudo ./worker/package/worker install-machine --cloud azure
164
+ ```
165
+
166
+ 5. Generalize. This removes the account you built with, so no machine made from the image carries it.
167
+ Run it from `/`, because it deletes your home directory, and the Azure agent stops with an error
168
+ when its working directory is gone:
169
+
170
+ ```bash
171
+ cd / && sudo waagent -force -deprovision+user && export HISTSIZE=0 && sync
172
+ ```
173
+
174
+ 6. Capture as in the Windows steps, with `--os-type Linux`.
175
+ 7. Name the image version's resource id in the environment's `image`.
176
+
177
+ If the image serves an app, end your own boot step with one request to the app. The first request after
178
+ a boot is slow, so this request takes that delay instead of the first user.
179
+
180
+ ### The model key and other tokens
181
+
182
+ Give the agent its model key in one of three ways. Each works on every machine, with or without our
183
+ egress edge. The edge and its Secrets are an addition, never needed for your own key.
184
+
185
+ 1. **The environment's `env`** (`provisionSpec.env`). The worker reads it when it starts. A declared value
186
+ replaces our image's placeholder, never a real value. The platform stores `env` values in plain text,
187
+ an environment read returns them, and the VM's startup data carries them. If that is not acceptable,
188
+ use route 2 or 3, or a Secret at our egress edge where one stands in front.
189
+ 2. **Baked into the image**, at machine scope, before Sysprep or generalizing. On Windows, that is the
190
+ `Environment` value (a multi-string) of `HKLM\SYSTEM\CurrentControlSet\Services\SfdkWorker`. Keep
191
+ the entries that are there, and add or replace only yours. On Linux, it is a drop-in on
192
+ `sfdk-worker.service`.
193
+ 3. **The `onStartAgent` hook** writes the harness's own key file in the agent's home:
194
+ `.claude/.credentials.json` for a Claude sign-in, `.codex/auth.json` for `codex`, or
195
+ `.pi/agent/auth.json` for `pi`. The worker keeps a real value it finds there. A raw Claude API key has
196
+ no file, so use route 1 or 2 for it.
197
+
198
+ The names:
199
+
200
+ - `claude` with an Anthropic API key or an Orchestra gateway key: `ANTHROPIC_API_KEY`. With a gateway
201
+ key, keep the agent's model gateway on. The platform sets the gateway address.
202
+ - `claude` with a Claude subscription token: `ORCHESTRA_WORKER_CLAUDE_OAUTH_TOKEN`. A renewing sign-in:
203
+ `ORCHESTRA_WORKER_CLAUDE_ACCESS_TOKEN` and `ORCHESTRA_WORKER_CLAUDE_REFRESH_TOKEN`.
204
+ - `codex`: `ORCHESTRA_WORKER_OPENAI_API_KEY`, or `ORCHESTRA_WORKER_CODEX_PERSONAL_ACCESS_TOKEN`.
205
+ - `pi`: `ORCHESTRA_WORKER_OPENAI_API_KEY` or `ORCHESTRA_WORKER_CLAUDE_OAUTH_TOKEN`.
206
+ `ORCHESTRA_WORKER_PI_PROVIDER` chooses the provider.
207
+
208
+ Never restart `SfdkWorker` or `sfdk-worker.service` to load a key. A restart after the worker registered
209
+ stops the machine's work, and the platform parks the VM. The next message starts it again, 1 to 2
210
+ minutes later.
211
+
212
+ - A gateway key's `monthlyCreditCap` stops the key when it is reached. One short turn can cost about 30
213
+ credits, so a low cap fails the next turn with `budget_exceeded`.
214
+ - If you restart a machine's VM yourself, the platform stops the VM. The next message starts it again.
215
+
30
216
  ## For coding agents
31
217
 
32
218
  - `orchestra worker --help` lists the worker commands. `orchestra worker <command> --help` gives their flags.
package/docs/REFERENCE.md CHANGED
@@ -12,11 +12,11 @@ The worker exposes no API of its own. Every route it calls is the platform's.
12
12
 
13
13
  | path | what it holds |
14
14
  |---|---|
15
- | `cmd/worker/` | the one binary: `run`, `install`, `enroll`, `check`, `version` |
15
+ | `cmd/worker/` | the one binary: `run`, `install`, `install-machine`, `boot-files`, `enroll`, `check`, `trust-nested`, `screen`, `version` |
16
16
  | `identity/` | the four identity exchanges — claim, refresh, reattach-challenge, reattach — the holder key, and the loop that keeps the machine token alive |
17
17
  | `broker/` | the protocol on the message broker: the connection, the register on every connect, the heartbeat and the status cadence, the pull of this machine's own work consumer, and the publisher every other package sends through |
18
18
  | `env/` | the machine-side environment the platform composes onto a launch, read from the names the contract declares |
19
- | `facts/` | what this build knows about the four harness families: the program to install and the digest that authenticates it, the environment each family is handed, the templates it seeds, and every location its content lands in — embedded in the binary, so one release digest covers the facts and the program that reads them |
19
+ | `facts/` | what this build knows about the four harness families: the program to install and the digest that authenticates it, the environment each family is handed, the templates it seeds, and every location its content lands in; and, in `machine.json`, the pins of what `install-machine` puts on a machine beside the worker — Docker, WinDivert and the agent's Node — and where a launch's certificate files land. Both are embedded in the binary, so one release digest covers the facts and the program that reads them |
20
20
  | `harness/` | the only place family-specific knowledge lives: the launch plan, the content layout, the store lookup, the mid-turn message each family accepts, and the installer that puts the pinned Node and a family's programs under the worker root |
21
21
  | `process/` | the agent's setup and the harness process behind each session placement: the start, the stop and the last save a remove asks for, the startup fence over what a previous run left, and the stop of everything when the worker is told to stop |
22
22
  | `stream/` | the queue: every placement message and every prompt, steer and cancel pulled off this machine's work consumer, the ACP client that opens a session's harness conversation and runs its turns, each turn's events batched to the platform and published live, and the answer every placement message is owed |
@@ -94,10 +94,12 @@ shapes the schema ships, and nothing here re-declares one.
94
94
  **The machine-wide service is the image role's, and the role is the whole of what asks for it.** An
95
95
  `image` gets it — a property list under `/Library/LaunchDaemons`, a unit under `/etc/systemd/system`,
96
96
  a Windows service — because the platform builds the image with nobody logged in to it and nobody
97
- typing the command, and the builder is already root. No flag selects that scope, on any role.
97
+ typing the command, and the builder is already root. No flag selects that scope, on any role. A
98
+ virtual-machine image is made by `worker install-machine` below, which our bakes run; the `image` role
99
+ stays for a container image, whose own command is the worker.
98
100
 
99
101
  `--root` follows the scope the same way: `~/.sfdk/worker` (`%LOCALAPPDATA%\sfdk\worker` on Windows) for
100
- a `user` install, `/var/lib/sfdk/worker` (`%ProgramData%\orchestra\worker`) for the other two. A `user`
102
+ a `user` install, `/var/lib/sfdk/worker` (`%ProgramData%\sfdk\worker`) for the other two. A `user`
101
103
  install writes its log under that root, at `log/worker.log`, because no service manager in that scope
102
104
  keeps one a person can read.
103
105
 
@@ -137,10 +139,51 @@ shapes the schema ships, and nothing here re-declares one.
137
139
  family's programs, and `workspaces/<family>`, the directory that family's harness runs in — one
138
140
  create at install covers all three, and a worker enrolled on somebody's own machine can take no
139
141
  second one.
142
+ - **`worker install-machine --cloud azure|aws [--os windows|linux] [--harness <families>|none]
143
+ [--egress-redirect] [--docker] [--node]`** makes the host it runs on into a machine image, in eleven steps
144
+ the package [README](../README.md) lists with the hosts each one runs on. It runs elevated, takes no
145
+ `--root` and installs under the machine-wide root. Each step reads the current state, changes only what
146
+ differs, reads the result back and prints `ok: <step>` or `changed: <step>`; the first failure stops the
147
+ run. So a second run on a converged host changes nothing, and a run that stopped part way is repaired by
148
+ running it again. It refuses a host that has already booted as a machine — a boot file or `<root>/state`
149
+ is there — because removing one is not a repair, and it refuses a running worker service. On Windows it
150
+ creates `<root>`, the install root `C:\software-factory` and its `etc` folder for SYSTEM and
151
+ Administrators alone, with Users also reading and running the install root, whose `bin` and `node` are
152
+ on the machine path; a folder already there is kept, so a host that made one first keeps its
153
+ permissions.
154
+
155
+ The service runs from a copy of the release package at `<root>/package`, because the self-update
156
+ replaces the directory the running binary sits in; the step compares that copy's `worker version`
157
+ with its own, and it refuses a package unpacked under `<root>/package` or holding it. The cloud step
158
+ owns the start type. `aws` starts the service at every boot, after the
159
+ platform's user data. `azure` cannot order the worker after its boot file on Windows, so there the
160
+ service is demand-start and the scheduled task `orchestra-azure-userdata` runs `<root>\package\worker.exe
161
+ boot-files --cloud azure` as SYSTEM at startup, with a 10-minute limit and three restarts a minute
162
+ apart; on Linux the oneshot unit `orchestra-azure-userdata.service` runs the same command, ordered before
163
+ the worker's unit, which requires it. Azure on Linux also installs WALinuxAgent's and azure-vm-utils'
164
+ udev rules, which name a data disk by its LUN. `aws` removes the Azure task, or the Azure unit and the
165
+ worker unit's link to it, that an earlier `azure` run left. The optional steps fetch what they install from the pins
166
+ in `facts/machine.json` and check each archive's SHA-256 — Node against `nodejs.org`'s published
167
+ `SHASUMS256.txt` — before anything is unpacked. A new Node on Windows replaces only the archive's own
168
+ files, `node.exe` last, so npm's global packages in its folder and their commands stay. The last step runs `worker check` in-process with the
169
+ profile that holds only what this command installs: `launcher` for `azure`, `enrolled` for `aws`. A
170
+ machine a person enrolls is not an image and keeps `worker install --role worker`; `--cloud none` is
171
+ refused and says so.
172
+ - **`worker boot-files --cloud azure`** is the start-up task of an Azure image. It reads the VM's
173
+ `compute/userData` from the instance metadata service at `169.254.169.254` with the `Metadata: true`
174
+ header and no proxy, sixty times two seconds apart. The text is base64 of one JSON object of strings
175
+ with the keys `machine.env`, `transport-trust-roots.pem` and `egress-ca.pem`; an unknown key, a value
176
+ that is not a string or a missing `machine.env` fails the boot. `machine.env` goes where the EC2 lanes
177
+ put the boot file, the two certificates to the guest paths in `facts/machine.json`, and a known file
178
+ this boot does not carry is removed, so a resumed VM never reads its previous launch's file. Each file
179
+ is written under a staged name of its own, created new with its permissions before any byte, and
180
+ renamed into place: on Linux at modes `0600`, `0600` and `0644`, the egress authority being the one the
181
+ agent's programs read, and on Windows readable by SYSTEM and Administrators alone. On Windows it starts `SfdkWorker` last; on Linux systemd starts the worker's unit after this one ends.
140
182
  - **`worker enroll`** redeems the enrollment token this machine was given, prints the row it was
141
183
  issued, and then serves that machine. It does not stop at the redemption, because the holder key
142
184
  the redemption bound lives in this process.
143
- - **`worker check [--harness <families>] [--root <dir>]`** reads the runtime image contract from
185
+ - **`worker check [--harness <families>|none] [--root <dir>] [--profile hosted|launcher|enrolled]
186
+ [--output json]`** reads the runtime image contract from
144
187
  inside an image, which is where the rest of that contract cannot be read. An inspection from the
145
188
  container runtime sees the command, the account it starts as, the platform it was built for and the
146
189
  version label; whether a family's programs are there at the versions this build's facts pin, whether
@@ -156,6 +199,18 @@ shapes the schema ships, and nothing here re-declares one.
156
199
  it is used. With no `--harness` it checks the rows that belong to no family and says so — a customer
157
200
  image installs the families it needs, so holding one to every family this build can host would
158
201
  refuse it for lacking programs nothing on it was ever going to run.
202
+
203
+ `--profile` names the machine the image is for, and each profile holds the image only to what that
204
+ machine runs. `hosted` is our own images: every row above, and on Linux `/home` owned by uid 1000
205
+ where it is not a mount point. `launcher` is a customer's image their Launcher starts, which has no
206
+ egress edge in front of it: no WinDivert and no CLI, and the `/home` row. `enrolled` is a customer's
207
+ image the platform's EC2 lane starts: no WinDivert, no CLI and no `/home` row. With no `--profile` the
208
+ check reads the `hosted` rows without `/home`, which is how the local environment runs it inside a
209
+ container whose `/home` nobody prepared, and reports no profile. `--output json` answers the rows as a
210
+ document with `held`, `missed`, `families` and, when a profile was named, `profile`; on Windows it
211
+ also carries `restartPending`, set while Component Based Servicing's `RebootPending` key, Windows
212
+ Update's `RebootRequired` key or the Session Manager's `PendingFileRenameOperations` value is there.
213
+ A pending restart is reported and never refused: Sysprep refuses to generalize while one is pending.
159
214
  - **`worker trust-nested [--registry <host>]... [--root <dir>]`** lets the containers this machine
160
215
  runs trust the egress edge, which nothing does by default. It reads the authority from
161
216
  `SFDK_EGRESS_CA_FILE`, which the worker sets on every harness process and on the setup script;
@@ -204,7 +259,7 @@ set is a concern this machine does not have.
204
259
  | `SFDK_EGRESS_LISTEN_PORT` | where the redirect lands, which is the shim's own listen port |
205
260
  | `SFDK_EGRESS_IPV6` | `true` mirrors the redirect through `ip6tables` |
206
261
  | `SFDK_EGRESS_PROXY` | `on`, the default, or `off`; `off` tells each harness that no edge of ours stands in front of this machine, as on an enrolled one. The platform writes `off` into every Launcher machine's boot file, because no proxy entrance of ours stands in front of one yet |
207
- | `SFDK_RUNTIME_ENVIRONMENT` | a whole environment folded into one JSON object of string values, for a boot file whose lines cannot carry a line break; each pair is placed unless already set, except that with `SFDK_EGRESS_PROXY=off` a pair replaces a name that holds exactly the image's egress placeholder |
262
+ | `SFDK_RUNTIME_ENVIRONMENT` | a whole environment folded into one JSON object of string values, for a boot file whose lines cannot carry a line break; each pair is placed unless already set, except that a non-blank pair replaces a name that holds exactly the image's placeholder |
208
263
  | `SFDK_VOLUME_MOUNTS` | the volumes this launch declares, as one JSON document |
209
264
  | `SFDK_MACHINE_SLUG` | the machine's platform-minted slug: the leading label of its preview hostnames, and what the tunnel's upgrade signs |
210
265
  | `SFDK_TUNNEL_ENDPOINT_URL` | where the preview gateway serves its tunnel listener; its scheme is the whole TLS statement for that hop |
@@ -214,10 +269,10 @@ set is a concern this machine does not have.
214
269
  **The worker reads that file itself, on every operating system, and no service manager is handed it.**
215
270
  Every `worker run` places each pair into its own environment before it serves, leaving alone any name
216
271
  that is already set, so a person's own foreground run still wins over the file. One name already set
217
- is replaced: where the switch `SFDK_EGRESS_PROXY` is `off`, no edge replaces the image's placeholder
218
- credential on the way out, so a value the launch declared replaces a name that holds exactly a
219
- placeholder the family facts list. That is how a customer's own token in `provisionSpec.env` reaches the
220
- harness on a Launcher machine; it rides the machine's startup data in plain text. systemd's
272
+ is replaced, on every machine: a non-blank value the launch declared replaces a name that holds exactly
273
+ a placeholder the family facts list, whether or not an egress edge stands in front. That is how a
274
+ customer's own token in `provisionSpec.env` reaches the harness; it rides the machine's startup data in
275
+ plain text. systemd's
221
276
  `EnvironmentFile=` is deliberately not used: it processes backslash escapes in an unquoted value, so
222
277
  the two characters `\n` that carry a line break inside `SFDK_RUNTIME_ENVIRONMENT` would arrive as a bare
223
278
  `n` and the certificate folded in there would hold no certificate at all. A machine with no file
@@ -226,7 +281,8 @@ stops the start and is named.
226
281
 
227
282
  Where the file sits is the one thing that differs, and only because of who may write it. On a Linux
228
283
  machine the platform launched, cloud-init writes `/etc/sfdk/machine.env` from the user data and the run
229
- reads it; no install by a person writes there. A `worker` install that registers a service writes
284
+ reads it; on an Azure machine `worker boot-files` writes the same file from the VM's userData, and
285
+ `<root>\machine.env` on Windows. No install by a person writes there. A `worker` install that registers a service writes
230
286
  `<root>/machine.env` under the worker's own root — `C:\ProgramData\sfdk\worker\machine.env` on a default
231
287
  machine-wide Windows install — because an install that registers the worker in one person's own session
232
288
  cannot write under `/etc`. A Linux run reads both, the machine-wide one first. The platform's user data writes that file on a machine
@@ -260,7 +316,7 @@ things in place in one order that is not interchangeable:
260
316
  nothing behind it. On Windows an inbound firewall rule is written first as well: the rewritten
261
317
  packet arrives as an inbound connection, which Windows Server blocks by default.
262
318
  3. **The redirect** — `iptables` on Ubuntu, WinDivert on Windows. The two WinDivert files are loaded
263
- by absolute path from `<root>\bin`, where the image bake stages them, and never through the
319
+ by absolute path from `<root>\bin`, where `install-machine --egress-redirect` places them, and never through the
264
320
  operating system's own search order: opening the driver installs and starts a kernel service.
265
321
 
266
322
  Each accepted connection's original destination is recovered (`SO_ORIGINAL_DST` on Linux, the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orchestraworks/worker",
3
- "version": "0.0.138",
3
+ "version": "0.0.140",
4
4
  "type": "module",
5
5
  "description": "The Orchestra worker.",
6
6
  "license": "Apache-2.0",
@@ -22,10 +22,10 @@
22
22
  "docs/REFERENCE.md"
23
23
  ],
24
24
  "optionalDependencies": {
25
- "@orchestraworks/worker-linux-x64": "0.0.138",
26
- "@orchestraworks/worker-linux-arm64": "0.0.138",
27
- "@orchestraworks/worker-darwin-x64": "0.0.138",
28
- "@orchestraworks/worker-darwin-arm64": "0.0.138",
29
- "@orchestraworks/worker-win32-x64": "0.0.138"
25
+ "@orchestraworks/worker-linux-x64": "0.0.140",
26
+ "@orchestraworks/worker-linux-arm64": "0.0.140",
27
+ "@orchestraworks/worker-darwin-x64": "0.0.140",
28
+ "@orchestraworks/worker-darwin-arm64": "0.0.140",
29
+ "@orchestraworks/worker-win32-x64": "0.0.140"
30
30
  }
31
31
  }