Skip to content

Commit 436c59a

Browse files
authored
fix(rpm): restore 0.0.0.0 bind address for Podman via default gateway.toml (#1438)
* fix(rpm): restore 0.0.0.0 bind address for Podman via default gateway.toml The gateway binary default changed to 127.0.0.1 in recent commits (b61a98d, f257ed0). This breaks the Podman compute driver because sandbox containers reach the gateway over the host network bridge and cannot connect to the loopback address. Ship a default TOML config template that the RPM systemd unit seeds into ~/.config/openshell/gateway.toml on first start. The template sets bind_address = "0.0.0.0:17670" and pins compute_drivers = ["podman"] to prevent unexpected driver selection when Docker is also installed. The binary default remains 127.0.0.1 (secure-by-default for non-RPM installs). Changes: - deploy/rpm/gateway.toml.default: new default config template - openshell.spec: install template to %{_datadir}/openshell-gateway/; add ExecStartPre to seed ~/.config/openshell/gateway.toml on first start; add %check assertions for template presence and unit reference - deploy/rpm/CONFIGURATION.md: document default config, override paths, and updated bind address throughout - deploy/rpm/QUICKSTART.md: update bind address note for RPM installs - crates/openshell-server/src/config_file.rs: contract test that parses the RPM template through load() and asserts bind_address=0.0.0.0 and compute_drivers=[podman] - e2e/with-podman-gateway.sh: start from RPM template as base config so e2e exercises the same TOML path RPM users get on first start * fix(rpm): restore openshell_python_version macro in dist-info metadata * fix(rpm): reset Packit-managed version fields to match main baseline Version, Source0, and Source1 were stamped to 0.0.43 by Packit CI during branch builds. Reset to 0.0.37 (current main baseline) so the spec diff only contains our intentional changes. Packit's fix-spec-file action will re-stamp these fields at build time. * Revert "fix(rpm): reset Packit-managed version fields to match main baseline" This reverts commit 8ef9d7a. * fix(rpm): introduce openshell_version macro; remove hardcoded versions Add %global openshell_version as the single source of truth for the package version. Version:, Source0:, Source1:, openshell_cargo_version, and openshell_python_version all expand from this one macro. Update .packit.yaml fix-spec-file to patch %global openshell_version instead of the Version:, Source0:, and Source1: lines individually.
1 parent c5d1d76 commit 436c59a

7 files changed

Lines changed: 189 additions & 33 deletions

File tree

‎.packit.yaml‎

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,10 @@ actions:
3535
- 'bash -c "echo openshell-${PACKIT_PROJECT_VERSION}.tar.gz"'
3636

3737
fix-spec-file:
38-
# Update Source0 to the generated tarball name
39-
- 'bash -c "sed -i \"s|^Source0:.*|Source0: openshell-${PACKIT_PROJECT_VERSION}.tar.gz|\" openshell.spec"'
40-
# Update Source1 to the generated vendor tarball name
41-
- 'bash -c "sed -i \"s|^Source1:.*|Source1: openshell-${PACKIT_PROJECT_VERSION}-vendor.tar.xz|\" openshell.spec"'
42-
# Update Version
43-
- 'bash -c "sed -i -r \"s/^Version:(\\s*)\\S+/Version:\\1${PACKIT_RPMSPEC_VERSION}/\" openshell.spec"'
38+
# Update the canonical version macro. Version:, Source0:, Source1:, and all
39+
# other version references expand from %{openshell_version} so only this
40+
# one line needs updating.
41+
- 'bash -c "sed -i -r \"s/^%global openshell_version .*/%global openshell_version ${PACKIT_RPMSPEC_VERSION}/\" openshell.spec"'
4442
# Update Release
4543
- 'bash -c "RELEASE=${OPENSHELL_RPM_RELEASE:-${PACKIT_RPMSPEC_RELEASE}} && sed -i -r \"s/^Release:(\\s*)\\S+/Release:\\1${RELEASE}%{?dist}/\" openshell.spec"'
4644
# Keep embedded binary metadata aligned with the release workflow. Python

‎crates/openshell-server/src/config_file.rs‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,4 +515,47 @@ version = 2
515515
.expect_err("missing file must be io error");
516516
assert!(matches!(err, ConfigFileError::Io { .. }));
517517
}
518+
519+
/// Contract test: the RPM default config template must parse against the
520+
/// current schema and must pin the settings that Podman deployments require.
521+
///
522+
/// This test loads `deploy/rpm/gateway.toml.default` through the same
523+
/// `load()` path that the gateway uses at runtime, catching:
524+
/// - template corruption or unknown fields (`deny_unknown_fields`)
525+
/// - schema drift (version bump or field renames)
526+
/// - accidental changes to the bind address or compute driver list
527+
#[test]
528+
fn rpm_default_config_parses_and_has_podman_defaults() {
529+
let path =
530+
Path::new(env!("CARGO_MANIFEST_DIR")).join("../../deploy/rpm/gateway.toml.default");
531+
let config =
532+
load(&path).expect("deploy/rpm/gateway.toml.default must parse against current schema");
533+
let gw = &config.openshell.gateway;
534+
535+
let addr = gw
536+
.bind_address
537+
.expect("bind_address must be explicitly set in the RPM default config");
538+
assert!(
539+
addr.ip().is_unspecified(),
540+
"RPM default bind_address must be 0.0.0.0 so Podman sandbox containers \
541+
can reach the gateway over the host network bridge, got {addr}"
542+
);
543+
assert_eq!(
544+
addr.port(),
545+
openshell_core::config::DEFAULT_SERVER_PORT,
546+
"RPM default port must match DEFAULT_SERVER_PORT ({})",
547+
openshell_core::config::DEFAULT_SERVER_PORT
548+
);
549+
550+
let drivers = gw
551+
.compute_drivers
552+
.as_ref()
553+
.expect("compute_drivers must be explicitly set in the RPM default config");
554+
assert_eq!(
555+
drivers,
556+
&[ComputeDriverKind::Podman],
557+
"RPM default must pin compute_drivers to [podman] to prevent unexpected \
558+
driver selection when Docker is also installed"
559+
);
560+
}
518561
}

