Skip to content

feat(auth): per-user sandbox ownership enforcement#18

Merged
pdettori merged 3 commits into
mvp-v2from
feat/per-user-sandbox-ownership-1976
Jun 16, 2026
Merged

feat(auth): per-user sandbox ownership enforcement#18
pdettori merged 3 commits into
mvp-v2from
feat/per-user-sandbox-ownership-1976

Conversation

@pdettori

Copy link
Copy Markdown
Member

Summary

Implements Task A from kagenti/kagenti#1976 (per-user sandbox ownership on a shared OpenShell gateway).

  • Adds auth/ownership.rs module with core ownership functions: stamp_owner, check_owner, owner_selector, and sanitize_subject
  • Stamps openshell.ai/owner label on sandboxes at creation time from the verified OIDC identity
  • Gates all sandbox operations (get, delete, watch, exec, ssh, service) on ownership verification
  • Injects owner filter into ListSandboxes selector so users only see their own sandboxes
  • Admin role bypass for cross-user operations
  • Backward compatible: pre-existing sandboxes (no owner label) remain accessible; Anonymous/LocalDev principals pass through unchanged

Design Decisions

Decision Choice Rationale
Subject format UUID passthrough, SHA-256 fallback Keycloak UUIDs are already valid K8s label values
Reserved prefix openshell.ai/ Client-supplied keys with this prefix are stripped on create
Legacy sandbox access Allow (no owner label = open) Avoids breaking existing deployments on upgrade
Admin detection state.config.oidc.admin_role Consistent with existing AuthzPolicy
OIDC disabled Skip ownership entirely Principal is None → no stamp, no filter, no check

Test Plan

  • Unit tests in ownership.rs (20 tests covering all branches)
  • CI compilation gate (no local Rust toolchain — relies on Nix flakes in CI)
  • Integration test with OIDC-enabled server (future PR)

Addresses kagenti/kagenti#1976

Assisted-By: Claude Code

pdettori added 3 commits June 15, 2026 22:26
Add an `auth/ownership.rs` module that stamps an `openshell.ai/owner`
label on sandboxes at creation time (from the verified OIDC identity)
and gates access on subsequent operations.

Key behaviors:
- CreateSandbox: strips client-supplied reserved keys, stamps owner
- ListSandboxes: injects owner filter into the label selector
- Get/Delete/Watch/Exec/SSH/Service handlers: verify caller owns the
  sandbox before proceeding
- Admin bypass: callers with the configured admin role skip ownership
- Backward compat: sandboxes without owner label (pre-existing) and
  anonymous/LocalDev principals (OIDC disabled) are allowed through

Addresses kagenti/kagenti#1976 task A.

Signed-off-by: Paolo Dettori <paolo@dettori.dev>
Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Paolo Dettori <dettori@us.ibm.com>
Break long method chains across multiple lines to satisfy the project's
rustfmt configuration.

Signed-off-by: Paolo Dettori <paolo@dettori.dev>
Signed-off-by: Paolo Dettori <dettori@us.ibm.com>
- Move `use sha2` and `use std::fmt::Write` to module top (items-after-statements)
- Add `#![allow(clippy::result_large_err)]` (consistent with other handlers)
- Use `let...else` instead of match for early returns (manual-let-else)
- Nest or-patterns in require_identity (unnested-or-patterns)
- Collapse nested if in revoke_ssh handler (collapsible-if)

Signed-off-by: Paolo Dettori <paolo@dettori.dev>
Signed-off-by: Paolo Dettori <dettori@us.ibm.com>
@pdettori pdettori force-pushed the feat/per-user-sandbox-ownership-1976 branch from 80f9e60 to f2fa5bd Compare June 16, 2026 02:48
@pdettori pdettori merged commit 3ade5e5 into mvp-v2 Jun 16, 2026
8 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant