Skip to content

Commit 475f6dd

Browse files
authored
test(e2e): run podman suite with tmachine
Signed-off-by: Evan Lezar <elezar@nvidia.com>
1 parent 0c29d8e commit 475f6dd

7 files changed

Lines changed: 207 additions & 8 deletions

File tree

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ jobs:
261261
test-matrix: >-
262262
[
263263
{"environment":"fedora-podman-rootful","installer":"binaries","testsuite":"driver-podman"},
264+
{"environment":"fedora-podman-rootless","installer":"binaries","testsuite":"e2e-podman"},
264265
{"environment":"fedora-podman-rootless","installer":"binaries","testsuite":"driver-podman"}
265266
]
266267

‎TESTING.md‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,23 @@ Rust tests that still apply. Run the Podman-backed Rust CLI e2e suite:
254254
mise run e2e:podman
255255
```
256256

257+
Run the portable subset in a disposable rootless Podman guest:
258+
259+
```shell
260+
nix run .#build-artifacts
261+
nix run .#tmachine -- test fedora-podman-rootless binaries e2e-podman
262+
nix run .#tmachine -- test fedora-podman-rootless binaries driver-podman
263+
```
264+
265+
The `e2e-podman` testsuite runs a nextest archive built with the corresponding
266+
Rust feature. The separate `driver-podman` testsuite compares OpenShell and
267+
direct Podman user-namespace mappings for the default, `auto`, `keep-id`, and
268+
private profiles. The E2E archive excludes binaries that still depend on
269+
wrapper-owned gateway controls, host fixtures, missing guest tools, or
270+
nondeterministic relay setup.
271+
`tests/artifacts.nix` keeps the explicit follow-up list so those binaries cannot
272+
appear as false passes or silently re-enter the archive.
273+
257274
Run the VM-backed Rust CLI e2e suite:
258275

259276
```shell

‎e2e/rust/tests/live_policy_update.rs‎

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ use openshell_e2e::harness::output::{extract_field, strip_ansi};
3232
use openshell_e2e::harness::sandbox::SandboxGuard;
3333
use tempfile::NamedTempFile;
3434

35+
const SPARSE_POLICY: &str = include_str!(concat!(
36+
env!("CARGO_MANIFEST_DIR"),
37+
"/../../examples/policy-advisor/sandbox-policy.yaml"
38+
));
39+
3540
// ---------------------------------------------------------------------------
3641
// Policy YAML builders
3742
// ---------------------------------------------------------------------------
@@ -126,6 +131,15 @@ landlock:
126131
Ok(file)
127132
}
128133

