cases

package
v0.2.19 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 11, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Overview

Package cases contains shared e2e test case builders that are reused across multiple test suites. Each function returns a features.Feature that can be handed to testenv.Test(t, feature) in any suite.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AgentCLIFlow

func AgentCLIFlow() features.Feature

AgentCLIFlow returns a feature that exercises the full user-facing CLI journey:

  1. railgrid login --hub-url <hub> --token <token>
  2. railgrid edge create <name> --type kubernetes
  3. railgrid edge join-command <name> → capture output, parse Option C args
  4. Start agent using parsed flags (railgrid agent run)
  5. Wait for edge to become Ready
  6. railgrid edge kubeconfig <name> --output <path>
  7. kubectl --kubeconfig <path> get nodes → verify cluster access

This closes the gap where "join-command" output was never executed in tests: any format change in the output would now be caught immediately.

func AgentConnectsWithJoinToken

func AgentConnectsWithJoinToken() features.Feature

AgentConnectsWithJoinToken verifies that a railgrid agent can bootstrap its connection to the hub using only the Edge join token (no hub kubeconfig / service-account token required). After a successful token exchange the edge must reach the Ready phase.

func AgentEdgeJoin

func AgentEdgeJoin() features.Feature

AgentEdgeJoin returns a feature that starts a railgrid-agent, waits for the edge to become Ready, and asserts the edge proxy is reachable. Only use this in suites that set up both a hub and an agent cluster.

func AgentHelmInstall

func AgentHelmInstall() features.Feature

AgentHelmInstall verifies that a kubernetes-type edge agent can be deployed into an agent cluster via the local railgrid-agent Helm chart. The helm install uses --wait so it completes only when the Deployment is ready; the test then waits for the hub edge to reach Ready.

func AgentJoinKubernetes

func AgentJoinKubernetes() features.Feature

AgentJoinKubernetes verifies that a kubernetes-type edge agent can be deployed into an agent cluster via `railgrid agent join --type kubernetes`. The command installs the agent as a Kubernetes Deployment in railgrid-agent and exits; the test then waits for the Deployment to become available and the hub edge to reach Ready.

func CrossWorkspaceEdgeIsolation

func CrossWorkspaceEdgeIsolation() features.Feature

CrossWorkspaceEdgeIsolation verifies bidirectional multi-tenant isolation: User A cannot access User B's edges and User B cannot access User A's edges via the hub proxy.

Regression test for issue #81: "Cross-workspace edge isolation (security)".

Flow:

  1. User A performs headless OIDC login → kubeconfig + ID token.
  2. User A creates an Edge resource in their kcp workspace.
  3. User B performs headless OIDC login → ID token.
  4. User B creates an Edge resource in their kcp workspace.
  5. User B's token → User A's edge proxy URL → expect 401/403.
  6. User A's token → User B's edge proxy URL → expect 401/403.

This test requires a Dex setup with at least two static users (User A and User B). It is skipped when the second user is not configured or when Dex is not available (non-OIDC suite).

func EdgeFailoverIsolation

func EdgeFailoverIsolation() features.Feature

EdgeFailoverIsolation verifies that when edge-1 goes offline, a VirtualWorkload targeting only edge-2 is unaffected.

func EdgeLifecycle

func EdgeLifecycle() features.Feature

EdgeLifecycle returns a feature that creates, lists, and deletes an edge.

func EdgeListAccuracyUnderChurn

func EdgeListAccuracyUnderChurn() features.Feature

EdgeListAccuracyUnderChurn verifies that `railgrid edge list` accurately reflects Ready / Disconnected state as agents stop and start.

func EdgeReconnect

func EdgeReconnect() features.Feature

EdgeReconnect verifies that after edge-1 goes offline and reconnects, a VirtualWorkload targeting it is re-scheduled.

func EdgeTunnelResilience

func EdgeTunnelResilience() features.Feature

EdgeTunnelResilience returns a feature that verifies the agent reconnects after a brief disconnect. Only use this in suites that set up an agent cluster.

func EdgeURLSet

func EdgeURLSet() features.Feature

EdgeURLSet verifies that status.URL is populated after a kubernetes-type edge connects and that the URL ends in "/k8s".

func HubHealth

func HubHealth() features.Feature

HubHealth returns a feature that asserts /healthz and /readyz return 200.

func HubProxyMembershipIsolation

func HubProxyMembershipIsolation() features.Feature

HubProxyMembershipIsolation verifies the membership-gated proxy: each user reaches only the workspace clusters their UserMembershipIndex covers, with cross-user access refused until granted, and bare paths rejected.

func InvalidJoinTokenReturns401

func InvalidJoinTokenReturns401() features.Feature

InvalidJoinTokenReturns401 verifies that the hub rejects agent connections that present an incorrect join token, and that the edge never reaches the Ready phase as a result.