‎deploy/rpm/CONFIGURATION.md‎

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,65 @@ the RPM package on Fedora and RHEL systems.
66
For first-time setup, see QUICKSTART.md. For troubleshooting, see
77
TROUBLESHOOTING.md.
88

9+
## Default configuration
10+
11+
The RPM ships a default TOML configuration template at
12+
`/usr/share/openshell-gateway/gateway.toml.default`. On first start of
13+
`openshell-gateway.service`, the systemd unit copies this template to
14+
`~/.config/openshell/gateway.toml` if no config file exists there yet.
15+
16+
The defaults are tuned for rootless Podman use:
17+
18+
```toml
19+
[openshell]
20+
version = 1
21+
22+
[openshell.gateway]
23+
bind_address = "0.0.0.0:17670"
24+
compute_drivers = ["podman"]
25+
```
26+
27+
`bind_address = "0.0.0.0:17670"` is required because Podman sandbox
28+
containers reach the gateway over the host network bridge and cannot
29+
connect to `127.0.0.1` inside the gateway's network namespace. mTLS is
30+
enabled by default and protects all connections.
31+
32+
`compute_drivers = ["podman"]` pins the compute driver to Podman. Without
33+
this, the gateway auto-detects in order: Kubernetes, Podman, Docker. Pinning
34+
prevents unexpected driver selection if Docker is also installed on the host.
35+
36+
### Customizing the configuration
37+
38+
Edit `~/.config/openshell/gateway.toml` directly. The template at
39+
`/usr/share/openshell-gateway/gateway.toml.default` is not read at runtime
40+
and is not overwritten by RPM upgrades.
41+
42+
To apply environment variable overrides that persist across upgrades without
43+
editing the TOML file, add them to `~/.config/openshell/gateway.env`:
44+
45+
```shell
46+
# Example: restrict to loopback only
47+
OPENSHELL_BIND_ADDRESS=127.0.0.1
48+
```
49+
50+
To override the path to the TOML config file entirely:
51+
52+
```shell
53+
# In ~/.config/openshell/gateway.env
54+
OPENSHELL_GATEWAY_CONFIG=/path/to/custom/gateway.toml
55+
```
56+
57+
For one-off service overrides that persist across package upgrades:
58+
59+
```shell
60+
systemctl --user edit openshell-gateway
61+
```
62+
963
## TLS (mTLS)
1064

1165
The RPM enables mutual TLS by default. The gateway requires a valid
1266
client certificate for all API connections and listens on
13-
`127.0.0.1:17670` by default.
67+
`0.0.0.0:17670` by default (see "Default configuration" above).
1468

1569
### Auto-generated certificates
1670

@@ -152,8 +206,8 @@ overrides that persist across package upgrades.
152206

153207
| TOML option | Default | Description |
154208
|-------------|---------|-------------|
155-
| `bind_address` | `127.0.0.1:17670` | Address for the gRPC/HTTP API. |
156-
| `compute_drivers` | unset | When unset, the gateway auto-detects Kubernetes, then Podman, then Docker. Set `compute_drivers = ["podman"]` to force Podman. |
209+
| `bind_address` | `0.0.0.0:17670` (RPM default) | Address for the gRPC/HTTP API. |
210+
| `compute_drivers` | `["podman"]` (RPM default) | When unset, the gateway auto-detects Kubernetes, then Podman, then Docker. The RPM default pins to Podman. |
157211
| `default_image` | `ghcr.io/nvidia/openshell-community/sandboxes/base:latest` | Default sandbox image. |
158212
| `supervisor_image` | `ghcr.io/nvidia/openshell/supervisor:latest` | Supervisor image mounted into Podman sandboxes. |
159213
| `guest_tls_ca`, `guest_tls_cert`, `guest_tls_key` | auto-generated paths | Client TLS material bind-mounted into sandbox containers. |
@@ -173,9 +227,8 @@ settings:
173227
version = 1
174228

175229
[openshell.gateway]
176-
bind_address = "127.0.0.1:17670"
177-
# Leave unset to auto-detect the compute driver.
178-
# compute_drivers = ["podman"]
230+
bind_address = "0.0.0.0:17670"
231+
compute_drivers = ["podman"]
179232
default_image = "ghcr.io/nvidia/openshell-community/sandboxes/base:latest"
180233

181234
[openshell.drivers.podman]
@@ -239,7 +292,9 @@ For air-gapped environments:
239292
| Gateway binary | `/usr/bin/openshell-gateway` |
240293
| CLI binary | `/usr/bin/openshell` |
241294
| Systemd user unit | `/usr/lib/systemd/user/openshell-gateway.service` |
295+
| Default TOML config template (read-only) | `/usr/share/openshell-gateway/gateway.toml.default` |
296+
| Active gateway TOML configuration | `~/.config/openshell/gateway.toml` |
297+
| Optional environment variable overrides | `~/.config/openshell/gateway.env` |
242298
| TLS certificates | `~/.local/state/openshell/tls/` |
243299
| CLI client certs | `~/.config/openshell/gateways/openshell/mtls/` |
244300
| Gateway database | `~/.local/state/openshell/gateway/openshell.db` |
245-
| Optional gateway TOML configuration | `~/.config/openshell/gateway.toml` |

‎deploy/rpm/QUICKSTART.md‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,11 @@ On first start, the gateway automatically generates:
6565

6666
- A self-signed PKI bundle (CA, server cert, client cert) for mTLS
6767

68-
> **Note:** The gateway binds to `127.0.0.1:17670` by default. Mutual
69-
> TLS (mTLS) is enabled automatically on first start, requiring a valid
70-
> client certificate for every connection. See CONFIGURATION.md for
71-
> details.
68+
> **Note:** The RPM default configuration binds to `0.0.0.0:17670` so
69+
> Podman sandbox containers can reach the gateway over the host network
70+
> bridge. Mutual TLS (mTLS) is enabled automatically on first start,
71+
> requiring a valid client certificate for every connection. See
72+
> CONFIGURATION.md for details.
7273
7374
Verify the service is running:
7475

‎deploy/rpm/gateway.toml.default‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
#
4+
# Default gateway configuration for RPM installs.
5+
#
6+
# This file is seeded to ~/.config/openshell/gateway.toml on first start
7+
# of the openshell-gateway.service systemd user unit. Edit that copy to
8+
# customize. This file is not read directly at runtime.
9+
#
10+
# Configuration precedence (highest to lowest):
11+
# CLI flag > OPENSHELL_* env var > TOML file > built-in default
12+
#
13+
# To override settings without editing this file, set OPENSHELL_* variables
14+
# in ~/.config/openshell/gateway.env or run:
15+
# systemctl --user edit openshell-gateway
16+
17+
[openshell]
18+
version = 1
19+
20+
[openshell.gateway]
21+
# Podman sandbox containers reach the gateway over the host network bridge,
22+
# which requires binding to all interfaces. Override to 127.0.0.1:17670 if
23+
# you don't use Podman or want loopback-only access (e.g. behind a reverse
24+
# proxy). mTLS is enabled by default and protects all connections.
25+
bind_address = "0.0.0.0:17670"
26+
27+
# Pin to the Podman compute driver. Without this, the gateway auto-detects
28+
# in order: Kubernetes, Podman, Docker. Pinning prevents unexpected driver
29+
# selection if Docker is also installed on the host.
30+
compute_drivers = ["podman"]

