Repository navigation
test(conformance): port the credential gating e2e tests - #5318
Conversation
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
|
Label |
|
🌿 Preview your docs: https://nvidia-preview-pr-5318.docs.buildwithfern.com/openshell |
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Port the six credential gating scenarios from e2e/rust/tests/credential_gating.rs into a conformance suite. Each test imports its own provider profile and creates a provider under a run-unique name, creates sandboxes from the Python test image through the CLI, and reaches probe servers on the host through host.openshell.internal. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
The conformance suite now creates sandboxes from testkit::python_image(). Docker and Podman runners build openshell/e2e-python:dev also in e2e-conformance-only mode, and the Kubernetes and VM runners default OPENSHELL_TEST_PYTHON_IMAGE to the pullable uv Python image. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Add testkit::policy (a base policy from base-policy.yaml, allow(), and Endpoint settings), install_provider(), YamlFile, ExecOutput::success(), and PYTHON_BINARIES, so suites build policies and providers the same way. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Add host-server-support with HttpRecorder and WebSocketRecorder, servers on the test host that sandboxes reach through host.openshell.internal. Move the host-gateway feature test onto them and onto testkit's base policy. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Use testkit's policy helpers and install_provider and host-server-support's recorders, and assert on the requests that reached the host server instead of verdicts the sandbox clients print. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
8e5c8d7 to
566b39d
Compare
|
/ok to test 566b39d |
The external-driver lane renders server.hostGatewayIP, but only the in-process driver reads it from the gateway TOML. The standalone driver takes OPENSHELL_HOST_GATEWAY_IP, which the post-renderer never set, so sandbox policy DNS refused host.openshell.internal on that lane. Copy the chart's rendered value into the driver container when present. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
|
/ok to test 99bbed4 |
Compatibility review (advisory)New or updated breaking changes; see the full report for all findings. 1. cli — No explicit risk acceptance foundOPENSHELL_E2E_KUBERNETES_FEATURES=e2e,e2e-kubernetes mise run e2e:kubernetes previously excluded host-dependent credential tests but now runs them unconditionally through openshell-conformance.
Review details
Advisory review; publication gates are unchanged. |
Conformance has to run against any gateway, and the unpublished openshell/e2e-python:dev image only exists where a lane built or loaded it. Default to the pinned uv Python image, which any gateway can pull, and keep OPENSHELL_TEST_PYTHON_IMAGE as the override. Host lanes no longer build the workload image for conformance. The base test policy names no workload user, so drivers use a default non-root user on images without one, and host_gateway runs python3 from PATH. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
|
/ok to test 61504a3 |
- The WebSocket recorder reads frames until the connection ends, and the test waits for that before checking that no binary frame arrived. - The HTTP recorder keeps the request head and body apart. The REST tests compare the body exactly and check the secret appears nowhere, and failure messages redact it. - testkit errors keep the gateway's gRPC status code, and the admission test checks for FailedPrecondition. - The policy create request destructures the SDK spec, so a new field fails to compile instead of being dropped. - host_gateway no longer retries its connection. - Docs state that conformance requires sandboxes to reach the test machine as host.openshell.internal. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
|
/ok to test 3a31220 |
elezar
left a comment
There was a problem hiding this comment.
Thanks for the port. The recorder-based assertions are a clear improvement on the old verdict strings, and keeping all six scenarios while moving them onto shared helpers is the right shape for the pilot.
I'd like two things changed before this merges, plus some smaller suggestions inline:
- Drop
61504a338(the default Python image change) and handle "conformance runs on any gateway" in a follow-up. - Give the WebSocket test a positive control, so the denial assertion can fail.
Remote-cluster behaviour (inline comment on TESTING.md) is fine as a tracked follow-up.
…mage The tmachine installers load it and the Docker and Podman lanes build it, so those lanes don't pull an image inside a test's timeout or lose curl, git and openssl. The Kubernetes and VM lanes keep using the pinned public image through OPENSHELL_TEST_PYTHON_IMAGE, and the base test policy names the sandbox user again. Running conformance against any gateway without an override is left to a follow-up. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
|
/ok to test 9ab1be1 |
Compatibility review (advisory)New or updated breaking changes; see the full report for all findings. 1. cli — Risk explicitly accepted
Review details
Advisory review; publication gates are unchanged. |
The test passed whenever no binary frame reached upstream, whatever the reason. It now first sends the same frame from a sandbox without the provider and requires that it arrives, so the denial check can fail. Unit tests check that WebSocketRecorder sees a binary frame after a long text frame, and none among text frames. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
|
/ok to test 4ff621b |
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
|
/ok to test e5e72bf |
Use tungstenite's derive_accept_key instead of hashing with sha1 and base64 directly, and split host-server into http.rs and websocket.rs. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
… is missing The post-renderer copied the host gateway IP whenever the chart rendered any hostAliases. It now matches the host.openshell.internal entry, and fails if the lane set server.hostGatewayIP but no such entry rendered. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
…r create import_profile reads the profile's id from its YAML and returns it, and create_provider takes the provider name and type separately, so the provider name no longer has to match the profile id. install_provider does both. Document that policy::allow merges binaries under one name and that an override Python image must use a PYTHON_BINARIES path. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
|
/ok to test e22087f |
…gating-pilot/matthewgrossman Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
|
/ok to test aeec397 |
testkit creates things through Context methods, such as cx.sandbox(..) and cx.on_cleanup(..), so import_profile, create_provider and install_provider become cx methods instead of free functions. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
|
/ok to test 6ebaf4d |
…gating-pilot/matthewgrossman Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
|
/ok to test 16e7f7e |
elezar
left a comment
There was a problem hiding this comment.
Approving. Both of my requested changes are addressed (the default image is back to openshell/e2e-python:dev, and the WebSocket test has a positive control), and the six credential-gating tests passed on the Kubernetes workspace-managed, Kubernetes external-driver, VM and k3s-ha lanes in run 42763840495.
Remote clusters are still a known gap, tracked in #5409, where I added a proposal to move the four host-dependent tests to a features suite.
Nits, non-blocking:
- Use
Error::from_statusat the remainingfrom_error(&status)sites incontext.rs(:217,:559,:576,:594), sogrpc_code()is kept wherever atonic::Statusis mapped. HttpRecorderhas no unit tests. A few coveringContent-Lengthbodies and the chunked case would match what the WebSocket recorder has.
Summary
Port the six credential gating e2e tests from #5264 into the conformance family, and remove the old
e2e/rusttest. This is the pilot port for #5296. The pieces the port needed that other tests will need too are shared: policy helpers and provider install in testkit, and a newtests/support/host-servercrate for servers on the test host. The existinghost-gatewayfeature test now uses them as well.Related Issue
Closes #5317
Part of #5281. Pilot for #5296, which stays open. Ports the tests from #5264.
What the tests check, and what they needed
The #5264 tests check what the sandbox supervisor does with a provider credential when the sandbox sends traffic out:
tls: skip), unless the endpoint opts in.request_body_credential_rewriteis on.policy setadds its environment variable to a running sandbox, and unbinding removes it.Porting them needed four things. Each was added as a generic helper, and
host-gateway, an existing feature test that had its own copies, now uses the shared ones.tests/support/host-server(host-server-support):HttpRecorder::start(body)answers every request with200andbody.wait_for_requests(n)returns the requests, head and body apart, oncenhave arrived. It readsContent-Lengthbodies, not chunked ones.WebSocketRecorder::start()completes the WebSocket handshake. It then reads frames until a close frame, the end of the connection, or a 10s timeout.wait_for_handshake()waits for the handshake, andwait_until_finished()waits for the connection to end and reports whether a binary frame arrived.host.openshell.internal, and stop when dropped. It lives intests/support/, alongside the Keycloak fixture, because it's a service outside OpenShell that any suite can use.host-gatewayreplaces its hand-written server withHttpRecorder.protocol: restorwebsocket,tls: skip, body rewriting,credential_binding,allow_uninspected_credentials). Before this PR, tests wrote out a whole policy as a YAML string. New testkit moduletestkit::policy:base()readsbase-policy.yaml: the filesystem and process settings every sandbox needs, and no network access.allow(&mut policy, name, host, port, binaries)adds an endpoint. ItsEndpointsetters are named after the YAML fields, e.g..rest(Access::Full).credential_binding(&provider).to_yaml()renders the policy for CLI commands such aspolicy set.PYTHON_BINARIESnames the pathspython3runs from intestkit::python_image()images, which differ between the workload image and the pullable uv image.cx.sandbox(..).policy(..)rejected both, and these tests need all three.cx.import_profile(profile_yaml)imports a profile and returns itsid, read from the YAML, andcx.create_provider(name, type, credentials)creates a provider. Each registers its cleanup before creating.cx.install_provider(name, profile_yaml, credentials)does both.testkit::YamlFilewrites YAML to a temporary file for CLI commands that read one (profile import,policy set);host-gatewayreplaces itsPolicyFilecopy with it.ExecOutput::success()fails a test on a non-zeroexecexit, likeCliOutput::success().Helpers for OpenShell itself (sandboxes, policies, providers, the CLI) go in testkit. Fixtures for services outside OpenShell go in
tests/support/.Changes
credential_gating, one file with the same six scenarios and unique names as test(e2e): split credential_gating into independent parallel tests #5264, built on the helpers above.create()error: the gRPC code must beFailedPrecondition, and the message keeps test(e2e): split credential_gating into independent parallel tests #5264's wording checks. testkit'sErrornow keeps the gateway's status code (grpc_code(),testkit::GrpcCode). The CLI is used forprofile import,provider createandpolicy set --wait.testkit::python_image()still defaults toopenshell/e2e-python:dev. The Docker and Podman runners now build it for conformance, as the tmachine installers already load it. The Kubernetes and VM runners setOPENSHELL_TEST_PYTHON_IMAGEto a pinned public uv Python image unless it is already set. A gateway outside these lanes has to setOPENSHELL_TEST_PYTHON_IMAGE; running conformance against any gateway without an override is a follow-up.host_gatewayrunspython3fromPATHand allowsPYTHON_BINARIES, so it works with either image, and no longer retries its connection for 20s: the credential tests never did, and the server listens before the sandbox is created.server.hostGatewayIPinto the standalone driver'sOPENSHELL_HOST_GATEWAY_IP. Before, only the in-process driver got it, so sandboxes on that lane couldn't resolvehost.openshell.internal. The lane hadn't run a host-reachability test before. The renderer fails if the lane set the IP but the chart rendered nohost.openshell.internalalias.e2e/rust/tests/credential_gating.rs, its[[test]]entry, and itsPODMAN_CI_TESTSentry.TESTING.mdlist the suite and state that conformance requires the machine running it to be reachable from sandboxes ashost.openshell.internal.Gaps found by the pilot (for #5296)
cx.sandbox(suffix). testkit doesn't check this before sending the request.e2e/rust/e2e-*.shscripts, not tmachine.Testing
cargo fmtandcargo clippy --locked --all-targets -D warningson testkit, support, features and conformance.testkit unit tests: 43 passed.
check_cargo_lockfile_alignment.pyandcheck-conformance-program.sh(22 tests) pass.Local Podman (macOS,
e2e/with-podman-gateway.sh):openshell-conformance run credential_gatingpassed 6/6 in 33.7s.host_gatewaypassed.policy_binding_requires_inspection_or_opt_inpolicy_binding_rest_body_keeps_placeholder_without_rewritepolicy_binding_rest_body_rewrite_sends_secret_upstreampolicy_binding_updates_provider_environment_liveprofile_rest_endpoint_keeps_body_placeholderprofile_websocket_endpoint_denies_binary_framesNot run locally: Docker (Docker Desktop requires sign-in), k3s, k3s-ha. CI covers these rows.
CI: copy-pr-bot doesn't sync draft PRs, so E2E runs only after a maintainer comments
/ok to test <sha>. In #5264, the WebSocket test took 60–120s on Kubernetes. If k3s or k3s-ha hit the per-test timeout, I'll raise it here rather than change.config/nextest.toml(see #5295).Checklist