Skip to content

Commit 17ce738

Browse files
authored
fix(ci)!: remove gateway callback listener dependency (#3365)
* fix(ci): repair post-merge release canary Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(packaging): bootstrap canary runtime prerequisites Signed-off-by: Drew Newberry <anewberry@nvidia.com> * ci(canary): collect macOS VM diagnostics Signed-off-by: Drew Newberry <anewberry@nvidia.com> * ci(canary): pin libkrun-compatible macOS runner Signed-off-by: Drew Newberry <anewberry@nvidia.com> * ci(canary): limit macOS smoke test to package startup Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(compute)!: remove gateway callback listeners Run Docker supervisors on host networking so they use the operator-configured primary gateway endpoint. Remove the unused compute-driver callback listener negotiation and listener-scoped routing machinery. BREAKING CHANGE: The ComputeDriver API no longer exposes GetGatewayListenerRequirements or GatewayListenerRequirement. External drivers must regenerate bindings and connect supervisors to the configured primary gateway endpoint. Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(docker): use sandbox runtime image in launcher Signed-off-by: Drew Newberry <anewberry@nvidia.com> * test(podman): exercise production endpoint selection Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(e2e): route supervisors to reachable gateways Signed-off-by: Drew Newberry <anewberry@nvidia.com> * test(e2e): align Podman endpoint fixtures Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(docker): preserve host aliases for supervisors Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(docker): align sandbox host gateway pin Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(e2e): address Docker fixtures by bridge IP Signed-off-by: Drew Newberry <anewberry@nvidia.com> * test(e2e): serialize sandbox lifecycle cases Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(e2e): host Docker TCP fixture with gateway Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(e2e): use loopback for host-network supervisor Signed-off-by: Drew Newberry <anewberry@nvidia.com> --------- Signed-off-by: Drew Newberry <anewberry@nvidia.com>
1 parent d91b199 commit 17ce738

56 files changed

Lines changed: 737 additions & 3148 deletions

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: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ helm install openshell oci://ghcr.io/nvidia/openshell/helm-chart \
112112
--namespace openshell --create-namespace \
113113
--set server.disableTls=true \
114114
--set server.telemetryEnabled=false \
115+
--set supervisor.sandboxRuntime.networkPolicyEnforced=true \
115116
--wait --timeout 5m
116117
117118
kubectl wait --namespace openshell \

.github/workflows/release-canary.yml

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,28 @@ jobs:
3535
launchctl setenv OPENSHELL_COMPUTE_DRIVER vm
3636
launchctl setenv OPENSHELL_TELEMETRY_ENABLED "$OPENSHELL_TELEMETRY_ENABLED"
3737
38-
- name: Install and check status
38+
- name: Install and check gateway status
3939
run: |
4040
set -euo pipefail
4141
curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/${{ github.event.workflow_run.head_sha || github.sha }}/install.sh | sh
42+
openshell --version
4243
openshell status
43-
sandbox="release-canary-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
44-
openshell sandbox create --name "$sandbox" --detach
45-
openshell sandbox exec --name "$sandbox" --no-tty -- true
46-
openshell sandbox delete "$sandbox"
44+
45+
# GitHub-hosted macOS runners do not expose the Hypervisor.framework
46+
# support libkrun needs. Sandbox launch is covered by the VM E2E lane.
47+
- name: Collect Homebrew diagnostics
48+
if: failure()
49+
run: |
50+
set +e
51+
brew services info openshell
52+
for log in \
53+
"$(brew --prefix)/var/log/openshell/openshell-gateway.out.log" \
54+
"$(brew --prefix)/var/log/openshell/openshell-gateway.err.log"; do
55+
if [ -f "$log" ]; then
56+
echo "--- $log ---"
57+
tail -n 300 "$log"
58+
fi
59+
done
4760
4861
ubuntu:
4962
name: Ubuntu Docker
@@ -68,7 +81,7 @@ jobs:
6881
set -euo pipefail
6982
curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/${{ github.event.workflow_run.head_sha || github.sha }}/install.sh | sh
7083
openshell status
71-
sandbox="release-canary-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
84+
sandbox="rc-${GITHUB_RUN_ID}"
7285
openshell sandbox create --name "$sandbox" --detach
7386
openshell sandbox exec --name "$sandbox" --no-tty -- true
7487
openshell sandbox delete "$sandbox"
@@ -153,7 +166,7 @@ jobs:
153166
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/0/bus \
154167
OPENSHELL_VERSION="$OPENSHELL_VERSION" \
155168
OPENSHELL_TELEMETRY_ENABLED="$OPENSHELL_TELEMETRY_ENABLED" \
156-
CANARY_SANDBOX="release-canary-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" \
169+
CANARY_SANDBOX="rc-${GITHUB_RUN_ID}" \
157170
INSTALL_SH_URL="https://raw.githubusercontent.com/NVIDIA/OpenShell/${{ github.event.workflow_run.head_sha || github.sha }}/install.sh" \
158171
bash -s <<'EOF'
159172
set -euo pipefail
@@ -235,7 +248,7 @@ jobs:
235248
- name: Create and exercise a sandbox
236249
run: |
237250
set -euo pipefail
238-
sandbox="release-canary-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
251+
sandbox="rc-${GITHUB_RUN_ID}"
239252
openshell sandbox create --name "$sandbox" --detach
240253
openshell sandbox exec --name "$sandbox" --no-tty -- true
241254
openshell sandbox delete "$sandbox"
@@ -292,7 +305,9 @@ jobs:
292305
--version 0.0.0-dev \
293306
--namespace "$RELEASE_NAMESPACE" --create-namespace \
294307
--set server.disableTls=true \
308+
--set server.auth.allowUnauthenticatedUsers=true \
295309
--set "server.telemetryEnabled=${OPENSHELL_TELEMETRY_ENABLED}" \
310+
--set supervisor.sandboxRuntime.networkPolicyEnforced=true \
296311
--wait --timeout 5m
297312
298313
- name: Verify gateway pod is Ready
@@ -333,7 +348,7 @@ jobs:
333348
set -euo pipefail
334349
openshell gateway add http://127.0.0.1:8080 --local --name "$KIND_GATEWAY_NAME"
335350
openshell status
336-
sandbox="release-canary-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
351+
sandbox="rc-${GITHUB_RUN_ID}"
337352
openshell sandbox create --name "$sandbox" --detach
338353
openshell sandbox exec --name "$sandbox" --no-tty -- true
339354
openshell sandbox delete "$sandbox"

architecture/compute-runtimes.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,9 @@ creation. Drivers that enforce policy outside the standard supervisor fetch
5151
later revisions through `GetSandboxConfig` and acknowledge them through
5252
`ReportPolicyStatus`.
5353
Process-identity omissions are preserved across this boundary so every driver
54-
can apply its native image or runtime defaults. Driver-requested listeners are
55-
structurally validated and remain restricted to sandbox callback RPCs.
54+
can apply its native image or runtime defaults. Drivers connect supervisors to
55+
the operator-configured gateway endpoint; they do not request additional
56+
gateway listeners.
5657

5758
Canonical main-process support is part of the `ComputeDriver` contract. Every
5859
in-tree and extension driver must forward the exact specification; it is not an

architecture/gateway.md

Lines changed: 22 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ attachments; and asks compute runtimes to create or delete sandbox workloads.
66

77
## Responsibilities
88

9-
- Authenticate clients and sandbox callbacks.
9+
- Authenticate clients and sandbox supervisor sessions.
1010
- Serve gRPC APIs for sandbox lifecycle, provider management, policy updates,
1111
settings, logs, watch streams, and relay forwarding.
1212
- Serve HTTP endpoints for health, WebSocket tunnels, and edge-auth flows.
@@ -49,7 +49,7 @@ versions fail before runtime construction, and driver settings belong only to
4949
Package lifecycle code may replace an exact package-generated v1 default, but
5050
it preserves edited configurations for explicit operator migration.
5151

52-
Gateway listener TLS and sandbox callback TLS are separate inputs. A selected
52+
Gateway listener TLS and sandbox supervisor TLS are separate inputs. A selected
5353
local Docker, Podman, or VM driver requires a complete guest bundle whenever
5454
the gateway listener uses TLS; package-managed local TLS can supply that bundle.
5555
Kubernetes instead projects guest credentials through its configured Secret.
@@ -141,24 +141,16 @@ template, provider, and service collection list RPCs use the same field with an
141141
all-workspaces marker. Platform-global policy operations omit both `sandbox`
142142
and `workspace_scope`, while sandbox policy operations require both.
143143

144-
Docker and Podman report the local address through which their sandboxes can
145-
reach the gateway. When the primary listener covers that address, the gateway
146-
reuses it; sandbox JWT authentication and its RPC allowlist remain the callback
147-
authorization boundary. When the primary listener does not cover the address,
148-
the gateway adds a callback-only listener. Additional callback listeners accept
149-
only gRPC methods classified as sandbox-callable by the gateway's generated
150-
authorization metadata. They reject user and administrator APIs, health,
151-
reflection, and HTTP routes before normal request
152-
authentication. The operator-configured primary listener retains the full
153-
multiplexed API surface.
154-
155-
The `rpc_auth` classification is also the source of truth for negotiated
156-
listener exposure: marking an RPC as `sandbox` or `dual` makes it callable on
157-
these listeners. Review such changes as both authorization and network-surface
158-
changes. Listener requirements are currently authorized only for the built-in
159-
Docker and Podman drivers. Operator-granted listener capabilities for external
160-
drivers are tracked in
161-
[#2539](https://github.com/NVIDIA/OpenShell/issues/2539).
144+
Docker and Podman supervisors use host networking and connect through the
145+
gateway's primary listener. On Linux, local supervisors use the primary
146+
loopback endpoint. Sandbox JWT authentication and the generated sandbox RPC
147+
allowlist remain the authorization boundary; the gateway does not negotiate or
148+
bind compute-driver-specific listeners.
149+
150+
The `rpc_auth` classification is the source of truth for supervisor access.
151+
Marking an RPC as `sandbox` or `dual` makes it callable by an authenticated
152+
sandbox principal on the primary listener. Review such changes as
153+
authorization-surface changes.
162154

163155
Operators can configure a gateway-wide gRPC request rate limit. The limit is
164156
applied only to gRPC API traffic after protocol multiplexing; health, metrics,
@@ -1059,25 +1051,16 @@ system entry instead of pretending to delete package-manager owned state.
10591051

10601052
- Gateway TLS and client certificate distribution are deployment concerns owned
10611053
by the operator or packaging layer.
1062-
- Compute runtimes own the mechanics of starting workloads and injecting
1063-
callback configuration. Local Docker, Podman, and VM callback endpoints can
1064-
be derived from their fixed host aliases. Kubernetes requires an explicit
1065-
endpoint from driver placement; Helm renders it from the gateway Service
1066-
name and namespace rather than inferring it from sandbox placement.
1067-
- Docker-backed local gateways use Docker's `host-gateway` callback alias on
1068-
macOS and Docker Desktop-style runtimes. They request IPv4 loopback callback
1069-
reachability and add a listener only when the primary does not cover it.
1070-
Native Linux Docker may expose an additional bridge-gateway listener because
1071-
the host can bind that bridge IP.
1072-
- Podman-backed macOS gateways use gvproxy's host-loopback IP for sandbox host
1073-
aliases by default so stale Podman machine images do not need Podman's
1074-
`host-gateway` resolver. Linux Podman keeps the resolver unless
1075-
`host_gateway_ip` is configured. Rootful Podman can request its exact bridge
1076-
gateway listener. Rootless Podman explicitly reporting pasta requests the
1077-
private IPv4 source selected by the host default route rather than an
1078-
arbitrary private interface. Slirp4netns, other helpers, and missing helper
1079-
metadata fail closed for local callbacks until a rootless-network namespace
1080-
relay is available.
1054+
- Compute runtimes own the mechanics of starting workloads and injecting the
1055+
gateway endpoint. Docker and Podman supervisors use host networking; local
1056+
Linux supervisors use the gateway's primary loopback endpoint. Kubernetes
1057+
uses the gateway Service rendered by Helm. VM supervisors use their
1058+
runtime-specific host route.
1059+
- Docker Desktop requires host networking to be enabled and cannot combine it
1060+
with Enhanced Container Isolation. Set an explicit remote `grpc_endpoint`
1061+
when the gateway is not reachable on the Docker daemon host.
1062+
- Podman Machine uses gvproxy's host-loopback route on macOS. Native Linux
1063+
Podman uses the primary loopback endpoint.
10811064
- Gateway restarts recover persisted objects from storage, but live relay
10821065
streams must be re-established by supervisors.
10831066
- User-facing behavior changes must update published docs in `docs/`; this file

architecture/sandbox.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ The canonical main process receives the declared workload environment before
400400
supervisor-only values are stripped and provider placeholders are injected.
401401
Template environment is treated like user-provided sandbox environment. It can
402402
shape the workload child, but it cannot override driver-controlled identity,
403-
gateway callback, TLS, relay socket, proxy, provider, or supervisor coordination
403+
gateway endpoint, TLS, relay socket, proxy, provider, or supervisor coordination
404404
variables. Drivers and the supervisor rewrite those reserved values after image
405405
and template environment are considered.
406406

crates/openshell-core/src/driver_utils.rs

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -7,58 +7,6 @@ use std::path::{Path, PathBuf};
77

88
use crate::proto::compute::v1::DriverSandbox;
99

10-
/// Built-in sandbox network callback routes used to derive a callback endpoint
11-
/// when an operator does not configure a per-driver `grpc_endpoint` override.
12-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13-
pub enum GatewayCallbackRoute {
14-
/// A Docker container reaches the host through Docker's gateway alias.
15-
Docker,
16-
/// A Podman container reaches the host through Podman's gateway alias.
17-
Podman,
18-
/// A libkrun guest reaches the host through gvproxy's gateway alias.
19-
Vm,
20-
}
21-
22-
/// Build the endpoint a sandbox uses to call its gateway for a known route.
23-
///
24-
/// The result is deliberately derived by the gateway rather than baked into
25-
/// individual driver defaults. A configured `grpc_endpoint` remains an
26-
/// operator override for remote or non-standard deployments.
27-
#[must_use]
28-
pub fn gateway_callback_endpoint(
29-
route: GatewayCallbackRoute,
30-
gateway_port: u16,
31-
gateway_tls_enabled: bool,
32-
) -> String {
33-
let scheme = if gateway_tls_enabled { "https" } else { "http" };
34-
let host = match route {
35-
GatewayCallbackRoute::Docker | GatewayCallbackRoute::Vm => "host.openshell.internal",
36-
GatewayCallbackRoute::Podman => "host.containers.internal",
37-
};
38-
format!("{scheme}://{host}:{gateway_port}")
39-
}
40-
41-
#[cfg(test)]
42-
mod callback_endpoint_tests {
43-
use super::{GatewayCallbackRoute, gateway_callback_endpoint};
44-
45-
#[test]
46-
fn derives_endpoint_for_each_builtin_route() {
47-
assert_eq!(
48-
gateway_callback_endpoint(GatewayCallbackRoute::Docker, 17670, false),
49-
"http://host.openshell.internal:17670"
50-
);
51-
assert_eq!(
52-
gateway_callback_endpoint(GatewayCallbackRoute::Podman, 17670, true),
53-
"https://host.containers.internal:17670"
54-
);
55-
assert_eq!(
56-
gateway_callback_endpoint(GatewayCallbackRoute::Vm, 17670, true),
57-
"https://host.openshell.internal:17670"
58-
);
59-
}
60-
}
61-
6210
// ---------------------------------------------------------------------------
6311
// Sandbox container/pod label keys (openshell.ai/ namespace)
6412
// ---------------------------------------------------------------------------

crates/openshell-driver-docker/README.md

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ mediates every supported TCP and DNS operation, attributes it to the calling
3535
binary, and sends the request across the private channel. The supervisor
3636
authorizes the request before it opens an upstream connection. Docker's absent
3737
workload network is the mandatory outer fence if mediation fails or is
38-
bypassed. Only the trusted supervisor companion joins the driver-owned bridge,
39-
where it originates approved egress and can resolve other services on that
40-
network.
38+
bypassed. The trusted supervisor companion uses Docker host networking, where
39+
it reaches the gateway's primary loopback listener and originates approved
40+
egress.
4141

4242
The driver copies trusted runtime bytes from the configured supervisor image
4343
through the Docker archive API. No workload launch depends on a host bind
@@ -73,7 +73,7 @@ LSM decisions remain authoritative.
7373
| `cap_drop = ALL`, no `cap_add`, no-new-privileges | Prevents either container from acquiring Linux capabilities. |
7474
| Docker default seccomp and AppArmor profiles | Retains runtime hardening; startup confirmation fails closed if nested seccomp notification is unavailable. |
7575
| `network_mode = none` on the workload | Removes direct external routes. |
76-
| Driver-owned bridge on the supervisor | Lets the trusted supervisor originate approved gateway and upstream connections and use Docker service discovery. |
76+
| `network_mode = host` on the supervisor | Lets the trusted supervisor reach the gateway's primary loopback listener and originate approved upstream connections. |
7777
| `restart_policy = no` | Keeps canonical main-process exit terminal. |
7878
| `PidsLimit` | Applies the configured sandbox PID budget. Omit `sandbox_pids_limit` to use OpenShell's default. Explicit zero is invalid. |
7979
| Private named volumes | One carries the authenticated sandbox/supervisor channel. The other is mounted only into the supervisor and contains its JWT and private gateway credentials. |
@@ -128,22 +128,25 @@ dynamically linked glibc `/openshell-supervisor` binary that runs in the
128128
host-networked supervisor container. Release and gateway image builds bake
129129
matching image tags into the binary.
130130

131-
## Callback and TLS
131+
## Gateway session and TLS
132132

133133
`OPENSHELL_ENDPOINT` and gateway authentication material are injected only into
134134
the supervisor companion. The workload never receives the sandbox JWT, gateway
135135
client TLS key, policy authority, or interception CA private key.
136136

137-
When no endpoint is configured, the driver derives
138-
`host.openshell.internal:<gateway-port>`. Native Linux uses the managed bridge
139-
gateway. Docker Desktop and compatible VM-backed daemons use Docker's
140-
`host-gateway` route. A configured HTTPS server certificate must include the
137+
When no endpoint is configured, the supervisor connects to
138+
`127.0.0.1:<gateway-port>`. Set `grpc_endpoint` when the gateway is not on the
139+
Docker daemon host. A configured HTTPS server certificate must include the
141140
endpoint host in its subject alternative names.
142141

143-
The driver pins a concrete managed-bridge address in the sandbox descriptor.
144-
For Docker's special `host-gateway` route, it leaves the address unpinned so
145-
the supervisor resolves the driver-injected alias in its own container. This
146-
avoids treating the Docker VM's loopback as the desktop host.
142+
The driver publishes host loopback as the backend address for
143+
`host.openshell.internal`. Policy DNS resolves that reserved name through the
144+
mediated path, so policies can reach host services without a Docker bridge,
145+
container DNS alias, or another gateway listener.
146+
147+
Docker Engine on Linux supports host networking directly. Docker Desktop
148+
requires host networking to be enabled in Settings and does not support it
149+
when Enhanced Container Isolation is enabled.
147150

148151
The supervisor owns these security-critical variables:
149152

0 commit comments

Comments
 (0)