feat(workspace): add workspace resource model with scoping, membershi…#2243
feat(workspace): add workspace resource model with scoping, membershi…#2243derekwaynecarr wants to merge 11 commits into
Conversation
2468c04 to
77ef1fc
Compare
Thread workspace through compute drivers (Docker, Podman, K8s) with
converged container naming (openshell-{workspace}--{name}-{id}),
workspace labels, and label-based lookup. Fix sandbox-side policy sync
to use learned workspace instead of hardcoding empty string. Fix TUI
all-workspaces view to use per-row workspace for sandbox actions. Add
provider profile to workspace deletion blocking check. Thread workspace
through SSH config generation with workspace-qualified host aliases.
Signed-off-by: Derek Carr <decarr@redhat.com>
Add workspace as a required parameter for resource-scoped operations (create, get, delete, wait_ready, wait_deleted) and optional for list operations that support all_workspaces global lookup. Rename ClusterInferenceConfig to InferenceRouteConfig and set_cluster/get_cluster to set_route/get_route to match the renamed proto RPCs. Signed-off-by: Derek Carr <decarr@redhat.com>
77ef1fc to
7bba756
Compare
| for (object_type, label) in [ | ||
| (Sandbox::object_type(), "sandbox"), | ||
| (Provider::object_type(), "provider"), | ||
| (StoredProviderProfile::object_type(), "provider profile"), |
There was a problem hiding this comment.
From CodeRabbit review:
Include SSH sessions in workspace deletion blockers.
ObjectWorkspace for SshSession marks sessions as workspace-scoped, but deletion does not check SshSession::object_type(). A workspace can therefore be removed while session records still reference it.
for (object_type, label) in [
(Sandbox::object_type(), "sandbox"),
(Provider::object_type(), "provider"),
+ (SshSession::object_type(), "SSH session"),
(ServiceEndpoint::object_type(), "service"),
(InferenceRoute::object_type(), "inference route"),
] {
- Backfill provider_credential_refresh_state in workspace migration - Set requires_workspace() to true for refresh state - Reject consecutive hyphens in workspace and sandbox names - Restore parse_host rejection of consecutive hyphens in all segments - Pass workspace from SSH session metadata in put_if call - Require explicit workspace in Python SDK Sandbox() constructor - Add sandbox name character validation matching workspace rules Signed-off-by: Derek Carr <decarr@redhat.com>
- Add watch channel to broadcast workspace from policy poll loop to denial and activity flush tasks, fixing proposals targeting the wrong workspace for non-default sandboxes - Add set_workspace() to CachedOpenShellClient for pre-seeding workspace on fresh connections - Use selected_provider_workspace() in TUI provider get/delete actions instead of current_workspace, fixing cross-workspace misrouting Signed-off-by: Derek Carr <decarr@redhat.com>
Signed-off-by: Derek Carr <decarr@redhat.com>
…le scope binding Provider profiles can be global (platform-scoped) or workspace-scoped. Previously, profile lookups used the ambient request workspace, which caused pre-existing global profiles (workspace="") to become invisible after the workspace migration. Add a `profile_workspace` field to the Provider proto that explicitly declares where the provider's type profile is stored. The field must be empty (global) or match the provider's own workspace — cross-workspace references are rejected. All profile lookup call sites now use `provider.profile_workspace` instead of the ambient workspace. Existing serialized providers get `profile_workspace=""` via protobuf defaults, correctly pointing to their global profiles with no migration. CLI gains `--global-profile` flag on `provider create`. Signed-off-by: Derek Carr <decarr@redhat.com>
…-back handle_revoke_ssh_session passed empty string for workspace in put_if instead of session.object_workspace(), dropping the workspace on the revoked session record. Signed-off-by: Derek Carr <decarr@redhat.com>
The lint handler was passing an empty string to profile_conflict_diagnostics instead of using the request workspace, so it only checked for conflicts in global scope rather than the workspace the user specified. Signed-off-by: Derek Carr <decarr@redhat.com>
- Fix proto comments: ListProviderProfilesRequest.workspace no longer claims two-tier merged resolution, LintProviderProfilesRequest.workspace now documents that it is used for conflict detection - Converge Podman driver labels to openshell.ai/ prefix by importing from driver_utils, matching Docker and Kubernetes drivers - Replace debug_assert with runtime PersistenceError for workspace enforcement in put_message, put_scoped_message, and cas_update_message - Add comment in parse_host explaining -- delimiter safety invariant - Read OPENSHELL_WORKSPACE env var in tab completers instead of defaulting to empty string - Remove unused _workspace params from provider_refresh_defaults and dynamic_token_grant_bindings_for_provider - Remove scattered workspace "default" fallbacks in service_routing, inference, and compute; normalization is handled by resolve_workspace at the handler layer Signed-off-by: Derek Carr <decarr@redhat.com>
- Backfill policy and draft_chunk object types in migration - Add label selector support to all_workspaces sandbox listing - Replace per-member deletion loop with batch delete_all_in_workspace - Extract shared validate_dns1123_label helper from duplicated validation - Add count_in_workspace for efficient member cap enforcement - Document intentional omission of workspace filter in list_by_scope Signed-off-by: Derek Carr <decarr@redhat.com>
Fix workspace-scoped cleanup bugs: settings deletion used empty workspace instead of sandbox workspace, migration backfill missed sandbox_settings, SSH session cleanup scanned globally instead of by workspace, and workspace deletion did not check for blocking sandbox_settings records. Add K8s resource name length validation to reject names exceeding DNS-1123 63-char limit. Update RFC 0011 to match Phase 1 implementation: document inference RPC rename, UpdateProviderProfiles with optimistic concurrency, Provider profile_workspace field, Python SDK workspace requirements, service hostname breaking change, and persistence validation behavior. Signed-off-by: Derek Carr <decarr@redhat.com>
Principal review — actionable findingsFraming: Phase 1 ships the workspace data model + membership records but no per-workspace authorization — BlockersB1 — Decoded objects don't hydrate
Fix: add a B2 — TUI provider credential update targets the active workspace, not the selected row → cross-workspace credential overwrite. CONFIRMED. B3 — Migration doesn't backfill Should-fixS1 — S2 — S3 — Sandbox watch-channel workspace seeded only on the initial poll success → permanent silent telemetry loss. CONFIRMED. In S4 — S5 — SDK S6 — No upgrade/backfill test. CONFIRMED gap. Minor
Note: the inference |
|
Generated using Codex and gpt-5.5. Principal engineer review findings:
|
Potential Concerns (automated review)
Review conducted by Claude (Sonnet 5). |
Deep review — verified against PR head
|
Summary
Implements Phase 1 of RFC 0011 — the workspace and membership model that provides hard isolation boundaries for multi-player OpenShell deployments.
from context
method for infrastructure operations (reconciler, resume, provider refresh)
principal for bundle resolution; thread --workspace through CLI inference commands
CRUD and membership subcommands; inference help text updated from "gateway-level" to "workspace-level"
Related Issue
#1977
Changes
workspace fields on set/get request/response messages
Testing
Known remaining work