‎e2e/with-podman-gateway.sh‎

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -359,10 +359,18 @@ toml_string() {
359359
}
360360

361361
GATEWAY_CONFIG="${STATE_DIR}/gateway.toml"
362+
363+
# Start from the RPM default template so this e2e test exercises the same
364+
# TOML config path that RPM users get on first start. The template sets
365+
# bind_address = "0.0.0.0:17670" and compute_drivers = ["podman"]; those
366+
# values must be correct for Podman e2e to pass, which means a regression
367+
# to the template (wrong bind address, wrong driver) will surface here.
368+
#
369+
# We append the driver-specific table and override the port via CLI flag
370+
# (CLI > TOML in the merge precedence) so the test can use an ephemeral port.
371+
cp "${ROOT}/deploy/rpm/gateway.toml.default" "${GATEWAY_CONFIG}"
362372
{
363-
printf '[openshell]\nversion = 1\n\n'
364-
printf '[openshell.gateway]\nlog_level = "info"\n\n'
365-
printf '[openshell.drivers.podman]\n'
373+
printf '\n[openshell.drivers.podman]\n'
366374
# The Podman driver scopes isolation by network rather than namespace.
367375
printf 'network_name = %s\n' "$(toml_string "${PODMAN_NETWORK_NAME}")"
368376
printf 'gateway_port = %s\n' "${HOST_PORT}"
@@ -380,14 +388,14 @@ GATEWAY_CONFIG="${STATE_DIR}/gateway.toml"
380388
if [ -n "${OPENSHELL_PODMAN_SOCKET:-}" ]; then
381389
printf 'socket_path = %s\n' "$(toml_string "${OPENSHELL_PODMAN_SOCKET}")"
382390
fi
383-
} > "${GATEWAY_CONFIG}"
391+
} >> "${GATEWAY_CONFIG}"
384392