134+
fn write_sparse_policy() -> Result<NamedTempFile, String> {
135+
let mut file = NamedTempFile::new().map_err(|e| format!("create temp policy file: {e}"))?;
136+
file.write_all(SPARSE_POLICY.as_bytes())
137+
.map_err(|e| format!("write temp policy file: {e}"))?;
138+
file.flush()
139+
.map_err(|e| format!("flush temp policy file: {e}"))?;
140+
Ok(file)
141+
}
142+
129143
// ---------------------------------------------------------------------------
130144
// CLI helpers
131145
// ---------------------------------------------------------------------------
@@ -629,18 +643,18 @@ async fn live_policy_update_from_empty_network_policies() {
629643
/// no revision remaining `Pending` once the acknowledgement lands.
630644
#[tokio::test]
631645
async fn initial_sparse_policy_is_acknowledged_as_loaded() {
632-
// Repo-relative path to the sparse network-only policy fixture.
633-
let sparse_policy = concat!(
634-
env!("CARGO_MANIFEST_DIR"),
635-
"/../../examples/policy-advisor/sandbox-policy.yaml"
636-
);
646+
let sparse_policy = write_sparse_policy().expect("write sparse policy fixture");
647+
let sparse_policy_path = sparse_policy
648+
.path()
649+
.to_str()
650+
.expect("sparse policy path is not UTF-8");
637651

638652
let mut guard = SandboxGuard::create_keep_with_args(
639653
&[
640654
"--name",
641655
"e2e-sparse-enrich",
642656
"--policy",
643-
sparse_policy,
657+
sparse_policy_path,
644658
"--no-tty",
645659
],
646660
&["sh", "-c", "echo Ready && sleep infinity"],
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
---
5+
- name: Run Podman E2E archive tests
6+
hosts: all
7+
gather_facts: false
8+
vars:
9+
podman_e2e_test_root: /var/lib/openshell-driver-tests/podman-e2e
10+
tasks:
11+
- name: Wait for SSH
12+
ansible.builtin.wait_for_connection:
13+
14+
- name: Create Podman E2E test directory
15+
become: true
16+
ansible.builtin.file:
17+
path: "{{ podman_e2e_test_root }}"
18+
state: directory
19+
owner: tmachine
20+
group: tmachine
21+
mode: "0700"
22+
23+
- name: Install Podman E2E test bundle
24+
become: true
25+
ansible.builtin.unarchive:
26+
src: "{{ openshell_podman_e2e_test_bundle }}"
27+
dest: "{{ podman_e2e_test_root }}"
28+
owner: tmachine
29+
group: tmachine
30+
31+
- name: Remove any previous OpenShell gateway registration
32+
ansible.builtin.command:
33+
argv: [/usr/local/bin/openshell, gateway, remove, tmachine]
34+
changed_when: false
35+
failed_when: false
36+
37+
- name: Register the configured OpenShell gateway
38+
ansible.builtin.command:
39+
argv: [/usr/local/bin/openshell, gateway, add, http://127.0.0.1:17670, --local, --name, tmachine]
40+
41+
- name: Run Podman E2E archive tests
42+
ansible.builtin.command:
43+
argv:
44+
- cargo-nextest
45+
- nextest
46+
- run
47+
- --archive-file
48+
- "{{ podman_e2e_test_root }}/tests.tar.zst"
49+
- --workspace-remap
50+
- "{{ podman_e2e_test_root }}"
51+
- --test-threads
52+
- "1"
53+
- --no-fail-fast
54+
environment:
55+
CONTAINER_ENGINE: podman
56+
CONTAINER_HOST: unix:///run/user/1000/podman/podman.sock
57+
HOME: /home/tmachine
58+
OPENSHELL_BIN: /usr/local/bin/openshell
59+
OPENSHELL_E2E_CONTAINER_ENGINE_UNSET_XDG_CONFIG_HOME: "1"
60+
OPENSHELL_E2E_DRIVER: podman
61+
OPENSHELL_E2E_NETWORK_NAME: tmachine
62+
OPENSHELL_E2E_SANDBOX_NAMESPACE: tmachine
63+
OPENSHELL_GATEWAY: tmachine
64+
OPENSHELL_PODMAN_SOCKET: /run/user/1000/podman/podman.sock
65+
XDG_RUNTIME_DIR: /run/user/1000
66+
register: podman_e2e_test_result
67+
changed_when: false
68+
failed_when: false
69+
70+
- name: Show Podman E2E test diagnostics
71+
ansible.builtin.debug:
72+
var: podman_e2e_test_result.stderr_lines
73+
74+
- name: Show Podman E2E test result
75+
ansible.builtin.debug:
76+
var: podman_e2e_test_result.stdout_lines
77+
78+
- name: Capture OpenShell gateway journal after Podman E2E test failure
79+
become: true
80+
ansible.builtin.command:
81+
argv: [journalctl, --unit, openshell-gateway.service, --no-pager, --lines, "200"]
82+
changed_when: false
83+
failed_when: false
84+
when: podman_e2e_test_result.rc != 0
85+
register: podman_e2e_gateway_journal
86+
87+
- name: Show OpenShell gateway journal after Podman E2E test failure
88+
ansible.builtin.debug:
89+
var: podman_e2e_gateway_journal.stdout_lines
90+
when: podman_e2e_test_result.rc != 0
91+
92+
- name: Require Podman E2E archive success
93+
ansible.builtin.assert:
94+
that: [podman_e2e_test_result.rc == 0]
95+
fail_msg: Podman E2E archive tests failed

‎tests/ansible/roles/openshell_gateway/templates/gateway-podman.toml.j2‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ sandbox_runtime_image = "docker.io/openshell/sandbox:tmachine"
99
supervisor_image = "docker.io/openshell/supervisor:tmachine"
1010
network_name = "tmachine"
1111
health_check_interval_secs = 10
12+
stop_timeout_secs = 15
1213
{% endblock %}

‎tests/artifacts.nix‎

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ let
2424
package,
2525
target,
2626
output,
27+
features ? null,
28+
filter ? "kind(test)",
2729
}:
2830
pkgs.writeShellApplication {
2931
name = "build-${name}-test-archive";
@@ -56,7 +58,8 @@ let
5658
--manifest-path "$manifest_path" \
5759
--target ${target} \
5860
-p ${package} \
59-
-E 'kind(test)' \
61+
${pkgs.lib.optionalString (features != null) "--features ${pkgs.lib.escapeShellArg features}"} \
62+
-E ${pkgs.lib.escapeShellArg filter} \
6063
--archive-file "$bundle_dir/tests.tar.zst"
6164
6265
cd "$workspace_root"
@@ -92,6 +95,49 @@ let
9295
target = muslToolchain.target;
9396
output = "artifacts/test-archives/${muslToolchain.target}/provider-refresh-keycloak-tests.tar";
9497
};
98+
99+
# Follow-up: migrate these wrapper-coupled tests once tmachine provides their
100+
# managed-gateway controls, SPIFFE fixtures, caller driver-config setting,
101+
# guest tools, and matching workload-image identity behavior. The corporate
102+
# proxy and gateway-start binaries currently self-skip without wrapper-owned
103+
# gateway metadata, so exclude them rather than report false passes. The
104+
# dedicated driver-podman suite retains user-namespace coverage.
105+
podmanE2eExcludedBinaries = [
106+
"credential_gating"
107+
"driver_config_volume"
108+
"forward_proxy_graphql_l7"
109+
"forward_proxy_jsonrpc_l7"
110+
"forward_proxy_l7_bypass"
111+
"host_gateway_alias"
112+
"landlock"
113+
"local_driver_token_restart"
114+
# Standalone tmachine runs can time out while opening the localhost relay.
115+
# Follow up on making the relay setup deterministic before restoring it.
116+
"no_proxy"
117+
"podman_corporate_proxy"
118+
"podman_gateway_start"
119+
"podman_oci_identity"
120+
"podman_userns"
121+
"provider_auto_create"
122+
"provider_refresh_handles"
123+
"provider_token_exchange"
124+
"proxy_egress_pipeline"
125+
# Nextest archive filters cannot select individual tests. These binaries
126+
# contain both passing cases and cases that need guest tools (`script` and
127+
# `git`), so keep the complete binaries in the follow-up bucket.
128+
"sandbox_lifecycle"
129+
"sync"
130+
# Needs a prebuilt musl DNS probe in guest artifact mode; tracked in #3009.
131+
"transparent_tcp"
132+
"websocket_conformance"
133+
"workspace_lifecycle"
134+
];
135+
podmanE2eArchiveFilter =
136+
let
137+
excludedBinaries = map (binary: "binary(=${binary})") podmanE2eExcludedBinaries;
138+
in
139+
"kind(test) and not (${pkgs.lib.concatStringsSep " or " excludedBinaries})";
140+
95141
podmanDriverArchive = mkTestArchive {
96142
name = "podman-driver";
97143
workspacePath = "tests/suites/drivers";
@@ -100,9 +146,24 @@ let
100146
target = muslToolchain.target;
101147
output = "artifacts/test-archives/${muslToolchain.target}/openshell-podman-tests.tar";
102148
};
149+
podmanE2eArchive = mkTestArchive {
150+
name = "podman-e2e";
151+
workspacePath = "e2e/rust";
152+
manifestPath = "e2e/rust/Cargo.toml";
153+
package = "openshell-e2e";
154+
target = muslToolchain.target;
155+
output = "artifacts/test-archives/${muslToolchain.target}/openshell-podman-e2e-tests.tar";
156+
features = "e2e-podman";
157+
filter = podmanE2eArchiveFilter;
158+
};
103159
in
104160
rec {
105-
inherit conformanceCliArchive providerRefreshKeycloakArchive podmanDriverArchive;
161+
inherit
162+
conformanceCliArchive
163+
providerRefreshKeycloakArchive
164+
podmanDriverArchive
165+
podmanE2eArchive
166+
;
106167

107168
binaries = pkgs.writeShellApplication {
108169
name = "build-artifacts-binaries";
@@ -148,17 +209,20 @@ rec {
148209
conformanceCliArchive
149210
providerRefreshKeycloakArchive
150211
podmanDriverArchive
212+
podmanE2eArchive
151213
];
152214
text = ''
153215
build-openshell-conformance-test-archive
154216
build-provider-refresh-keycloak-test-archive
155217
build-podman-driver-test-archive
218+
build-podman-e2e-test-archive
156219
'';
157220
};
158221

159222
images = pkgs.writeShellApplication {
160223
name = "build-artifacts-images";
161224
runtimeInputs = [
225+
pkgs.coreutils
162226
pkgs.docker-client
163227
pkgs.git
164228
];

‎tests/config.nix‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,13 @@ let
133133
provider_refresh_keycloak_test_bundle = "../artifacts/test-archives/${muslTarget}/provider-refresh-keycloak-tests.tar";
134134
};
135135
}
136+
{
137+
name = "e2e-podman";
138+
playbooks = [ "ansible/playbooks/drivers/podman/e2e.yaml" ];
139+
inputs = {
140+
openshell_podman_e2e_test_bundle = "../artifacts/test-archives/${muslTarget}/openshell-podman-e2e-tests.tar";
141+
};
142+
}
136143
{
137144
name = "driver-podman";
138145
playbooks = [

0 commit comments

Comments
 (0)