Skip to content

Commit 02b664b

Browse files
jhjaggarsdrew
andauthored
refactor(config): normalize and enforce gateway schema v2 (#2814)
* refactor(config): normalize compute driver field names Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * refactor(config): introduce canonical gateway fields Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * refactor(config): enforce gateway schema version 2 Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * fix(config): preserve compute driver runtime guarantees Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * fix(config): address schema v2 review regressions Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * fix(config): complete schema v2 migration safeguards Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(config): expand schema v2 regression coverage Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(config): add schema v2 parity manifest Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * fix(config): correct parity manifest inventory Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * docs(config): record schema v2 intentional changes Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * docs(config): disposition schema v2 parity gaps Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(e2e): add dual schema parity harness Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(e2e): establish compute lifecycle parity baseline Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * fix(config): preserve gateway option compatibility Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(e2e): record gateway option parity Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * docs(config): close gateway-wide parity gaps Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * fix(podman): apply configured pids limit Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(e2e): validate Podman option parity Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(e2e): add Kubernetes option parity harness Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(e2e): record Kubernetes option parity Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(e2e): disposition VM parity lanes Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(e2e): add external driver parity lane Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * fix(e2e): preserve external driver pull policy Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(e2e): attest parity artifacts and launches Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(e2e): require clean parity build sources Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(e2e): bind parity runtime artifacts Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * fix(e2e): use isolated supervisor tags Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * fix(e2e): qualify parity image tags Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * fix(e2e): serve parity supervisor locally Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(e2e): isolate parity podman services Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(e2e): harden parity evidence provenance Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(e2e): pin parity sandbox artifacts Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(e2e): attest parity runtime inputs Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(e2e): bind parity runtime evidence Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(e2e): record compute boundary parity Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(e2e): disposition cross-cutting parity lanes Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * fix(packaging): preflight gateway config upgrades Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * fix(config): preserve rebase integration guarantees Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(ci): isolate temporary git signing config Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * fix(config): update remaining schema v2 consumers Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * fix(ci): provide e2fs tools to VM tests Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * fix(config): align preflight with gateway startup Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * fix(vm): preserve rootfs tar configuration Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * chore(config): adopt duration unit constructors Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * fix(packaging): preflight RPM gateway config Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * fix(config): address driver review findings Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * fix(e2e): require fresh semantic parity evidence Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * fix(docker): update tests for renamed sandbox label Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> * test(gateway): preserve selective driver coverage after rebase Signed-off-by: Drew Newberry <anewberry@nvidia.com> --------- Signed-off-by: Jesse Jaggars <jjaggars@redhat.com> Signed-off-by: Drew Newberry <anewberry@nvidia.com> Co-authored-by: Drew Newberry <anewberry@nvidia.com>
1 parent 3112e9c commit 02b664b

135 files changed

Lines changed: 15589 additions & 2209 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.agents/skills/test-release-canary/SKILL.md‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ does not contribute to product usage metrics.
2626

2727
`install.sh` defaults to the *latest tagged* release — the canary is therefore checking that the most recent public release still installs, not the just-published `dev` build. The `kubernetes` job is the exception: it pins to `0.0.0-dev` chart + `:dev` images.
2828

29+
The host-package jobs exercise fresh installs, not upgrades from a persisted
30+
schema-v1 gateway config. Validate Homebrew and RPM exact-default migration with
31+
the release-tooling and package lifecycle tests before relying on the canary.
32+
2933
The canary does not install or import `@nvidia/openshell-sdk`. TypeScript SDK
3034
validation lives in the `TypeScript SDK` branch check, including a publish
3135
dry-run. The tagged release workflow publishes the package to GitHub Packages;
@@ -131,7 +135,7 @@ Loopback registration auto-derives the gateway name to `openshell` if `--name` i
131135
| Symptom | Likely cause | Where to look |
132136
|---|---|---|
133137
| `macos`/`ubuntu`/`fedora` job fails on `install.sh` | Latest tagged release missing an asset, checksum mismatch, or `install.sh` regression on this branch. | Job log around the `curl … install.sh \| sh` step. |
134-
| `macos`/`ubuntu`/`fedora` job fails on `openshell status` | Local gateway service did not start (systemd/brew/podman). Often a driver issue. | Service logs in the job log; `OPENSHELL_DRIVERS` env in the "Ensure …" step. |
138+
| `macos`/`ubuntu`/`fedora` job fails on `openshell status` | Local gateway service did not start (systemd/brew/podman). Often a driver issue. | Service logs in the job log; `OPENSHELL_COMPUTE_DRIVER` env in the "Ensure …" step. |
135139
| `ubuntu-snap` fails after interface connection | The gateway did not recover after Docker became available, or did not become reachable within the 30-second bound. | Failure diagnostics dump Snap service/connection/change state, gateway and snapd journals, Snap logs, and port 17670 listeners. |
136140
| `kubernetes` job fails on `helm install --wait` | Chart did not deploy in 5 min — usually image pull failure or readiness probe failing. | "Diagnostics on failure" step dumps `helm status`, manifest, pod describe, pod logs. |
137141
| `kubernetes` job fails on `kubectl wait` | Gateway pod stuck `CrashLoopBackOff` or `ImagePullBackOff`. | Diagnostics dump; check `:dev` image existence at `ghcr.io/nvidia/openshell/gateway`. |

‎.github/workflows/branch-checks.yml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,11 @@ jobs:
243243
- name: Test
244244
run: mise run test:python
245245

246+
- name: Test local gateway configuration helpers
247+
run: |
248+
bash tasks/scripts/test-gateway-pull-policy.sh
249+
bash tasks/scripts/test-gateway-config.sh
250+
246251
go:
247252
name: Go SDK
248253
needs: pr_metadata

‎.github/workflows/release-canary.yml‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
steps:
3232
- name: Ensure VM driver
3333
run: |
34-
launchctl setenv OPENSHELL_DRIVERS vm
34+
launchctl setenv OPENSHELL_COMPUTE_DRIVER vm
3535
launchctl setenv OPENSHELL_TELEMETRY_ENABLED "$OPENSHELL_TELEMETRY_ENABLED"
3636
3737
- name: Install and check status
@@ -53,7 +53,7 @@ jobs:
5353
fi
5454
sudo systemctl start docker || sudo service docker start
5555
mkdir -p "${HOME}/.config/openshell"
56-
printf 'OPENSHELL_DRIVERS=docker\nOPENSHELL_TELEMETRY_ENABLED=%s\n' \
56+
printf 'OPENSHELL_COMPUTE_DRIVER=docker\nOPENSHELL_TELEMETRY_ENABLED=%s\n' \
5757
"$OPENSHELL_TELEMETRY_ENABLED" > "${HOME}/.config/openshell/gateway.env"
5858
docker info
5959
@@ -145,7 +145,7 @@ jobs:
145145
bash -s <<'EOF'
146146
set -euo pipefail
147147
mkdir -p "${HOME}/.config/openshell"
148-
printf 'OPENSHELL_DRIVERS=podman\nOPENSHELL_TELEMETRY_ENABLED=%s\n' \
148+
printf 'OPENSHELL_COMPUTE_DRIVER=podman\nOPENSHELL_TELEMETRY_ENABLED=%s\n' \
149149
"$OPENSHELL_TELEMETRY_ENABLED" > "${HOME}/.config/openshell/gateway.env"
150150
podman info
151151
curl -LsSf "${INSTALL_SH_URL}" | sh
@@ -301,7 +301,7 @@ jobs:
301301
run: |
302302
set -euo pipefail
303303
mkdir -p "${HOME}/.config/openshell"
304-
printf 'OPENSHELL_DRIVERS=docker\n' > "${HOME}/.config/openshell/gateway.env"
304+
printf 'OPENSHELL_COMPUTE_DRIVER=docker\n' > "${HOME}/.config/openshell/gateway.env"
305305
curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/${{ github.event.workflow_run.head_sha || github.sha }}/install.sh | sh
306306
307307
- name: Register kind gateway and check status

‎Cargo.lock‎

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎architecture/compute-runtimes.md‎

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,19 @@ defines the available implementation set, while the runtime consumes a generic
127127
registry. Adding or removing a compiled driver therefore changes registration
128128
rather than the server's selection flow. Alternate gateway binaries can install
129129
their own `ComputeDriverFactory` registrations and hand the completed registry
130-
to `run_cli_with_compute_drivers`; factories receive merged driver config and
131-
return either an in-process driver or a gateway-managed remote endpoint. The
132-
server constructs the common runtime adapter and snapshots `GetCapabilities`
133-
for either result. A configured UDS endpoint still takes precedence over a
134-
compiled registration with the same name.
130+
to `run_cli_with_compute_drivers`. Factories expose the same side-effect-free
131+
configuration validation to package preflight and runtime startup, receive only
132+
the selected `[openshell.drivers.<name>]` table, and return either an in-process
133+
driver or a gateway-managed remote endpoint when built. Existing out-of-tree
134+
factories that implement only runtime construction remain source-compatible and
135+
can start normally, but package preflight fails closed until they explicitly
136+
advertise and implement side-effect-free configuration validation. If a selected config file
137+
omits the selector, preflight validates each configured table that belongs to an
138+
auto-detectable registration. It does not run runtime detection probes because
139+
those probes can connect local sockets or launch bounded discovery commands.
140+
Preflight never builds a driver or connects to its transport. The server constructs the common runtime
141+
adapter and snapshots `GetCapabilities` for either result. A configured UDS
142+
endpoint still takes precedence over a compiled registration with the same name.
135143

136144
The `openshell-gateway` composition crate exposes one feature per first-party
137145
registration: `compute-driver-kubernetes`, `compute-driver-docker`,
@@ -256,7 +264,7 @@ delete, reconciliation removes the row; otherwise it can remain `Deleting`.
256264
| Podman | Rootless or single-machine deployments. | Container plus nested sandbox namespace. | Uses the Podman REST API and CDI GPU devices when available. Delivers the supervisor via OCI image volume by default; falls back to extracting the binary to a host-side cache and bind-mounting it when `userns` is configured (overlay does not support idmapped mounts). Advertises the combined-supervisor policy-DNS and transparent-TCP substrate. |
257265
| Kubernetes | Cluster deployment through Helm. | Pod plus nested sandbox namespace. | Uses Kubernetes API objects, service accounts, secrets, PVC-backed workspace storage, and GPU resources. |
258266
| VM | Experimental microVM isolation. | Per-sandbox libkrun VM. | Managed endpoint-backed driver. The gateway spawns `openshell-driver-vm`, waits for its Unix socket, and then consumes it through the same remote `compute_driver.proto` path used by unmanaged endpoint drivers. The VM driver boots a cached bootstrap `rootfs.ext4`, prepares requested OCI images inside a bootstrap VM with `umoci`, attaches the prepared image disk read-only, and gives each sandbox a writable `overlay.ext4` for merged-root changes and runtime material. The driver persists each accepted launch request beside the overlay and restarts those VMs on driver startup without recreating the overlay. |
259-
| Extension | Out-of-tree drivers operated alongside the gateway. | Whatever boundary the driver implements. | Selected by a custom `compute_drivers = ["<name>"]` entry with `[openshell.drivers.<name>].socket_path`, or at launch time by pairing `--drivers <name>` with `--compute-driver-socket=<path>`. A launch-time endpoint may use a canonical built-in name to preserve its driver-config key while replacing in-process construction. The gateway connects to an operator-provisioned UDS, snapshots `GetCapabilities`, and dispatches all sandbox lifecycle calls through `compute_driver.proto`. The driver process and socket lifecycle are operator-owned; the gateway does not spawn, supervise, or remove unmanaged extension drivers. The trust boundary is the socket's filesystem permissions: the operator must ensure only the gateway uid can read/write it. |
267+
| Extension | Out-of-tree drivers operated alongside the gateway. | Whatever boundary the driver implements. | Selected by a custom `compute_driver = "<name>"` entry with `[openshell.drivers.<name>].socket_path`, or at launch time by pairing `--compute-driver <name>` with `--compute-driver-socket=<path>`. A launch-time endpoint may use a canonical built-in name to preserve its driver-config key while replacing in-process construction. The gateway connects to an operator-provisioned UDS, snapshots `GetCapabilities`, and dispatches all sandbox lifecycle calls through `compute_driver.proto`. The driver process and socket lifecycle are operator-owned; the gateway does not spawn, supervise, or remove unmanaged extension drivers. The trust boundary is the socket's filesystem permissions: the operator must ensure only the gateway uid can read/write it. |
260268

261269
Per-sandbox CPU and memory values currently enter the driver layer through
262270
template resource limits. Docker and Podman apply them as runtime limits.
@@ -293,10 +301,27 @@ pinned dialing, relay behavior, and OCSF decisions. Docker and Podman advertise
293301
they implement and validate the same complete contract. The capability marker
294302
is driver-owned supervisor input and is removed from workload environments.
295303

296-
Kubernetes deployments may set an AppArmor profile on sandbox agent containers
297-
through the driver configuration. The Helm chart defaults sandbox agents to
298-
`Unconfined` so runtime/default AppArmor profiles do not block supervisor
299-
network namespace setup on AppArmor-enabled nodes.
304+
Kubernetes, Docker, and Podman share one AppArmor configuration model:
305+
`RuntimeDefault`, `Unconfined`, or `Localhost/<profile>`. Each driver translates
306+
that model to its native API and rejects an explicitly requested confined
307+
profile when its backend reports AppArmor unavailable. Docker keeps its
308+
historical explicit `Unconfined` default. Podman sends no override when the
309+
field is omitted, preserving the runtime-selected profile; development paths
310+
that require the supervisor's namespace mount setup opt into `Unconfined`
311+
explicitly. The Helm chart independently uses `Unconfined` for Kubernetes.
312+
313+
Corporate proxy settings are driver-owned supervisor inputs. Docker, Podman,
314+
and VM propagate `https_proxy`, `no_proxy`, an optional root-only auth file,
315+
and the explicit cleartext-Basic-auth acknowledgement without allowing
316+
workload environment to override them. Podman and VM can also project an
317+
operator CA bundle for an HTTPS or TLS-intercepting proxy. The VM driver validates and
318+
stages its credential and CA bundle under fixed guest paths, then forwards
319+
those paths through the protected supervisor argument file rather than the
320+
guest environment. Local containers project provider SPIFFE
321+
through a dedicated host UNIX-socket parent mount. A VM cannot safely expose
322+
that host socket: it accepts only a separately operated, concrete TCP listener
323+
when `provider_spiffe_allow_guest_tcp = true` explicitly acknowledges guest
324+
access. Host-only sockets are never implicitly forwarded to VM guests.
300325

301326
The Kubernetes deployment packaging has two ownership boundaries. The gateway
302327
chart owns the gateway workload, configuration, Services, PKI, and
@@ -314,10 +339,14 @@ can request a specific number of GPUs or the driver-specific default behaviour.
314339
For all in-tree drivers, this is equivalent to selecting a single GPU.
315340

316341
VM runtime state paths are derived only from driver-validated sandbox IDs
317-
matching `[A-Za-z0-9._-]{1,128}`. The gateway-owned VM driver socket uses a
318-
private `run/` directory plus Unix peer UID/PID checks. Standalone
319-
unauthenticated TCP mode is disabled unless explicitly enabled for local
320-
development.
342+
matching `[A-Za-z0-9._-]{1,128}`. Each writable overlay records its effective
343+
sandbox UID/GID so later rootfs cache changes cannot rewrite persisted file
344+
ownership. Unmarked pre-migration overlays recover identity from concrete
345+
overlay or prepared-rootfs state, an explicit operator override, or the current
346+
image account. The driver never assumes `10001:10001`; it preserves that legacy
347+
identity only when persisted state reports it. The gateway-owned VM driver
348+
socket uses a private `run/` directory plus Unix peer UID/PID checks. Standalone unauthenticated TCP
349+
mode is disabled unless explicitly enabled for local development.
321350

322351
Runtime-specific implementation notes belong in the driver crate README:
323352

‎architecture/gateway.md‎

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,20 @@ immediately without a grace period. Finalization is persisted separately from
3737
the exit result; the gateway deletes an ephemeral sandbox only after the
3838
finalized supervisor session disconnects.
3939

40+
## Configuration Boundary
41+
42+
The gateway accepts exactly schema version 2. Missing, legacy, and future
43+
versions fail before runtime construction, and driver settings belong only to
44+
`[openshell.drivers.<name>]`. The process does not migrate legacy files.
45+
Package lifecycle code may replace an exact package-generated v1 default, but
46+
it preserves edited configurations for explicit operator migration.
47+
48+
Gateway listener TLS and sandbox callback TLS are separate inputs. A selected
49+
local Docker, Podman, or VM driver requires a complete guest bundle whenever
50+
the gateway listener uses TLS; package-managed local TLS can supply that bundle.
51+
Kubernetes instead projects guest credentials through its configured Secret.
52+
The gateway validates this requirement before constructing the selected driver.
53+
4054
## Protocol and Auth
4155

4256
The gateway listens on one service port and multiplexes gRPC and HTTP traffic.
@@ -255,10 +269,10 @@ controllers and `agents.x-k8s.io/v1alpha1` ownerReferences from existing
255269
deployments. Supervisors renew gateway JWTs in memory before expiry only while
256270
the sandbox record still exists. Older tokens are not server-revoked; shared
257271
deployments bound replay exposure with short `gateway_jwt.ttl_secs` lifetimes.
258-
The config default is
259-
`gateway_jwt.ttl_secs = 0` for local single-player Docker, Podman, and VM
260-
gateways; those tokens carry `exp = 0` and do not expire. Kubernetes and other
261-
shared deployments should set a positive TTL.
272+
Omitting `gateway_jwt.ttl_secs` selects non-expiring tokens for local
273+
single-player Docker, Podman, and VM gateways; those tokens carry `exp = 0`.
274+
Kubernetes and other shared deployments should set a positive TTL. Explicit
275+
zero is rejected.
262276

263277
Gateway JWT signing-key rotation is currently an offline operator action. The
264278
runtime loads one active signing key and one matching public verification key
@@ -758,9 +772,10 @@ Gateway CLI flag > gateway OPENSHELL_* env var > TOML file > built-in defa
758772
```
759773

760774
The TOML file is opt-in via `--config <PATH>` / `OPENSHELL_GATEWAY_CONFIG`.
761-
Driver implementation settings live in the TOML driver tables. See
762-
`docs/reference/gateway-config.mdx` for worked per-driver examples and RFC
763-
0003 for the full schema.
775+
Driver implementation settings live exclusively in TOML driver tables. The
776+
selector is the singular `[openshell.gateway] compute_driver`; legacy
777+
`compute_drivers` lists are rejected. See `docs/reference/gateway-config.mdx`
778+
for worked per-driver examples and RFC 0003 for the full schema.
764779

765780
Each installation has an operator-assigned gateway name. Configure it with
766781
`[openshell.gateway].name`, `--name`, or `OPENSHELL_GATEWAY_NAME`.
@@ -774,26 +789,20 @@ aliases, network names, and the sandbox JWT issuer.
774789
`database_url` is env-only and rejected when present in the file
775790
(`OPENSHELL_DB_URL` / `--db-url`).
776791

777-
### Driver inheritance
778-
779-
`[openshell.gateway]` carries a small set of values (`sandbox_namespace`,
780-
`default_image`,
781-
`supervisor_image`, `guest_tls_ca/cert/key`, `client_tls_secret_name`,
782-
`host_gateway_ip`, `enable_user_namespaces`) that are inherited into each
783-
driver's `[openshell.drivers.<name>]` table when the driver-specific table
784-
does not override them. The allowlist is per-driver so a gateway-wide
785-
default cannot land in a driver that does not understand it (e.g.
786-
`client_tls_secret_name` is K8s-only).
792+
### Driver ownership
787793

788-
`image_pull_policy` is intentionally **not** inheritable: Kubernetes uses
789-
`Always | IfNotPresent | Never` (passed verbatim to the K8s API) while
790-
Podman uses the lowercase enum `always | missing | never | newer`. No
791-
value means the same thing in both, so the key lives only under each
792-
driver's own table.
794+
`[openshell.gateway]` contains gateway process settings only. Each selected
795+
driver reads its own configuration exclusively from
796+
`[openshell.drivers.<name>]`; values are never inherited from gateway scope.
797+
Kubernetes owns `namespace`, `default_image`, `supervisor_image`,
798+
`client_tls_secret_name`, `service_account_name`, `host_gateway_ip`,
799+
`enable_user_namespaces`, and `sa_token_ttl_secs`. Docker uses
800+
`sandbox_label` instead of the legacy `sandbox_namespace` name. Podman and VM
801+
likewise own their image, endpoint, and runtime settings in their tables.
793802

794-
Driver-specific values that are not part of the inheritance allowlist
795-
(e.g. Podman `socket_path`, VM `vcpus`) only come from the driver's own
796-
table.
803+
`image_pull_policy` uses the shared canonical vocabulary
804+
`always | if_not_present | never | newer`. Drivers translate it to their runtime
805+
APIs; `newer` is supported only by Podman and rejected by Docker and Kubernetes.
797806

798807
### OTLP export
799808

@@ -867,7 +876,10 @@ system entry instead of pretending to delete package-manager owned state.
867876
- Gateway TLS and client certificate distribution are deployment concerns owned
868877
by the operator or packaging layer.
869878
- Compute runtimes own the mechanics of starting workloads and injecting
870-
callback configuration.
879+
callback configuration. Local Docker, Podman, and VM callback endpoints can
880+
be derived from their fixed host aliases. Kubernetes requires an explicit
881+
endpoint from deployment topology; Helm renders it from the gateway Service
882+
name and namespace rather than inferring it from sandbox placement.
871883
- Docker-backed local gateways use Docker's `host-gateway` callback alias on
872884
macOS and Docker Desktop-style runtimes. They request IPv4 loopback callback
873885
reachability and add a listener only when the primary does not cover it.

0 commit comments

Comments
 (0)