385393
GATEWAY_ARGS=(
386394
--config "${GATEWAY_CONFIG}"
387-
--bind-address 0.0.0.0
395+
# bind_address and compute_drivers come from the RPM template; no CLI flags
396+
# needed. Port is overridden via CLI (CLI > TOML) for ephemeral port selection.
388397
--port "${HOST_PORT}"
389398
--health-port "${HEALTH_PORT}"
390-
--drivers podman
391399
--tls-cert "${PKI_DIR}/server/tls.crt"
392400
--tls-key "${PKI_DIR}/server/tls.key"
393401
--tls-client-ca "${PKI_DIR}/ca.crt"

‎openshell.spec‎

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
# SPDX-License-Identifier: Apache-2.0
33

44
%global crate openshell
5-
%global openshell_cargo_version %{version}
5+
%global openshell_version 0.0.37
6+
%global openshell_cargo_version %{openshell_version}
67
# Python dist-info metadata intentionally follows the RPM Version. Dev build
78
# identity is represented by Release for RPM packages.
8-
%global openshell_python_version %{version}
9+
%global openshell_python_version %{openshell_version}
910

1011
# Cargo/Rust builds with vendored deps do not produce debugsource listings
1112
# in the format redhat-rpm-config expects (especially on EPEL).
@@ -18,14 +19,14 @@
1819
%global image_tag dev
1920

2021
Name: openshell
21-
Version: 0.0.37
22-
Release: 1.20260506170246815148.rpm.dev.106.g99e94469%{?dist}
22+
Version: %{openshell_version}
23+
Release: 1.20260518180028805757.podman.toml.gateway.listener.11.g8c0cb7c8%{?dist}
2324
Summary: Safe, sandboxed runtimes for autonomous AI agents
2425

2526
License: Apache-2.0
2627
URL: https://github.com/NVIDIA/OpenShell
27-
Source0: openshell-0.0.37.tar.gz
28-
Source1: openshell-0.0.37-vendor.tar.xz
28+
Source0: openshell-%{openshell_version}.tar.gz
29+
Source1: openshell-%{openshell_version}-vendor.tar.xz
2930

3031
ExclusiveArch: x86_64 aarch64
3132

@@ -127,6 +128,11 @@ install -Dpm 0755 target/release/%{name} %{buildroot}%{_bindir}/%{name}
127128
# --- Gateway binary ---
128129
install -Dpm 0755 target/release/%{name}-gateway %{buildroot}%{_bindir}/%{name}-gateway
129130

131+
# --- Default gateway TOML config template ---
132+
# Shipped as a read-only reference in %{_datadir}. The systemd unit seeds a
133+
# user-level copy at ~/.config/openshell/gateway.toml on first start.
134+
install -Dpm 0644 deploy/rpm/gateway.toml.default %{buildroot}%{_datadir}/%{name}-gateway/gateway.toml.default
135+
130136
# --- Gateway systemd user unit ---
131137
# Installed to the systemd user unit directory so any user can run:
132138
# systemctl --user enable --now openshell-gateway.service
@@ -140,12 +146,17 @@ Wants=podman.socket
140146

141147
[Service]
142148
Type=exec
143-
# PKI is auto-generated on first start. Client certs are placed in
144-
# ~/.config/openshell/gateways/openshell/mtls/ so the CLI discovers them
145-
# automatically. Gateway runtime defaults are used unless a TOML config
146-
# exists in the default user config location or OPENSHELL_GATEWAY_CONFIG is set.
149+
# On first start the unit seeds a default TOML config and generates PKI.
150+
# Client certs are placed in ~/.config/openshell/gateways/openshell/mtls/ so
151+
# the CLI discovers them automatically.
147152
# See /usr/share/doc/openshell-gateway/ for details.
148153

154+
# Seed a default TOML config on first start if the user has not created one.
155+
# The template ships at /usr/share/openshell-gateway/gateway.toml.default.
156+
# Edit ~/.config/openshell/gateway.toml to customize.
157+
# %%E expands to $XDG_CONFIG_HOME (~/.config) in user units.
158+
ExecStartPre=/bin/sh -c 'test -f %%E/openshell/gateway.toml || install -Dm644 /usr/share/openshell-gateway/gateway.toml.default %%E/openshell/gateway.toml'
159+
149160
# Auto-generate PKI on first start if not present.
150161
# %%S expands to $XDG_STATE_HOME (~/.local/state) in user units.
151162
ExecStartPre=/usr/bin/openshell-gateway generate-certs --output-dir %%S/openshell/tls --server-san host.openshell.internal
@@ -220,6 +231,15 @@ touch %{buildroot}%{python3_sitelib}/%{name}-%{openshell_python_version}.dist-in
220231
# build environment.
221232
PYTHONPATH=%{buildroot}%{python3_sitelib} %{python3} -c "from importlib.metadata import version; v = version('openshell'); print(v); assert v == '%{openshell_python_version}', f'expected %{openshell_python_version}, got {v}'"
222233

234+
# Verify the RPM default TOML config template was installed.
235+
# A missing template means first-start seeding silently falls back to the
236+
# binary default of 127.0.0.1, which breaks Podman sandbox connectivity.
237+
test -f %{buildroot}%{_datadir}/%{name}-gateway/gateway.toml.default
238+
239+
# Verify the systemd unit references the template in its ExecStartPre seed step.
240+
# If this grep fails, the first-start seeding logic was removed from the unit.
241+
grep -q 'gateway.toml.default' %{buildroot}%{_userunitdir}/%{name}-gateway.service
242+
223243
%post gateway
224244
%systemd_user_post %{name}-gateway.service
225245

@@ -246,6 +266,7 @@ PYTHONPATH=%{buildroot}%{python3_sitelib} %{python3} -c "from importlib.metadata
246266
%doc %{_docdir}/%{name}-gateway/TROUBLESHOOTING.md
247267
%{_bindir}/%{name}-gateway
248268
%{_userunitdir}/%{name}-gateway.service
269+
%{_datadir}/%{name}-gateway/gateway.toml.default
249270
%{_mandir}/man8/openshell-gateway.8*
250271

251272
%files -n python3-%{name}

0 commit comments

Comments
 (0)