func JoinTokenClearedAfterRegistration

func JoinTokenClearedAfterRegistration() features.Feature

JoinTokenClearedAfterRegistration verifies that after a join-token agent successfully connects to the hub:

  1. status.joinToken is cleared (so the one-time token can't be reused)
  2. The Registered condition is set to True

func JoinTokenIsSetAfterEdgeCreation

func JoinTokenIsSetAfterEdgeCreation() features.Feature

JoinTokenIsSetAfterEdgeCreation verifies that the hub controller (TokenReconciler) generates a non-empty join token in Edge.Status.JoinToken shortly after the Edge resource is created.

The token must be a 44-character base64url string — the expected encoding of 32 cryptographically-random bytes via base64.URLEncoding.

func JoinTokenKubernetesMode

func JoinTokenKubernetesMode() features.Feature

JoinTokenKubernetesMode verifies that a kubernetes-type edge can bootstrap its connection to the hub using only a join token (no pre-provisioned hub kubeconfig / ServiceAccount credential). After the token exchange the edge must reach the Ready phase and the k8s proxy must be reachable.

func JoinTokenReconnectWithSavedKubeconfig

func JoinTokenReconnectWithSavedKubeconfig() features.Feature

JoinTokenReconnectWithSavedKubeconfig verifies the full reconnect-after-restart flow:

  1. Agent authenticates with a bootstrap join token.
  2. Hub exchanges the token for a kubeconfig and returns it in X-Railgrid-Agent-Kubeconfig; the agent saves it to disk.
  3. Agent process is stopped.
  4. A fresh agent process for the same edge starts WITHOUT a token.
  5. It auto-detects the saved kubeconfig and reconnects; edge reaches Ready.

func JoinTokenSSHCredentialsStoredAfterConnect

func JoinTokenSSHCredentialsStoredAfterConnect() features.Feature

JoinTokenSSHCredentialsStoredAfterConnect verifies that when a server-type agent connects with a join token AND provides SSH credentials via command flags, the hub stores those credentials in edge.status.sshCredentials.

In join-token mode the agent cannot call the kcp API directly (the token is not a valid kcp credential), so SSH credentials are sent as X-Railgrid-SSH-* WebSocket headers during the initial tunnel establishment. The hub's agent-proxy builder reads those headers and persists the credentials as a k8s Secret, then links the Secret in edge.status.sshCredentials.

func K8sProxyAccess

func K8sProxyAccess() features.Feature

K8sProxyAccess verifies that kubectl against status.URL returns the edge cluster's resources (nodes and namespaces). This is an end-to-end test of the k8s proxy path through the hub.

Only use this in suites that set up both a hub and at least one agent cluster.

func K8sProxyExec

func K8sProxyExec() features.Feature

K8sProxyExec verifies that kubectl exec works through the k8s proxy endpoint, testing the SPDY upgrade/hijack path in the hub reverse proxy.

Flow:

  1. Create edge + start agent → wait for Ready.
  2. Get status.URL.
  3. kubectl apply a busybox Pod via KubectlWithURL.
  4. Wait for the Pod to be Running (max 5 min — busybox may need to pull).
  5. kubectl exec <pod> -- echo railgrid_exec_ok via KubectlWithURL.
  6. Assert output contains the marker.
  7. Cleanup: delete the Pod, stop agent, delete edge.

func K8sProxyWrite

func K8sProxyWrite() features.Feature

K8sProxyWrite verifies that a resource can be written to the edge cluster via the k8s proxy endpoint (kubectl apply through status.URL).

Flow:

  1. Create edge + start agent → wait for Ready.
  2. Get status.URL.
  3. kubectl apply a ConfigMap via KubectlWithURL.
  4. kubectl get configmap to confirm it exists.
  5. Cleanup: delete the ConfigMap, stop agent, delete edge.

func K8sProxyWriteIsolation

func K8sProxyWriteIsolation() features.Feature

K8sProxyWriteIsolation verifies that a ConfigMap written via the k8s proxy lands on the edge cluster and NOT on the hub cluster.

Regression test for issue #80: "k8s proxy write must be isolated to edge cluster, not hub".

Flow:

  1. Create a kubernetes-type edge + start agent → wait for Ready.
  2. Apply a ConfigMap via the edge proxy URL (status.URL/k8s).
  3. Confirm the ConfigMap EXISTS on the edge cluster (direct AgentKubeconfig).
  4. Confirm the ConfigMap does NOT exist on the hub cluster (HubKubeconfig).

The test is skipped when no agent kubeconfig is available in the environment (e.g. external-kcp suites where the agent cluster is not directly accessible).

func LabelBasedScheduling

func LabelBasedScheduling() features.Feature

LabelBasedScheduling verifies that a VirtualWorkload with an edge-label selector is scheduled only to the matching edge.

func MCPEndpoint

func MCPEndpoint() features.Feature

MCPEndpoint verifies the per-tenant MCP endpoint with a full protocol flow: initialize → tools/list → tools/call namespaces_list → tools/call pods_list_in_namespace.

func MCPURL

func MCPURL() features.Feature

MCPURL verifies that `railgrid mcp url` prints valid MCP endpoint URLs.

func MultiOrgIsolation

func MultiOrgIsolation() features.Feature

MultiOrgIsolation is a comprehensive isolation test for the hub REST surface from PR #214. It verifies that User B (a different OIDC identity than User A) cannot observe or mutate any of the org, workspace, membership, or service-account state User A creates.

Requires the OIDC suite (two static users in Dex).

func OIDCCrossUserEdgeIsolation

func OIDCCrossUserEdgeIsolation() features.Feature

OIDCCrossUserEdgeIsolation verifies that OIDC User B cannot access an edge registered by OIDC User A via the hub proxy. Regression test for the OIDC auth bypass fixed in #75 (see also issue #63, #79).

Flow:

  1. User A performs a headless OIDC login → obtains kubeconfig + ID token.
  2. User A creates an Edge resource in their kcp workspace.
  3. User B performs a headless OIDC login → obtains an ID token (different identity).
  4. User B sends a GET request to User A's edge proxy URL using their own token.
  5. Assert the hub returns 401 or 403 (never 200/500).

This test requires a Dex setup with at least two static users (DexTestUserEmail and DexTestUser2Email). It is skipped when the second user is not configured or when Dex is not available (non-OIDC suite).

func ProxyInvalidToken

func ProxyInvalidToken() features.Feature

ProxyInvalidToken verifies that the edges-proxy handler rejects requests carrying invalid Bearer tokens with HTTP 401 or 403.

Two sub-cases are exercised:

  1. A completely opaque garbage token ("Bearer <random-string>").
  2. A syntactically well-formed but cryptographically invalid JWT.

func ProxyUnauthenticated

func ProxyUnauthenticated() features.Feature

ProxyUnauthenticated verifies that a request to the edges proxy without a Bearer token is rejected with HTTP 401 Unauthorized.

The edges proxy handler (pkg/virtual/builder/edges_proxy_builder.go) checks for a valid bearer token as its very first step — before any path parsing or cluster lookup — so this test does not require a running agent or edge resource: it only needs a reachable hub.

func SSHDockerServerModeConnect

func SSHDockerServerModeConnect() features.Feature

SSHDockerServerModeConnect is the Docker-based variant of SSHServerModeConnect. It runs lscr.io/linuxserver/openssh-server in a container (--network host) alongside a railgrid server-mode agent, and verifies the full SSH path through the hub tunnel.

The agent authenticates using a real hub-generated join token (not a static dev token) to exercise the full join-token bootstrap flow end-to-end.

func SSHEdgeURLSet

func SSHEdgeURLSet() features.Feature

SSHEdgeURLSet verifies that status.URL is populated for server-type edges and that the URL ends in "/ssh". It follows the same setup as SSHServerModeConnect but only asserts on the URL field.

func SSHOIDCUsernameMapping

func SSHOIDCUsernameMapping() features.Feature

SSHOIDCUsernameMapping verifies that when sshUserMapping=identity, the SSH session is established as the caller's OIDC identity (kcp username obtained via TokenReview). This test requires the OIDC suite (Dex); it is skipped in the standalone suite.

Flow:

  1. Headless OIDC login as the Dex test user → kubeconfig + ID token.
  2. ResolveCallerIdentity against the OIDC kubeconfig → expectedUser.
  3. Generate SSH keypair; configure TestSSHServer to accept any username.
  4. Start a server-mode agent using the OIDC kubeconfig (registers the Edge in the OIDC user's kcp workspace).
  5. Wait for the Edge to become Ready.
  6. Create a Secret containing the SSH private key in the OIDC workspace.
  7. Patch the Edge with sshUserMapping=identity + sshCredentialsRef.
  8. DialSSH using the OIDC kubeconfig (hub receives OIDC token, performs TokenReview, and uses the result as the SSH username).
  9. Assert TestSSHServer recorded the connection as expectedUser.

func SSHServerModeConnect

func SSHServerModeConnect() features.Feature

SSHServerModeConnect verifies the full SSH path end-to-end:

  1. Start an embedded test SSH server + railgrid agent (--mode=server) as subprocesses
  2. Wait for the Edge resource to become Ready on the hub
  3. Run `railgrid ssh <name> -- echo <marker>` and verify the marker in output
  4. Verify interactive PTY (WebSocket, resize, keystrokes, output)
  5. Hold the session for the configured duration and assert it stays alive

func SSHUserMappingIdentity

func SSHUserMappingIdentity() features.Feature

SSHUserMappingIdentity verifies that when sshUserMapping=identity, the hub uses the caller's kcp/OIDC username as the SSH username. The SSH key comes from spec.server.sshCredentialsRef.

func SSHUserMappingInherited

func SSHUserMappingInherited() features.Feature

SSHUserMappingInherited verifies that when sshUserMapping=inherited (or unset / default), the hub uses credentials reported by the agent at registration time (Edge.Status.SSHCredentials). The agent is started with --ssh-user=testuser --ssh-password=testpassword; the test runs `echo $USER` over SSH and checks the output is "testuser".

func SSHUserMappingProvided

func SSHUserMappingProvided() features.Feature

SSHUserMappingProvided verifies that when sshUserMapping=provided, the hub reads the SSH username and key entirely from spec.server.sshCredentialsRef. The agent does NOT report any SSH credentials.

func StaticTokenLogin

func StaticTokenLogin() features.Feature

StaticTokenLogin returns a feature that asserts railgrid login succeeds with the static dev-token.

func TenancyOrgCRUD

func TenancyOrgCRUD() features.Feature

TenancyOrgCRUD walks the full Org lifecycle: create → get → rename → soft-delete → check deletionRequestedAt → undelete → re-rename → final soft-delete. Each step is a separate assess so a regression in one stage doesn't mask later behaviour.

func TenancyPersonalOrgSoftDelete

func TenancyPersonalOrgSoftDelete() features.Feature

TenancyPersonalOrgSoftDelete verifies the API contract for the caller's personal org: the bootstrap creates one on first /api/orgs call, a direct DELETE on it is accepted (the soft-delete reconciler picks it up), and Undelete restores it within the grace window. Pins the API behavior so a future guardrail addition has to update this test rather than silently change behavior.

func TenancySACRUD

func TenancySACRUD() features.Feature

TenancySACRUD walks the SA lifecycle: create → list → issue token → revoke (DELETE all tokens) → delete SA. Token usage against a tenancy endpoint is verified in TenancySATokenAccess below.

func TenancySATokenAccess

func TenancySATokenAccess() features.Feature

TenancySATokenAccess verifies an issued SA token can actually authenticate against the workspace whose endpoints it was minted for. Without this the rest of the SA tests only prove the surface accepts our calls, not that tokens are real.

func TenancySATokenCrossWorkspace

func TenancySATokenCrossWorkspace() features.Feature

TenancySATokenCrossWorkspace verifies that a SA token issued in (orgA, wsA) does not work against (orgB, wsB) belonging to a different user. Skipped outside the OIDC suite (we need two distinct identities).

func TenancySoftDeleteHidesOrg

func TenancySoftDeleteHidesOrg() features.Feature

TenancySoftDeleteHidesOrg verifies the UMI-driven org list does not expose soft-deleted orgs to the caller, but does expose them again after undelete. This is the observable contract; whether the marker lives on the Org CR or on the UMI entry is implementation detail.

func TenancyTenantHeaders

func TenancyTenantHeaders() features.Feature

TenancyTenantHeaders verifies the tenant middleware rejects requests where the X-Railgrid-Org/X-Railgrid-Workspace headers are missing, point at a non-existent org, or don't match the URL path.

func TenancyWorkspaceCRUD

func TenancyWorkspaceCRUD() features.Feature

TenancyWorkspaceCRUD creates an org, then walks the workspace lifecycle: create → patch displayName → soft-delete → undelete.

func TokenReconcilerNoReissueAfterRegistration

func TokenReconcilerNoReissueAfterRegistration() features.Feature

TokenReconcilerNoReissueAfterRegistration verifies that the TokenReconciler does NOT generate a new join token once an edge is marked Registered=True. This ensures the one-shot bootstrap token cannot be recycled after the first successful agent registration.

func TwoAgentsJoin

func TwoAgentsJoin() features.Feature

TwoAgentsJoin returns a feature that starts two railgrid-agents connecting to the same hub and verifies both edges appear as Ready.

func WorkloadDeployment

func WorkloadDeployment() features.Feature

WorkloadDeployment verifies the full workload delivery pipeline:

  1. Create an edge with label "env=e2e-wl" and start a railgrid-agent.
  2. Apply a VirtualWorkload targeting edges with that label (simple pause spec).
  3. Wait for a Placement to be created by the hub scheduler (max 2 min).
  4. Wait for a Deployment to appear on the edge cluster via the k8s proxy (max 2 min).
  5. Teardown: delete VirtualWorkload, delete edge, stop agent.

The workload reconciler on the agent side converts Placements into local Deployments (pkg/agent/reconciler/workload.go). The Deployment name matches the VirtualWorkload name.

func WorkloadIsolation

func WorkloadIsolation() features.Feature

WorkloadIsolation verifies that a workload placed on edge-1 is not visible (no Placement) on edge-2.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL