From d3828140b4185004568c58cabd9cbfd751abda31 Mon Sep 17 00:00:00 2001 From: Joshua Pritchard Date: Thu, 19 Mar 2026 20:48:46 -0400 Subject: [PATCH 1/5] First pass at openshell working --- Makefile | 34 + e2e/deploy_test.go | 231 + internal/daemon/docker-compose.yml | 6 + .../api/handlers/v0/provider_adapters.go | 14 +- internal/registry/api/server.go | 52 +- .../011_seed_openshell_provider.sql | 6 + .../registry/platforms/openshell/client.go | 316 + .../platforms/openshell/client_test.go | 171 + .../platforms/openshell/deployment_adapter.go | 233 + .../openshell/deployment_adapter_test.go | 415 ++ .../openshell/proto/OPENSHELL_PROTO_VERSION | 1 + .../platforms/openshell/proto/datamodel.proto | 89 + .../openshell/proto/gen/datamodel.pb.go | 777 +++ .../openshell/proto/gen/inference.pb.go | 798 +++ .../openshell/proto/gen/inference_grpc.pb.go | 214 + .../openshell/proto/gen/openshell.pb.go | 5149 +++++++++++++++++ .../openshell/proto/gen/openshell_grpc.pb.go | 1340 +++++ .../openshell/proto/gen/sandbox.pb.go | 872 +++ .../platforms/openshell/proto/inference.proto | 114 + .../platforms/openshell/proto/openshell.proto | 827 +++ .../platforms/openshell/proto/sandbox.proto | 126 + .../platforms/openshell/provider_config.go | 7 + internal/registry/registry_app.go | 2 + ui/components/deploy-server-dialog.tsx | 52 +- ui/lib/platform-display.ts | 13 + 25 files changed, 11850 insertions(+), 9 deletions(-) create mode 100644 internal/registry/database/migrations/011_seed_openshell_provider.sql create mode 100644 internal/registry/platforms/openshell/client.go create mode 100644 internal/registry/platforms/openshell/client_test.go create mode 100644 internal/registry/platforms/openshell/deployment_adapter.go create mode 100644 internal/registry/platforms/openshell/deployment_adapter_test.go create mode 100644 internal/registry/platforms/openshell/proto/OPENSHELL_PROTO_VERSION create mode 100644 internal/registry/platforms/openshell/proto/datamodel.proto create mode 100644 internal/registry/platforms/openshell/proto/gen/datamodel.pb.go create mode 100644 internal/registry/platforms/openshell/proto/gen/inference.pb.go create mode 100644 internal/registry/platforms/openshell/proto/gen/inference_grpc.pb.go create mode 100644 internal/registry/platforms/openshell/proto/gen/openshell.pb.go create mode 100644 internal/registry/platforms/openshell/proto/gen/openshell_grpc.pb.go create mode 100644 internal/registry/platforms/openshell/proto/gen/sandbox.pb.go create mode 100644 internal/registry/platforms/openshell/proto/inference.proto create mode 100644 internal/registry/platforms/openshell/proto/openshell.proto create mode 100644 internal/registry/platforms/openshell/proto/sandbox.proto create mode 100644 internal/registry/platforms/openshell/provider_config.go create mode 100644 ui/lib/platform-display.ts diff --git a/Makefile b/Makefile index ad5e8442..3c7582b2 100644 --- a/Makefile +++ b/Makefile @@ -547,3 +547,37 @@ helm-unittest-install: _helm-check ## Install the helm-unittest plugin if neede HELM_PLUGIN_INSTALL_FLAGS="$(HELM_PLUGIN_INSTALL_FLAGS)" \ bash ./scripts/install-helm-unittest.sh +# ────────────────────────────────────────────────────────────────────────────── +# OpenShell proto vendoring +# ────────────────────────────────────────────────────────────────────────────── +OPENSHELL_PROTO_VERSION := $(shell cat internal/registry/platforms/openshell/proto/OPENSHELL_PROTO_VERSION) +OPENSHELL_PROTO_REPO := NVIDIA/OpenShell +OPENSHELL_PROTO_DIR := internal/registry/platforms/openshell/proto + +.PHONY: sync-openshell-proto +sync-openshell-proto: ## Fetch OpenShell protos from upstream and regenerate Go code (requires protoc) + @echo "Fetching OpenShell protos at $(OPENSHELL_PROTO_VERSION)..." + @for f in openshell datamodel sandbox inference; do \ + curl -sfL "https://raw.githubusercontent.com/$(OPENSHELL_PROTO_REPO)/$(OPENSHELL_PROTO_VERSION)/proto/$$f.proto" \ + -o "$(OPENSHELL_PROTO_DIR)/$$f.proto"; \ + done + @echo "Installing protoc Go plugins..." + @go install google.golang.org/protobuf/cmd/protoc-gen-go@latest + @go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest + @echo "Generating Go code..." + $(eval OPENSHELL_GO_PKG := github.com/agentregistry-dev/agentregistry/internal/registry/platforms/openshell/proto/gen) + @protoc --go_out=. --go-grpc_out=. \ + --go_opt=module=github.com/agentregistry-dev/agentregistry \ + --go-grpc_opt=module=github.com/agentregistry-dev/agentregistry \ + --go_opt=Mopenshell.proto=$(OPENSHELL_GO_PKG) \ + --go_opt=Mdatamodel.proto=$(OPENSHELL_GO_PKG) \ + --go_opt=Msandbox.proto=$(OPENSHELL_GO_PKG) \ + --go_opt=Minference.proto=$(OPENSHELL_GO_PKG) \ + --go-grpc_opt=Mopenshell.proto=$(OPENSHELL_GO_PKG) \ + --go-grpc_opt=Mdatamodel.proto=$(OPENSHELL_GO_PKG) \ + --go-grpc_opt=Msandbox.proto=$(OPENSHELL_GO_PKG) \ + --go-grpc_opt=Minference.proto=$(OPENSHELL_GO_PKG) \ + -I $(OPENSHELL_PROTO_DIR) \ + $(OPENSHELL_PROTO_DIR)/*.proto + @echo "Done. Proto version: $(OPENSHELL_PROTO_VERSION)" + diff --git a/e2e/deploy_test.go b/e2e/deploy_test.go index bc7c4fec..5c7f54d7 100644 --- a/e2e/deploy_test.go +++ b/e2e/deploy_test.go @@ -22,6 +22,9 @@ const localDeployComposeProject = "agentregistry_runtime" type deployTarget struct { name string // subtest name (e.g. "local", "kubernetes") deplArgs []string // extra args appended to the deploy command + // setup is called once before deploying to perform any provider-specific + // prerequisite work (e.g. creating the provider in the registry). + setup func(t *testing.T) // verify is called after deploy succeeds; use it to assert the // deployment is actually running (e.g. check Docker containers). // resourceName is the agent/MCP name being deployed. @@ -58,6 +61,19 @@ var agentDeployTargets = []deployTarget{ } }, }, + { + name: "openshell", + deplArgs: []string{"--provider-id", "openshell-default"}, + setup: func(t *testing.T) { + ensureOpenShellProvider(t) + }, + verify: func(t *testing.T, agentName string) { + waitForOpenShellSandbox(t, agentName, 120*time.Second) + }, + cleanup: func(t *testing.T, agentName string) { + deleteOpenShellSandbox(t, agentName) + }, + }, } var mcpDeployTargets = []deployTarget{ @@ -88,6 +104,16 @@ var mcpDeployTargets = []deployTarget{ } }, }, + { + name: "openshell", + deplArgs: []string{"--provider-id", "openshell-default"}, + setup: func(t *testing.T) { + ensureOpenShellProvider(t) + }, + cleanup: func(t *testing.T, mcpName string) { + deleteOpenShellSandbox(t, mcpName) + }, + }, } func TestAgentDeployCreate(t *testing.T) { @@ -96,6 +122,12 @@ func TestAgentDeployCreate(t *testing.T) { if target.name == "kubernetes" && !IsK8sBackend() { t.Skip("skipping kubernetes deploy target: E2E_BACKEND=docker") } + if target.name == "openshell" && !isOpenShellAvailable() { + t.Skip("skipping openshell deploy target: openshell CLI not available or gateway not healthy") + } + if target.setup != nil { + target.setup(t) + } regURL := RegistryURL(t) tmpDir := t.TempDir() agentName := UniqueAgentName("e2edpl" + target.name[:3]) @@ -124,6 +156,10 @@ func TestAgentDeployCreate(t *testing.T) { t.Log("Loading image into Kind cluster...") loadDockerImageToKind(t, agentImage) } + if target.name == "openshell" { + t.Log("Loading image into OpenShell K3s cluster...") + loadDockerImageToOpenShell(t, agentImage) + } }) t.Run("publish", func(t *testing.T) { @@ -168,6 +204,12 @@ func TestMCPDeployCreate(t *testing.T) { if target.name == "kubernetes" && !IsK8sBackend() { t.Skip("skipping kubernetes deploy target: E2E_BACKEND=docker") } + if target.name == "openshell" && !isOpenShellAvailable() { + t.Skip("skipping openshell deploy target: openshell CLI not available or gateway not healthy") + } + if target.setup != nil { + target.setup(t) + } regURL := RegistryURL(t) tmpDir := t.TempDir() mcpName := UniqueNameWithPrefix("e2e-dpl-" + target.name[:3]) @@ -204,6 +246,10 @@ func TestMCPDeployCreate(t *testing.T) { t.Log("Loading image into Kind cluster...") loadDockerImageToKind(t, defaultImage) } + if target.name == "openshell" { + t.Log("Loading image into OpenShell K3s cluster...") + loadDockerImageToOpenShell(t, defaultImage) + } }) t.Run("publish", func(t *testing.T) { @@ -707,6 +753,62 @@ func kubeContextForE2E(t *testing.T) string { return strings.TrimSpace(ctx) } +// loadDockerImageToOpenShell pushes a local Docker image into OpenShell's K3s +// containerd so that sandbox pods can use it with imagePullPolicy=IfNotPresent. +// It discovers the OpenShell gateway container via "openshell gateway info" and +// pipes "docker save" into "ctr images import" inside the container. +func loadDockerImageToOpenShell(t *testing.T, imageRef string) { + t.Helper() + + // Discover the OpenShell gateway Docker container name. + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + cmd := exec.CommandContext(ctx, "docker", "ps", + "--filter", "name=openshell-cluster-", + "--format", "{{.Names}}") + out, err := cmd.Output() + if err != nil { + t.Fatalf("failed to find OpenShell gateway container: %v", err) + } + containerName := strings.TrimSpace(string(out)) + if containerName == "" { + t.Fatal("no OpenShell gateway container found") + } + // If multiple lines, take the first one. + if idx := strings.Index(containerName, "\n"); idx > 0 { + containerName = containerName[:idx] + } + + t.Logf("Pushing image %q into OpenShell K3s container %q...", imageRef, containerName) + + // Pipe docker save -> ctr images import inside the gateway container. + ctx2, cancel2 := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel2() + + saveCmd := exec.CommandContext(ctx2, "docker", "save", imageRef) + importCmd := exec.CommandContext(ctx2, "docker", "exec", "-i", containerName, + "ctr", "-n", "k8s.io", "images", "import", "--all-platforms", "-") + + pipe, err := saveCmd.StdoutPipe() + if err != nil { + t.Fatalf("failed to create pipe: %v", err) + } + importCmd.Stdin = pipe + + if err := saveCmd.Start(); err != nil { + t.Fatalf("docker save failed to start: %v", err) + } + importOut, importErr := importCmd.CombinedOutput() + if saveErr := saveCmd.Wait(); saveErr != nil { + t.Fatalf("docker save failed: %v", saveErr) + } + if importErr != nil { + t.Fatalf("ctr images import failed: %v\n%s", importErr, string(importOut)) + } + + t.Logf("Successfully loaded %q into OpenShell K3s", imageRef) +} + func loadDockerImageToKind(t *testing.T, imageRef string) { t.Helper() @@ -929,6 +1031,12 @@ func TestAgentDeployWithPrompts(t *testing.T) { if target.name == "kubernetes" && !IsK8sBackend() { t.Skip("skipping kubernetes deploy target: E2E_BACKEND=docker") } + if target.name == "openshell" && !isOpenShellAvailable() { + t.Skip("skipping openshell deploy target: openshell CLI not available or gateway not healthy") + } + if target.setup != nil { + target.setup(t) + } regURL := RegistryURL(t) tmpDir := t.TempDir() agentName := UniqueAgentName("e2eprm" + target.name[:3]) @@ -993,6 +1101,9 @@ func TestAgentDeployWithPrompts(t *testing.T) { if target.name == "kubernetes" { loadDockerImageToKind(t, agentImage) } + if target.name == "openshell" { + loadDockerImageToOpenShell(t, agentImage) + } }) t.Run("publish", func(t *testing.T) { @@ -1130,3 +1241,123 @@ func configMapDataKeys(data map[string]string) []string { } return keys } + +// isOpenShellAvailable checks whether the openshell CLI is on PATH and the +// gateway is healthy. Returns false when OpenShell is not installed. +func isOpenShellAvailable() bool { + if _, err := exec.LookPath("openshell"); err != nil { + return false + } + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + cmd := exec.CommandContext(ctx, "openshell", "gateway", "info") + return cmd.Run() == nil +} + +// ensureOpenShellProvider verifies that the "openshell-default" provider +// exists in the registry (seeded by migration 011). If the registry is running +// an older schema that predates the migration, it creates the provider via the +// API as a fallback. +func ensureOpenShellProvider(t *testing.T) { + t.Helper() + regURL := RegistryURL(t) + client := &http.Client{Timeout: 10 * time.Second} + + // The provider should already exist from the DB migration seed. + resp, err := client.Get(regURL + "/providers/openshell-default") + if err == nil { + resp.Body.Close() + if resp.StatusCode == http.StatusOK { + return + } + } + + // Fallback: create it if the migration hasn't been applied yet. + t.Log("openshell-default provider not found, creating via API...") + body := strings.NewReader(`{"id":"openshell-default","name":"OpenShell Default","platform":"openshell","config":{}}`) + req, err := http.NewRequest(http.MethodPost, regURL+"/providers", body) + if err != nil { + t.Fatalf("failed to build provider create request: %v", err) + } + req.Header.Set("Content-Type", "application/json") + resp, err = client.Do(req) + if err != nil { + t.Fatalf("failed to create openshell-default provider: %v", err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { + t.Fatalf("unexpected status creating openshell-default provider: %d", resp.StatusCode) + } + t.Log("created openshell-default provider via API fallback") +} + +// waitForOpenShellSandbox polls `openshell sandbox list` until a sandbox +// whose name contains the given resource name appears, or the timeout expires. +// The adapter generates sandbox names from the deployment ID, so we do a +// substring match on the resource name to account for name mangling. +func waitForOpenShellSandbox(t *testing.T, resourceName string, timeout time.Duration) { + t.Helper() + deadline := time.Now().Add(timeout) + // Sanitise the resource name the same way the adapter does (lowercase, replace dots/slashes with dashes). + sanitised := strings.ToLower(resourceName) + sanitised = strings.NewReplacer("/", "-", ".", "-").Replace(sanitised) + for time.Now().Before(deadline) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + cmd := exec.CommandContext(ctx, "openshell", "sandbox", "list") + out, err := cmd.Output() + cancel() + if err == nil { + for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") { + if strings.Contains(strings.ToLower(line), sanitised) { + t.Logf("OpenShell sandbox matching %q found: %s", resourceName, strings.TrimSpace(line)) + return + } + } + } + time.Sleep(3 * time.Second) + } + + // Dump sandbox list for debugging before failing. + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + cmd := exec.CommandContext(ctx, "openshell", "sandbox", "list") + if out, err := cmd.CombinedOutput(); err == nil { + t.Logf("OpenShell sandboxes:\n%s", string(out)) + } + t.Fatalf("Timed out waiting for OpenShell sandbox matching %q (timeout %v)", resourceName, timeout) +} + +// deleteOpenShellSandbox removes any OpenShell sandboxes whose name contains +// the given resource name. Uses substring matching because the adapter +// generates sandbox names that include (but are not equal to) the resource name. +func deleteOpenShellSandbox(t *testing.T, resourceName string) { + t.Helper() + sanitised := strings.ToLower(resourceName) + sanitised = strings.NewReplacer("/", "-", ".", "-").Replace(sanitised) + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + // List sandboxes and delete any that match. + cmd := exec.CommandContext(ctx, "openshell", "sandbox", "list", "--names") + out, err := cmd.Output() + if err != nil { + t.Logf("Warning: failed to list OpenShell sandboxes for cleanup: %v", err) + return + } + + for _, name := range strings.Split(strings.TrimSpace(string(out)), "\n") { + name = strings.TrimSpace(name) + if name == "" { + continue + } + if strings.Contains(strings.ToLower(name), sanitised) { + delCmd := exec.CommandContext(ctx, "openshell", "sandbox", "delete", name) + if delOut, delErr := delCmd.CombinedOutput(); delErr != nil { + t.Logf("Warning: failed to delete OpenShell sandbox %s: %v\n%s", name, delErr, string(delOut)) + } else { + t.Logf("Deleted OpenShell sandbox %s", name) + } + } + } +} diff --git a/internal/daemon/docker-compose.yml b/internal/daemon/docker-compose.yml index 43df5ffc..39345c7a 100644 --- a/internal/daemon/docker-compose.yml +++ b/internal/daemon/docker-compose.yml @@ -45,6 +45,10 @@ services: # Temporarily only for local development AGENT_REGISTRY_ENABLE_REGISTRY_VALIDATION: "false" KUBECONFIG: "/root/.kube/config" + # OpenShell gateway + OPENSHELL_GATEWAY_ENDPOINT: "host.docker.internal:8080" + OPENSHELL_GATEWAY_MTLS_DIR: "/root/.config/openshell/mtls" + OPENSHELL_GATEWAY_TLS_SERVER_NAME: "127.0.0.1" # AGENT_REGISTRY_ENABLE_ANONYMOUS_AUTH: "false" # AGENT_REGISTRY_ENABLE_REGISTRY_VALIDATION: "true" ports: @@ -58,6 +62,8 @@ services: - /tmp:/tmp # Mount kubeconfig as read-only source; the entrypoint rewrites it for Docker networking - ~/.kube/config:/root/.kube/config.orig:ro + # Mount OpenShell mTLS certs for gateway authentication + - ~/.config/openshell/gateways/ar-dev/mtls:/root/.config/openshell/mtls:ro depends_on: postgres: condition: service_healthy diff --git a/internal/registry/api/handlers/v0/provider_adapters.go b/internal/registry/api/handlers/v0/provider_adapters.go index ff1a86a7..fe4be547 100644 --- a/internal/registry/api/handlers/v0/provider_adapters.go +++ b/internal/registry/api/handlers/v0/provider_adapters.go @@ -75,11 +75,15 @@ type kubernetesProviderAdapter struct { providerAdapterBase } -// NOTE: local and kubernetes currently share the same adapter base behavior. +type openshellProviderAdapter struct { + providerAdapterBase +} + +// NOTE: local, kubernetes, and openshell currently share the same adapter base behavior. // Provider CRUD remains extension-driven, and these concrete adapter types are // kept explicit so platform-specific validation can diverge later if needed. -// DefaultProviderPlatformAdapters returns OSS provider adapters for local and kubernetes. +// DefaultProviderPlatformAdapters returns OSS provider adapters for local, kubernetes, and openshell. func DefaultProviderPlatformAdapters(registry service.RegistryService) map[string]registrytypes.ProviderPlatformAdapter { return map[string]registrytypes.ProviderPlatformAdapter{ "local": &localProviderAdapter{ @@ -94,5 +98,11 @@ func DefaultProviderPlatformAdapters(registry service.RegistryService) map[strin registry: registry, }, }, + "openshell": &openshellProviderAdapter{ + providerAdapterBase: providerAdapterBase{ + providerPlatform: "openshell", + registry: registry, + }, + }, } } diff --git a/internal/registry/api/server.go b/internal/registry/api/server.go index a72707ff..31f96d03 100644 --- a/internal/registry/api/server.go +++ b/internal/registry/api/server.go @@ -25,6 +25,7 @@ import ( var embeddedUI embed.FS // createUIHandler creates an HTTP handler for serving the embedded UI files +// with SPA-aware routing for Next.js static export func createUIHandler() (http.Handler, error) { // Extract the ui/dist subdirectory from the embedded filesystem uiFS, err := fs.Sub(embeddedUI, "ui/dist") @@ -32,8 +33,55 @@ func createUIHandler() (http.Handler, error) { return nil, err } - // Create a file server for the UI - return http.FileServer(http.FS(uiFS)), nil + httpFS := http.FS(uiFS) + fileServer := http.FileServer(httpFS) + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + path := r.URL.Path + + // Try the exact path first (handles static assets like .js, .css, etc.) + if f, err := httpFS.Open(path); err == nil { + f.Close() + // Check if it's a file (not a directory) — serve it directly + if stat, err := f.(interface{ Stat() (fs.FileInfo, error) }).Stat(); err == nil && !stat.IsDir() { + fileServer.ServeHTTP(w, r) + return + } + } + + // For paths without extensions (route requests), try {path}.html + // This handles Next.js static export where /deployed -> deployed.html + cleanPath := strings.TrimSuffix(path, "/") + if cleanPath != "" && !strings.Contains(cleanPath[strings.LastIndex(cleanPath, "/")+1:], ".") { + htmlPath := cleanPath + ".html" + if f, err := httpFS.Open(htmlPath); err == nil { + f.Close() + r.URL.Path = htmlPath + fileServer.ServeHTTP(w, r) + return + } + } + + // Try {path}/index.html for directory-style routes + indexPath := strings.TrimSuffix(path, "/") + "/index.html" + if f, err := httpFS.Open(indexPath); err == nil { + f.Close() + r.URL.Path = indexPath + fileServer.ServeHTTP(w, r) + return + } + + // Fall back to /index.html for client-side routing + if f, err := httpFS.Open("/index.html"); err == nil { + f.Close() + r.URL.Path = "/index.html" + fileServer.ServeHTTP(w, r) + return + } + + // Nothing found + http.NotFound(w, r) + }), nil } // TrailingSlashMiddleware redirects requests with trailing slashes to their canonical form diff --git a/internal/registry/database/migrations/011_seed_openshell_provider.sql b/internal/registry/database/migrations/011_seed_openshell_provider.sql new file mode 100644 index 00000000..fa6c5f2a --- /dev/null +++ b/internal/registry/database/migrations/011_seed_openshell_provider.sql @@ -0,0 +1,6 @@ +-- Seed the default OpenShell provider so it is available out of the box, +-- matching the pattern established for local and kubernetes-default. + +INSERT INTO providers (id, name, platform, config) +VALUES ('openshell-default', 'OpenShell Default', 'openshell', '{}'::jsonb) +ON CONFLICT (id) DO NOTHING; diff --git a/internal/registry/platforms/openshell/client.go b/internal/registry/platforms/openshell/client.go new file mode 100644 index 00000000..1e902884 --- /dev/null +++ b/internal/registry/platforms/openshell/client.go @@ -0,0 +1,316 @@ +package openshell + +import ( + "context" + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + + pb "github.com/agentregistry-dev/agentregistry/internal/registry/platforms/openshell/proto/gen" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" +) + +// Client is the interface for interacting with an OpenShell gateway. +type Client interface { + CreateSandbox(ctx context.Context, opts CreateSandboxOpts) (*SandboxInfo, error) + GetSandbox(ctx context.Context, name string) (*SandboxInfo, error) + ListSandboxes(ctx context.Context) ([]SandboxInfo, error) + DeleteSandbox(ctx context.Context, name string) error + GetSandboxLogs(ctx context.Context, sandboxID string) ([]string, error) + HealthCheck(ctx context.Context) error + Close() error +} + +// CreateSandboxOpts holds the parameters for creating a sandbox. +type CreateSandboxOpts struct { + Name string + Image string + Env map[string]string + Providers []string // OpenShell provider names to attach + GPU bool +} + +// SandboxInfo holds the status of a sandbox. +type SandboxInfo struct { + ID string + Name string + Phase string // SANDBOX_PHASE_PROVISIONING, SANDBOX_PHASE_READY, etc. +} + +// gatewayMetadata is the structure of ~/.config/openshell/gateways/{name}/metadata.json. +type gatewayMetadata struct { + Endpoint string `json:"endpoint,omitempty"` + GatewayEndpoint string `json:"gateway_endpoint,omitempty"` +} + +// grpcClient implements Client using the OpenShell gRPC API. +type grpcClient struct { + conn *grpc.ClientConn + client pb.OpenShellClient +} + +// NewGRPCClient creates a Client by discovering the gateway endpoint and mTLS certs. +// +// Resolution order: +// 1. OPENSHELL_GATEWAY_ENDPOINT env var — if set, connects directly (with +// OPENSHELL_GATEWAY_INSECURE=true to skip mTLS, useful for local dev). +// 2. ~/.config/openshell/gateways/{gatewayName}/metadata.json — standard +// OpenShell config with mTLS certs. +// +// If gatewayName is empty, it auto-discovers the first available gateway. +func NewGRPCClient(gatewayName string) (Client, error) { + // Option 1: explicit endpoint via env var. + if endpoint := os.Getenv("OPENSHELL_GATEWAY_ENDPOINT"); endpoint != "" { + var tlsCfg *tls.Config + if os.Getenv("OPENSHELL_GATEWAY_INSECURE") == "true" { + // Skip mTLS entirely. + } else if mtlsDir := os.Getenv("OPENSHELL_GATEWAY_MTLS_DIR"); mtlsDir != "" { + // Load certs from explicit directory. + var err error + tlsCfg, err = loadMTLSConfig(mtlsDir) + if err != nil { + return nil, fmt.Errorf("load mTLS config from %s: %w", mtlsDir, err) + } + } else { + // Fall back to gateway filesystem config for certs. + if gatewayName == "" { + gatewayName = "default" + } + configDir, err := gatewayConfigDir(gatewayName) + if err != nil { + return nil, fmt.Errorf("resolve openshell config dir: %w", err) + } + tlsCfg, err = loadMTLSConfig(filepath.Join(configDir, "mtls")) + if err != nil { + return nil, fmt.Errorf("load mTLS config: %w", err) + } + } + return NewGRPCClientFromEndpoint(endpoint, tlsCfg) + } + + // Option 2: discover from filesystem config. + if gatewayName == "" { + var dErr error + gatewayName, dErr = discoverGatewayName() + if dErr != nil { + return nil, fmt.Errorf("discover openshell gateway: %w", dErr) + } + } + + configDir, err := gatewayConfigDir(gatewayName) + if err != nil { + return nil, fmt.Errorf("resolve openshell config dir: %w", err) + } + + metadata, err := loadGatewayMetadata(configDir) + if err != nil { + return nil, fmt.Errorf("load gateway metadata: %w", err) + } + + tlsCfg, err := loadMTLSConfig(filepath.Join(configDir, "mtls")) + if err != nil { + return nil, fmt.Errorf("load mTLS config: %w", err) + } + + return NewGRPCClientFromEndpoint(metadata.Endpoint, tlsCfg) +} + +// NewGRPCClientFromEndpoint creates a Client from an explicit endpoint and TLS config. +// If tlsCfg is nil, an insecure connection is used (for testing). +// The endpoint should be host:port; any https:// or http:// prefix is stripped. +func NewGRPCClientFromEndpoint(endpoint string, tlsCfg *tls.Config) (Client, error) { + endpoint = strings.TrimPrefix(endpoint, "https://") + endpoint = strings.TrimPrefix(endpoint, "http://") + var dialOpts []grpc.DialOption + if tlsCfg != nil { + dialOpts = append(dialOpts, grpc.WithTransportCredentials(credentials.NewTLS(tlsCfg))) + } else { + dialOpts = append(dialOpts, grpc.WithTransportCredentials(insecure.NewCredentials())) + } + + conn, err := grpc.NewClient(endpoint, dialOpts...) + if err != nil { + return nil, fmt.Errorf("dial openshell gateway %s: %w", endpoint, err) + } + + return &grpcClient{ + conn: conn, + client: pb.NewOpenShellClient(conn), + }, nil +} + +func (c *grpcClient) CreateSandbox(ctx context.Context, opts CreateSandboxOpts) (*SandboxInfo, error) { + resp, err := c.client.CreateSandbox(ctx, &pb.CreateSandboxRequest{ + Name: opts.Name, + Spec: &pb.SandboxSpec{ + Environment: opts.Env, + Providers: opts.Providers, + Gpu: opts.GPU, + Template: &pb.SandboxTemplate{ + Image: opts.Image, + }, + }, + }) + if err != nil { + return nil, fmt.Errorf("create sandbox: %w", err) + } + return sandboxToInfo(resp.GetSandbox()), nil +} + +func (c *grpcClient) GetSandbox(ctx context.Context, name string) (*SandboxInfo, error) { + resp, err := c.client.GetSandbox(ctx, &pb.GetSandboxRequest{Name: name}) + if err != nil { + return nil, fmt.Errorf("get sandbox %s: %w", name, err) + } + return sandboxToInfo(resp.GetSandbox()), nil +} + +func (c *grpcClient) ListSandboxes(ctx context.Context) ([]SandboxInfo, error) { + resp, err := c.client.ListSandboxes(ctx, &pb.ListSandboxesRequest{}) + if err != nil { + return nil, fmt.Errorf("list sandboxes: %w", err) + } + result := make([]SandboxInfo, len(resp.GetSandboxes())) + for i, s := range resp.GetSandboxes() { + result[i] = *sandboxToInfo(s) + } + return result, nil +} + +func (c *grpcClient) DeleteSandbox(ctx context.Context, name string) error { + _, err := c.client.DeleteSandbox(ctx, &pb.DeleteSandboxRequest{Name: name}) + if err != nil { + return fmt.Errorf("delete sandbox %s: %w", name, err) + } + return nil +} + +func (c *grpcClient) GetSandboxLogs(ctx context.Context, sandboxID string) ([]string, error) { + resp, err := c.client.GetSandboxLogs(ctx, &pb.GetSandboxLogsRequest{SandboxId: sandboxID}) + if err != nil { + return nil, fmt.Errorf("get sandbox logs %s: %w", sandboxID, err) + } + lines := make([]string, len(resp.GetLogs())) + for i, entry := range resp.GetLogs() { + lines[i] = entry.GetMessage() + } + return lines, nil +} + +func (c *grpcClient) HealthCheck(ctx context.Context) error { + resp, err := c.client.Health(ctx, &pb.HealthRequest{}) + if err != nil { + return fmt.Errorf("health check: %w", err) + } + if resp.GetStatus() != pb.ServiceStatus_SERVICE_STATUS_HEALTHY { + return fmt.Errorf("gateway unhealthy: %s", resp.GetStatus().String()) + } + return nil +} + +func (c *grpcClient) Close() error { + if c.conn != nil { + return c.conn.Close() + } + return nil +} + +// sandboxToInfo converts a proto Sandbox to our domain SandboxInfo. +func sandboxToInfo(s *pb.Sandbox) *SandboxInfo { + if s == nil { + return &SandboxInfo{} + } + return &SandboxInfo{ + ID: s.GetId(), + Name: s.GetName(), + Phase: s.GetPhase().String(), + } +} + +// discoverGatewayName finds the first available gateway in ~/.config/openshell/gateways/. +func discoverGatewayName() (string, error) { + home, err := os.UserHomeDir() + if err != nil { + return "", fmt.Errorf("get home dir: %w", err) + } + gatewaysDir := filepath.Join(home, ".config", "openshell", "gateways") + entries, err := os.ReadDir(gatewaysDir) + if err != nil { + return "", fmt.Errorf("no openshell gateways found in %s: %w", gatewaysDir, err) + } + for _, e := range entries { + if e.IsDir() { + metaPath := filepath.Join(gatewaysDir, e.Name(), "metadata.json") + if _, sErr := os.Stat(metaPath); sErr == nil { + return e.Name(), nil + } + } + } + return "", fmt.Errorf("no openshell gateways found in %s", gatewaysDir) +} + +// gatewayConfigDir returns the path to the OpenShell gateway config directory. +func gatewayConfigDir(gatewayName string) (string, error) { + home, err := os.UserHomeDir() + if err != nil { + return "", fmt.Errorf("get home dir: %w", err) + } + return filepath.Join(home, ".config", "openshell", "gateways", gatewayName), nil +} + +// loadGatewayMetadata reads the gateway metadata.json file. +func loadGatewayMetadata(configDir string) (*gatewayMetadata, error) { + data, err := os.ReadFile(filepath.Join(configDir, "metadata.json")) + if err != nil { + return nil, fmt.Errorf("read metadata.json: %w", err) + } + var meta gatewayMetadata + if err := json.Unmarshal(data, &meta); err != nil { + return nil, fmt.Errorf("parse metadata.json: %w", err) + } + // Support both "endpoint" and "gateway_endpoint" field names. + if meta.Endpoint == "" && meta.GatewayEndpoint != "" { + meta.Endpoint = meta.GatewayEndpoint + } + if meta.Endpoint == "" { + return nil, fmt.Errorf("metadata.json: endpoint is empty") + } + return &meta, nil +} + +// loadMTLSConfig loads mTLS certificates from a directory containing ca.crt, tls.crt, tls.key. +func loadMTLSConfig(mtlsDir string) (*tls.Config, error) { + caCert, err := os.ReadFile(filepath.Join(mtlsDir, "ca.crt")) + if err != nil { + return nil, fmt.Errorf("read ca.crt: %w", err) + } + + cert, err := tls.LoadX509KeyPair( + filepath.Join(mtlsDir, "tls.crt"), + filepath.Join(mtlsDir, "tls.key"), + ) + if err != nil { + return nil, fmt.Errorf("load client certificate: %w", err) + } + + caCertPool := x509.NewCertPool() + if !caCertPool.AppendCertsFromPEM(caCert) { + return nil, fmt.Errorf("failed to append CA certificate") + } + + return &tls.Config{ + Certificates: []tls.Certificate{cert}, + RootCAs: caCertPool, + MinVersion: tls.VersionTLS12, + // Allow overriding the expected server name for environments where the + // connect address differs from the cert's CN/SAN (e.g. Docker connecting + // to host.docker.internal with a cert issued for 127.0.0.1). + ServerName: os.Getenv("OPENSHELL_GATEWAY_TLS_SERVER_NAME"), + }, nil +} diff --git a/internal/registry/platforms/openshell/client_test.go b/internal/registry/platforms/openshell/client_test.go new file mode 100644 index 00000000..831ac246 --- /dev/null +++ b/internal/registry/platforms/openshell/client_test.go @@ -0,0 +1,171 @@ +package openshell + +import ( + "encoding/json" + "os" + "path/filepath" + "testing" + + pb "github.com/agentregistry-dev/agentregistry/internal/registry/platforms/openshell/proto/gen" +) + +func TestLoadGatewayMetadata(t *testing.T) { + tests := []struct { + name string + content string + wantErr bool + wantEP string + }{ + { + name: "valid metadata with endpoint", + content: `{"endpoint": "localhost:9090"}`, + wantEP: "localhost:9090", + }, + { + name: "valid metadata with gateway_endpoint", + content: `{"gateway_endpoint": "https://127.0.0.1:8080"}`, + wantEP: "https://127.0.0.1:8080", + }, + { + name: "empty endpoint", + content: `{"endpoint": ""}`, + wantErr: true, + }, + { + name: "invalid json", + content: `{invalid`, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + dir := t.TempDir() + if err := os.WriteFile(filepath.Join(dir, "metadata.json"), []byte(tt.content), 0o644); err != nil { + t.Fatal(err) + } + + meta, err := loadGatewayMetadata(dir) + if (err != nil) != tt.wantErr { + t.Fatalf("loadGatewayMetadata() error = %v, wantErr %v", err, tt.wantErr) + } + if err == nil && meta.Endpoint != tt.wantEP { + t.Errorf("endpoint = %q, want %q", meta.Endpoint, tt.wantEP) + } + }) + } +} + +func TestLoadGatewayMetadata_MissingFile(t *testing.T) { + _, err := loadGatewayMetadata(t.TempDir()) + if err == nil { + t.Fatal("expected error for missing metadata.json") + } +} + +func TestLoadMTLSConfig(t *testing.T) { + mtlsDir := t.TempDir() + + // Test missing files + _, err := loadMTLSConfig(mtlsDir) + if err == nil { + t.Fatal("expected error for missing certs") + } +} + +func TestSandboxToInfo(t *testing.T) { + tests := []struct { + name string + phase pb.SandboxPhase + want string + }{ + {"ready", pb.SandboxPhase_SANDBOX_PHASE_READY, "SANDBOX_PHASE_READY"}, + {"provisioning", pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING, "SANDBOX_PHASE_PROVISIONING"}, + {"error", pb.SandboxPhase_SANDBOX_PHASE_ERROR, "SANDBOX_PHASE_ERROR"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + info := sandboxToInfo(&pb.Sandbox{Id: "id-1", Name: tt.name, Phase: tt.phase}) + if info.Name != tt.name { + t.Errorf("Name = %q, want %q", info.Name, tt.name) + } + if info.Phase != tt.want { + t.Errorf("Phase = %q, want %q", info.Phase, tt.want) + } + }) + } +} + +func TestSandboxToInfo_Nil(t *testing.T) { + info := sandboxToInfo(nil) + if info == nil { + t.Fatal("expected non-nil SandboxInfo for nil input") + } + if info.ID != "" || info.Name != "" { + t.Errorf("expected zero value SandboxInfo, got %+v", info) + } +} + +func TestGatewayConfigDir(t *testing.T) { + dir, err := gatewayConfigDir("test-gw") + if err != nil { + t.Fatal(err) + } + if !filepath.IsAbs(dir) { + t.Errorf("expected absolute path, got %q", dir) + } + if filepath.Base(dir) != "test-gw" { + t.Errorf("expected dir to end with gateway name, got %q", dir) + } +} + +func TestCreateSandboxOptsMapping(t *testing.T) { + opts := CreateSandboxOpts{ + Name: "my-sandbox", + Image: "my-image:latest", + Env: map[string]string{"KEY": "VAL"}, + Providers: []string{"openai", "anthropic"}, + GPU: true, + } + + if opts.Name != "my-sandbox" { + t.Errorf("Name = %q, want %q", opts.Name, "my-sandbox") + } + if opts.Image != "my-image:latest" { + t.Errorf("Image = %q, want %q", opts.Image, "my-image:latest") + } + if len(opts.Env) != 1 || opts.Env["KEY"] != "VAL" { + t.Errorf("Env = %v, want {KEY: VAL}", opts.Env) + } + if len(opts.Providers) != 2 { + t.Errorf("Providers len = %d, want 2", len(opts.Providers)) + } + if !opts.GPU { + t.Error("GPU = false, want true") + } +} + +func TestNewGRPCClientFromEndpoint_Insecure(t *testing.T) { + client, err := NewGRPCClientFromEndpoint("localhost:0", nil) + if err != nil { + t.Fatalf("NewGRPCClientFromEndpoint() error = %v", err) + } + defer client.Close() +} + +func TestGatewayMetadataJSON(t *testing.T) { + meta := gatewayMetadata{Endpoint: "example.com:443"} + data, err := json.Marshal(meta) + if err != nil { + t.Fatal(err) + } + + var decoded gatewayMetadata + if err := json.Unmarshal(data, &decoded); err != nil { + t.Fatal(err) + } + if decoded.Endpoint != meta.Endpoint { + t.Errorf("roundtrip: got %q, want %q", decoded.Endpoint, meta.Endpoint) + } +} diff --git a/internal/registry/platforms/openshell/deployment_adapter.go b/internal/registry/platforms/openshell/deployment_adapter.go new file mode 100644 index 00000000..e696be5f --- /dev/null +++ b/internal/registry/platforms/openshell/deployment_adapter.go @@ -0,0 +1,233 @@ +package openshell + +import ( + "context" + "fmt" + "log/slog" + "strings" + "sync" + "time" + + "github.com/agentregistry-dev/agentregistry/internal/registry/platforms/utils" + "github.com/agentregistry-dev/agentregistry/internal/registry/service" + "github.com/agentregistry-dev/agentregistry/pkg/models" + "github.com/agentregistry-dev/agentregistry/pkg/registry/database" +) + +const ( + sandboxReadyTimeout = 120 * time.Second + sandboxPollInterval = 2 * time.Second + // Phase enum string values from the generated proto. + sandboxPhaseReady = "SANDBOX_PHASE_READY" + sandboxPhaseError = "SANDBOX_PHASE_ERROR" +) + +type openshellDeploymentAdapter struct { + registry service.RegistryService + client Client + clientOnce sync.Once + clientErr error + gatewayName string +} + +// NewOpenShellDeploymentAdapter creates a new deployment adapter for the OpenShell platform. +// The client can be nil — it will be lazily created on first deploy using env vars or +// gateway filesystem config. +func NewOpenShellDeploymentAdapter(registry service.RegistryService, client Client) *openshellDeploymentAdapter { + return &openshellDeploymentAdapter{ + registry: registry, + client: client, + } +} + +// getClient returns the gRPC client, creating it lazily if needed. +func (a *openshellDeploymentAdapter) getClient() (Client, error) { + if a.client != nil { + return a.client, nil + } + a.clientOnce.Do(func() { + slog.Info("openshell: lazily creating gRPC client") + c, err := NewGRPCClient(a.gatewayName) + if err != nil { + slog.Error("openshell: failed to create gRPC client", "error", err) + a.clientErr = fmt.Errorf("openshell client not configured: %w", err) + return + } + slog.Info("openshell: gRPC client created successfully") + a.client = c + }) + if a.clientErr != nil { + return nil, a.clientErr + } + return a.client, nil +} + +func (a *openshellDeploymentAdapter) Platform() string { return "openshell" } + +func (a *openshellDeploymentAdapter) SupportedResourceTypes() []string { + return []string{"mcp", "agent"} +} + +func (a *openshellDeploymentAdapter) Deploy(ctx context.Context, req *models.Deployment) (*models.DeploymentActionResult, error) { + slog.Info("openshell: deploy started", "server", req.ServerName, "provider", req.ProviderID) + client, err := a.getClient() + if err != nil { + return nil, err + } + slog.Info("openshell: client ready") + if err := utils.ValidateDeploymentRequest(req, false); err != nil { + return nil, err + } + + sandboxName := sandboxNameForDeployment(req) + image, env, providers, err := a.resolveDeploymentSpec(ctx, req) + if err != nil { + return nil, err + } + slog.Info("openshell: resolved spec", "sandbox", sandboxName, "image", image) + + opts := CreateSandboxOpts{ + Name: sandboxName, + Image: image, + Env: env, + Providers: providers, + } + + slog.Info("openshell: calling CreateSandbox") + if _, err := client.CreateSandbox(ctx, opts); err != nil { + return nil, fmt.Errorf("create openshell sandbox: %w", err) + } + slog.Info("openshell: sandbox created, waiting for ready") + + if err := a.waitForReady(ctx, client, sandboxName); err != nil { + return nil, err + } + + return &models.DeploymentActionResult{Status: models.DeploymentStatusDeployed}, nil +} + +func (a *openshellDeploymentAdapter) Undeploy(_ context.Context, deployment *models.Deployment) error { + client, err := a.getClient() + if err != nil { + return err + } + if err := utils.ValidateDeploymentRequest(deployment, true); err != nil { + return err + } + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + sandboxName := sandboxNameForDeployment(deployment) + if err := client.DeleteSandbox(ctx, sandboxName); err != nil { + return fmt.Errorf("delete openshell sandbox: %w", err) + } + return nil +} + +func (a *openshellDeploymentAdapter) GetLogs(ctx context.Context, deployment *models.Deployment) ([]string, error) { + client, err := a.getClient() + if err != nil { + return nil, err + } + if deployment == nil { + return nil, fmt.Errorf("deployment is required: %w", database.ErrInvalidInput) + } + sandboxName := sandboxNameForDeployment(deployment) + return client.GetSandboxLogs(ctx, sandboxName) +} + +func (a *openshellDeploymentAdapter) Cancel(ctx context.Context, deployment *models.Deployment) error { + client, err := a.getClient() + if err != nil { + return err + } + if deployment == nil { + return fmt.Errorf("deployment is required: %w", database.ErrInvalidInput) + } + sandboxName := sandboxNameForDeployment(deployment) + return client.DeleteSandbox(ctx, sandboxName) +} + +func (a *openshellDeploymentAdapter) Discover(_ context.Context, _ string) ([]*models.Deployment, error) { + return []*models.Deployment{}, nil +} + +// resolveDeploymentSpec extracts the container image, environment variables, and provider +// names from the deployment by resolving the resource in the registry. +func (a *openshellDeploymentAdapter) resolveDeploymentSpec( + ctx context.Context, + deployment *models.Deployment, +) (image string, env map[string]string, providers []string, err error) { + resourceType := strings.ToLower(strings.TrimSpace(deployment.ResourceType)) + switch resourceType { + case "mcp": + server, sErr := utils.BuildPlatformMCPServer(ctx, a.registry, deployment, "") + if sErr != nil { + return "", nil, nil, sErr + } + if server.Local != nil && server.Local.Deployment.Image != "" { + return server.Local.Deployment.Image, mergeEnv(deployment.Env, server.Local.Deployment.Env), nil, nil + } + return "", nil, nil, fmt.Errorf("openshell requires a container image for MCP server %s", server.Name) + + case "agent": + resolved, rErr := utils.ResolveAgent(ctx, a.registry, deployment, "") + if rErr != nil { + return "", nil, nil, rErr + } + return resolved.Agent.Deployment.Image, mergeEnv(deployment.Env, resolved.Agent.Deployment.Env), nil, nil + + default: + return "", nil, nil, fmt.Errorf("invalid resource type %q: %w", deployment.ResourceType, database.ErrInvalidInput) + } +} + +// waitForReady polls GetSandbox until the sandbox reaches the Ready phase or times out. +func (a *openshellDeploymentAdapter) waitForReady(ctx context.Context, client Client, sandboxName string) error { + deadline := time.Now().Add(sandboxReadyTimeout) + for { + if time.Now().After(deadline) { + return fmt.Errorf("timeout waiting for openshell sandbox %s to become ready", sandboxName) + } + + info, err := client.GetSandbox(ctx, sandboxName) + if err != nil { + slog.Warn("polling openshell sandbox", "name", sandboxName, "error", err) + } else { + slog.Info("openshell: sandbox phase", "name", sandboxName, "phase", info.Phase) + switch info.Phase { + case sandboxPhaseReady: + return nil + case sandboxPhaseError: + return fmt.Errorf("openshell sandbox %s entered error phase", sandboxName) + } + } + + select { + case <-ctx.Done(): + return ctx.Err() + case <-time.After(sandboxPollInterval): + } + } +} + +// sandboxNameForDeployment derives a K8s-compatible sandbox name from the deployment. +func sandboxNameForDeployment(deployment *models.Deployment) string { + if deployment == nil { + return "" + } + return utils.GenerateInternalNameForDeployment(deployment.ServerName, deployment.ID) +} + +// mergeEnv combines base and override env maps, with override taking precedence. +func mergeEnv(base, override map[string]string) map[string]string { + result := make(map[string]string, len(base)+len(override)) + for k, v := range base { + result[k] = v + } + for k, v := range override { + result[k] = v + } + return result +} diff --git a/internal/registry/platforms/openshell/deployment_adapter_test.go b/internal/registry/platforms/openshell/deployment_adapter_test.go new file mode 100644 index 00000000..8dc4c263 --- /dev/null +++ b/internal/registry/platforms/openshell/deployment_adapter_test.go @@ -0,0 +1,415 @@ +package openshell + +import ( + "context" + "fmt" + "testing" + + platformtypes "github.com/agentregistry-dev/agentregistry/internal/registry/platforms/types" + servicetesting "github.com/agentregistry-dev/agentregistry/internal/registry/service/testing" + "github.com/agentregistry-dev/agentregistry/pkg/models" + apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" + "github.com/modelcontextprotocol/registry/pkg/model" +) + +// mockClient implements Client for testing. +type mockClient struct { + createFn func(ctx context.Context, opts CreateSandboxOpts) (*SandboxInfo, error) + getFn func(ctx context.Context, name string) (*SandboxInfo, error) + listFn func(ctx context.Context) ([]SandboxInfo, error) + deleteFn func(ctx context.Context, name string) error + logsFn func(ctx context.Context, name string) ([]string, error) + healthFn func(ctx context.Context) error +} + +func (m *mockClient) CreateSandbox(ctx context.Context, opts CreateSandboxOpts) (*SandboxInfo, error) { + if m.createFn != nil { + return m.createFn(ctx, opts) + } + return &SandboxInfo{ID: "sb-1", Name: opts.Name, Phase: "SANDBOX_PHASE_PROVISIONING"}, nil +} + +func (m *mockClient) GetSandbox(ctx context.Context, name string) (*SandboxInfo, error) { + if m.getFn != nil { + return m.getFn(ctx, name) + } + return &SandboxInfo{ID: "sb-1", Name: name, Phase: "SANDBOX_PHASE_READY"}, nil +} + +func (m *mockClient) ListSandboxes(ctx context.Context) ([]SandboxInfo, error) { + if m.listFn != nil { + return m.listFn(ctx) + } + return nil, nil +} + +func (m *mockClient) DeleteSandbox(ctx context.Context, name string) error { + if m.deleteFn != nil { + return m.deleteFn(ctx, name) + } + return nil +} + +func (m *mockClient) GetSandboxLogs(ctx context.Context, name string) ([]string, error) { + if m.logsFn != nil { + return m.logsFn(ctx, name) + } + return nil, nil +} + +func (m *mockClient) HealthCheck(ctx context.Context) error { + if m.healthFn != nil { + return m.healthFn(ctx) + } + return nil +} + +func (m *mockClient) Close() error { return nil } + +func newTestRegistry() *servicetesting.FakeRegistry { + registry := servicetesting.NewFakeRegistry() + registry.GetAgentByNameAndVersionFn = func(_ context.Context, name, version string) (*models.AgentResponse, error) { + return &models.AgentResponse{ + Agent: models.AgentJSON{ + AgentManifest: models.AgentManifest{ + Name: name, + Image: "test-agent-image:latest", + }, + Version: version, + }, + }, nil + } + registry.ResolveAgentManifestSkillsFn = func(_ context.Context, _ *models.AgentManifest) ([]platformtypes.AgentSkillRef, error) { + return nil, nil + } + registry.ResolveAgentManifestPromptsFn = func(_ context.Context, _ *models.AgentManifest) ([]platformtypes.ResolvedPrompt, error) { + return nil, nil + } + return registry +} + +func TestDeploy_Agent_CallsCreateSandbox(t *testing.T) { + var createdOpts CreateSandboxOpts + client := &mockClient{ + createFn: func(_ context.Context, opts CreateSandboxOpts) (*SandboxInfo, error) { + createdOpts = opts + return &SandboxInfo{ID: "sb-1", Name: opts.Name, Phase: "SANDBOX_PHASE_PROVISIONING"}, nil + }, + } + + registry := newTestRegistry() + adapter := NewOpenShellDeploymentAdapter(registry, client) + + deployment := &models.Deployment{ + ID: "dep-123", + ServerName: "my-agent", + Version: "1.0.0", + ResourceType: "agent", + ProviderID: "openshell-default", + Env: map[string]string{"MY_KEY": "my-val"}, + } + + result, err := adapter.Deploy(context.Background(), deployment) + if err != nil { + t.Fatalf("Deploy() error = %v", err) + } + if result.Status != models.DeploymentStatusDeployed { + t.Errorf("status = %q, want %q", result.Status, models.DeploymentStatusDeployed) + } + if createdOpts.Image != "test-agent-image:latest" { + t.Errorf("image = %q, want %q", createdOpts.Image, "test-agent-image:latest") + } + if createdOpts.Name == "" { + t.Error("sandbox name should not be empty") + } +} + +func TestDeploy_MCP_CallsCreateSandbox(t *testing.T) { + var createdOpts CreateSandboxOpts + client := &mockClient{ + createFn: func(_ context.Context, opts CreateSandboxOpts) (*SandboxInfo, error) { + createdOpts = opts + return &SandboxInfo{ID: "sb-2", Name: opts.Name, Phase: "SANDBOX_PHASE_PROVISIONING"}, nil + }, + } + + registry := newTestRegistry() + registry.GetServerByNameAndVersionFn = func(_ context.Context, name, version string) (*apiv0.ServerResponse, error) { + return &apiv0.ServerResponse{ + Server: apiv0.ServerJSON{ + Name: name, + Version: version, + Packages: []model.Package{ + { + RegistryType: "oci", + Identifier: "test-mcp-image:latest", + }, + }, + }, + }, nil + } + + adapter := NewOpenShellDeploymentAdapter(registry, client) + + deployment := &models.Deployment{ + ID: "dep-456", + ServerName: "my-mcp", + Version: "2.0.0", + ResourceType: "mcp", + ProviderID: "openshell-default", + } + + result, err := adapter.Deploy(context.Background(), deployment) + if err != nil { + t.Fatalf("Deploy() error = %v", err) + } + if result.Status != models.DeploymentStatusDeployed { + t.Errorf("status = %q, want %q", result.Status, models.DeploymentStatusDeployed) + } + if createdOpts.Name == "" { + t.Error("sandbox name should not be empty") + } +} + +func TestUndeploy_CallsDeleteSandbox(t *testing.T) { + var deletedName string + client := &mockClient{ + deleteFn: func(_ context.Context, name string) error { + deletedName = name + return nil + }, + } + + adapter := NewOpenShellDeploymentAdapter(newTestRegistry(), client) + + deployment := &models.Deployment{ + ID: "dep-789", + ServerName: "my-agent", + Version: "1.0.0", + ResourceType: "agent", + ProviderID: "openshell-default", + } + + if err := adapter.Undeploy(context.Background(), deployment); err != nil { + t.Fatalf("Undeploy() error = %v", err) + } + if deletedName == "" { + t.Error("expected DeleteSandbox to be called") + } +} + +func TestGetLogs_ReturnsLogLines(t *testing.T) { + client := &mockClient{ + logsFn: func(_ context.Context, _ string) ([]string, error) { + return []string{"line1", "line2", "line3"}, nil + }, + } + + adapter := NewOpenShellDeploymentAdapter(newTestRegistry(), client) + + deployment := &models.Deployment{ + ID: "dep-logs", + ServerName: "my-agent", + Version: "1.0.0", + ResourceType: "agent", + ProviderID: "openshell-default", + } + + logs, err := adapter.GetLogs(context.Background(), deployment) + if err != nil { + t.Fatalf("GetLogs() error = %v", err) + } + if len(logs) != 3 { + t.Errorf("log lines = %d, want 3", len(logs)) + } +} + +func TestDeploy_ValidationError(t *testing.T) { + adapter := NewOpenShellDeploymentAdapter(newTestRegistry(), &mockClient{}) + + tests := []struct { + name string + deployment *models.Deployment + }{ + {"nil deployment", nil}, + {"missing provider id", &models.Deployment{ + ServerName: "test", + Version: "1.0.0", + ResourceType: "agent", + }}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := adapter.Deploy(context.Background(), tt.deployment) + if err == nil { + t.Fatal("expected validation error") + } + }) + } +} + +func TestDeploy_WaitsForReadyPhase(t *testing.T) { + callCount := 0 + client := &mockClient{ + getFn: func(_ context.Context, name string) (*SandboxInfo, error) { + callCount++ + if callCount < 3 { + return &SandboxInfo{ID: "sb-1", Name: name, Phase: "SANDBOX_PHASE_PROVISIONING"}, nil + } + return &SandboxInfo{ID: "sb-1", Name: name, Phase: "SANDBOX_PHASE_READY"}, nil + }, + } + + adapter := NewOpenShellDeploymentAdapter(newTestRegistry(), client) + + deployment := &models.Deployment{ + ID: "dep-poll", + ServerName: "poll-agent", + Version: "1.0.0", + ResourceType: "agent", + ProviderID: "openshell-default", + } + + result, err := adapter.Deploy(context.Background(), deployment) + if err != nil { + t.Fatalf("Deploy() error = %v", err) + } + if result.Status != models.DeploymentStatusDeployed { + t.Errorf("status = %q, want %q", result.Status, models.DeploymentStatusDeployed) + } + if callCount < 3 { + t.Errorf("expected at least 3 GetSandbox polls, got %d", callCount) + } +} + +func TestDeploy_ErrorPhase(t *testing.T) { + client := &mockClient{ + getFn: func(_ context.Context, name string) (*SandboxInfo, error) { + return &SandboxInfo{ID: "sb-1", Name: name, Phase: "SANDBOX_PHASE_ERROR"}, nil + }, + } + + adapter := NewOpenShellDeploymentAdapter(newTestRegistry(), client) + + deployment := &models.Deployment{ + ID: "dep-err", + ServerName: "err-agent", + Version: "1.0.0", + ResourceType: "agent", + ProviderID: "openshell-default", + } + + _, err := adapter.Deploy(context.Background(), deployment) + if err == nil { + t.Fatal("expected error for sandbox in Error phase") + } +} + +func TestPlatform(t *testing.T) { + adapter := NewOpenShellDeploymentAdapter(newTestRegistry(), &mockClient{}) + if p := adapter.Platform(); p != "openshell" { + t.Errorf("Platform() = %q, want %q", p, "openshell") + } +} + +func TestSupportedResourceTypes(t *testing.T) { + adapter := NewOpenShellDeploymentAdapter(newTestRegistry(), &mockClient{}) + types := adapter.SupportedResourceTypes() + if len(types) != 2 { + t.Errorf("SupportedResourceTypes() len = %d, want 2", len(types)) + } +} + +func TestDiscover_ReturnsEmpty(t *testing.T) { + adapter := NewOpenShellDeploymentAdapter(newTestRegistry(), &mockClient{}) + result, err := adapter.Discover(context.Background(), "any") + if err != nil { + t.Fatalf("Discover() error = %v", err) + } + if len(result) != 0 { + t.Errorf("Discover() len = %d, want 0", len(result)) + } +} + +func TestCancel_DeletesSandbox(t *testing.T) { + var deletedName string + client := &mockClient{ + deleteFn: func(_ context.Context, name string) error { + deletedName = name + return nil + }, + } + + adapter := NewOpenShellDeploymentAdapter(newTestRegistry(), client) + deployment := &models.Deployment{ + ID: "dep-cancel", + ServerName: "cancel-agent", + Version: "1.0.0", + ResourceType: "agent", + ProviderID: "openshell-default", + } + + if err := adapter.Cancel(context.Background(), deployment); err != nil { + t.Fatalf("Cancel() error = %v", err) + } + if deletedName == "" { + t.Error("expected DeleteSandbox to be called") + } +} + +func TestMergeEnv(t *testing.T) { + base := map[string]string{"A": "1", "B": "2"} + override := map[string]string{"B": "3", "C": "4"} + result := mergeEnv(base, override) + if result["A"] != "1" { + t.Errorf("A = %q, want 1", result["A"]) + } + if result["B"] != "3" { + t.Errorf("B = %q, want 3 (override)", result["B"]) + } + if result["C"] != "4" { + t.Errorf("C = %q, want 4", result["C"]) + } +} + +func TestSandboxNameForDeployment(t *testing.T) { + deployment := &models.Deployment{ + ID: "dep-123", + ServerName: "my-agent", + } + name := sandboxNameForDeployment(deployment) + if name == "" { + t.Error("expected non-empty sandbox name") + } +} + +func TestSandboxNameForDeployment_Nil(t *testing.T) { + name := sandboxNameForDeployment(nil) + if name != "" { + t.Errorf("expected empty name for nil deployment, got %q", name) + } +} + +func TestDeploy_CreateSandboxError(t *testing.T) { + client := &mockClient{ + createFn: func(_ context.Context, _ CreateSandboxOpts) (*SandboxInfo, error) { + return nil, fmt.Errorf("connection refused") + }, + } + + adapter := NewOpenShellDeploymentAdapter(newTestRegistry(), client) + + deployment := &models.Deployment{ + ID: "dep-fail", + ServerName: "fail-agent", + Version: "1.0.0", + ResourceType: "agent", + ProviderID: "openshell-default", + } + + _, err := adapter.Deploy(context.Background(), deployment) + if err == nil { + t.Fatal("expected error from CreateSandbox failure") + } +} diff --git a/internal/registry/platforms/openshell/proto/OPENSHELL_PROTO_VERSION b/internal/registry/platforms/openshell/proto/OPENSHELL_PROTO_VERSION new file mode 100644 index 00000000..3527dbc1 --- /dev/null +++ b/internal/registry/platforms/openshell/proto/OPENSHELL_PROTO_VERSION @@ -0,0 +1 @@ +v0.0.11 diff --git a/internal/registry/platforms/openshell/proto/datamodel.proto b/internal/registry/platforms/openshell/proto/datamodel.proto new file mode 100644 index 00000000..157afb51 --- /dev/null +++ b/internal/registry/platforms/openshell/proto/datamodel.proto @@ -0,0 +1,89 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package openshell.datamodel.v1; + +import "google/protobuf/struct.proto"; +import "sandbox.proto"; + +// Sandbox model stored by OpenShell. +message Sandbox { + string id = 1; + string name = 2; + string namespace = 3; + SandboxSpec spec = 4; + SandboxStatus status = 5; + SandboxPhase phase = 6; + // Milliseconds since Unix epoch when the sandbox was created. + int64 created_at_ms = 7; + // Currently active policy version (updated when sandbox reports loaded). + uint32 current_policy_version = 8; +} + +// OpenShell-level sandbox spec. +message SandboxSpec { + string log_level = 1; + map environment = 5; + SandboxTemplate template = 6; + // Required sandbox policy configuration. + openshell.sandbox.v1.SandboxPolicy policy = 7; + // Provider names to attach to this sandbox. + repeated string providers = 8; + // Request NVIDIA GPU resources for this sandbox. + bool gpu = 9; +} + +// Sandbox template mapped onto Kubernetes pod template inputs. +message SandboxTemplate { + string image = 1; + string runtime_class_name = 2; + string agent_socket = 3; + map labels = 4; + map annotations = 5; + map environment = 6; + google.protobuf.Struct resources = 7; + google.protobuf.Struct pod_template = 8; + google.protobuf.Struct volume_claim_templates = 9; +} + +// Sandbox status captured from Kubernetes. +message SandboxStatus { + string sandbox_name = 1; + string agent_pod = 2; + string agent_fd = 3; + string sandbox_fd = 4; + repeated SandboxCondition conditions = 5; +} + +// Sandbox condition mirrors Kubernetes conditions. +message SandboxCondition { + string type = 1; + string status = 2; + string reason = 3; + string message = 4; + string last_transition_time = 5; +} + +// High-level sandbox lifecycle phase. +enum SandboxPhase { + SANDBOX_PHASE_UNSPECIFIED = 0; + SANDBOX_PHASE_PROVISIONING = 1; + SANDBOX_PHASE_READY = 2; + SANDBOX_PHASE_ERROR = 3; + SANDBOX_PHASE_DELETING = 4; + SANDBOX_PHASE_UNKNOWN = 5; +} + +// Provider model stored by OpenShell. +message Provider { + string id = 1; + string name = 2; + // Canonical provider type slug (for example: "claude", "gitlab"). + string type = 3; + // Secret values used for authentication. + map credentials = 4; + // Non-secret provider configuration. + map config = 5; +} diff --git a/internal/registry/platforms/openshell/proto/gen/datamodel.pb.go b/internal/registry/platforms/openshell/proto/gen/datamodel.pb.go new file mode 100644 index 00000000..519e36a5 --- /dev/null +++ b/internal/registry/platforms/openshell/proto/gen/datamodel.pb.go @@ -0,0 +1,777 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v7.34.0 +// source: datamodel.proto + +package gen + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + structpb "google.golang.org/protobuf/types/known/structpb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// High-level sandbox lifecycle phase. +type SandboxPhase int32 + +const ( + SandboxPhase_SANDBOX_PHASE_UNSPECIFIED SandboxPhase = 0 + SandboxPhase_SANDBOX_PHASE_PROVISIONING SandboxPhase = 1 + SandboxPhase_SANDBOX_PHASE_READY SandboxPhase = 2 + SandboxPhase_SANDBOX_PHASE_ERROR SandboxPhase = 3 + SandboxPhase_SANDBOX_PHASE_DELETING SandboxPhase = 4 + SandboxPhase_SANDBOX_PHASE_UNKNOWN SandboxPhase = 5 +) + +// Enum value maps for SandboxPhase. +var ( + SandboxPhase_name = map[int32]string{ + 0: "SANDBOX_PHASE_UNSPECIFIED", + 1: "SANDBOX_PHASE_PROVISIONING", + 2: "SANDBOX_PHASE_READY", + 3: "SANDBOX_PHASE_ERROR", + 4: "SANDBOX_PHASE_DELETING", + 5: "SANDBOX_PHASE_UNKNOWN", + } + SandboxPhase_value = map[string]int32{ + "SANDBOX_PHASE_UNSPECIFIED": 0, + "SANDBOX_PHASE_PROVISIONING": 1, + "SANDBOX_PHASE_READY": 2, + "SANDBOX_PHASE_ERROR": 3, + "SANDBOX_PHASE_DELETING": 4, + "SANDBOX_PHASE_UNKNOWN": 5, + } +) + +func (x SandboxPhase) Enum() *SandboxPhase { + p := new(SandboxPhase) + *p = x + return p +} + +func (x SandboxPhase) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SandboxPhase) Descriptor() protoreflect.EnumDescriptor { + return file_datamodel_proto_enumTypes[0].Descriptor() +} + +func (SandboxPhase) Type() protoreflect.EnumType { + return &file_datamodel_proto_enumTypes[0] +} + +func (x SandboxPhase) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SandboxPhase.Descriptor instead. +func (SandboxPhase) EnumDescriptor() ([]byte, []int) { + return file_datamodel_proto_rawDescGZIP(), []int{0} +} + +// Sandbox model stored by OpenShell. +type Sandbox struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Namespace string `protobuf:"bytes,3,opt,name=namespace,proto3" json:"namespace,omitempty"` + Spec *SandboxSpec `protobuf:"bytes,4,opt,name=spec,proto3" json:"spec,omitempty"` + Status *SandboxStatus `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` + Phase SandboxPhase `protobuf:"varint,6,opt,name=phase,proto3,enum=openshell.datamodel.v1.SandboxPhase" json:"phase,omitempty"` + // Milliseconds since Unix epoch when the sandbox was created. + CreatedAtMs int64 `protobuf:"varint,7,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` + // Currently active policy version (updated when sandbox reports loaded). + CurrentPolicyVersion uint32 `protobuf:"varint,8,opt,name=current_policy_version,json=currentPolicyVersion,proto3" json:"current_policy_version,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Sandbox) Reset() { + *x = Sandbox{} + mi := &file_datamodel_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Sandbox) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Sandbox) ProtoMessage() {} + +func (x *Sandbox) ProtoReflect() protoreflect.Message { + mi := &file_datamodel_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Sandbox.ProtoReflect.Descriptor instead. +func (*Sandbox) Descriptor() ([]byte, []int) { + return file_datamodel_proto_rawDescGZIP(), []int{0} +} + +func (x *Sandbox) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *Sandbox) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Sandbox) GetNamespace() string { + if x != nil { + return x.Namespace + } + return "" +} + +func (x *Sandbox) GetSpec() *SandboxSpec { + if x != nil { + return x.Spec + } + return nil +} + +func (x *Sandbox) GetStatus() *SandboxStatus { + if x != nil { + return x.Status + } + return nil +} + +func (x *Sandbox) GetPhase() SandboxPhase { + if x != nil { + return x.Phase + } + return SandboxPhase_SANDBOX_PHASE_UNSPECIFIED +} + +func (x *Sandbox) GetCreatedAtMs() int64 { + if x != nil { + return x.CreatedAtMs + } + return 0 +} + +func (x *Sandbox) GetCurrentPolicyVersion() uint32 { + if x != nil { + return x.CurrentPolicyVersion + } + return 0 +} + +// OpenShell-level sandbox spec. +type SandboxSpec struct { + state protoimpl.MessageState `protogen:"open.v1"` + LogLevel string `protobuf:"bytes,1,opt,name=log_level,json=logLevel,proto3" json:"log_level,omitempty"` + Environment map[string]string `protobuf:"bytes,5,rep,name=environment,proto3" json:"environment,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Template *SandboxTemplate `protobuf:"bytes,6,opt,name=template,proto3" json:"template,omitempty"` + // Required sandbox policy configuration. + Policy *SandboxPolicy `protobuf:"bytes,7,opt,name=policy,proto3" json:"policy,omitempty"` + // Provider names to attach to this sandbox. + Providers []string `protobuf:"bytes,8,rep,name=providers,proto3" json:"providers,omitempty"` + // Request NVIDIA GPU resources for this sandbox. + Gpu bool `protobuf:"varint,9,opt,name=gpu,proto3" json:"gpu,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxSpec) Reset() { + *x = SandboxSpec{} + mi := &file_datamodel_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxSpec) ProtoMessage() {} + +func (x *SandboxSpec) ProtoReflect() protoreflect.Message { + mi := &file_datamodel_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SandboxSpec.ProtoReflect.Descriptor instead. +func (*SandboxSpec) Descriptor() ([]byte, []int) { + return file_datamodel_proto_rawDescGZIP(), []int{1} +} + +func (x *SandboxSpec) GetLogLevel() string { + if x != nil { + return x.LogLevel + } + return "" +} + +func (x *SandboxSpec) GetEnvironment() map[string]string { + if x != nil { + return x.Environment + } + return nil +} + +func (x *SandboxSpec) GetTemplate() *SandboxTemplate { + if x != nil { + return x.Template + } + return nil +} + +func (x *SandboxSpec) GetPolicy() *SandboxPolicy { + if x != nil { + return x.Policy + } + return nil +} + +func (x *SandboxSpec) GetProviders() []string { + if x != nil { + return x.Providers + } + return nil +} + +func (x *SandboxSpec) GetGpu() bool { + if x != nil { + return x.Gpu + } + return false +} + +// Sandbox template mapped onto Kubernetes pod template inputs. +type SandboxTemplate struct { + state protoimpl.MessageState `protogen:"open.v1"` + Image string `protobuf:"bytes,1,opt,name=image,proto3" json:"image,omitempty"` + RuntimeClassName string `protobuf:"bytes,2,opt,name=runtime_class_name,json=runtimeClassName,proto3" json:"runtime_class_name,omitempty"` + AgentSocket string `protobuf:"bytes,3,opt,name=agent_socket,json=agentSocket,proto3" json:"agent_socket,omitempty"` + Labels map[string]string `protobuf:"bytes,4,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Annotations map[string]string `protobuf:"bytes,5,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Environment map[string]string `protobuf:"bytes,6,rep,name=environment,proto3" json:"environment,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Resources *structpb.Struct `protobuf:"bytes,7,opt,name=resources,proto3" json:"resources,omitempty"` + PodTemplate *structpb.Struct `protobuf:"bytes,8,opt,name=pod_template,json=podTemplate,proto3" json:"pod_template,omitempty"` + VolumeClaimTemplates *structpb.Struct `protobuf:"bytes,9,opt,name=volume_claim_templates,json=volumeClaimTemplates,proto3" json:"volume_claim_templates,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxTemplate) Reset() { + *x = SandboxTemplate{} + mi := &file_datamodel_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxTemplate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxTemplate) ProtoMessage() {} + +func (x *SandboxTemplate) ProtoReflect() protoreflect.Message { + mi := &file_datamodel_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SandboxTemplate.ProtoReflect.Descriptor instead. +func (*SandboxTemplate) Descriptor() ([]byte, []int) { + return file_datamodel_proto_rawDescGZIP(), []int{2} +} + +func (x *SandboxTemplate) GetImage() string { + if x != nil { + return x.Image + } + return "" +} + +func (x *SandboxTemplate) GetRuntimeClassName() string { + if x != nil { + return x.RuntimeClassName + } + return "" +} + +func (x *SandboxTemplate) GetAgentSocket() string { + if x != nil { + return x.AgentSocket + } + return "" +} + +func (x *SandboxTemplate) GetLabels() map[string]string { + if x != nil { + return x.Labels + } + return nil +} + +func (x *SandboxTemplate) GetAnnotations() map[string]string { + if x != nil { + return x.Annotations + } + return nil +} + +func (x *SandboxTemplate) GetEnvironment() map[string]string { + if x != nil { + return x.Environment + } + return nil +} + +func (x *SandboxTemplate) GetResources() *structpb.Struct { + if x != nil { + return x.Resources + } + return nil +} + +func (x *SandboxTemplate) GetPodTemplate() *structpb.Struct { + if x != nil { + return x.PodTemplate + } + return nil +} + +func (x *SandboxTemplate) GetVolumeClaimTemplates() *structpb.Struct { + if x != nil { + return x.VolumeClaimTemplates + } + return nil +} + +// Sandbox status captured from Kubernetes. +type SandboxStatus struct { + state protoimpl.MessageState `protogen:"open.v1"` + SandboxName string `protobuf:"bytes,1,opt,name=sandbox_name,json=sandboxName,proto3" json:"sandbox_name,omitempty"` + AgentPod string `protobuf:"bytes,2,opt,name=agent_pod,json=agentPod,proto3" json:"agent_pod,omitempty"` + AgentFd string `protobuf:"bytes,3,opt,name=agent_fd,json=agentFd,proto3" json:"agent_fd,omitempty"` + SandboxFd string `protobuf:"bytes,4,opt,name=sandbox_fd,json=sandboxFd,proto3" json:"sandbox_fd,omitempty"` + Conditions []*SandboxCondition `protobuf:"bytes,5,rep,name=conditions,proto3" json:"conditions,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxStatus) Reset() { + *x = SandboxStatus{} + mi := &file_datamodel_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxStatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxStatus) ProtoMessage() {} + +func (x *SandboxStatus) ProtoReflect() protoreflect.Message { + mi := &file_datamodel_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SandboxStatus.ProtoReflect.Descriptor instead. +func (*SandboxStatus) Descriptor() ([]byte, []int) { + return file_datamodel_proto_rawDescGZIP(), []int{3} +} + +func (x *SandboxStatus) GetSandboxName() string { + if x != nil { + return x.SandboxName + } + return "" +} + +func (x *SandboxStatus) GetAgentPod() string { + if x != nil { + return x.AgentPod + } + return "" +} + +func (x *SandboxStatus) GetAgentFd() string { + if x != nil { + return x.AgentFd + } + return "" +} + +func (x *SandboxStatus) GetSandboxFd() string { + if x != nil { + return x.SandboxFd + } + return "" +} + +func (x *SandboxStatus) GetConditions() []*SandboxCondition { + if x != nil { + return x.Conditions + } + return nil +} + +// Sandbox condition mirrors Kubernetes conditions. +type SandboxCondition struct { + state protoimpl.MessageState `protogen:"open.v1"` + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` + Reason string `protobuf:"bytes,3,opt,name=reason,proto3" json:"reason,omitempty"` + Message string `protobuf:"bytes,4,opt,name=message,proto3" json:"message,omitempty"` + LastTransitionTime string `protobuf:"bytes,5,opt,name=last_transition_time,json=lastTransitionTime,proto3" json:"last_transition_time,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxCondition) Reset() { + *x = SandboxCondition{} + mi := &file_datamodel_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxCondition) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxCondition) ProtoMessage() {} + +func (x *SandboxCondition) ProtoReflect() protoreflect.Message { + mi := &file_datamodel_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SandboxCondition.ProtoReflect.Descriptor instead. +func (*SandboxCondition) Descriptor() ([]byte, []int) { + return file_datamodel_proto_rawDescGZIP(), []int{4} +} + +func (x *SandboxCondition) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *SandboxCondition) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +func (x *SandboxCondition) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +func (x *SandboxCondition) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *SandboxCondition) GetLastTransitionTime() string { + if x != nil { + return x.LastTransitionTime + } + return "" +} + +// Provider model stored by OpenShell. +type Provider struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // Canonical provider type slug (for example: "claude", "gitlab"). + Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` + // Secret values used for authentication. + Credentials map[string]string `protobuf:"bytes,4,rep,name=credentials,proto3" json:"credentials,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // Non-secret provider configuration. + Config map[string]string `protobuf:"bytes,5,rep,name=config,proto3" json:"config,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Provider) Reset() { + *x = Provider{} + mi := &file_datamodel_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Provider) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Provider) ProtoMessage() {} + +func (x *Provider) ProtoReflect() protoreflect.Message { + mi := &file_datamodel_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Provider.ProtoReflect.Descriptor instead. +func (*Provider) Descriptor() ([]byte, []int) { + return file_datamodel_proto_rawDescGZIP(), []int{5} +} + +func (x *Provider) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *Provider) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Provider) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *Provider) GetCredentials() map[string]string { + if x != nil { + return x.Credentials + } + return nil +} + +func (x *Provider) GetConfig() map[string]string { + if x != nil { + return x.Config + } + return nil +} + +var File_datamodel_proto protoreflect.FileDescriptor + +const file_datamodel_proto_rawDesc = "" + + "\n" + + "\x0fdatamodel.proto\x12\x16openshell.datamodel.v1\x1a\x1cgoogle/protobuf/struct.proto\x1a\rsandbox.proto\"\xd9\x02\n" + + "\aSandbox\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x1c\n" + + "\tnamespace\x18\x03 \x01(\tR\tnamespace\x127\n" + + "\x04spec\x18\x04 \x01(\v2#.openshell.datamodel.v1.SandboxSpecR\x04spec\x12=\n" + + "\x06status\x18\x05 \x01(\v2%.openshell.datamodel.v1.SandboxStatusR\x06status\x12:\n" + + "\x05phase\x18\x06 \x01(\x0e2$.openshell.datamodel.v1.SandboxPhaseR\x05phase\x12\"\n" + + "\rcreated_at_ms\x18\a \x01(\x03R\vcreatedAtMs\x124\n" + + "\x16current_policy_version\x18\b \x01(\rR\x14currentPolicyVersion\"\xf4\x02\n" + + "\vSandboxSpec\x12\x1b\n" + + "\tlog_level\x18\x01 \x01(\tR\blogLevel\x12V\n" + + "\venvironment\x18\x05 \x03(\v24.openshell.datamodel.v1.SandboxSpec.EnvironmentEntryR\venvironment\x12C\n" + + "\btemplate\x18\x06 \x01(\v2'.openshell.datamodel.v1.SandboxTemplateR\btemplate\x12;\n" + + "\x06policy\x18\a \x01(\v2#.openshell.sandbox.v1.SandboxPolicyR\x06policy\x12\x1c\n" + + "\tproviders\x18\b \x03(\tR\tproviders\x12\x10\n" + + "\x03gpu\x18\t \x01(\bR\x03gpu\x1a>\n" + + "\x10EnvironmentEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xfa\x05\n" + + "\x0fSandboxTemplate\x12\x14\n" + + "\x05image\x18\x01 \x01(\tR\x05image\x12,\n" + + "\x12runtime_class_name\x18\x02 \x01(\tR\x10runtimeClassName\x12!\n" + + "\fagent_socket\x18\x03 \x01(\tR\vagentSocket\x12K\n" + + "\x06labels\x18\x04 \x03(\v23.openshell.datamodel.v1.SandboxTemplate.LabelsEntryR\x06labels\x12Z\n" + + "\vannotations\x18\x05 \x03(\v28.openshell.datamodel.v1.SandboxTemplate.AnnotationsEntryR\vannotations\x12Z\n" + + "\venvironment\x18\x06 \x03(\v28.openshell.datamodel.v1.SandboxTemplate.EnvironmentEntryR\venvironment\x125\n" + + "\tresources\x18\a \x01(\v2\x17.google.protobuf.StructR\tresources\x12:\n" + + "\fpod_template\x18\b \x01(\v2\x17.google.protobuf.StructR\vpodTemplate\x12M\n" + + "\x16volume_claim_templates\x18\t \x01(\v2\x17.google.protobuf.StructR\x14volumeClaimTemplates\x1a9\n" + + "\vLabelsEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\x1a>\n" + + "\x10AnnotationsEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\x1a>\n" + + "\x10EnvironmentEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xd3\x01\n" + + "\rSandboxStatus\x12!\n" + + "\fsandbox_name\x18\x01 \x01(\tR\vsandboxName\x12\x1b\n" + + "\tagent_pod\x18\x02 \x01(\tR\bagentPod\x12\x19\n" + + "\bagent_fd\x18\x03 \x01(\tR\aagentFd\x12\x1d\n" + + "\n" + + "sandbox_fd\x18\x04 \x01(\tR\tsandboxFd\x12H\n" + + "\n" + + "conditions\x18\x05 \x03(\v2(.openshell.datamodel.v1.SandboxConditionR\n" + + "conditions\"\xa2\x01\n" + + "\x10SandboxCondition\x12\x12\n" + + "\x04type\x18\x01 \x01(\tR\x04type\x12\x16\n" + + "\x06status\x18\x02 \x01(\tR\x06status\x12\x16\n" + + "\x06reason\x18\x03 \x01(\tR\x06reason\x12\x18\n" + + "\amessage\x18\x04 \x01(\tR\amessage\x120\n" + + "\x14last_transition_time\x18\x05 \x01(\tR\x12lastTransitionTime\"\xd8\x02\n" + + "\bProvider\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x12\n" + + "\x04type\x18\x03 \x01(\tR\x04type\x12S\n" + + "\vcredentials\x18\x04 \x03(\v21.openshell.datamodel.v1.Provider.CredentialsEntryR\vcredentials\x12D\n" + + "\x06config\x18\x05 \x03(\v2,.openshell.datamodel.v1.Provider.ConfigEntryR\x06config\x1a>\n" + + "\x10CredentialsEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\x1a9\n" + + "\vConfigEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01*\xb6\x01\n" + + "\fSandboxPhase\x12\x1d\n" + + "\x19SANDBOX_PHASE_UNSPECIFIED\x10\x00\x12\x1e\n" + + "\x1aSANDBOX_PHASE_PROVISIONING\x10\x01\x12\x17\n" + + "\x13SANDBOX_PHASE_READY\x10\x02\x12\x17\n" + + "\x13SANDBOX_PHASE_ERROR\x10\x03\x12\x1a\n" + + "\x16SANDBOX_PHASE_DELETING\x10\x04\x12\x19\n" + + "\x15SANDBOX_PHASE_UNKNOWN\x10\x05b\x06proto3" + +var ( + file_datamodel_proto_rawDescOnce sync.Once + file_datamodel_proto_rawDescData []byte +) + +func file_datamodel_proto_rawDescGZIP() []byte { + file_datamodel_proto_rawDescOnce.Do(func() { + file_datamodel_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_datamodel_proto_rawDesc), len(file_datamodel_proto_rawDesc))) + }) + return file_datamodel_proto_rawDescData +} + +var file_datamodel_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_datamodel_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_datamodel_proto_goTypes = []any{ + (SandboxPhase)(0), // 0: openshell.datamodel.v1.SandboxPhase + (*Sandbox)(nil), // 1: openshell.datamodel.v1.Sandbox + (*SandboxSpec)(nil), // 2: openshell.datamodel.v1.SandboxSpec + (*SandboxTemplate)(nil), // 3: openshell.datamodel.v1.SandboxTemplate + (*SandboxStatus)(nil), // 4: openshell.datamodel.v1.SandboxStatus + (*SandboxCondition)(nil), // 5: openshell.datamodel.v1.SandboxCondition + (*Provider)(nil), // 6: openshell.datamodel.v1.Provider + nil, // 7: openshell.datamodel.v1.SandboxSpec.EnvironmentEntry + nil, // 8: openshell.datamodel.v1.SandboxTemplate.LabelsEntry + nil, // 9: openshell.datamodel.v1.SandboxTemplate.AnnotationsEntry + nil, // 10: openshell.datamodel.v1.SandboxTemplate.EnvironmentEntry + nil, // 11: openshell.datamodel.v1.Provider.CredentialsEntry + nil, // 12: openshell.datamodel.v1.Provider.ConfigEntry + (*SandboxPolicy)(nil), // 13: openshell.sandbox.v1.SandboxPolicy + (*structpb.Struct)(nil), // 14: google.protobuf.Struct +} +var file_datamodel_proto_depIdxs = []int32{ + 2, // 0: openshell.datamodel.v1.Sandbox.spec:type_name -> openshell.datamodel.v1.SandboxSpec + 4, // 1: openshell.datamodel.v1.Sandbox.status:type_name -> openshell.datamodel.v1.SandboxStatus + 0, // 2: openshell.datamodel.v1.Sandbox.phase:type_name -> openshell.datamodel.v1.SandboxPhase + 7, // 3: openshell.datamodel.v1.SandboxSpec.environment:type_name -> openshell.datamodel.v1.SandboxSpec.EnvironmentEntry + 3, // 4: openshell.datamodel.v1.SandboxSpec.template:type_name -> openshell.datamodel.v1.SandboxTemplate + 13, // 5: openshell.datamodel.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 8, // 6: openshell.datamodel.v1.SandboxTemplate.labels:type_name -> openshell.datamodel.v1.SandboxTemplate.LabelsEntry + 9, // 7: openshell.datamodel.v1.SandboxTemplate.annotations:type_name -> openshell.datamodel.v1.SandboxTemplate.AnnotationsEntry + 10, // 8: openshell.datamodel.v1.SandboxTemplate.environment:type_name -> openshell.datamodel.v1.SandboxTemplate.EnvironmentEntry + 14, // 9: openshell.datamodel.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct + 14, // 10: openshell.datamodel.v1.SandboxTemplate.pod_template:type_name -> google.protobuf.Struct + 14, // 11: openshell.datamodel.v1.SandboxTemplate.volume_claim_templates:type_name -> google.protobuf.Struct + 5, // 12: openshell.datamodel.v1.SandboxStatus.conditions:type_name -> openshell.datamodel.v1.SandboxCondition + 11, // 13: openshell.datamodel.v1.Provider.credentials:type_name -> openshell.datamodel.v1.Provider.CredentialsEntry + 12, // 14: openshell.datamodel.v1.Provider.config:type_name -> openshell.datamodel.v1.Provider.ConfigEntry + 15, // [15:15] is the sub-list for method output_type + 15, // [15:15] is the sub-list for method input_type + 15, // [15:15] is the sub-list for extension type_name + 15, // [15:15] is the sub-list for extension extendee + 0, // [0:15] is the sub-list for field type_name +} + +func init() { file_datamodel_proto_init() } +func file_datamodel_proto_init() { + if File_datamodel_proto != nil { + return + } + file_sandbox_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_datamodel_proto_rawDesc), len(file_datamodel_proto_rawDesc)), + NumEnums: 1, + NumMessages: 12, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_datamodel_proto_goTypes, + DependencyIndexes: file_datamodel_proto_depIdxs, + EnumInfos: file_datamodel_proto_enumTypes, + MessageInfos: file_datamodel_proto_msgTypes, + }.Build() + File_datamodel_proto = out.File + file_datamodel_proto_goTypes = nil + file_datamodel_proto_depIdxs = nil +} diff --git a/internal/registry/platforms/openshell/proto/gen/inference.pb.go b/internal/registry/platforms/openshell/proto/gen/inference.pb.go new file mode 100644 index 00000000..315695ef --- /dev/null +++ b/internal/registry/platforms/openshell/proto/gen/inference.pb.go @@ -0,0 +1,798 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v7.34.0 +// source: inference.proto + +package gen + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Persisted cluster inference configuration. +// +// Only `provider_name` and `model_id` are stored; endpoint, protocols, +// credentials, and auth style are resolved from the provider at bundle time. +type ClusterInferenceConfig struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Provider record name backing this route. + ProviderName string `protobuf:"bytes,1,opt,name=provider_name,json=providerName,proto3" json:"provider_name,omitempty"` + // Model identifier to force on generation calls. + ModelId string `protobuf:"bytes,2,opt,name=model_id,json=modelId,proto3" json:"model_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ClusterInferenceConfig) Reset() { + *x = ClusterInferenceConfig{} + mi := &file_inference_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ClusterInferenceConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClusterInferenceConfig) ProtoMessage() {} + +func (x *ClusterInferenceConfig) ProtoReflect() protoreflect.Message { + mi := &file_inference_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClusterInferenceConfig.ProtoReflect.Descriptor instead. +func (*ClusterInferenceConfig) Descriptor() ([]byte, []int) { + return file_inference_proto_rawDescGZIP(), []int{0} +} + +func (x *ClusterInferenceConfig) GetProviderName() string { + if x != nil { + return x.ProviderName + } + return "" +} + +func (x *ClusterInferenceConfig) GetModelId() string { + if x != nil { + return x.ModelId + } + return "" +} + +// Storage envelope for the managed cluster inference route. +type InferenceRoute struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Config *ClusterInferenceConfig `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"` + // Object name ("inference.local" for the user-facing route, + // "sandbox-system" for the sandbox system-level route). + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + // Monotonic version incremented on every update. + Version uint64 `protobuf:"varint,4,opt,name=version,proto3" json:"version,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InferenceRoute) Reset() { + *x = InferenceRoute{} + mi := &file_inference_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InferenceRoute) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InferenceRoute) ProtoMessage() {} + +func (x *InferenceRoute) ProtoReflect() protoreflect.Message { + mi := &file_inference_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InferenceRoute.ProtoReflect.Descriptor instead. +func (*InferenceRoute) Descriptor() ([]byte, []int) { + return file_inference_proto_rawDescGZIP(), []int{1} +} + +func (x *InferenceRoute) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *InferenceRoute) GetConfig() *ClusterInferenceConfig { + if x != nil { + return x.Config + } + return nil +} + +func (x *InferenceRoute) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *InferenceRoute) GetVersion() uint64 { + if x != nil { + return x.Version + } + return 0 +} + +type SetClusterInferenceRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Provider record name to use for credentials + endpoint mapping. + ProviderName string `protobuf:"bytes,1,opt,name=provider_name,json=providerName,proto3" json:"provider_name,omitempty"` + // Model identifier to force on generation calls. + ModelId string `protobuf:"bytes,2,opt,name=model_id,json=modelId,proto3" json:"model_id,omitempty"` + // Route name to target. Empty string defaults to "inference.local" (user-facing). + // Use "sandbox-system" for the sandbox system-level inference route. + RouteName string `protobuf:"bytes,3,opt,name=route_name,json=routeName,proto3" json:"route_name,omitempty"` + // Verify the resolved upstream endpoint synchronously before persistence. + Verify bool `protobuf:"varint,4,opt,name=verify,proto3" json:"verify,omitempty"` + // Skip synchronous endpoint validation before persistence. + NoVerify bool `protobuf:"varint,5,opt,name=no_verify,json=noVerify,proto3" json:"no_verify,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SetClusterInferenceRequest) Reset() { + *x = SetClusterInferenceRequest{} + mi := &file_inference_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SetClusterInferenceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetClusterInferenceRequest) ProtoMessage() {} + +func (x *SetClusterInferenceRequest) ProtoReflect() protoreflect.Message { + mi := &file_inference_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetClusterInferenceRequest.ProtoReflect.Descriptor instead. +func (*SetClusterInferenceRequest) Descriptor() ([]byte, []int) { + return file_inference_proto_rawDescGZIP(), []int{2} +} + +func (x *SetClusterInferenceRequest) GetProviderName() string { + if x != nil { + return x.ProviderName + } + return "" +} + +func (x *SetClusterInferenceRequest) GetModelId() string { + if x != nil { + return x.ModelId + } + return "" +} + +func (x *SetClusterInferenceRequest) GetRouteName() string { + if x != nil { + return x.RouteName + } + return "" +} + +func (x *SetClusterInferenceRequest) GetVerify() bool { + if x != nil { + return x.Verify + } + return false +} + +func (x *SetClusterInferenceRequest) GetNoVerify() bool { + if x != nil { + return x.NoVerify + } + return false +} + +type ValidatedEndpoint struct { + state protoimpl.MessageState `protogen:"open.v1"` + Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` + Protocol string `protobuf:"bytes,2,opt,name=protocol,proto3" json:"protocol,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ValidatedEndpoint) Reset() { + *x = ValidatedEndpoint{} + mi := &file_inference_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ValidatedEndpoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidatedEndpoint) ProtoMessage() {} + +func (x *ValidatedEndpoint) ProtoReflect() protoreflect.Message { + mi := &file_inference_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValidatedEndpoint.ProtoReflect.Descriptor instead. +func (*ValidatedEndpoint) Descriptor() ([]byte, []int) { + return file_inference_proto_rawDescGZIP(), []int{3} +} + +func (x *ValidatedEndpoint) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *ValidatedEndpoint) GetProtocol() string { + if x != nil { + return x.Protocol + } + return "" +} + +type SetClusterInferenceResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + ProviderName string `protobuf:"bytes,1,opt,name=provider_name,json=providerName,proto3" json:"provider_name,omitempty"` + ModelId string `protobuf:"bytes,2,opt,name=model_id,json=modelId,proto3" json:"model_id,omitempty"` + Version uint64 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"` + // Route name that was configured. + RouteName string `protobuf:"bytes,4,opt,name=route_name,json=routeName,proto3" json:"route_name,omitempty"` + // Whether endpoint verification ran as part of this request. + ValidationPerformed bool `protobuf:"varint,5,opt,name=validation_performed,json=validationPerformed,proto3" json:"validation_performed,omitempty"` + // The concrete endpoints that were probed during validation, when available. + ValidatedEndpoints []*ValidatedEndpoint `protobuf:"bytes,6,rep,name=validated_endpoints,json=validatedEndpoints,proto3" json:"validated_endpoints,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SetClusterInferenceResponse) Reset() { + *x = SetClusterInferenceResponse{} + mi := &file_inference_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SetClusterInferenceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetClusterInferenceResponse) ProtoMessage() {} + +func (x *SetClusterInferenceResponse) ProtoReflect() protoreflect.Message { + mi := &file_inference_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetClusterInferenceResponse.ProtoReflect.Descriptor instead. +func (*SetClusterInferenceResponse) Descriptor() ([]byte, []int) { + return file_inference_proto_rawDescGZIP(), []int{4} +} + +func (x *SetClusterInferenceResponse) GetProviderName() string { + if x != nil { + return x.ProviderName + } + return "" +} + +func (x *SetClusterInferenceResponse) GetModelId() string { + if x != nil { + return x.ModelId + } + return "" +} + +func (x *SetClusterInferenceResponse) GetVersion() uint64 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *SetClusterInferenceResponse) GetRouteName() string { + if x != nil { + return x.RouteName + } + return "" +} + +func (x *SetClusterInferenceResponse) GetValidationPerformed() bool { + if x != nil { + return x.ValidationPerformed + } + return false +} + +func (x *SetClusterInferenceResponse) GetValidatedEndpoints() []*ValidatedEndpoint { + if x != nil { + return x.ValidatedEndpoints + } + return nil +} + +type GetClusterInferenceRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Route name to query. Empty string defaults to "inference.local" (user-facing). + // Use "sandbox-system" for the sandbox system-level inference route. + RouteName string `protobuf:"bytes,1,opt,name=route_name,json=routeName,proto3" json:"route_name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetClusterInferenceRequest) Reset() { + *x = GetClusterInferenceRequest{} + mi := &file_inference_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetClusterInferenceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetClusterInferenceRequest) ProtoMessage() {} + +func (x *GetClusterInferenceRequest) ProtoReflect() protoreflect.Message { + mi := &file_inference_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetClusterInferenceRequest.ProtoReflect.Descriptor instead. +func (*GetClusterInferenceRequest) Descriptor() ([]byte, []int) { + return file_inference_proto_rawDescGZIP(), []int{5} +} + +func (x *GetClusterInferenceRequest) GetRouteName() string { + if x != nil { + return x.RouteName + } + return "" +} + +type GetClusterInferenceResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + ProviderName string `protobuf:"bytes,1,opt,name=provider_name,json=providerName,proto3" json:"provider_name,omitempty"` + ModelId string `protobuf:"bytes,2,opt,name=model_id,json=modelId,proto3" json:"model_id,omitempty"` + Version uint64 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"` + // Route name that was queried. + RouteName string `protobuf:"bytes,4,opt,name=route_name,json=routeName,proto3" json:"route_name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetClusterInferenceResponse) Reset() { + *x = GetClusterInferenceResponse{} + mi := &file_inference_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetClusterInferenceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetClusterInferenceResponse) ProtoMessage() {} + +func (x *GetClusterInferenceResponse) ProtoReflect() protoreflect.Message { + mi := &file_inference_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetClusterInferenceResponse.ProtoReflect.Descriptor instead. +func (*GetClusterInferenceResponse) Descriptor() ([]byte, []int) { + return file_inference_proto_rawDescGZIP(), []int{6} +} + +func (x *GetClusterInferenceResponse) GetProviderName() string { + if x != nil { + return x.ProviderName + } + return "" +} + +func (x *GetClusterInferenceResponse) GetModelId() string { + if x != nil { + return x.ModelId + } + return "" +} + +func (x *GetClusterInferenceResponse) GetVersion() uint64 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *GetClusterInferenceResponse) GetRouteName() string { + if x != nil { + return x.RouteName + } + return "" +} + +type GetInferenceBundleRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetInferenceBundleRequest) Reset() { + *x = GetInferenceBundleRequest{} + mi := &file_inference_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetInferenceBundleRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetInferenceBundleRequest) ProtoMessage() {} + +func (x *GetInferenceBundleRequest) ProtoReflect() protoreflect.Message { + mi := &file_inference_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetInferenceBundleRequest.ProtoReflect.Descriptor instead. +func (*GetInferenceBundleRequest) Descriptor() ([]byte, []int) { + return file_inference_proto_rawDescGZIP(), []int{7} +} + +// A single resolved route ready for sandbox-local execution. +type ResolvedRoute struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + BaseUrl string `protobuf:"bytes,2,opt,name=base_url,json=baseUrl,proto3" json:"base_url,omitempty"` + Protocols []string `protobuf:"bytes,3,rep,name=protocols,proto3" json:"protocols,omitempty"` + ApiKey string `protobuf:"bytes,4,opt,name=api_key,json=apiKey,proto3" json:"api_key,omitempty"` + ModelId string `protobuf:"bytes,5,opt,name=model_id,json=modelId,proto3" json:"model_id,omitempty"` + ProviderType string `protobuf:"bytes,6,opt,name=provider_type,json=providerType,proto3" json:"provider_type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ResolvedRoute) Reset() { + *x = ResolvedRoute{} + mi := &file_inference_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ResolvedRoute) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResolvedRoute) ProtoMessage() {} + +func (x *ResolvedRoute) ProtoReflect() protoreflect.Message { + mi := &file_inference_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResolvedRoute.ProtoReflect.Descriptor instead. +func (*ResolvedRoute) Descriptor() ([]byte, []int) { + return file_inference_proto_rawDescGZIP(), []int{8} +} + +func (x *ResolvedRoute) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ResolvedRoute) GetBaseUrl() string { + if x != nil { + return x.BaseUrl + } + return "" +} + +func (x *ResolvedRoute) GetProtocols() []string { + if x != nil { + return x.Protocols + } + return nil +} + +func (x *ResolvedRoute) GetApiKey() string { + if x != nil { + return x.ApiKey + } + return "" +} + +func (x *ResolvedRoute) GetModelId() string { + if x != nil { + return x.ModelId + } + return "" +} + +func (x *ResolvedRoute) GetProviderType() string { + if x != nil { + return x.ProviderType + } + return "" +} + +type GetInferenceBundleResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Routes []*ResolvedRoute `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"` + // Opaque revision tag for cache freshness checks. + Revision string `protobuf:"bytes,2,opt,name=revision,proto3" json:"revision,omitempty"` + // Timestamp (epoch ms) when this bundle was generated. + GeneratedAtMs int64 `protobuf:"varint,3,opt,name=generated_at_ms,json=generatedAtMs,proto3" json:"generated_at_ms,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetInferenceBundleResponse) Reset() { + *x = GetInferenceBundleResponse{} + mi := &file_inference_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetInferenceBundleResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetInferenceBundleResponse) ProtoMessage() {} + +func (x *GetInferenceBundleResponse) ProtoReflect() protoreflect.Message { + mi := &file_inference_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetInferenceBundleResponse.ProtoReflect.Descriptor instead. +func (*GetInferenceBundleResponse) Descriptor() ([]byte, []int) { + return file_inference_proto_rawDescGZIP(), []int{9} +} + +func (x *GetInferenceBundleResponse) GetRoutes() []*ResolvedRoute { + if x != nil { + return x.Routes + } + return nil +} + +func (x *GetInferenceBundleResponse) GetRevision() string { + if x != nil { + return x.Revision + } + return "" +} + +func (x *GetInferenceBundleResponse) GetGeneratedAtMs() int64 { + if x != nil { + return x.GeneratedAtMs + } + return 0 +} + +var File_inference_proto protoreflect.FileDescriptor + +const file_inference_proto_rawDesc = "" + + "\n" + + "\x0finference.proto\x12\x16openshell.inference.v1\"X\n" + + "\x16ClusterInferenceConfig\x12#\n" + + "\rprovider_name\x18\x01 \x01(\tR\fproviderName\x12\x19\n" + + "\bmodel_id\x18\x02 \x01(\tR\amodelId\"\x96\x01\n" + + "\x0eInferenceRoute\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12F\n" + + "\x06config\x18\x02 \x01(\v2..openshell.inference.v1.ClusterInferenceConfigR\x06config\x12\x12\n" + + "\x04name\x18\x03 \x01(\tR\x04name\x12\x18\n" + + "\aversion\x18\x04 \x01(\x04R\aversion\"\xb0\x01\n" + + "\x1aSetClusterInferenceRequest\x12#\n" + + "\rprovider_name\x18\x01 \x01(\tR\fproviderName\x12\x19\n" + + "\bmodel_id\x18\x02 \x01(\tR\amodelId\x12\x1d\n" + + "\n" + + "route_name\x18\x03 \x01(\tR\trouteName\x12\x16\n" + + "\x06verify\x18\x04 \x01(\bR\x06verify\x12\x1b\n" + + "\tno_verify\x18\x05 \x01(\bR\bnoVerify\"A\n" + + "\x11ValidatedEndpoint\x12\x10\n" + + "\x03url\x18\x01 \x01(\tR\x03url\x12\x1a\n" + + "\bprotocol\x18\x02 \x01(\tR\bprotocol\"\xa5\x02\n" + + "\x1bSetClusterInferenceResponse\x12#\n" + + "\rprovider_name\x18\x01 \x01(\tR\fproviderName\x12\x19\n" + + "\bmodel_id\x18\x02 \x01(\tR\amodelId\x12\x18\n" + + "\aversion\x18\x03 \x01(\x04R\aversion\x12\x1d\n" + + "\n" + + "route_name\x18\x04 \x01(\tR\trouteName\x121\n" + + "\x14validation_performed\x18\x05 \x01(\bR\x13validationPerformed\x12Z\n" + + "\x13validated_endpoints\x18\x06 \x03(\v2).openshell.inference.v1.ValidatedEndpointR\x12validatedEndpoints\";\n" + + "\x1aGetClusterInferenceRequest\x12\x1d\n" + + "\n" + + "route_name\x18\x01 \x01(\tR\trouteName\"\x96\x01\n" + + "\x1bGetClusterInferenceResponse\x12#\n" + + "\rprovider_name\x18\x01 \x01(\tR\fproviderName\x12\x19\n" + + "\bmodel_id\x18\x02 \x01(\tR\amodelId\x12\x18\n" + + "\aversion\x18\x03 \x01(\x04R\aversion\x12\x1d\n" + + "\n" + + "route_name\x18\x04 \x01(\tR\trouteName\"\x1b\n" + + "\x19GetInferenceBundleRequest\"\xb5\x01\n" + + "\rResolvedRoute\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x19\n" + + "\bbase_url\x18\x02 \x01(\tR\abaseUrl\x12\x1c\n" + + "\tprotocols\x18\x03 \x03(\tR\tprotocols\x12\x17\n" + + "\aapi_key\x18\x04 \x01(\tR\x06apiKey\x12\x19\n" + + "\bmodel_id\x18\x05 \x01(\tR\amodelId\x12#\n" + + "\rprovider_type\x18\x06 \x01(\tR\fproviderType\"\x9f\x01\n" + + "\x1aGetInferenceBundleResponse\x12=\n" + + "\x06routes\x18\x01 \x03(\v2%.openshell.inference.v1.ResolvedRouteR\x06routes\x12\x1a\n" + + "\brevision\x18\x02 \x01(\tR\brevision\x12&\n" + + "\x0fgenerated_at_ms\x18\x03 \x01(\x03R\rgeneratedAtMs2\x88\x03\n" + + "\tInference\x12{\n" + + "\x12GetInferenceBundle\x121.openshell.inference.v1.GetInferenceBundleRequest\x1a2.openshell.inference.v1.GetInferenceBundleResponse\x12~\n" + + "\x13SetClusterInference\x122.openshell.inference.v1.SetClusterInferenceRequest\x1a3.openshell.inference.v1.SetClusterInferenceResponse\x12~\n" + + "\x13GetClusterInference\x122.openshell.inference.v1.GetClusterInferenceRequest\x1a3.openshell.inference.v1.GetClusterInferenceResponseB(\n" + + "$com.anthropic.openshell.inference.v1P\x01b\x06proto3" + +var ( + file_inference_proto_rawDescOnce sync.Once + file_inference_proto_rawDescData []byte +) + +func file_inference_proto_rawDescGZIP() []byte { + file_inference_proto_rawDescOnce.Do(func() { + file_inference_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_inference_proto_rawDesc), len(file_inference_proto_rawDesc))) + }) + return file_inference_proto_rawDescData +} + +var file_inference_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_inference_proto_goTypes = []any{ + (*ClusterInferenceConfig)(nil), // 0: openshell.inference.v1.ClusterInferenceConfig + (*InferenceRoute)(nil), // 1: openshell.inference.v1.InferenceRoute + (*SetClusterInferenceRequest)(nil), // 2: openshell.inference.v1.SetClusterInferenceRequest + (*ValidatedEndpoint)(nil), // 3: openshell.inference.v1.ValidatedEndpoint + (*SetClusterInferenceResponse)(nil), // 4: openshell.inference.v1.SetClusterInferenceResponse + (*GetClusterInferenceRequest)(nil), // 5: openshell.inference.v1.GetClusterInferenceRequest + (*GetClusterInferenceResponse)(nil), // 6: openshell.inference.v1.GetClusterInferenceResponse + (*GetInferenceBundleRequest)(nil), // 7: openshell.inference.v1.GetInferenceBundleRequest + (*ResolvedRoute)(nil), // 8: openshell.inference.v1.ResolvedRoute + (*GetInferenceBundleResponse)(nil), // 9: openshell.inference.v1.GetInferenceBundleResponse +} +var file_inference_proto_depIdxs = []int32{ + 0, // 0: openshell.inference.v1.InferenceRoute.config:type_name -> openshell.inference.v1.ClusterInferenceConfig + 3, // 1: openshell.inference.v1.SetClusterInferenceResponse.validated_endpoints:type_name -> openshell.inference.v1.ValidatedEndpoint + 8, // 2: openshell.inference.v1.GetInferenceBundleResponse.routes:type_name -> openshell.inference.v1.ResolvedRoute + 7, // 3: openshell.inference.v1.Inference.GetInferenceBundle:input_type -> openshell.inference.v1.GetInferenceBundleRequest + 2, // 4: openshell.inference.v1.Inference.SetClusterInference:input_type -> openshell.inference.v1.SetClusterInferenceRequest + 5, // 5: openshell.inference.v1.Inference.GetClusterInference:input_type -> openshell.inference.v1.GetClusterInferenceRequest + 9, // 6: openshell.inference.v1.Inference.GetInferenceBundle:output_type -> openshell.inference.v1.GetInferenceBundleResponse + 4, // 7: openshell.inference.v1.Inference.SetClusterInference:output_type -> openshell.inference.v1.SetClusterInferenceResponse + 6, // 8: openshell.inference.v1.Inference.GetClusterInference:output_type -> openshell.inference.v1.GetClusterInferenceResponse + 6, // [6:9] is the sub-list for method output_type + 3, // [3:6] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_inference_proto_init() } +func file_inference_proto_init() { + if File_inference_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_inference_proto_rawDesc), len(file_inference_proto_rawDesc)), + NumEnums: 0, + NumMessages: 10, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_inference_proto_goTypes, + DependencyIndexes: file_inference_proto_depIdxs, + MessageInfos: file_inference_proto_msgTypes, + }.Build() + File_inference_proto = out.File + file_inference_proto_goTypes = nil + file_inference_proto_depIdxs = nil +} diff --git a/internal/registry/platforms/openshell/proto/gen/inference_grpc.pb.go b/internal/registry/platforms/openshell/proto/gen/inference_grpc.pb.go new file mode 100644 index 00000000..5bb377ad --- /dev/null +++ b/internal/registry/platforms/openshell/proto/gen/inference_grpc.pb.go @@ -0,0 +1,214 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.6.1 +// - protoc v7.34.0 +// source: inference.proto + +package gen + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + Inference_GetInferenceBundle_FullMethodName = "/openshell.inference.v1.Inference/GetInferenceBundle" + Inference_SetClusterInference_FullMethodName = "/openshell.inference.v1.Inference/SetClusterInference" + Inference_GetClusterInference_FullMethodName = "/openshell.inference.v1.Inference/GetClusterInference" +) + +// InferenceClient is the client API for Inference service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Inference service provides cluster inference configuration and bundle delivery. +type InferenceClient interface { + // Return the resolved inference route bundle for sandbox-local execution. + GetInferenceBundle(ctx context.Context, in *GetInferenceBundleRequest, opts ...grpc.CallOption) (*GetInferenceBundleResponse, error) + // Set cluster-level inference configuration. + // + // This controls how requests sent to `inference.local` are routed. + SetClusterInference(ctx context.Context, in *SetClusterInferenceRequest, opts ...grpc.CallOption) (*SetClusterInferenceResponse, error) + // Get cluster-level inference configuration. + GetClusterInference(ctx context.Context, in *GetClusterInferenceRequest, opts ...grpc.CallOption) (*GetClusterInferenceResponse, error) +} + +type inferenceClient struct { + cc grpc.ClientConnInterface +} + +func NewInferenceClient(cc grpc.ClientConnInterface) InferenceClient { + return &inferenceClient{cc} +} + +func (c *inferenceClient) GetInferenceBundle(ctx context.Context, in *GetInferenceBundleRequest, opts ...grpc.CallOption) (*GetInferenceBundleResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetInferenceBundleResponse) + err := c.cc.Invoke(ctx, Inference_GetInferenceBundle_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *inferenceClient) SetClusterInference(ctx context.Context, in *SetClusterInferenceRequest, opts ...grpc.CallOption) (*SetClusterInferenceResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SetClusterInferenceResponse) + err := c.cc.Invoke(ctx, Inference_SetClusterInference_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *inferenceClient) GetClusterInference(ctx context.Context, in *GetClusterInferenceRequest, opts ...grpc.CallOption) (*GetClusterInferenceResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetClusterInferenceResponse) + err := c.cc.Invoke(ctx, Inference_GetClusterInference_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// InferenceServer is the server API for Inference service. +// All implementations must embed UnimplementedInferenceServer +// for forward compatibility. +// +// Inference service provides cluster inference configuration and bundle delivery. +type InferenceServer interface { + // Return the resolved inference route bundle for sandbox-local execution. + GetInferenceBundle(context.Context, *GetInferenceBundleRequest) (*GetInferenceBundleResponse, error) + // Set cluster-level inference configuration. + // + // This controls how requests sent to `inference.local` are routed. + SetClusterInference(context.Context, *SetClusterInferenceRequest) (*SetClusterInferenceResponse, error) + // Get cluster-level inference configuration. + GetClusterInference(context.Context, *GetClusterInferenceRequest) (*GetClusterInferenceResponse, error) + mustEmbedUnimplementedInferenceServer() +} + +// UnimplementedInferenceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedInferenceServer struct{} + +func (UnimplementedInferenceServer) GetInferenceBundle(context.Context, *GetInferenceBundleRequest) (*GetInferenceBundleResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetInferenceBundle not implemented") +} +func (UnimplementedInferenceServer) SetClusterInference(context.Context, *SetClusterInferenceRequest) (*SetClusterInferenceResponse, error) { + return nil, status.Error(codes.Unimplemented, "method SetClusterInference not implemented") +} +func (UnimplementedInferenceServer) GetClusterInference(context.Context, *GetClusterInferenceRequest) (*GetClusterInferenceResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetClusterInference not implemented") +} +func (UnimplementedInferenceServer) mustEmbedUnimplementedInferenceServer() {} +func (UnimplementedInferenceServer) testEmbeddedByValue() {} + +// UnsafeInferenceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to InferenceServer will +// result in compilation errors. +type UnsafeInferenceServer interface { + mustEmbedUnimplementedInferenceServer() +} + +func RegisterInferenceServer(s grpc.ServiceRegistrar, srv InferenceServer) { + // If the following call panics, it indicates UnimplementedInferenceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&Inference_ServiceDesc, srv) +} + +func _Inference_GetInferenceBundle_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetInferenceBundleRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(InferenceServer).GetInferenceBundle(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Inference_GetInferenceBundle_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(InferenceServer).GetInferenceBundle(ctx, req.(*GetInferenceBundleRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Inference_SetClusterInference_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetClusterInferenceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(InferenceServer).SetClusterInference(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Inference_SetClusterInference_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(InferenceServer).SetClusterInference(ctx, req.(*SetClusterInferenceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Inference_GetClusterInference_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetClusterInferenceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(InferenceServer).GetClusterInference(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Inference_GetClusterInference_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(InferenceServer).GetClusterInference(ctx, req.(*GetClusterInferenceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Inference_ServiceDesc is the grpc.ServiceDesc for Inference service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Inference_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "openshell.inference.v1.Inference", + HandlerType: (*InferenceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetInferenceBundle", + Handler: _Inference_GetInferenceBundle_Handler, + }, + { + MethodName: "SetClusterInference", + Handler: _Inference_SetClusterInference_Handler, + }, + { + MethodName: "GetClusterInference", + Handler: _Inference_GetClusterInference_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "inference.proto", +} diff --git a/internal/registry/platforms/openshell/proto/gen/openshell.pb.go b/internal/registry/platforms/openshell/proto/gen/openshell.pb.go new file mode 100644 index 00000000..3ca06031 --- /dev/null +++ b/internal/registry/platforms/openshell/proto/gen/openshell.pb.go @@ -0,0 +1,5149 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v7.34.0 +// source: openshell.proto + +package gen + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Policy load status. +type PolicyStatus int32 + +const ( + PolicyStatus_POLICY_STATUS_UNSPECIFIED PolicyStatus = 0 + // Server received the update; sandbox has not yet loaded it. + PolicyStatus_POLICY_STATUS_PENDING PolicyStatus = 1 + // Sandbox successfully applied this policy version. + PolicyStatus_POLICY_STATUS_LOADED PolicyStatus = 2 + // Sandbox attempted to apply but failed; LKG policy remains active. + PolicyStatus_POLICY_STATUS_FAILED PolicyStatus = 3 + // A newer version was persisted before the sandbox loaded this one. + PolicyStatus_POLICY_STATUS_SUPERSEDED PolicyStatus = 4 +) + +// Enum value maps for PolicyStatus. +var ( + PolicyStatus_name = map[int32]string{ + 0: "POLICY_STATUS_UNSPECIFIED", + 1: "POLICY_STATUS_PENDING", + 2: "POLICY_STATUS_LOADED", + 3: "POLICY_STATUS_FAILED", + 4: "POLICY_STATUS_SUPERSEDED", + } + PolicyStatus_value = map[string]int32{ + "POLICY_STATUS_UNSPECIFIED": 0, + "POLICY_STATUS_PENDING": 1, + "POLICY_STATUS_LOADED": 2, + "POLICY_STATUS_FAILED": 3, + "POLICY_STATUS_SUPERSEDED": 4, + } +) + +func (x PolicyStatus) Enum() *PolicyStatus { + p := new(PolicyStatus) + *p = x + return p +} + +func (x PolicyStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (PolicyStatus) Descriptor() protoreflect.EnumDescriptor { + return file_openshell_proto_enumTypes[0].Descriptor() +} + +func (PolicyStatus) Type() protoreflect.EnumType { + return &file_openshell_proto_enumTypes[0] +} + +func (x PolicyStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use PolicyStatus.Descriptor instead. +func (PolicyStatus) EnumDescriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{0} +} + +// Service status enum. +type ServiceStatus int32 + +const ( + ServiceStatus_SERVICE_STATUS_UNSPECIFIED ServiceStatus = 0 + ServiceStatus_SERVICE_STATUS_HEALTHY ServiceStatus = 1 + ServiceStatus_SERVICE_STATUS_DEGRADED ServiceStatus = 2 + ServiceStatus_SERVICE_STATUS_UNHEALTHY ServiceStatus = 3 +) + +// Enum value maps for ServiceStatus. +var ( + ServiceStatus_name = map[int32]string{ + 0: "SERVICE_STATUS_UNSPECIFIED", + 1: "SERVICE_STATUS_HEALTHY", + 2: "SERVICE_STATUS_DEGRADED", + 3: "SERVICE_STATUS_UNHEALTHY", + } + ServiceStatus_value = map[string]int32{ + "SERVICE_STATUS_UNSPECIFIED": 0, + "SERVICE_STATUS_HEALTHY": 1, + "SERVICE_STATUS_DEGRADED": 2, + "SERVICE_STATUS_UNHEALTHY": 3, + } +) + +func (x ServiceStatus) Enum() *ServiceStatus { + p := new(ServiceStatus) + *p = x + return p +} + +func (x ServiceStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ServiceStatus) Descriptor() protoreflect.EnumDescriptor { + return file_openshell_proto_enumTypes[1].Descriptor() +} + +func (ServiceStatus) Type() protoreflect.EnumType { + return &file_openshell_proto_enumTypes[1] +} + +func (x ServiceStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ServiceStatus.Descriptor instead. +func (ServiceStatus) EnumDescriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{1} +} + +// Health check request. +type HealthRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HealthRequest) Reset() { + *x = HealthRequest{} + mi := &file_openshell_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HealthRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HealthRequest) ProtoMessage() {} + +func (x *HealthRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HealthRequest.ProtoReflect.Descriptor instead. +func (*HealthRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{0} +} + +// Health check response. +type HealthResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Service status. + Status ServiceStatus `protobuf:"varint,1,opt,name=status,proto3,enum=openshell.v1.ServiceStatus" json:"status,omitempty"` + // Service version. + Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HealthResponse) Reset() { + *x = HealthResponse{} + mi := &file_openshell_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HealthResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HealthResponse) ProtoMessage() {} + +func (x *HealthResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HealthResponse.ProtoReflect.Descriptor instead. +func (*HealthResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{1} +} + +func (x *HealthResponse) GetStatus() ServiceStatus { + if x != nil { + return x.Status + } + return ServiceStatus_SERVICE_STATUS_UNSPECIFIED +} + +func (x *HealthResponse) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +// Create sandbox request. +type CreateSandboxRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Spec *SandboxSpec `protobuf:"bytes,1,opt,name=spec,proto3" json:"spec,omitempty"` + // Optional user-supplied sandbox name. When empty the server generates one. + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateSandboxRequest) Reset() { + *x = CreateSandboxRequest{} + mi := &file_openshell_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateSandboxRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateSandboxRequest) ProtoMessage() {} + +func (x *CreateSandboxRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateSandboxRequest.ProtoReflect.Descriptor instead. +func (*CreateSandboxRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{2} +} + +func (x *CreateSandboxRequest) GetSpec() *SandboxSpec { + if x != nil { + return x.Spec + } + return nil +} + +func (x *CreateSandboxRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +// Get sandbox request. +type GetSandboxRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox name (canonical lookup key). + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetSandboxRequest) Reset() { + *x = GetSandboxRequest{} + mi := &file_openshell_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetSandboxRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSandboxRequest) ProtoMessage() {} + +func (x *GetSandboxRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSandboxRequest.ProtoReflect.Descriptor instead. +func (*GetSandboxRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{3} +} + +func (x *GetSandboxRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +// List sandboxes request. +type ListSandboxesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Limit uint32 `protobuf:"varint,1,opt,name=limit,proto3" json:"limit,omitempty"` + Offset uint32 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListSandboxesRequest) Reset() { + *x = ListSandboxesRequest{} + mi := &file_openshell_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListSandboxesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListSandboxesRequest) ProtoMessage() {} + +func (x *ListSandboxesRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListSandboxesRequest.ProtoReflect.Descriptor instead. +func (*ListSandboxesRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{4} +} + +func (x *ListSandboxesRequest) GetLimit() uint32 { + if x != nil { + return x.Limit + } + return 0 +} + +func (x *ListSandboxesRequest) GetOffset() uint32 { + if x != nil { + return x.Offset + } + return 0 +} + +// Delete sandbox request. +type DeleteSandboxRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox name (canonical lookup key). + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteSandboxRequest) Reset() { + *x = DeleteSandboxRequest{} + mi := &file_openshell_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteSandboxRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSandboxRequest) ProtoMessage() {} + +func (x *DeleteSandboxRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSandboxRequest.ProtoReflect.Descriptor instead. +func (*DeleteSandboxRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{5} +} + +func (x *DeleteSandboxRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +// Sandbox response. +type SandboxResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Sandbox *Sandbox `protobuf:"bytes,1,opt,name=sandbox,proto3" json:"sandbox,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxResponse) Reset() { + *x = SandboxResponse{} + mi := &file_openshell_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxResponse) ProtoMessage() {} + +func (x *SandboxResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SandboxResponse.ProtoReflect.Descriptor instead. +func (*SandboxResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{6} +} + +func (x *SandboxResponse) GetSandbox() *Sandbox { + if x != nil { + return x.Sandbox + } + return nil +} + +// List sandboxes response. +type ListSandboxesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Sandboxes []*Sandbox `protobuf:"bytes,1,rep,name=sandboxes,proto3" json:"sandboxes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListSandboxesResponse) Reset() { + *x = ListSandboxesResponse{} + mi := &file_openshell_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListSandboxesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListSandboxesResponse) ProtoMessage() {} + +func (x *ListSandboxesResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListSandboxesResponse.ProtoReflect.Descriptor instead. +func (*ListSandboxesResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{7} +} + +func (x *ListSandboxesResponse) GetSandboxes() []*Sandbox { + if x != nil { + return x.Sandboxes + } + return nil +} + +// Delete sandbox response. +type DeleteSandboxResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Deleted bool `protobuf:"varint,1,opt,name=deleted,proto3" json:"deleted,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteSandboxResponse) Reset() { + *x = DeleteSandboxResponse{} + mi := &file_openshell_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteSandboxResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSandboxResponse) ProtoMessage() {} + +func (x *DeleteSandboxResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSandboxResponse.ProtoReflect.Descriptor instead. +func (*DeleteSandboxResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{8} +} + +func (x *DeleteSandboxResponse) GetDeleted() bool { + if x != nil { + return x.Deleted + } + return false +} + +// Create SSH session request. +type CreateSshSessionRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox id. + SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateSshSessionRequest) Reset() { + *x = CreateSshSessionRequest{} + mi := &file_openshell_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateSshSessionRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateSshSessionRequest) ProtoMessage() {} + +func (x *CreateSshSessionRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateSshSessionRequest.ProtoReflect.Descriptor instead. +func (*CreateSshSessionRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{9} +} + +func (x *CreateSshSessionRequest) GetSandboxId() string { + if x != nil { + return x.SandboxId + } + return "" +} + +// Create SSH session response. +type CreateSshSessionResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox id. + SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` + // Session token for the gateway tunnel. + Token string `protobuf:"bytes,2,opt,name=token,proto3" json:"token,omitempty"` + // Gateway host for SSH proxy connection. + GatewayHost string `protobuf:"bytes,3,opt,name=gateway_host,json=gatewayHost,proto3" json:"gateway_host,omitempty"` + // Gateway port for SSH proxy connection. + GatewayPort uint32 `protobuf:"varint,4,opt,name=gateway_port,json=gatewayPort,proto3" json:"gateway_port,omitempty"` + // Gateway scheme (http or https). + GatewayScheme string `protobuf:"bytes,5,opt,name=gateway_scheme,json=gatewayScheme,proto3" json:"gateway_scheme,omitempty"` + // HTTP path for the CONNECT/upgrade endpoint. + ConnectPath string `protobuf:"bytes,6,opt,name=connect_path,json=connectPath,proto3" json:"connect_path,omitempty"` + // Optional host key fingerprint. + HostKeyFingerprint string `protobuf:"bytes,7,opt,name=host_key_fingerprint,json=hostKeyFingerprint,proto3" json:"host_key_fingerprint,omitempty"` + // Expiry timestamp in milliseconds since epoch. 0 means no expiry. + ExpiresAtMs int64 `protobuf:"varint,8,opt,name=expires_at_ms,json=expiresAtMs,proto3" json:"expires_at_ms,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateSshSessionResponse) Reset() { + *x = CreateSshSessionResponse{} + mi := &file_openshell_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateSshSessionResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateSshSessionResponse) ProtoMessage() {} + +func (x *CreateSshSessionResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateSshSessionResponse.ProtoReflect.Descriptor instead. +func (*CreateSshSessionResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{10} +} + +func (x *CreateSshSessionResponse) GetSandboxId() string { + if x != nil { + return x.SandboxId + } + return "" +} + +func (x *CreateSshSessionResponse) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +func (x *CreateSshSessionResponse) GetGatewayHost() string { + if x != nil { + return x.GatewayHost + } + return "" +} + +func (x *CreateSshSessionResponse) GetGatewayPort() uint32 { + if x != nil { + return x.GatewayPort + } + return 0 +} + +func (x *CreateSshSessionResponse) GetGatewayScheme() string { + if x != nil { + return x.GatewayScheme + } + return "" +} + +func (x *CreateSshSessionResponse) GetConnectPath() string { + if x != nil { + return x.ConnectPath + } + return "" +} + +func (x *CreateSshSessionResponse) GetHostKeyFingerprint() string { + if x != nil { + return x.HostKeyFingerprint + } + return "" +} + +func (x *CreateSshSessionResponse) GetExpiresAtMs() int64 { + if x != nil { + return x.ExpiresAtMs + } + return 0 +} + +// Revoke SSH session request. +type RevokeSshSessionRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Session token to revoke. + Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RevokeSshSessionRequest) Reset() { + *x = RevokeSshSessionRequest{} + mi := &file_openshell_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RevokeSshSessionRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RevokeSshSessionRequest) ProtoMessage() {} + +func (x *RevokeSshSessionRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RevokeSshSessionRequest.ProtoReflect.Descriptor instead. +func (*RevokeSshSessionRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{11} +} + +func (x *RevokeSshSessionRequest) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +// Revoke SSH session response. +type RevokeSshSessionResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // True when a session was revoked. + Revoked bool `protobuf:"varint,1,opt,name=revoked,proto3" json:"revoked,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RevokeSshSessionResponse) Reset() { + *x = RevokeSshSessionResponse{} + mi := &file_openshell_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RevokeSshSessionResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RevokeSshSessionResponse) ProtoMessage() {} + +func (x *RevokeSshSessionResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RevokeSshSessionResponse.ProtoReflect.Descriptor instead. +func (*RevokeSshSessionResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{12} +} + +func (x *RevokeSshSessionResponse) GetRevoked() bool { + if x != nil { + return x.Revoked + } + return false +} + +// Execute command request. +type ExecSandboxRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox id. + SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` + // Command and arguments. + Command []string `protobuf:"bytes,2,rep,name=command,proto3" json:"command,omitempty"` + // Optional working directory. + Workdir string `protobuf:"bytes,3,opt,name=workdir,proto3" json:"workdir,omitempty"` + // Optional environment overrides. + Environment map[string]string `protobuf:"bytes,4,rep,name=environment,proto3" json:"environment,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // Optional timeout in seconds. 0 means no timeout. + TimeoutSeconds uint32 `protobuf:"varint,5,opt,name=timeout_seconds,json=timeoutSeconds,proto3" json:"timeout_seconds,omitempty"` + // Optional stdin payload passed to the command. + Stdin []byte `protobuf:"bytes,6,opt,name=stdin,proto3" json:"stdin,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExecSandboxRequest) Reset() { + *x = ExecSandboxRequest{} + mi := &file_openshell_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExecSandboxRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecSandboxRequest) ProtoMessage() {} + +func (x *ExecSandboxRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecSandboxRequest.ProtoReflect.Descriptor instead. +func (*ExecSandboxRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{13} +} + +func (x *ExecSandboxRequest) GetSandboxId() string { + if x != nil { + return x.SandboxId + } + return "" +} + +func (x *ExecSandboxRequest) GetCommand() []string { + if x != nil { + return x.Command + } + return nil +} + +func (x *ExecSandboxRequest) GetWorkdir() string { + if x != nil { + return x.Workdir + } + return "" +} + +func (x *ExecSandboxRequest) GetEnvironment() map[string]string { + if x != nil { + return x.Environment + } + return nil +} + +func (x *ExecSandboxRequest) GetTimeoutSeconds() uint32 { + if x != nil { + return x.TimeoutSeconds + } + return 0 +} + +func (x *ExecSandboxRequest) GetStdin() []byte { + if x != nil { + return x.Stdin + } + return nil +} + +// One stdout chunk from a sandbox exec. +type ExecSandboxStdout struct { + state protoimpl.MessageState `protogen:"open.v1"` + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExecSandboxStdout) Reset() { + *x = ExecSandboxStdout{} + mi := &file_openshell_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExecSandboxStdout) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecSandboxStdout) ProtoMessage() {} + +func (x *ExecSandboxStdout) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecSandboxStdout.ProtoReflect.Descriptor instead. +func (*ExecSandboxStdout) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{14} +} + +func (x *ExecSandboxStdout) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + +// One stderr chunk from a sandbox exec. +type ExecSandboxStderr struct { + state protoimpl.MessageState `protogen:"open.v1"` + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExecSandboxStderr) Reset() { + *x = ExecSandboxStderr{} + mi := &file_openshell_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExecSandboxStderr) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecSandboxStderr) ProtoMessage() {} + +func (x *ExecSandboxStderr) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecSandboxStderr.ProtoReflect.Descriptor instead. +func (*ExecSandboxStderr) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{15} +} + +func (x *ExecSandboxStderr) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + +// Final exit status for a sandbox exec. +type ExecSandboxExit struct { + state protoimpl.MessageState `protogen:"open.v1"` + ExitCode int32 `protobuf:"varint,1,opt,name=exit_code,json=exitCode,proto3" json:"exit_code,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExecSandboxExit) Reset() { + *x = ExecSandboxExit{} + mi := &file_openshell_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExecSandboxExit) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecSandboxExit) ProtoMessage() {} + +func (x *ExecSandboxExit) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecSandboxExit.ProtoReflect.Descriptor instead. +func (*ExecSandboxExit) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{16} +} + +func (x *ExecSandboxExit) GetExitCode() int32 { + if x != nil { + return x.ExitCode + } + return 0 +} + +// One event in a sandbox exec stream. +type ExecSandboxEvent struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Payload: + // + // *ExecSandboxEvent_Stdout + // *ExecSandboxEvent_Stderr + // *ExecSandboxEvent_Exit + Payload isExecSandboxEvent_Payload `protobuf_oneof:"payload"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExecSandboxEvent) Reset() { + *x = ExecSandboxEvent{} + mi := &file_openshell_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExecSandboxEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecSandboxEvent) ProtoMessage() {} + +func (x *ExecSandboxEvent) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecSandboxEvent.ProtoReflect.Descriptor instead. +func (*ExecSandboxEvent) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{17} +} + +func (x *ExecSandboxEvent) GetPayload() isExecSandboxEvent_Payload { + if x != nil { + return x.Payload + } + return nil +} + +func (x *ExecSandboxEvent) GetStdout() *ExecSandboxStdout { + if x != nil { + if x, ok := x.Payload.(*ExecSandboxEvent_Stdout); ok { + return x.Stdout + } + } + return nil +} + +func (x *ExecSandboxEvent) GetStderr() *ExecSandboxStderr { + if x != nil { + if x, ok := x.Payload.(*ExecSandboxEvent_Stderr); ok { + return x.Stderr + } + } + return nil +} + +func (x *ExecSandboxEvent) GetExit() *ExecSandboxExit { + if x != nil { + if x, ok := x.Payload.(*ExecSandboxEvent_Exit); ok { + return x.Exit + } + } + return nil +} + +type isExecSandboxEvent_Payload interface { + isExecSandboxEvent_Payload() +} + +type ExecSandboxEvent_Stdout struct { + Stdout *ExecSandboxStdout `protobuf:"bytes,1,opt,name=stdout,proto3,oneof"` +} + +type ExecSandboxEvent_Stderr struct { + Stderr *ExecSandboxStderr `protobuf:"bytes,2,opt,name=stderr,proto3,oneof"` +} + +type ExecSandboxEvent_Exit struct { + Exit *ExecSandboxExit `protobuf:"bytes,3,opt,name=exit,proto3,oneof"` +} + +func (*ExecSandboxEvent_Stdout) isExecSandboxEvent_Payload() {} + +func (*ExecSandboxEvent_Stderr) isExecSandboxEvent_Payload() {} + +func (*ExecSandboxEvent_Exit) isExecSandboxEvent_Payload() {} + +// SSH session record stored in persistence. +type SshSession struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Unique id (token). + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // Sandbox id. + SandboxId string `protobuf:"bytes,2,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` + // Session token. + Token string `protobuf:"bytes,3,opt,name=token,proto3" json:"token,omitempty"` + // Creation timestamp in milliseconds since epoch. + CreatedAtMs int64 `protobuf:"varint,4,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` + // Revoked flag. + Revoked bool `protobuf:"varint,5,opt,name=revoked,proto3" json:"revoked,omitempty"` + // Human-friendly name (auto-generated if not provided). + Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"` + // Expiry timestamp in milliseconds since epoch. 0 means no expiry + // (backward-compatible default for sessions created before this field existed). + ExpiresAtMs int64 `protobuf:"varint,7,opt,name=expires_at_ms,json=expiresAtMs,proto3" json:"expires_at_ms,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SshSession) Reset() { + *x = SshSession{} + mi := &file_openshell_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SshSession) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SshSession) ProtoMessage() {} + +func (x *SshSession) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SshSession.ProtoReflect.Descriptor instead. +func (*SshSession) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{18} +} + +func (x *SshSession) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *SshSession) GetSandboxId() string { + if x != nil { + return x.SandboxId + } + return "" +} + +func (x *SshSession) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +func (x *SshSession) GetCreatedAtMs() int64 { + if x != nil { + return x.CreatedAtMs + } + return 0 +} + +func (x *SshSession) GetRevoked() bool { + if x != nil { + return x.Revoked + } + return false +} + +func (x *SshSession) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *SshSession) GetExpiresAtMs() int64 { + if x != nil { + return x.ExpiresAtMs + } + return 0 +} + +// Watch sandbox request. +type WatchSandboxRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox id. + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // Stream sandbox status snapshots. + FollowStatus bool `protobuf:"varint,2,opt,name=follow_status,json=followStatus,proto3" json:"follow_status,omitempty"` + // Stream openshell-server process logs correlated to this sandbox. + FollowLogs bool `protobuf:"varint,3,opt,name=follow_logs,json=followLogs,proto3" json:"follow_logs,omitempty"` + // Stream platform events correlated to this sandbox. + FollowEvents bool `protobuf:"varint,4,opt,name=follow_events,json=followEvents,proto3" json:"follow_events,omitempty"` + // Replay the last N log lines (best-effort) before following. + LogTailLines uint32 `protobuf:"varint,5,opt,name=log_tail_lines,json=logTailLines,proto3" json:"log_tail_lines,omitempty"` + // Replay the last N platform events (best-effort) before following. + EventTail uint32 `protobuf:"varint,6,opt,name=event_tail,json=eventTail,proto3" json:"event_tail,omitempty"` + // Stop streaming once the sandbox reaches a terminal phase (READY or ERROR). + StopOnTerminal bool `protobuf:"varint,7,opt,name=stop_on_terminal,json=stopOnTerminal,proto3" json:"stop_on_terminal,omitempty"` + // Only include log lines with timestamp >= this value (milliseconds since epoch). + // 0 means no time filter. Applies to both tail replay and live streaming. + LogSinceMs int64 `protobuf:"varint,8,opt,name=log_since_ms,json=logSinceMs,proto3" json:"log_since_ms,omitempty"` + // Filter by log source (e.g. "gateway", "sandbox"). Empty means all sources. + LogSources []string `protobuf:"bytes,9,rep,name=log_sources,json=logSources,proto3" json:"log_sources,omitempty"` + // Minimum log level to include (e.g. "INFO", "WARN", "ERROR"). Empty means all levels. + LogMinLevel string `protobuf:"bytes,10,opt,name=log_min_level,json=logMinLevel,proto3" json:"log_min_level,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *WatchSandboxRequest) Reset() { + *x = WatchSandboxRequest{} + mi := &file_openshell_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WatchSandboxRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WatchSandboxRequest) ProtoMessage() {} + +func (x *WatchSandboxRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WatchSandboxRequest.ProtoReflect.Descriptor instead. +func (*WatchSandboxRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{19} +} + +func (x *WatchSandboxRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *WatchSandboxRequest) GetFollowStatus() bool { + if x != nil { + return x.FollowStatus + } + return false +} + +func (x *WatchSandboxRequest) GetFollowLogs() bool { + if x != nil { + return x.FollowLogs + } + return false +} + +func (x *WatchSandboxRequest) GetFollowEvents() bool { + if x != nil { + return x.FollowEvents + } + return false +} + +func (x *WatchSandboxRequest) GetLogTailLines() uint32 { + if x != nil { + return x.LogTailLines + } + return 0 +} + +func (x *WatchSandboxRequest) GetEventTail() uint32 { + if x != nil { + return x.EventTail + } + return 0 +} + +func (x *WatchSandboxRequest) GetStopOnTerminal() bool { + if x != nil { + return x.StopOnTerminal + } + return false +} + +func (x *WatchSandboxRequest) GetLogSinceMs() int64 { + if x != nil { + return x.LogSinceMs + } + return 0 +} + +func (x *WatchSandboxRequest) GetLogSources() []string { + if x != nil { + return x.LogSources + } + return nil +} + +func (x *WatchSandboxRequest) GetLogMinLevel() string { + if x != nil { + return x.LogMinLevel + } + return "" +} + +// One event in a sandbox watch stream. +type SandboxStreamEvent struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Payload: + // + // *SandboxStreamEvent_Sandbox + // *SandboxStreamEvent_Log + // *SandboxStreamEvent_Event + // *SandboxStreamEvent_Warning + // *SandboxStreamEvent_DraftPolicyUpdate + Payload isSandboxStreamEvent_Payload `protobuf_oneof:"payload"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxStreamEvent) Reset() { + *x = SandboxStreamEvent{} + mi := &file_openshell_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxStreamEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxStreamEvent) ProtoMessage() {} + +func (x *SandboxStreamEvent) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[20] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SandboxStreamEvent.ProtoReflect.Descriptor instead. +func (*SandboxStreamEvent) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{20} +} + +func (x *SandboxStreamEvent) GetPayload() isSandboxStreamEvent_Payload { + if x != nil { + return x.Payload + } + return nil +} + +func (x *SandboxStreamEvent) GetSandbox() *Sandbox { + if x != nil { + if x, ok := x.Payload.(*SandboxStreamEvent_Sandbox); ok { + return x.Sandbox + } + } + return nil +} + +func (x *SandboxStreamEvent) GetLog() *SandboxLogLine { + if x != nil { + if x, ok := x.Payload.(*SandboxStreamEvent_Log); ok { + return x.Log + } + } + return nil +} + +func (x *SandboxStreamEvent) GetEvent() *PlatformEvent { + if x != nil { + if x, ok := x.Payload.(*SandboxStreamEvent_Event); ok { + return x.Event + } + } + return nil +} + +func (x *SandboxStreamEvent) GetWarning() *SandboxStreamWarning { + if x != nil { + if x, ok := x.Payload.(*SandboxStreamEvent_Warning); ok { + return x.Warning + } + } + return nil +} + +func (x *SandboxStreamEvent) GetDraftPolicyUpdate() *DraftPolicyUpdate { + if x != nil { + if x, ok := x.Payload.(*SandboxStreamEvent_DraftPolicyUpdate); ok { + return x.DraftPolicyUpdate + } + } + return nil +} + +type isSandboxStreamEvent_Payload interface { + isSandboxStreamEvent_Payload() +} + +type SandboxStreamEvent_Sandbox struct { + // Latest sandbox snapshot. + Sandbox *Sandbox `protobuf:"bytes,1,opt,name=sandbox,proto3,oneof"` +} + +type SandboxStreamEvent_Log struct { + // One server log line/event. + Log *SandboxLogLine `protobuf:"bytes,2,opt,name=log,proto3,oneof"` +} + +type SandboxStreamEvent_Event struct { + // One platform event. + Event *PlatformEvent `protobuf:"bytes,3,opt,name=event,proto3,oneof"` +} + +type SandboxStreamEvent_Warning struct { + // Warning from the server (e.g. missed messages due to lag). + Warning *SandboxStreamWarning `protobuf:"bytes,4,opt,name=warning,proto3,oneof"` +} + +type SandboxStreamEvent_DraftPolicyUpdate struct { + // Draft policy update notification. + DraftPolicyUpdate *DraftPolicyUpdate `protobuf:"bytes,5,opt,name=draft_policy_update,json=draftPolicyUpdate,proto3,oneof"` +} + +func (*SandboxStreamEvent_Sandbox) isSandboxStreamEvent_Payload() {} + +func (*SandboxStreamEvent_Log) isSandboxStreamEvent_Payload() {} + +func (*SandboxStreamEvent_Event) isSandboxStreamEvent_Payload() {} + +func (*SandboxStreamEvent_Warning) isSandboxStreamEvent_Payload() {} + +func (*SandboxStreamEvent_DraftPolicyUpdate) isSandboxStreamEvent_Payload() {} + +// Log line correlated to a sandbox. +type SandboxLogLine struct { + state protoimpl.MessageState `protogen:"open.v1"` + SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` + TimestampMs int64 `protobuf:"varint,2,opt,name=timestamp_ms,json=timestampMs,proto3" json:"timestamp_ms,omitempty"` + Level string `protobuf:"bytes,3,opt,name=level,proto3" json:"level,omitempty"` + Target string `protobuf:"bytes,4,opt,name=target,proto3" json:"target,omitempty"` + Message string `protobuf:"bytes,5,opt,name=message,proto3" json:"message,omitempty"` + // Log source: "gateway" (server-side) or "sandbox" (supervisor). + // Empty is treated as "gateway" for backward compatibility. + Source string `protobuf:"bytes,6,opt,name=source,proto3" json:"source,omitempty"` + // Structured key-value fields from the tracing event (e.g. dst_host, action). + Fields map[string]string `protobuf:"bytes,7,rep,name=fields,proto3" json:"fields,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxLogLine) Reset() { + *x = SandboxLogLine{} + mi := &file_openshell_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxLogLine) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxLogLine) ProtoMessage() {} + +func (x *SandboxLogLine) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SandboxLogLine.ProtoReflect.Descriptor instead. +func (*SandboxLogLine) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{21} +} + +func (x *SandboxLogLine) GetSandboxId() string { + if x != nil { + return x.SandboxId + } + return "" +} + +func (x *SandboxLogLine) GetTimestampMs() int64 { + if x != nil { + return x.TimestampMs + } + return 0 +} + +func (x *SandboxLogLine) GetLevel() string { + if x != nil { + return x.Level + } + return "" +} + +func (x *SandboxLogLine) GetTarget() string { + if x != nil { + return x.Target + } + return "" +} + +func (x *SandboxLogLine) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *SandboxLogLine) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +func (x *SandboxLogLine) GetFields() map[string]string { + if x != nil { + return x.Fields + } + return nil +} + +// Platform event correlated to a sandbox. +type PlatformEvent struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Event timestamp in milliseconds since epoch. + TimestampMs int64 `protobuf:"varint,1,opt,name=timestamp_ms,json=timestampMs,proto3" json:"timestamp_ms,omitempty"` + // Event source (e.g. "kubernetes", "docker", "process"). + Source string `protobuf:"bytes,2,opt,name=source,proto3" json:"source,omitempty"` + // Event type/severity (e.g. "Normal", "Warning"). + Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` + // Short reason code (e.g. "Started", "Pulled", "Failed"). + Reason string `protobuf:"bytes,4,opt,name=reason,proto3" json:"reason,omitempty"` + // Human-readable event message. + Message string `protobuf:"bytes,5,opt,name=message,proto3" json:"message,omitempty"` + // Optional metadata as key-value pairs. + Metadata map[string]string `protobuf:"bytes,6,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PlatformEvent) Reset() { + *x = PlatformEvent{} + mi := &file_openshell_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PlatformEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PlatformEvent) ProtoMessage() {} + +func (x *PlatformEvent) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[22] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PlatformEvent.ProtoReflect.Descriptor instead. +func (*PlatformEvent) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{22} +} + +func (x *PlatformEvent) GetTimestampMs() int64 { + if x != nil { + return x.TimestampMs + } + return 0 +} + +func (x *PlatformEvent) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +func (x *PlatformEvent) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *PlatformEvent) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +func (x *PlatformEvent) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *PlatformEvent) GetMetadata() map[string]string { + if x != nil { + return x.Metadata + } + return nil +} + +type SandboxStreamWarning struct { + state protoimpl.MessageState `protogen:"open.v1"` + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxStreamWarning) Reset() { + *x = SandboxStreamWarning{} + mi := &file_openshell_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxStreamWarning) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxStreamWarning) ProtoMessage() {} + +func (x *SandboxStreamWarning) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[23] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SandboxStreamWarning.ProtoReflect.Descriptor instead. +func (*SandboxStreamWarning) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{23} +} + +func (x *SandboxStreamWarning) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +// Create provider request. +type CreateProviderRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Provider *Provider `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateProviderRequest) Reset() { + *x = CreateProviderRequest{} + mi := &file_openshell_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateProviderRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateProviderRequest) ProtoMessage() {} + +func (x *CreateProviderRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[24] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateProviderRequest.ProtoReflect.Descriptor instead. +func (*CreateProviderRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{24} +} + +func (x *CreateProviderRequest) GetProvider() *Provider { + if x != nil { + return x.Provider + } + return nil +} + +// Get provider request. +type GetProviderRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetProviderRequest) Reset() { + *x = GetProviderRequest{} + mi := &file_openshell_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetProviderRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetProviderRequest) ProtoMessage() {} + +func (x *GetProviderRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[25] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetProviderRequest.ProtoReflect.Descriptor instead. +func (*GetProviderRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{25} +} + +func (x *GetProviderRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +// List providers request. +type ListProvidersRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Limit uint32 `protobuf:"varint,1,opt,name=limit,proto3" json:"limit,omitempty"` + Offset uint32 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListProvidersRequest) Reset() { + *x = ListProvidersRequest{} + mi := &file_openshell_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListProvidersRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListProvidersRequest) ProtoMessage() {} + +func (x *ListProvidersRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[26] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListProvidersRequest.ProtoReflect.Descriptor instead. +func (*ListProvidersRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{26} +} + +func (x *ListProvidersRequest) GetLimit() uint32 { + if x != nil { + return x.Limit + } + return 0 +} + +func (x *ListProvidersRequest) GetOffset() uint32 { + if x != nil { + return x.Offset + } + return 0 +} + +// Update provider request. +type UpdateProviderRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Provider *Provider `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateProviderRequest) Reset() { + *x = UpdateProviderRequest{} + mi := &file_openshell_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateProviderRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateProviderRequest) ProtoMessage() {} + +func (x *UpdateProviderRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[27] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateProviderRequest.ProtoReflect.Descriptor instead. +func (*UpdateProviderRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{27} +} + +func (x *UpdateProviderRequest) GetProvider() *Provider { + if x != nil { + return x.Provider + } + return nil +} + +// Delete provider request. +type DeleteProviderRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteProviderRequest) Reset() { + *x = DeleteProviderRequest{} + mi := &file_openshell_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteProviderRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteProviderRequest) ProtoMessage() {} + +func (x *DeleteProviderRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[28] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteProviderRequest.ProtoReflect.Descriptor instead. +func (*DeleteProviderRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{28} +} + +func (x *DeleteProviderRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +// Provider response. +type ProviderResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Provider *Provider `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProviderResponse) Reset() { + *x = ProviderResponse{} + mi := &file_openshell_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProviderResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProviderResponse) ProtoMessage() {} + +func (x *ProviderResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[29] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProviderResponse.ProtoReflect.Descriptor instead. +func (*ProviderResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{29} +} + +func (x *ProviderResponse) GetProvider() *Provider { + if x != nil { + return x.Provider + } + return nil +} + +// List providers response. +type ListProvidersResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Providers []*Provider `protobuf:"bytes,1,rep,name=providers,proto3" json:"providers,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListProvidersResponse) Reset() { + *x = ListProvidersResponse{} + mi := &file_openshell_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListProvidersResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListProvidersResponse) ProtoMessage() {} + +func (x *ListProvidersResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[30] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListProvidersResponse.ProtoReflect.Descriptor instead. +func (*ListProvidersResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{30} +} + +func (x *ListProvidersResponse) GetProviders() []*Provider { + if x != nil { + return x.Providers + } + return nil +} + +// Delete provider response. +type DeleteProviderResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Deleted bool `protobuf:"varint,1,opt,name=deleted,proto3" json:"deleted,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteProviderResponse) Reset() { + *x = DeleteProviderResponse{} + mi := &file_openshell_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteProviderResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteProviderResponse) ProtoMessage() {} + +func (x *DeleteProviderResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[31] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteProviderResponse.ProtoReflect.Descriptor instead. +func (*DeleteProviderResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{31} +} + +func (x *DeleteProviderResponse) GetDeleted() bool { + if x != nil { + return x.Deleted + } + return false +} + +// Get sandbox provider environment request. +type GetSandboxProviderEnvironmentRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The sandbox ID. + SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetSandboxProviderEnvironmentRequest) Reset() { + *x = GetSandboxProviderEnvironmentRequest{} + mi := &file_openshell_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetSandboxProviderEnvironmentRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSandboxProviderEnvironmentRequest) ProtoMessage() {} + +func (x *GetSandboxProviderEnvironmentRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[32] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSandboxProviderEnvironmentRequest.ProtoReflect.Descriptor instead. +func (*GetSandboxProviderEnvironmentRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{32} +} + +func (x *GetSandboxProviderEnvironmentRequest) GetSandboxId() string { + if x != nil { + return x.SandboxId + } + return "" +} + +// Get sandbox provider environment response. +type GetSandboxProviderEnvironmentResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Provider credential environment variables. + Environment map[string]string `protobuf:"bytes,1,rep,name=environment,proto3" json:"environment,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetSandboxProviderEnvironmentResponse) Reset() { + *x = GetSandboxProviderEnvironmentResponse{} + mi := &file_openshell_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetSandboxProviderEnvironmentResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSandboxProviderEnvironmentResponse) ProtoMessage() {} + +func (x *GetSandboxProviderEnvironmentResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[33] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSandboxProviderEnvironmentResponse.ProtoReflect.Descriptor instead. +func (*GetSandboxProviderEnvironmentResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{33} +} + +func (x *GetSandboxProviderEnvironmentResponse) GetEnvironment() map[string]string { + if x != nil { + return x.Environment + } + return nil +} + +// Update sandbox policy request. +type UpdateSandboxPolicyRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox name (canonical lookup key). + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // The new policy to apply. Only network_policies and inference fields may + // differ from the create-time policy; static fields (filesystem, landlock, + // process) must match version 1 or the request is rejected. + Policy *SandboxPolicy `protobuf:"bytes,2,opt,name=policy,proto3" json:"policy,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateSandboxPolicyRequest) Reset() { + *x = UpdateSandboxPolicyRequest{} + mi := &file_openshell_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateSandboxPolicyRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSandboxPolicyRequest) ProtoMessage() {} + +func (x *UpdateSandboxPolicyRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[34] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSandboxPolicyRequest.ProtoReflect.Descriptor instead. +func (*UpdateSandboxPolicyRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{34} +} + +func (x *UpdateSandboxPolicyRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *UpdateSandboxPolicyRequest) GetPolicy() *SandboxPolicy { + if x != nil { + return x.Policy + } + return nil +} + +// Update sandbox policy response. +type UpdateSandboxPolicyResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Assigned policy version (monotonically increasing per sandbox). + Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + // SHA-256 hash of the serialized policy payload. + PolicyHash string `protobuf:"bytes,2,opt,name=policy_hash,json=policyHash,proto3" json:"policy_hash,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateSandboxPolicyResponse) Reset() { + *x = UpdateSandboxPolicyResponse{} + mi := &file_openshell_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateSandboxPolicyResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSandboxPolicyResponse) ProtoMessage() {} + +func (x *UpdateSandboxPolicyResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[35] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSandboxPolicyResponse.ProtoReflect.Descriptor instead. +func (*UpdateSandboxPolicyResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{35} +} + +func (x *UpdateSandboxPolicyResponse) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *UpdateSandboxPolicyResponse) GetPolicyHash() string { + if x != nil { + return x.PolicyHash + } + return "" +} + +// Get sandbox policy status request. +type GetSandboxPolicyStatusRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox name (canonical lookup key). + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // The specific policy version to query. 0 means latest. + Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetSandboxPolicyStatusRequest) Reset() { + *x = GetSandboxPolicyStatusRequest{} + mi := &file_openshell_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetSandboxPolicyStatusRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSandboxPolicyStatusRequest) ProtoMessage() {} + +func (x *GetSandboxPolicyStatusRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[36] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSandboxPolicyStatusRequest.ProtoReflect.Descriptor instead. +func (*GetSandboxPolicyStatusRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{36} +} + +func (x *GetSandboxPolicyStatusRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *GetSandboxPolicyStatusRequest) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +// Get sandbox policy status response. +type GetSandboxPolicyStatusResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The queried policy revision. + Revision *SandboxPolicyRevision `protobuf:"bytes,1,opt,name=revision,proto3" json:"revision,omitempty"` + // The currently active (loaded) policy version for this sandbox. + ActiveVersion uint32 `protobuf:"varint,2,opt,name=active_version,json=activeVersion,proto3" json:"active_version,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetSandboxPolicyStatusResponse) Reset() { + *x = GetSandboxPolicyStatusResponse{} + mi := &file_openshell_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetSandboxPolicyStatusResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSandboxPolicyStatusResponse) ProtoMessage() {} + +func (x *GetSandboxPolicyStatusResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[37] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSandboxPolicyStatusResponse.ProtoReflect.Descriptor instead. +func (*GetSandboxPolicyStatusResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{37} +} + +func (x *GetSandboxPolicyStatusResponse) GetRevision() *SandboxPolicyRevision { + if x != nil { + return x.Revision + } + return nil +} + +func (x *GetSandboxPolicyStatusResponse) GetActiveVersion() uint32 { + if x != nil { + return x.ActiveVersion + } + return 0 +} + +// List sandbox policies request. +type ListSandboxPoliciesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox name (canonical lookup key). + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Limit uint32 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` + Offset uint32 `protobuf:"varint,3,opt,name=offset,proto3" json:"offset,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListSandboxPoliciesRequest) Reset() { + *x = ListSandboxPoliciesRequest{} + mi := &file_openshell_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListSandboxPoliciesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListSandboxPoliciesRequest) ProtoMessage() {} + +func (x *ListSandboxPoliciesRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[38] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListSandboxPoliciesRequest.ProtoReflect.Descriptor instead. +func (*ListSandboxPoliciesRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{38} +} + +func (x *ListSandboxPoliciesRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ListSandboxPoliciesRequest) GetLimit() uint32 { + if x != nil { + return x.Limit + } + return 0 +} + +func (x *ListSandboxPoliciesRequest) GetOffset() uint32 { + if x != nil { + return x.Offset + } + return 0 +} + +// List sandbox policies response. +type ListSandboxPoliciesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Revisions []*SandboxPolicyRevision `protobuf:"bytes,1,rep,name=revisions,proto3" json:"revisions,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListSandboxPoliciesResponse) Reset() { + *x = ListSandboxPoliciesResponse{} + mi := &file_openshell_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListSandboxPoliciesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListSandboxPoliciesResponse) ProtoMessage() {} + +func (x *ListSandboxPoliciesResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[39] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListSandboxPoliciesResponse.ProtoReflect.Descriptor instead. +func (*ListSandboxPoliciesResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{39} +} + +func (x *ListSandboxPoliciesResponse) GetRevisions() []*SandboxPolicyRevision { + if x != nil { + return x.Revisions + } + return nil +} + +// Report policy load status (called by sandbox runtime after reload attempt). +type ReportPolicyStatusRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox id. + SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` + // The policy version that was attempted. + Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` + // Load result status. + Status PolicyStatus `protobuf:"varint,3,opt,name=status,proto3,enum=openshell.v1.PolicyStatus" json:"status,omitempty"` + // Error message if status is FAILED. + LoadError string `protobuf:"bytes,4,opt,name=load_error,json=loadError,proto3" json:"load_error,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReportPolicyStatusRequest) Reset() { + *x = ReportPolicyStatusRequest{} + mi := &file_openshell_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReportPolicyStatusRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReportPolicyStatusRequest) ProtoMessage() {} + +func (x *ReportPolicyStatusRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[40] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReportPolicyStatusRequest.ProtoReflect.Descriptor instead. +func (*ReportPolicyStatusRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{40} +} + +func (x *ReportPolicyStatusRequest) GetSandboxId() string { + if x != nil { + return x.SandboxId + } + return "" +} + +func (x *ReportPolicyStatusRequest) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *ReportPolicyStatusRequest) GetStatus() PolicyStatus { + if x != nil { + return x.Status + } + return PolicyStatus_POLICY_STATUS_UNSPECIFIED +} + +func (x *ReportPolicyStatusRequest) GetLoadError() string { + if x != nil { + return x.LoadError + } + return "" +} + +// Report policy status response. +type ReportPolicyStatusResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReportPolicyStatusResponse) Reset() { + *x = ReportPolicyStatusResponse{} + mi := &file_openshell_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReportPolicyStatusResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReportPolicyStatusResponse) ProtoMessage() {} + +func (x *ReportPolicyStatusResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[41] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReportPolicyStatusResponse.ProtoReflect.Descriptor instead. +func (*ReportPolicyStatusResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{41} +} + +// A versioned policy revision with metadata. +type SandboxPolicyRevision struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Policy version (monotonically increasing per sandbox). + Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + // SHA-256 hash of the serialized policy payload. + PolicyHash string `protobuf:"bytes,2,opt,name=policy_hash,json=policyHash,proto3" json:"policy_hash,omitempty"` + // Load status of this revision. + Status PolicyStatus `protobuf:"varint,3,opt,name=status,proto3,enum=openshell.v1.PolicyStatus" json:"status,omitempty"` + // Error message if status is FAILED. + LoadError string `protobuf:"bytes,4,opt,name=load_error,json=loadError,proto3" json:"load_error,omitempty"` + // Milliseconds since epoch when this revision was created. + CreatedAtMs int64 `protobuf:"varint,5,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` + // Milliseconds since epoch when this revision was loaded by the sandbox. + LoadedAtMs int64 `protobuf:"varint,6,opt,name=loaded_at_ms,json=loadedAtMs,proto3" json:"loaded_at_ms,omitempty"` + // The full policy (only populated when explicitly requested). + Policy *SandboxPolicy `protobuf:"bytes,7,opt,name=policy,proto3" json:"policy,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxPolicyRevision) Reset() { + *x = SandboxPolicyRevision{} + mi := &file_openshell_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxPolicyRevision) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxPolicyRevision) ProtoMessage() {} + +func (x *SandboxPolicyRevision) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[42] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SandboxPolicyRevision.ProtoReflect.Descriptor instead. +func (*SandboxPolicyRevision) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{42} +} + +func (x *SandboxPolicyRevision) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *SandboxPolicyRevision) GetPolicyHash() string { + if x != nil { + return x.PolicyHash + } + return "" +} + +func (x *SandboxPolicyRevision) GetStatus() PolicyStatus { + if x != nil { + return x.Status + } + return PolicyStatus_POLICY_STATUS_UNSPECIFIED +} + +func (x *SandboxPolicyRevision) GetLoadError() string { + if x != nil { + return x.LoadError + } + return "" +} + +func (x *SandboxPolicyRevision) GetCreatedAtMs() int64 { + if x != nil { + return x.CreatedAtMs + } + return 0 +} + +func (x *SandboxPolicyRevision) GetLoadedAtMs() int64 { + if x != nil { + return x.LoadedAtMs + } + return 0 +} + +func (x *SandboxPolicyRevision) GetPolicy() *SandboxPolicy { + if x != nil { + return x.Policy + } + return nil +} + +// Get sandbox logs request (one-shot fetch). +type GetSandboxLogsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox id. + SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` + // Maximum number of log lines to return. 0 means use default (2000). + Lines uint32 `protobuf:"varint,2,opt,name=lines,proto3" json:"lines,omitempty"` + // Only include logs with timestamp >= this value (ms since epoch). 0 means no filter. + SinceMs int64 `protobuf:"varint,3,opt,name=since_ms,json=sinceMs,proto3" json:"since_ms,omitempty"` + // Filter by log source (e.g. "gateway", "sandbox"). Empty means all sources. + Sources []string `protobuf:"bytes,4,rep,name=sources,proto3" json:"sources,omitempty"` + // Minimum log level to include (e.g. "INFO", "WARN", "ERROR"). Empty means all levels. + MinLevel string `protobuf:"bytes,5,opt,name=min_level,json=minLevel,proto3" json:"min_level,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetSandboxLogsRequest) Reset() { + *x = GetSandboxLogsRequest{} + mi := &file_openshell_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetSandboxLogsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSandboxLogsRequest) ProtoMessage() {} + +func (x *GetSandboxLogsRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[43] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSandboxLogsRequest.ProtoReflect.Descriptor instead. +func (*GetSandboxLogsRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{43} +} + +func (x *GetSandboxLogsRequest) GetSandboxId() string { + if x != nil { + return x.SandboxId + } + return "" +} + +func (x *GetSandboxLogsRequest) GetLines() uint32 { + if x != nil { + return x.Lines + } + return 0 +} + +func (x *GetSandboxLogsRequest) GetSinceMs() int64 { + if x != nil { + return x.SinceMs + } + return 0 +} + +func (x *GetSandboxLogsRequest) GetSources() []string { + if x != nil { + return x.Sources + } + return nil +} + +func (x *GetSandboxLogsRequest) GetMinLevel() string { + if x != nil { + return x.MinLevel + } + return "" +} + +// Batch of log lines pushed from sandbox to server. +type PushSandboxLogsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The sandbox ID. + SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` + // Log lines to ingest. + Logs []*SandboxLogLine `protobuf:"bytes,2,rep,name=logs,proto3" json:"logs,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PushSandboxLogsRequest) Reset() { + *x = PushSandboxLogsRequest{} + mi := &file_openshell_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PushSandboxLogsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushSandboxLogsRequest) ProtoMessage() {} + +func (x *PushSandboxLogsRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[44] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PushSandboxLogsRequest.ProtoReflect.Descriptor instead. +func (*PushSandboxLogsRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{44} +} + +func (x *PushSandboxLogsRequest) GetSandboxId() string { + if x != nil { + return x.SandboxId + } + return "" +} + +func (x *PushSandboxLogsRequest) GetLogs() []*SandboxLogLine { + if x != nil { + return x.Logs + } + return nil +} + +// Push sandbox logs response. +type PushSandboxLogsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PushSandboxLogsResponse) Reset() { + *x = PushSandboxLogsResponse{} + mi := &file_openshell_proto_msgTypes[45] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PushSandboxLogsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushSandboxLogsResponse) ProtoMessage() {} + +func (x *PushSandboxLogsResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[45] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PushSandboxLogsResponse.ProtoReflect.Descriptor instead. +func (*PushSandboxLogsResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{45} +} + +// Get sandbox logs response. +type GetSandboxLogsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Log lines in chronological order. + Logs []*SandboxLogLine `protobuf:"bytes,1,rep,name=logs,proto3" json:"logs,omitempty"` + // Total number of lines in the server's buffer for this sandbox. + BufferTotal uint32 `protobuf:"varint,2,opt,name=buffer_total,json=bufferTotal,proto3" json:"buffer_total,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetSandboxLogsResponse) Reset() { + *x = GetSandboxLogsResponse{} + mi := &file_openshell_proto_msgTypes[46] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetSandboxLogsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSandboxLogsResponse) ProtoMessage() {} + +func (x *GetSandboxLogsResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[46] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSandboxLogsResponse.ProtoReflect.Descriptor instead. +func (*GetSandboxLogsResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{46} +} + +func (x *GetSandboxLogsResponse) GetLogs() []*SandboxLogLine { + if x != nil { + return x.Logs + } + return nil +} + +func (x *GetSandboxLogsResponse) GetBufferTotal() uint32 { + if x != nil { + return x.BufferTotal + } + return 0 +} + +// Observed HTTP method+path pattern from L7 inspection. +type L7RequestSample struct { + state protoimpl.MessageState `protogen:"open.v1"` + // HTTP method: GET, POST, PUT, DELETE, etc. + Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"` + // HTTP path: /v1/models, /repos/myorg/issues + Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` + // L7 decision: "audit" or "deny" (allowed requests not collected). + Decision string `protobuf:"bytes,3,opt,name=decision,proto3" json:"decision,omitempty"` + // Number of times this (method, path) was observed. + Count uint32 `protobuf:"varint,4,opt,name=count,proto3" json:"count,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *L7RequestSample) Reset() { + *x = L7RequestSample{} + mi := &file_openshell_proto_msgTypes[47] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *L7RequestSample) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*L7RequestSample) ProtoMessage() {} + +func (x *L7RequestSample) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[47] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use L7RequestSample.ProtoReflect.Descriptor instead. +func (*L7RequestSample) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{47} +} + +func (x *L7RequestSample) GetMethod() string { + if x != nil { + return x.Method + } + return "" +} + +func (x *L7RequestSample) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +func (x *L7RequestSample) GetDecision() string { + if x != nil { + return x.Decision + } + return "" +} + +func (x *L7RequestSample) GetCount() uint32 { + if x != nil { + return x.Count + } + return 0 +} + +// Structured denial summary from sandbox aggregator. +type DenialSummary struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox ID that produced this summary. + SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` + // Denied destination host. + Host string `protobuf:"bytes,2,opt,name=host,proto3" json:"host,omitempty"` + // Denied destination port. + Port uint32 `protobuf:"varint,3,opt,name=port,proto3" json:"port,omitempty"` + // Binary that attempted the connection. + Binary string `protobuf:"bytes,4,opt,name=binary,proto3" json:"binary,omitempty"` + // Process ancestor chain. + Ancestors []string `protobuf:"bytes,5,rep,name=ancestors,proto3" json:"ancestors,omitempty"` + // Denial reason from OPA evaluation. + DenyReason string `protobuf:"bytes,6,opt,name=deny_reason,json=denyReason,proto3" json:"deny_reason,omitempty"` + // First denial timestamp (ms since epoch). + FirstSeenMs int64 `protobuf:"varint,7,opt,name=first_seen_ms,json=firstSeenMs,proto3" json:"first_seen_ms,omitempty"` + // Most recent denial timestamp (ms since epoch). + LastSeenMs int64 `protobuf:"varint,8,opt,name=last_seen_ms,json=lastSeenMs,proto3" json:"last_seen_ms,omitempty"` + // Number of denials in the current window. + Count uint32 `protobuf:"varint,9,opt,name=count,proto3" json:"count,omitempty"` + // Events dropped during aggregator cooldown. + SuppressedCount uint32 `protobuf:"varint,10,opt,name=suppressed_count,json=suppressedCount,proto3" json:"suppressed_count,omitempty"` + // Cumulative lifetime count (never resets). + TotalCount uint32 `protobuf:"varint,11,opt,name=total_count,json=totalCount,proto3" json:"total_count,omitempty"` + // Distinct cmdline strings observed (sanitized of credentials). + SampleCmdlines []string `protobuf:"bytes,12,rep,name=sample_cmdlines,json=sampleCmdlines,proto3" json:"sample_cmdlines,omitempty"` + // SHA-256 of the binary for audit trail. + BinarySha256 string `protobuf:"bytes,13,opt,name=binary_sha256,json=binarySha256,proto3" json:"binary_sha256,omitempty"` + // True if emitted by stale-flush rather than threshold. + Persistent bool `protobuf:"varint,14,opt,name=persistent,proto3" json:"persistent,omitempty"` + // Denial category: "l4_deny", "l7_deny", "l7_audit", "ssrf". + DenialStage string `protobuf:"bytes,15,opt,name=denial_stage,json=denialStage,proto3" json:"denial_stage,omitempty"` + // Observed HTTP request patterns (from L7 inspection). + L7RequestSamples []*L7RequestSample `protobuf:"bytes,16,rep,name=l7_request_samples,json=l7RequestSamples,proto3" json:"l7_request_samples,omitempty"` + // True if L7 inspection was active during observation window. + L7InspectionActive bool `protobuf:"varint,17,opt,name=l7_inspection_active,json=l7InspectionActive,proto3" json:"l7_inspection_active,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DenialSummary) Reset() { + *x = DenialSummary{} + mi := &file_openshell_proto_msgTypes[48] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DenialSummary) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DenialSummary) ProtoMessage() {} + +func (x *DenialSummary) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[48] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DenialSummary.ProtoReflect.Descriptor instead. +func (*DenialSummary) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{48} +} + +func (x *DenialSummary) GetSandboxId() string { + if x != nil { + return x.SandboxId + } + return "" +} + +func (x *DenialSummary) GetHost() string { + if x != nil { + return x.Host + } + return "" +} + +func (x *DenialSummary) GetPort() uint32 { + if x != nil { + return x.Port + } + return 0 +} + +func (x *DenialSummary) GetBinary() string { + if x != nil { + return x.Binary + } + return "" +} + +func (x *DenialSummary) GetAncestors() []string { + if x != nil { + return x.Ancestors + } + return nil +} + +func (x *DenialSummary) GetDenyReason() string { + if x != nil { + return x.DenyReason + } + return "" +} + +func (x *DenialSummary) GetFirstSeenMs() int64 { + if x != nil { + return x.FirstSeenMs + } + return 0 +} + +func (x *DenialSummary) GetLastSeenMs() int64 { + if x != nil { + return x.LastSeenMs + } + return 0 +} + +func (x *DenialSummary) GetCount() uint32 { + if x != nil { + return x.Count + } + return 0 +} + +func (x *DenialSummary) GetSuppressedCount() uint32 { + if x != nil { + return x.SuppressedCount + } + return 0 +} + +func (x *DenialSummary) GetTotalCount() uint32 { + if x != nil { + return x.TotalCount + } + return 0 +} + +func (x *DenialSummary) GetSampleCmdlines() []string { + if x != nil { + return x.SampleCmdlines + } + return nil +} + +func (x *DenialSummary) GetBinarySha256() string { + if x != nil { + return x.BinarySha256 + } + return "" +} + +func (x *DenialSummary) GetPersistent() bool { + if x != nil { + return x.Persistent + } + return false +} + +func (x *DenialSummary) GetDenialStage() string { + if x != nil { + return x.DenialStage + } + return "" +} + +func (x *DenialSummary) GetL7RequestSamples() []*L7RequestSample { + if x != nil { + return x.L7RequestSamples + } + return nil +} + +func (x *DenialSummary) GetL7InspectionActive() bool { + if x != nil { + return x.L7InspectionActive + } + return false +} + +// A proposed policy rule with rationale and approval status. +type PolicyChunk struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Unique chunk identifier. + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // Approval status: "pending", "approved", "rejected". + Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` + // Proposed network_policies map key. + RuleName string `protobuf:"bytes,3,opt,name=rule_name,json=ruleName,proto3" json:"rule_name,omitempty"` + // The proposed network policy rule. + ProposedRule *NetworkPolicyRule `protobuf:"bytes,4,opt,name=proposed_rule,json=proposedRule,proto3" json:"proposed_rule,omitempty"` + // Human-readable explanation of why this rule is proposed. + Rationale string `protobuf:"bytes,5,opt,name=rationale,proto3" json:"rationale,omitempty"` + // Security concerns flagged by analysis (empty if none). + SecurityNotes string `protobuf:"bytes,6,opt,name=security_notes,json=securityNotes,proto3" json:"security_notes,omitempty"` + // Analysis confidence (0.0-1.0). 0 for mechanistic mode. + Confidence float32 `protobuf:"fixed32,7,opt,name=confidence,proto3" json:"confidence,omitempty"` + // IDs of denial summaries that led to this chunk. + DenialSummaryIds []string `protobuf:"bytes,8,rep,name=denial_summary_ids,json=denialSummaryIds,proto3" json:"denial_summary_ids,omitempty"` + // Creation timestamp (ms since epoch). + CreatedAtMs int64 `protobuf:"varint,9,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` + // When the user approved/rejected (ms since epoch). 0 if undecided. + DecidedAtMs int64 `protobuf:"varint,10,opt,name=decided_at_ms,json=decidedAtMs,proto3" json:"decided_at_ms,omitempty"` + // Recommendation stage: "initial" or "refined" (progressive L7 visibility). + Stage string `protobuf:"bytes,11,opt,name=stage,proto3" json:"stage,omitempty"` + // For stage="refined": the initial chunk this replaces. + SupersedesChunkId string `protobuf:"bytes,12,opt,name=supersedes_chunk_id,json=supersedesChunkId,proto3" json:"supersedes_chunk_id,omitempty"` + // How many times this endpoint has been seen across denial flush cycles. + HitCount int32 `protobuf:"varint,13,opt,name=hit_count,json=hitCount,proto3" json:"hit_count,omitempty"` + // First time this endpoint was proposed (ms since epoch). + FirstSeenMs int64 `protobuf:"varint,14,opt,name=first_seen_ms,json=firstSeenMs,proto3" json:"first_seen_ms,omitempty"` + // Most recent time this endpoint was re-proposed (ms since epoch). + LastSeenMs int64 `protobuf:"varint,15,opt,name=last_seen_ms,json=lastSeenMs,proto3" json:"last_seen_ms,omitempty"` + // Binary path that triggered the denial (denormalized for display convenience). + Binary string `protobuf:"bytes,16,opt,name=binary,proto3" json:"binary,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PolicyChunk) Reset() { + *x = PolicyChunk{} + mi := &file_openshell_proto_msgTypes[49] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PolicyChunk) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PolicyChunk) ProtoMessage() {} + +func (x *PolicyChunk) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[49] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PolicyChunk.ProtoReflect.Descriptor instead. +func (*PolicyChunk) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{49} +} + +func (x *PolicyChunk) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *PolicyChunk) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +func (x *PolicyChunk) GetRuleName() string { + if x != nil { + return x.RuleName + } + return "" +} + +func (x *PolicyChunk) GetProposedRule() *NetworkPolicyRule { + if x != nil { + return x.ProposedRule + } + return nil +} + +func (x *PolicyChunk) GetRationale() string { + if x != nil { + return x.Rationale + } + return "" +} + +func (x *PolicyChunk) GetSecurityNotes() string { + if x != nil { + return x.SecurityNotes + } + return "" +} + +func (x *PolicyChunk) GetConfidence() float32 { + if x != nil { + return x.Confidence + } + return 0 +} + +func (x *PolicyChunk) GetDenialSummaryIds() []string { + if x != nil { + return x.DenialSummaryIds + } + return nil +} + +func (x *PolicyChunk) GetCreatedAtMs() int64 { + if x != nil { + return x.CreatedAtMs + } + return 0 +} + +func (x *PolicyChunk) GetDecidedAtMs() int64 { + if x != nil { + return x.DecidedAtMs + } + return 0 +} + +func (x *PolicyChunk) GetStage() string { + if x != nil { + return x.Stage + } + return "" +} + +func (x *PolicyChunk) GetSupersedesChunkId() string { + if x != nil { + return x.SupersedesChunkId + } + return "" +} + +func (x *PolicyChunk) GetHitCount() int32 { + if x != nil { + return x.HitCount + } + return 0 +} + +func (x *PolicyChunk) GetFirstSeenMs() int64 { + if x != nil { + return x.FirstSeenMs + } + return 0 +} + +func (x *PolicyChunk) GetLastSeenMs() int64 { + if x != nil { + return x.LastSeenMs + } + return 0 +} + +func (x *PolicyChunk) GetBinary() string { + if x != nil { + return x.Binary + } + return "" +} + +// Notification that the draft policy was updated. +type DraftPolicyUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Current draft version. + DraftVersion uint64 `protobuf:"varint,1,opt,name=draft_version,json=draftVersion,proto3" json:"draft_version,omitempty"` + // Number of new chunks added in this update. + NewChunks uint32 `protobuf:"varint,2,opt,name=new_chunks,json=newChunks,proto3" json:"new_chunks,omitempty"` + // Total pending chunks awaiting approval. + TotalPending uint32 `protobuf:"varint,3,opt,name=total_pending,json=totalPending,proto3" json:"total_pending,omitempty"` + // Brief description of what changed. + Summary string `protobuf:"bytes,4,opt,name=summary,proto3" json:"summary,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DraftPolicyUpdate) Reset() { + *x = DraftPolicyUpdate{} + mi := &file_openshell_proto_msgTypes[50] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DraftPolicyUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DraftPolicyUpdate) ProtoMessage() {} + +func (x *DraftPolicyUpdate) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[50] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DraftPolicyUpdate.ProtoReflect.Descriptor instead. +func (*DraftPolicyUpdate) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{50} +} + +func (x *DraftPolicyUpdate) GetDraftVersion() uint64 { + if x != nil { + return x.DraftVersion + } + return 0 +} + +func (x *DraftPolicyUpdate) GetNewChunks() uint32 { + if x != nil { + return x.NewChunks + } + return 0 +} + +func (x *DraftPolicyUpdate) GetTotalPending() uint32 { + if x != nil { + return x.TotalPending + } + return 0 +} + +func (x *DraftPolicyUpdate) GetSummary() string { + if x != nil { + return x.Summary + } + return "" +} + +// Submit analysis results from sandbox to gateway. +type SubmitPolicyAnalysisRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Aggregated denial summaries. + Summaries []*DenialSummary `protobuf:"bytes,1,rep,name=summaries,proto3" json:"summaries,omitempty"` + // Proposed policy chunks (validated by sandbox OPA engine). + ProposedChunks []*PolicyChunk `protobuf:"bytes,2,rep,name=proposed_chunks,json=proposedChunks,proto3" json:"proposed_chunks,omitempty"` + // Analysis mode: "mechanistic" or "llm". + AnalysisMode string `protobuf:"bytes,3,opt,name=analysis_mode,json=analysisMode,proto3" json:"analysis_mode,omitempty"` + // Sandbox name. + Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SubmitPolicyAnalysisRequest) Reset() { + *x = SubmitPolicyAnalysisRequest{} + mi := &file_openshell_proto_msgTypes[51] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SubmitPolicyAnalysisRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitPolicyAnalysisRequest) ProtoMessage() {} + +func (x *SubmitPolicyAnalysisRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[51] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitPolicyAnalysisRequest.ProtoReflect.Descriptor instead. +func (*SubmitPolicyAnalysisRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{51} +} + +func (x *SubmitPolicyAnalysisRequest) GetSummaries() []*DenialSummary { + if x != nil { + return x.Summaries + } + return nil +} + +func (x *SubmitPolicyAnalysisRequest) GetProposedChunks() []*PolicyChunk { + if x != nil { + return x.ProposedChunks + } + return nil +} + +func (x *SubmitPolicyAnalysisRequest) GetAnalysisMode() string { + if x != nil { + return x.AnalysisMode + } + return "" +} + +func (x *SubmitPolicyAnalysisRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type SubmitPolicyAnalysisResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Number of chunks accepted by the gateway. + AcceptedChunks uint32 `protobuf:"varint,1,opt,name=accepted_chunks,json=acceptedChunks,proto3" json:"accepted_chunks,omitempty"` + // Number of chunks rejected by gateway validation. + RejectedChunks uint32 `protobuf:"varint,2,opt,name=rejected_chunks,json=rejectedChunks,proto3" json:"rejected_chunks,omitempty"` + // Reasons for each rejected chunk. + RejectionReasons []string `protobuf:"bytes,3,rep,name=rejection_reasons,json=rejectionReasons,proto3" json:"rejection_reasons,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SubmitPolicyAnalysisResponse) Reset() { + *x = SubmitPolicyAnalysisResponse{} + mi := &file_openshell_proto_msgTypes[52] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SubmitPolicyAnalysisResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitPolicyAnalysisResponse) ProtoMessage() {} + +func (x *SubmitPolicyAnalysisResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[52] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitPolicyAnalysisResponse.ProtoReflect.Descriptor instead. +func (*SubmitPolicyAnalysisResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{52} +} + +func (x *SubmitPolicyAnalysisResponse) GetAcceptedChunks() uint32 { + if x != nil { + return x.AcceptedChunks + } + return 0 +} + +func (x *SubmitPolicyAnalysisResponse) GetRejectedChunks() uint32 { + if x != nil { + return x.RejectedChunks + } + return 0 +} + +func (x *SubmitPolicyAnalysisResponse) GetRejectionReasons() []string { + if x != nil { + return x.RejectionReasons + } + return nil +} + +// Get draft policy for a sandbox. +type GetDraftPolicyRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox name. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Optional status filter: "pending", "approved", "rejected", or "" for all. + StatusFilter string `protobuf:"bytes,2,opt,name=status_filter,json=statusFilter,proto3" json:"status_filter,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetDraftPolicyRequest) Reset() { + *x = GetDraftPolicyRequest{} + mi := &file_openshell_proto_msgTypes[53] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetDraftPolicyRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetDraftPolicyRequest) ProtoMessage() {} + +func (x *GetDraftPolicyRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[53] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetDraftPolicyRequest.ProtoReflect.Descriptor instead. +func (*GetDraftPolicyRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{53} +} + +func (x *GetDraftPolicyRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *GetDraftPolicyRequest) GetStatusFilter() string { + if x != nil { + return x.StatusFilter + } + return "" +} + +type GetDraftPolicyResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Draft policy chunks. + Chunks []*PolicyChunk `protobuf:"bytes,1,rep,name=chunks,proto3" json:"chunks,omitempty"` + // LLM-generated summary of all analysis (empty in mechanistic mode). + RollingSummary string `protobuf:"bytes,2,opt,name=rolling_summary,json=rollingSummary,proto3" json:"rolling_summary,omitempty"` + // Current draft version. + DraftVersion uint64 `protobuf:"varint,3,opt,name=draft_version,json=draftVersion,proto3" json:"draft_version,omitempty"` + // When the last analysis completed (ms since epoch). + LastAnalyzedAtMs int64 `protobuf:"varint,4,opt,name=last_analyzed_at_ms,json=lastAnalyzedAtMs,proto3" json:"last_analyzed_at_ms,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetDraftPolicyResponse) Reset() { + *x = GetDraftPolicyResponse{} + mi := &file_openshell_proto_msgTypes[54] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetDraftPolicyResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetDraftPolicyResponse) ProtoMessage() {} + +func (x *GetDraftPolicyResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[54] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetDraftPolicyResponse.ProtoReflect.Descriptor instead. +func (*GetDraftPolicyResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{54} +} + +func (x *GetDraftPolicyResponse) GetChunks() []*PolicyChunk { + if x != nil { + return x.Chunks + } + return nil +} + +func (x *GetDraftPolicyResponse) GetRollingSummary() string { + if x != nil { + return x.RollingSummary + } + return "" +} + +func (x *GetDraftPolicyResponse) GetDraftVersion() uint64 { + if x != nil { + return x.DraftVersion + } + return 0 +} + +func (x *GetDraftPolicyResponse) GetLastAnalyzedAtMs() int64 { + if x != nil { + return x.LastAnalyzedAtMs + } + return 0 +} + +// Approve a single draft chunk. +type ApproveDraftChunkRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox name. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Chunk ID to approve. + ChunkId string `protobuf:"bytes,2,opt,name=chunk_id,json=chunkId,proto3" json:"chunk_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ApproveDraftChunkRequest) Reset() { + *x = ApproveDraftChunkRequest{} + mi := &file_openshell_proto_msgTypes[55] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ApproveDraftChunkRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApproveDraftChunkRequest) ProtoMessage() {} + +func (x *ApproveDraftChunkRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[55] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApproveDraftChunkRequest.ProtoReflect.Descriptor instead. +func (*ApproveDraftChunkRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{55} +} + +func (x *ApproveDraftChunkRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ApproveDraftChunkRequest) GetChunkId() string { + if x != nil { + return x.ChunkId + } + return "" +} + +type ApproveDraftChunkResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // New policy version after merge. + PolicyVersion uint32 `protobuf:"varint,1,opt,name=policy_version,json=policyVersion,proto3" json:"policy_version,omitempty"` + // SHA-256 hash of the new policy. + PolicyHash string `protobuf:"bytes,2,opt,name=policy_hash,json=policyHash,proto3" json:"policy_hash,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ApproveDraftChunkResponse) Reset() { + *x = ApproveDraftChunkResponse{} + mi := &file_openshell_proto_msgTypes[56] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ApproveDraftChunkResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApproveDraftChunkResponse) ProtoMessage() {} + +func (x *ApproveDraftChunkResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[56] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApproveDraftChunkResponse.ProtoReflect.Descriptor instead. +func (*ApproveDraftChunkResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{56} +} + +func (x *ApproveDraftChunkResponse) GetPolicyVersion() uint32 { + if x != nil { + return x.PolicyVersion + } + return 0 +} + +func (x *ApproveDraftChunkResponse) GetPolicyHash() string { + if x != nil { + return x.PolicyHash + } + return "" +} + +// Reject a single draft chunk. +type RejectDraftChunkRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox name. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Chunk ID to reject. + ChunkId string `protobuf:"bytes,2,opt,name=chunk_id,json=chunkId,proto3" json:"chunk_id,omitempty"` + // Optional reason for rejection (fed to LLM context in future analysis). + Reason string `protobuf:"bytes,3,opt,name=reason,proto3" json:"reason,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RejectDraftChunkRequest) Reset() { + *x = RejectDraftChunkRequest{} + mi := &file_openshell_proto_msgTypes[57] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RejectDraftChunkRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RejectDraftChunkRequest) ProtoMessage() {} + +func (x *RejectDraftChunkRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[57] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RejectDraftChunkRequest.ProtoReflect.Descriptor instead. +func (*RejectDraftChunkRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{57} +} + +func (x *RejectDraftChunkRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *RejectDraftChunkRequest) GetChunkId() string { + if x != nil { + return x.ChunkId + } + return "" +} + +func (x *RejectDraftChunkRequest) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +type RejectDraftChunkResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RejectDraftChunkResponse) Reset() { + *x = RejectDraftChunkResponse{} + mi := &file_openshell_proto_msgTypes[58] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RejectDraftChunkResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RejectDraftChunkResponse) ProtoMessage() {} + +func (x *RejectDraftChunkResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[58] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RejectDraftChunkResponse.ProtoReflect.Descriptor instead. +func (*RejectDraftChunkResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{58} +} + +// Approve all pending chunks. +type ApproveAllDraftChunksRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox name. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Include chunks with security_notes (default false: skips them). + IncludeSecurityFlagged bool `protobuf:"varint,2,opt,name=include_security_flagged,json=includeSecurityFlagged,proto3" json:"include_security_flagged,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ApproveAllDraftChunksRequest) Reset() { + *x = ApproveAllDraftChunksRequest{} + mi := &file_openshell_proto_msgTypes[59] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ApproveAllDraftChunksRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApproveAllDraftChunksRequest) ProtoMessage() {} + +func (x *ApproveAllDraftChunksRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[59] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApproveAllDraftChunksRequest.ProtoReflect.Descriptor instead. +func (*ApproveAllDraftChunksRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{59} +} + +func (x *ApproveAllDraftChunksRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ApproveAllDraftChunksRequest) GetIncludeSecurityFlagged() bool { + if x != nil { + return x.IncludeSecurityFlagged + } + return false +} + +type ApproveAllDraftChunksResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // New policy version after merge. + PolicyVersion uint32 `protobuf:"varint,1,opt,name=policy_version,json=policyVersion,proto3" json:"policy_version,omitempty"` + // SHA-256 hash of the new policy. + PolicyHash string `protobuf:"bytes,2,opt,name=policy_hash,json=policyHash,proto3" json:"policy_hash,omitempty"` + // Number of chunks approved. + ChunksApproved uint32 `protobuf:"varint,3,opt,name=chunks_approved,json=chunksApproved,proto3" json:"chunks_approved,omitempty"` + // Number of chunks skipped (security-flagged). + ChunksSkipped uint32 `protobuf:"varint,4,opt,name=chunks_skipped,json=chunksSkipped,proto3" json:"chunks_skipped,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ApproveAllDraftChunksResponse) Reset() { + *x = ApproveAllDraftChunksResponse{} + mi := &file_openshell_proto_msgTypes[60] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ApproveAllDraftChunksResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApproveAllDraftChunksResponse) ProtoMessage() {} + +func (x *ApproveAllDraftChunksResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[60] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApproveAllDraftChunksResponse.ProtoReflect.Descriptor instead. +func (*ApproveAllDraftChunksResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{60} +} + +func (x *ApproveAllDraftChunksResponse) GetPolicyVersion() uint32 { + if x != nil { + return x.PolicyVersion + } + return 0 +} + +func (x *ApproveAllDraftChunksResponse) GetPolicyHash() string { + if x != nil { + return x.PolicyHash + } + return "" +} + +func (x *ApproveAllDraftChunksResponse) GetChunksApproved() uint32 { + if x != nil { + return x.ChunksApproved + } + return 0 +} + +func (x *ApproveAllDraftChunksResponse) GetChunksSkipped() uint32 { + if x != nil { + return x.ChunksSkipped + } + return 0 +} + +// Edit a pending chunk in-place. +type EditDraftChunkRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox name. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Chunk ID to edit. + ChunkId string `protobuf:"bytes,2,opt,name=chunk_id,json=chunkId,proto3" json:"chunk_id,omitempty"` + // The modified rule (replaces existing proposed_rule). + ProposedRule *NetworkPolicyRule `protobuf:"bytes,3,opt,name=proposed_rule,json=proposedRule,proto3" json:"proposed_rule,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EditDraftChunkRequest) Reset() { + *x = EditDraftChunkRequest{} + mi := &file_openshell_proto_msgTypes[61] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EditDraftChunkRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EditDraftChunkRequest) ProtoMessage() {} + +func (x *EditDraftChunkRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[61] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EditDraftChunkRequest.ProtoReflect.Descriptor instead. +func (*EditDraftChunkRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{61} +} + +func (x *EditDraftChunkRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *EditDraftChunkRequest) GetChunkId() string { + if x != nil { + return x.ChunkId + } + return "" +} + +func (x *EditDraftChunkRequest) GetProposedRule() *NetworkPolicyRule { + if x != nil { + return x.ProposedRule + } + return nil +} + +type EditDraftChunkResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EditDraftChunkResponse) Reset() { + *x = EditDraftChunkResponse{} + mi := &file_openshell_proto_msgTypes[62] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EditDraftChunkResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EditDraftChunkResponse) ProtoMessage() {} + +func (x *EditDraftChunkResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[62] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EditDraftChunkResponse.ProtoReflect.Descriptor instead. +func (*EditDraftChunkResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{62} +} + +// Reverse an approval (remove merged rule from active policy). +type UndoDraftChunkRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox name. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Chunk ID to undo. + ChunkId string `protobuf:"bytes,2,opt,name=chunk_id,json=chunkId,proto3" json:"chunk_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UndoDraftChunkRequest) Reset() { + *x = UndoDraftChunkRequest{} + mi := &file_openshell_proto_msgTypes[63] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UndoDraftChunkRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UndoDraftChunkRequest) ProtoMessage() {} + +func (x *UndoDraftChunkRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[63] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UndoDraftChunkRequest.ProtoReflect.Descriptor instead. +func (*UndoDraftChunkRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{63} +} + +func (x *UndoDraftChunkRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *UndoDraftChunkRequest) GetChunkId() string { + if x != nil { + return x.ChunkId + } + return "" +} + +type UndoDraftChunkResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // New policy version after removal. + PolicyVersion uint32 `protobuf:"varint,1,opt,name=policy_version,json=policyVersion,proto3" json:"policy_version,omitempty"` + // SHA-256 hash of the updated policy. + PolicyHash string `protobuf:"bytes,2,opt,name=policy_hash,json=policyHash,proto3" json:"policy_hash,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UndoDraftChunkResponse) Reset() { + *x = UndoDraftChunkResponse{} + mi := &file_openshell_proto_msgTypes[64] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UndoDraftChunkResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UndoDraftChunkResponse) ProtoMessage() {} + +func (x *UndoDraftChunkResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[64] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UndoDraftChunkResponse.ProtoReflect.Descriptor instead. +func (*UndoDraftChunkResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{64} +} + +func (x *UndoDraftChunkResponse) GetPolicyVersion() uint32 { + if x != nil { + return x.PolicyVersion + } + return 0 +} + +func (x *UndoDraftChunkResponse) GetPolicyHash() string { + if x != nil { + return x.PolicyHash + } + return "" +} + +// Clear all pending draft chunks for a sandbox. +type ClearDraftChunksRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox name. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ClearDraftChunksRequest) Reset() { + *x = ClearDraftChunksRequest{} + mi := &file_openshell_proto_msgTypes[65] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ClearDraftChunksRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClearDraftChunksRequest) ProtoMessage() {} + +func (x *ClearDraftChunksRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[65] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClearDraftChunksRequest.ProtoReflect.Descriptor instead. +func (*ClearDraftChunksRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{65} +} + +func (x *ClearDraftChunksRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type ClearDraftChunksResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Number of chunks cleared. + ChunksCleared uint32 `protobuf:"varint,1,opt,name=chunks_cleared,json=chunksCleared,proto3" json:"chunks_cleared,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ClearDraftChunksResponse) Reset() { + *x = ClearDraftChunksResponse{} + mi := &file_openshell_proto_msgTypes[66] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ClearDraftChunksResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClearDraftChunksResponse) ProtoMessage() {} + +func (x *ClearDraftChunksResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[66] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClearDraftChunksResponse.ProtoReflect.Descriptor instead. +func (*ClearDraftChunksResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{66} +} + +func (x *ClearDraftChunksResponse) GetChunksCleared() uint32 { + if x != nil { + return x.ChunksCleared + } + return 0 +} + +// Get decision history for a sandbox's draft policy. +type GetDraftHistoryRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox name. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetDraftHistoryRequest) Reset() { + *x = GetDraftHistoryRequest{} + mi := &file_openshell_proto_msgTypes[67] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetDraftHistoryRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetDraftHistoryRequest) ProtoMessage() {} + +func (x *GetDraftHistoryRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[67] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetDraftHistoryRequest.ProtoReflect.Descriptor instead. +func (*GetDraftHistoryRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{67} +} + +func (x *GetDraftHistoryRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type DraftHistoryEntry struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Event timestamp (ms since epoch). + TimestampMs int64 `protobuf:"varint,1,opt,name=timestamp_ms,json=timestampMs,proto3" json:"timestamp_ms,omitempty"` + // Event type: "denial_detected", "analysis_cycle", "approved", + // "rejected", "edited", "undone", "cleared". + EventType string `protobuf:"bytes,2,opt,name=event_type,json=eventType,proto3" json:"event_type,omitempty"` + // Human-readable description. + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + // Associated chunk ID (if applicable). + ChunkId string `protobuf:"bytes,4,opt,name=chunk_id,json=chunkId,proto3" json:"chunk_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DraftHistoryEntry) Reset() { + *x = DraftHistoryEntry{} + mi := &file_openshell_proto_msgTypes[68] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DraftHistoryEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DraftHistoryEntry) ProtoMessage() {} + +func (x *DraftHistoryEntry) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[68] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DraftHistoryEntry.ProtoReflect.Descriptor instead. +func (*DraftHistoryEntry) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{68} +} + +func (x *DraftHistoryEntry) GetTimestampMs() int64 { + if x != nil { + return x.TimestampMs + } + return 0 +} + +func (x *DraftHistoryEntry) GetEventType() string { + if x != nil { + return x.EventType + } + return "" +} + +func (x *DraftHistoryEntry) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *DraftHistoryEntry) GetChunkId() string { + if x != nil { + return x.ChunkId + } + return "" +} + +type GetDraftHistoryResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Chronological decision history. + Entries []*DraftHistoryEntry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetDraftHistoryResponse) Reset() { + *x = GetDraftHistoryResponse{} + mi := &file_openshell_proto_msgTypes[69] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetDraftHistoryResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetDraftHistoryResponse) ProtoMessage() {} + +func (x *GetDraftHistoryResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[69] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetDraftHistoryResponse.ProtoReflect.Descriptor instead. +func (*GetDraftHistoryResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{69} +} + +func (x *GetDraftHistoryResponse) GetEntries() []*DraftHistoryEntry { + if x != nil { + return x.Entries + } + return nil +} + +var File_openshell_proto protoreflect.FileDescriptor + +const file_openshell_proto_rawDesc = "" + + "\n" + + "\x0fopenshell.proto\x12\fopenshell.v1\x1a\x0fdatamodel.proto\x1a\rsandbox.proto\"\x0f\n" + + "\rHealthRequest\"_\n" + + "\x0eHealthResponse\x123\n" + + "\x06status\x18\x01 \x01(\x0e2\x1b.openshell.v1.ServiceStatusR\x06status\x12\x18\n" + + "\aversion\x18\x02 \x01(\tR\aversion\"c\n" + + "\x14CreateSandboxRequest\x127\n" + + "\x04spec\x18\x01 \x01(\v2#.openshell.datamodel.v1.SandboxSpecR\x04spec\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\"'\n" + + "\x11GetSandboxRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\"D\n" + + "\x14ListSandboxesRequest\x12\x14\n" + + "\x05limit\x18\x01 \x01(\rR\x05limit\x12\x16\n" + + "\x06offset\x18\x02 \x01(\rR\x06offset\"*\n" + + "\x14DeleteSandboxRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\"L\n" + + "\x0fSandboxResponse\x129\n" + + "\asandbox\x18\x01 \x01(\v2\x1f.openshell.datamodel.v1.SandboxR\asandbox\"V\n" + + "\x15ListSandboxesResponse\x12=\n" + + "\tsandboxes\x18\x01 \x03(\v2\x1f.openshell.datamodel.v1.SandboxR\tsandboxes\"1\n" + + "\x15DeleteSandboxResponse\x12\x18\n" + + "\adeleted\x18\x01 \x01(\bR\adeleted\"8\n" + + "\x17CreateSshSessionRequest\x12\x1d\n" + + "\n" + + "sandbox_id\x18\x01 \x01(\tR\tsandboxId\"\xb5\x02\n" + + "\x18CreateSshSessionResponse\x12\x1d\n" + + "\n" + + "sandbox_id\x18\x01 \x01(\tR\tsandboxId\x12\x14\n" + + "\x05token\x18\x02 \x01(\tR\x05token\x12!\n" + + "\fgateway_host\x18\x03 \x01(\tR\vgatewayHost\x12!\n" + + "\fgateway_port\x18\x04 \x01(\rR\vgatewayPort\x12%\n" + + "\x0egateway_scheme\x18\x05 \x01(\tR\rgatewayScheme\x12!\n" + + "\fconnect_path\x18\x06 \x01(\tR\vconnectPath\x120\n" + + "\x14host_key_fingerprint\x18\a \x01(\tR\x12hostKeyFingerprint\x12\"\n" + + "\rexpires_at_ms\x18\b \x01(\x03R\vexpiresAtMs\"/\n" + + "\x17RevokeSshSessionRequest\x12\x14\n" + + "\x05token\x18\x01 \x01(\tR\x05token\"4\n" + + "\x18RevokeSshSessionResponse\x12\x18\n" + + "\arevoked\x18\x01 \x01(\bR\arevoked\"\xbb\x02\n" + + "\x12ExecSandboxRequest\x12\x1d\n" + + "\n" + + "sandbox_id\x18\x01 \x01(\tR\tsandboxId\x12\x18\n" + + "\acommand\x18\x02 \x03(\tR\acommand\x12\x18\n" + + "\aworkdir\x18\x03 \x01(\tR\aworkdir\x12S\n" + + "\venvironment\x18\x04 \x03(\v21.openshell.v1.ExecSandboxRequest.EnvironmentEntryR\venvironment\x12'\n" + + "\x0ftimeout_seconds\x18\x05 \x01(\rR\x0etimeoutSeconds\x12\x14\n" + + "\x05stdin\x18\x06 \x01(\fR\x05stdin\x1a>\n" + + "\x10EnvironmentEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"'\n" + + "\x11ExecSandboxStdout\x12\x12\n" + + "\x04data\x18\x01 \x01(\fR\x04data\"'\n" + + "\x11ExecSandboxStderr\x12\x12\n" + + "\x04data\x18\x01 \x01(\fR\x04data\".\n" + + "\x0fExecSandboxExit\x12\x1b\n" + + "\texit_code\x18\x01 \x01(\x05R\bexitCode\"\xc8\x01\n" + + "\x10ExecSandboxEvent\x129\n" + + "\x06stdout\x18\x01 \x01(\v2\x1f.openshell.v1.ExecSandboxStdoutH\x00R\x06stdout\x129\n" + + "\x06stderr\x18\x02 \x01(\v2\x1f.openshell.v1.ExecSandboxStderrH\x00R\x06stderr\x123\n" + + "\x04exit\x18\x03 \x01(\v2\x1d.openshell.v1.ExecSandboxExitH\x00R\x04exitB\t\n" + + "\apayload\"\xc7\x01\n" + + "\n" + + "SshSession\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x1d\n" + + "\n" + + "sandbox_id\x18\x02 \x01(\tR\tsandboxId\x12\x14\n" + + "\x05token\x18\x03 \x01(\tR\x05token\x12\"\n" + + "\rcreated_at_ms\x18\x04 \x01(\x03R\vcreatedAtMs\x12\x18\n" + + "\arevoked\x18\x05 \x01(\bR\arevoked\x12\x12\n" + + "\x04name\x18\x06 \x01(\tR\x04name\x12\"\n" + + "\rexpires_at_ms\x18\a \x01(\x03R\vexpiresAtMs\"\xe6\x02\n" + + "\x13WatchSandboxRequest\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12#\n" + + "\rfollow_status\x18\x02 \x01(\bR\ffollowStatus\x12\x1f\n" + + "\vfollow_logs\x18\x03 \x01(\bR\n" + + "followLogs\x12#\n" + + "\rfollow_events\x18\x04 \x01(\bR\ffollowEvents\x12$\n" + + "\x0elog_tail_lines\x18\x05 \x01(\rR\flogTailLines\x12\x1d\n" + + "\n" + + "event_tail\x18\x06 \x01(\rR\teventTail\x12(\n" + + "\x10stop_on_terminal\x18\a \x01(\bR\x0estopOnTerminal\x12 \n" + + "\flog_since_ms\x18\b \x01(\x03R\n" + + "logSinceMs\x12\x1f\n" + + "\vlog_sources\x18\t \x03(\tR\n" + + "logSources\x12\"\n" + + "\rlog_min_level\x18\n" + + " \x01(\tR\vlogMinLevel\"\xd6\x02\n" + + "\x12SandboxStreamEvent\x12;\n" + + "\asandbox\x18\x01 \x01(\v2\x1f.openshell.datamodel.v1.SandboxH\x00R\asandbox\x120\n" + + "\x03log\x18\x02 \x01(\v2\x1c.openshell.v1.SandboxLogLineH\x00R\x03log\x123\n" + + "\x05event\x18\x03 \x01(\v2\x1b.openshell.v1.PlatformEventH\x00R\x05event\x12>\n" + + "\awarning\x18\x04 \x01(\v2\".openshell.v1.SandboxStreamWarningH\x00R\awarning\x12Q\n" + + "\x13draft_policy_update\x18\x05 \x01(\v2\x1f.openshell.v1.DraftPolicyUpdateH\x00R\x11draftPolicyUpdateB\t\n" + + "\apayload\"\xaf\x02\n" + + "\x0eSandboxLogLine\x12\x1d\n" + + "\n" + + "sandbox_id\x18\x01 \x01(\tR\tsandboxId\x12!\n" + + "\ftimestamp_ms\x18\x02 \x01(\x03R\vtimestampMs\x12\x14\n" + + "\x05level\x18\x03 \x01(\tR\x05level\x12\x16\n" + + "\x06target\x18\x04 \x01(\tR\x06target\x12\x18\n" + + "\amessage\x18\x05 \x01(\tR\amessage\x12\x16\n" + + "\x06source\x18\x06 \x01(\tR\x06source\x12@\n" + + "\x06fields\x18\a \x03(\v2(.openshell.v1.SandboxLogLine.FieldsEntryR\x06fields\x1a9\n" + + "\vFieldsEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\x94\x02\n" + + "\rPlatformEvent\x12!\n" + + "\ftimestamp_ms\x18\x01 \x01(\x03R\vtimestampMs\x12\x16\n" + + "\x06source\x18\x02 \x01(\tR\x06source\x12\x12\n" + + "\x04type\x18\x03 \x01(\tR\x04type\x12\x16\n" + + "\x06reason\x18\x04 \x01(\tR\x06reason\x12\x18\n" + + "\amessage\x18\x05 \x01(\tR\amessage\x12E\n" + + "\bmetadata\x18\x06 \x03(\v2).openshell.v1.PlatformEvent.MetadataEntryR\bmetadata\x1a;\n" + + "\rMetadataEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"0\n" + + "\x14SandboxStreamWarning\x12\x18\n" + + "\amessage\x18\x01 \x01(\tR\amessage\"U\n" + + "\x15CreateProviderRequest\x12<\n" + + "\bprovider\x18\x01 \x01(\v2 .openshell.datamodel.v1.ProviderR\bprovider\"(\n" + + "\x12GetProviderRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\"D\n" + + "\x14ListProvidersRequest\x12\x14\n" + + "\x05limit\x18\x01 \x01(\rR\x05limit\x12\x16\n" + + "\x06offset\x18\x02 \x01(\rR\x06offset\"U\n" + + "\x15UpdateProviderRequest\x12<\n" + + "\bprovider\x18\x01 \x01(\v2 .openshell.datamodel.v1.ProviderR\bprovider\"+\n" + + "\x15DeleteProviderRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\"P\n" + + "\x10ProviderResponse\x12<\n" + + "\bprovider\x18\x01 \x01(\v2 .openshell.datamodel.v1.ProviderR\bprovider\"W\n" + + "\x15ListProvidersResponse\x12>\n" + + "\tproviders\x18\x01 \x03(\v2 .openshell.datamodel.v1.ProviderR\tproviders\"2\n" + + "\x16DeleteProviderResponse\x12\x18\n" + + "\adeleted\x18\x01 \x01(\bR\adeleted\"E\n" + + "$GetSandboxProviderEnvironmentRequest\x12\x1d\n" + + "\n" + + "sandbox_id\x18\x01 \x01(\tR\tsandboxId\"\xcf\x01\n" + + "%GetSandboxProviderEnvironmentResponse\x12f\n" + + "\venvironment\x18\x01 \x03(\v2D.openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntryR\venvironment\x1a>\n" + + "\x10EnvironmentEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"m\n" + + "\x1aUpdateSandboxPolicyRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12;\n" + + "\x06policy\x18\x02 \x01(\v2#.openshell.sandbox.v1.SandboxPolicyR\x06policy\"X\n" + + "\x1bUpdateSandboxPolicyResponse\x12\x18\n" + + "\aversion\x18\x01 \x01(\rR\aversion\x12\x1f\n" + + "\vpolicy_hash\x18\x02 \x01(\tR\n" + + "policyHash\"M\n" + + "\x1dGetSandboxPolicyStatusRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x18\n" + + "\aversion\x18\x02 \x01(\rR\aversion\"\x88\x01\n" + + "\x1eGetSandboxPolicyStatusResponse\x12?\n" + + "\brevision\x18\x01 \x01(\v2#.openshell.v1.SandboxPolicyRevisionR\brevision\x12%\n" + + "\x0eactive_version\x18\x02 \x01(\rR\ractiveVersion\"^\n" + + "\x1aListSandboxPoliciesRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x14\n" + + "\x05limit\x18\x02 \x01(\rR\x05limit\x12\x16\n" + + "\x06offset\x18\x03 \x01(\rR\x06offset\"`\n" + + "\x1bListSandboxPoliciesResponse\x12A\n" + + "\trevisions\x18\x01 \x03(\v2#.openshell.v1.SandboxPolicyRevisionR\trevisions\"\xa7\x01\n" + + "\x19ReportPolicyStatusRequest\x12\x1d\n" + + "\n" + + "sandbox_id\x18\x01 \x01(\tR\tsandboxId\x12\x18\n" + + "\aversion\x18\x02 \x01(\rR\aversion\x122\n" + + "\x06status\x18\x03 \x01(\x0e2\x1a.openshell.v1.PolicyStatusR\x06status\x12\x1d\n" + + "\n" + + "load_error\x18\x04 \x01(\tR\tloadError\"\x1c\n" + + "\x1aReportPolicyStatusResponse\"\xa8\x02\n" + + "\x15SandboxPolicyRevision\x12\x18\n" + + "\aversion\x18\x01 \x01(\rR\aversion\x12\x1f\n" + + "\vpolicy_hash\x18\x02 \x01(\tR\n" + + "policyHash\x122\n" + + "\x06status\x18\x03 \x01(\x0e2\x1a.openshell.v1.PolicyStatusR\x06status\x12\x1d\n" + + "\n" + + "load_error\x18\x04 \x01(\tR\tloadError\x12\"\n" + + "\rcreated_at_ms\x18\x05 \x01(\x03R\vcreatedAtMs\x12 \n" + + "\floaded_at_ms\x18\x06 \x01(\x03R\n" + + "loadedAtMs\x12;\n" + + "\x06policy\x18\a \x01(\v2#.openshell.sandbox.v1.SandboxPolicyR\x06policy\"\x9e\x01\n" + + "\x15GetSandboxLogsRequest\x12\x1d\n" + + "\n" + + "sandbox_id\x18\x01 \x01(\tR\tsandboxId\x12\x14\n" + + "\x05lines\x18\x02 \x01(\rR\x05lines\x12\x19\n" + + "\bsince_ms\x18\x03 \x01(\x03R\asinceMs\x12\x18\n" + + "\asources\x18\x04 \x03(\tR\asources\x12\x1b\n" + + "\tmin_level\x18\x05 \x01(\tR\bminLevel\"i\n" + + "\x16PushSandboxLogsRequest\x12\x1d\n" + + "\n" + + "sandbox_id\x18\x01 \x01(\tR\tsandboxId\x120\n" + + "\x04logs\x18\x02 \x03(\v2\x1c.openshell.v1.SandboxLogLineR\x04logs\"\x19\n" + + "\x17PushSandboxLogsResponse\"m\n" + + "\x16GetSandboxLogsResponse\x120\n" + + "\x04logs\x18\x01 \x03(\v2\x1c.openshell.v1.SandboxLogLineR\x04logs\x12!\n" + + "\fbuffer_total\x18\x02 \x01(\rR\vbufferTotal\"o\n" + + "\x0fL7RequestSample\x12\x16\n" + + "\x06method\x18\x01 \x01(\tR\x06method\x12\x12\n" + + "\x04path\x18\x02 \x01(\tR\x04path\x12\x1a\n" + + "\bdecision\x18\x03 \x01(\tR\bdecision\x12\x14\n" + + "\x05count\x18\x04 \x01(\rR\x05count\"\xe5\x04\n" + + "\rDenialSummary\x12\x1d\n" + + "\n" + + "sandbox_id\x18\x01 \x01(\tR\tsandboxId\x12\x12\n" + + "\x04host\x18\x02 \x01(\tR\x04host\x12\x12\n" + + "\x04port\x18\x03 \x01(\rR\x04port\x12\x16\n" + + "\x06binary\x18\x04 \x01(\tR\x06binary\x12\x1c\n" + + "\tancestors\x18\x05 \x03(\tR\tancestors\x12\x1f\n" + + "\vdeny_reason\x18\x06 \x01(\tR\n" + + "denyReason\x12\"\n" + + "\rfirst_seen_ms\x18\a \x01(\x03R\vfirstSeenMs\x12 \n" + + "\flast_seen_ms\x18\b \x01(\x03R\n" + + "lastSeenMs\x12\x14\n" + + "\x05count\x18\t \x01(\rR\x05count\x12)\n" + + "\x10suppressed_count\x18\n" + + " \x01(\rR\x0fsuppressedCount\x12\x1f\n" + + "\vtotal_count\x18\v \x01(\rR\n" + + "totalCount\x12'\n" + + "\x0fsample_cmdlines\x18\f \x03(\tR\x0esampleCmdlines\x12#\n" + + "\rbinary_sha256\x18\r \x01(\tR\fbinarySha256\x12\x1e\n" + + "\n" + + "persistent\x18\x0e \x01(\bR\n" + + "persistent\x12!\n" + + "\fdenial_stage\x18\x0f \x01(\tR\vdenialStage\x12K\n" + + "\x12l7_request_samples\x18\x10 \x03(\v2\x1d.openshell.v1.L7RequestSampleR\x10l7RequestSamples\x120\n" + + "\x14l7_inspection_active\x18\x11 \x01(\bR\x12l7InspectionActive\"\xbc\x04\n" + + "\vPolicyChunk\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x16\n" + + "\x06status\x18\x02 \x01(\tR\x06status\x12\x1b\n" + + "\trule_name\x18\x03 \x01(\tR\bruleName\x12L\n" + + "\rproposed_rule\x18\x04 \x01(\v2'.openshell.sandbox.v1.NetworkPolicyRuleR\fproposedRule\x12\x1c\n" + + "\trationale\x18\x05 \x01(\tR\trationale\x12%\n" + + "\x0esecurity_notes\x18\x06 \x01(\tR\rsecurityNotes\x12\x1e\n" + + "\n" + + "confidence\x18\a \x01(\x02R\n" + + "confidence\x12,\n" + + "\x12denial_summary_ids\x18\b \x03(\tR\x10denialSummaryIds\x12\"\n" + + "\rcreated_at_ms\x18\t \x01(\x03R\vcreatedAtMs\x12\"\n" + + "\rdecided_at_ms\x18\n" + + " \x01(\x03R\vdecidedAtMs\x12\x14\n" + + "\x05stage\x18\v \x01(\tR\x05stage\x12.\n" + + "\x13supersedes_chunk_id\x18\f \x01(\tR\x11supersedesChunkId\x12\x1b\n" + + "\thit_count\x18\r \x01(\x05R\bhitCount\x12\"\n" + + "\rfirst_seen_ms\x18\x0e \x01(\x03R\vfirstSeenMs\x12 \n" + + "\flast_seen_ms\x18\x0f \x01(\x03R\n" + + "lastSeenMs\x12\x16\n" + + "\x06binary\x18\x10 \x01(\tR\x06binary\"\x96\x01\n" + + "\x11DraftPolicyUpdate\x12#\n" + + "\rdraft_version\x18\x01 \x01(\x04R\fdraftVersion\x12\x1d\n" + + "\n" + + "new_chunks\x18\x02 \x01(\rR\tnewChunks\x12#\n" + + "\rtotal_pending\x18\x03 \x01(\rR\ftotalPending\x12\x18\n" + + "\asummary\x18\x04 \x01(\tR\asummary\"\xd5\x01\n" + + "\x1bSubmitPolicyAnalysisRequest\x129\n" + + "\tsummaries\x18\x01 \x03(\v2\x1b.openshell.v1.DenialSummaryR\tsummaries\x12B\n" + + "\x0fproposed_chunks\x18\x02 \x03(\v2\x19.openshell.v1.PolicyChunkR\x0eproposedChunks\x12#\n" + + "\ranalysis_mode\x18\x03 \x01(\tR\fanalysisMode\x12\x12\n" + + "\x04name\x18\x04 \x01(\tR\x04name\"\x9d\x01\n" + + "\x1cSubmitPolicyAnalysisResponse\x12'\n" + + "\x0faccepted_chunks\x18\x01 \x01(\rR\x0eacceptedChunks\x12'\n" + + "\x0frejected_chunks\x18\x02 \x01(\rR\x0erejectedChunks\x12+\n" + + "\x11rejection_reasons\x18\x03 \x03(\tR\x10rejectionReasons\"P\n" + + "\x15GetDraftPolicyRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12#\n" + + "\rstatus_filter\x18\x02 \x01(\tR\fstatusFilter\"\xc8\x01\n" + + "\x16GetDraftPolicyResponse\x121\n" + + "\x06chunks\x18\x01 \x03(\v2\x19.openshell.v1.PolicyChunkR\x06chunks\x12'\n" + + "\x0frolling_summary\x18\x02 \x01(\tR\x0erollingSummary\x12#\n" + + "\rdraft_version\x18\x03 \x01(\x04R\fdraftVersion\x12-\n" + + "\x13last_analyzed_at_ms\x18\x04 \x01(\x03R\x10lastAnalyzedAtMs\"I\n" + + "\x18ApproveDraftChunkRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x19\n" + + "\bchunk_id\x18\x02 \x01(\tR\achunkId\"c\n" + + "\x19ApproveDraftChunkResponse\x12%\n" + + "\x0epolicy_version\x18\x01 \x01(\rR\rpolicyVersion\x12\x1f\n" + + "\vpolicy_hash\x18\x02 \x01(\tR\n" + + "policyHash\"`\n" + + "\x17RejectDraftChunkRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x19\n" + + "\bchunk_id\x18\x02 \x01(\tR\achunkId\x12\x16\n" + + "\x06reason\x18\x03 \x01(\tR\x06reason\"\x1a\n" + + "\x18RejectDraftChunkResponse\"l\n" + + "\x1cApproveAllDraftChunksRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x128\n" + + "\x18include_security_flagged\x18\x02 \x01(\bR\x16includeSecurityFlagged\"\xb7\x01\n" + + "\x1dApproveAllDraftChunksResponse\x12%\n" + + "\x0epolicy_version\x18\x01 \x01(\rR\rpolicyVersion\x12\x1f\n" + + "\vpolicy_hash\x18\x02 \x01(\tR\n" + + "policyHash\x12'\n" + + "\x0fchunks_approved\x18\x03 \x01(\rR\x0echunksApproved\x12%\n" + + "\x0echunks_skipped\x18\x04 \x01(\rR\rchunksSkipped\"\x94\x01\n" + + "\x15EditDraftChunkRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x19\n" + + "\bchunk_id\x18\x02 \x01(\tR\achunkId\x12L\n" + + "\rproposed_rule\x18\x03 \x01(\v2'.openshell.sandbox.v1.NetworkPolicyRuleR\fproposedRule\"\x18\n" + + "\x16EditDraftChunkResponse\"F\n" + + "\x15UndoDraftChunkRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x19\n" + + "\bchunk_id\x18\x02 \x01(\tR\achunkId\"`\n" + + "\x16UndoDraftChunkResponse\x12%\n" + + "\x0epolicy_version\x18\x01 \x01(\rR\rpolicyVersion\x12\x1f\n" + + "\vpolicy_hash\x18\x02 \x01(\tR\n" + + "policyHash\"-\n" + + "\x17ClearDraftChunksRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\"A\n" + + "\x18ClearDraftChunksResponse\x12%\n" + + "\x0echunks_cleared\x18\x01 \x01(\rR\rchunksCleared\",\n" + + "\x16GetDraftHistoryRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\"\x92\x01\n" + + "\x11DraftHistoryEntry\x12!\n" + + "\ftimestamp_ms\x18\x01 \x01(\x03R\vtimestampMs\x12\x1d\n" + + "\n" + + "event_type\x18\x02 \x01(\tR\teventType\x12 \n" + + "\vdescription\x18\x03 \x01(\tR\vdescription\x12\x19\n" + + "\bchunk_id\x18\x04 \x01(\tR\achunkId\"T\n" + + "\x17GetDraftHistoryResponse\x129\n" + + "\aentries\x18\x01 \x03(\v2\x1f.openshell.v1.DraftHistoryEntryR\aentries*\x9a\x01\n" + + "\fPolicyStatus\x12\x1d\n" + + "\x19POLICY_STATUS_UNSPECIFIED\x10\x00\x12\x19\n" + + "\x15POLICY_STATUS_PENDING\x10\x01\x12\x18\n" + + "\x14POLICY_STATUS_LOADED\x10\x02\x12\x18\n" + + "\x14POLICY_STATUS_FAILED\x10\x03\x12\x1c\n" + + "\x18POLICY_STATUS_SUPERSEDED\x10\x04*\x86\x01\n" + + "\rServiceStatus\x12\x1e\n" + + "\x1aSERVICE_STATUS_UNSPECIFIED\x10\x00\x12\x1a\n" + + "\x16SERVICE_STATUS_HEALTHY\x10\x01\x12\x1b\n" + + "\x17SERVICE_STATUS_DEGRADED\x10\x02\x12\x1c\n" + + "\x18SERVICE_STATUS_UNHEALTHY\x10\x032\xc3\x17\n" + + "\tOpenShell\x12C\n" + + "\x06Health\x12\x1b.openshell.v1.HealthRequest\x1a\x1c.openshell.v1.HealthResponse\x12R\n" + + "\rCreateSandbox\x12\".openshell.v1.CreateSandboxRequest\x1a\x1d.openshell.v1.SandboxResponse\x12L\n" + + "\n" + + "GetSandbox\x12\x1f.openshell.v1.GetSandboxRequest\x1a\x1d.openshell.v1.SandboxResponse\x12X\n" + + "\rListSandboxes\x12\".openshell.v1.ListSandboxesRequest\x1a#.openshell.v1.ListSandboxesResponse\x12X\n" + + "\rDeleteSandbox\x12\".openshell.v1.DeleteSandboxRequest\x1a#.openshell.v1.DeleteSandboxResponse\x12a\n" + + "\x10CreateSshSession\x12%.openshell.v1.CreateSshSessionRequest\x1a&.openshell.v1.CreateSshSessionResponse\x12a\n" + + "\x10RevokeSshSession\x12%.openshell.v1.RevokeSshSessionRequest\x1a&.openshell.v1.RevokeSshSessionResponse\x12Q\n" + + "\vExecSandbox\x12 .openshell.v1.ExecSandboxRequest\x1a\x1e.openshell.v1.ExecSandboxEvent0\x01\x12U\n" + + "\x0eCreateProvider\x12#.openshell.v1.CreateProviderRequest\x1a\x1e.openshell.v1.ProviderResponse\x12O\n" + + "\vGetProvider\x12 .openshell.v1.GetProviderRequest\x1a\x1e.openshell.v1.ProviderResponse\x12X\n" + + "\rListProviders\x12\".openshell.v1.ListProvidersRequest\x1a#.openshell.v1.ListProvidersResponse\x12U\n" + + "\x0eUpdateProvider\x12#.openshell.v1.UpdateProviderRequest\x1a\x1e.openshell.v1.ProviderResponse\x12[\n" + + "\x0eDeleteProvider\x12#.openshell.v1.DeleteProviderRequest\x1a$.openshell.v1.DeleteProviderResponse\x12q\n" + + "\x10GetSandboxPolicy\x12-.openshell.sandbox.v1.GetSandboxPolicyRequest\x1a..openshell.sandbox.v1.GetSandboxPolicyResponse\x12j\n" + + "\x13UpdateSandboxPolicy\x12(.openshell.v1.UpdateSandboxPolicyRequest\x1a).openshell.v1.UpdateSandboxPolicyResponse\x12s\n" + + "\x16GetSandboxPolicyStatus\x12+.openshell.v1.GetSandboxPolicyStatusRequest\x1a,.openshell.v1.GetSandboxPolicyStatusResponse\x12j\n" + + "\x13ListSandboxPolicies\x12(.openshell.v1.ListSandboxPoliciesRequest\x1a).openshell.v1.ListSandboxPoliciesResponse\x12g\n" + + "\x12ReportPolicyStatus\x12'.openshell.v1.ReportPolicyStatusRequest\x1a(.openshell.v1.ReportPolicyStatusResponse\x12\x88\x01\n" + + "\x1dGetSandboxProviderEnvironment\x122.openshell.v1.GetSandboxProviderEnvironmentRequest\x1a3.openshell.v1.GetSandboxProviderEnvironmentResponse\x12[\n" + + "\x0eGetSandboxLogs\x12#.openshell.v1.GetSandboxLogsRequest\x1a$.openshell.v1.GetSandboxLogsResponse\x12`\n" + + "\x0fPushSandboxLogs\x12$.openshell.v1.PushSandboxLogsRequest\x1a%.openshell.v1.PushSandboxLogsResponse(\x01\x12U\n" + + "\fWatchSandbox\x12!.openshell.v1.WatchSandboxRequest\x1a .openshell.v1.SandboxStreamEvent0\x01\x12m\n" + + "\x14SubmitPolicyAnalysis\x12).openshell.v1.SubmitPolicyAnalysisRequest\x1a*.openshell.v1.SubmitPolicyAnalysisResponse\x12[\n" + + "\x0eGetDraftPolicy\x12#.openshell.v1.GetDraftPolicyRequest\x1a$.openshell.v1.GetDraftPolicyResponse\x12d\n" + + "\x11ApproveDraftChunk\x12&.openshell.v1.ApproveDraftChunkRequest\x1a'.openshell.v1.ApproveDraftChunkResponse\x12a\n" + + "\x10RejectDraftChunk\x12%.openshell.v1.RejectDraftChunkRequest\x1a&.openshell.v1.RejectDraftChunkResponse\x12p\n" + + "\x15ApproveAllDraftChunks\x12*.openshell.v1.ApproveAllDraftChunksRequest\x1a+.openshell.v1.ApproveAllDraftChunksResponse\x12[\n" + + "\x0eEditDraftChunk\x12#.openshell.v1.EditDraftChunkRequest\x1a$.openshell.v1.EditDraftChunkResponse\x12[\n" + + "\x0eUndoDraftChunk\x12#.openshell.v1.UndoDraftChunkRequest\x1a$.openshell.v1.UndoDraftChunkResponse\x12a\n" + + "\x10ClearDraftChunks\x12%.openshell.v1.ClearDraftChunksRequest\x1a&.openshell.v1.ClearDraftChunksResponse\x12^\n" + + "\x0fGetDraftHistory\x12$.openshell.v1.GetDraftHistoryRequest\x1a%.openshell.v1.GetDraftHistoryResponseB\x1e\n" + + "\x1acom.anthropic.openshell.v1P\x01b\x06proto3" + +var ( + file_openshell_proto_rawDescOnce sync.Once + file_openshell_proto_rawDescData []byte +) + +func file_openshell_proto_rawDescGZIP() []byte { + file_openshell_proto_rawDescOnce.Do(func() { + file_openshell_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_openshell_proto_rawDesc), len(file_openshell_proto_rawDesc))) + }) + return file_openshell_proto_rawDescData +} + +var file_openshell_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 74) +var file_openshell_proto_goTypes = []any{ + (PolicyStatus)(0), // 0: openshell.v1.PolicyStatus + (ServiceStatus)(0), // 1: openshell.v1.ServiceStatus + (*HealthRequest)(nil), // 2: openshell.v1.HealthRequest + (*HealthResponse)(nil), // 3: openshell.v1.HealthResponse + (*CreateSandboxRequest)(nil), // 4: openshell.v1.CreateSandboxRequest + (*GetSandboxRequest)(nil), // 5: openshell.v1.GetSandboxRequest + (*ListSandboxesRequest)(nil), // 6: openshell.v1.ListSandboxesRequest + (*DeleteSandboxRequest)(nil), // 7: openshell.v1.DeleteSandboxRequest + (*SandboxResponse)(nil), // 8: openshell.v1.SandboxResponse + (*ListSandboxesResponse)(nil), // 9: openshell.v1.ListSandboxesResponse + (*DeleteSandboxResponse)(nil), // 10: openshell.v1.DeleteSandboxResponse + (*CreateSshSessionRequest)(nil), // 11: openshell.v1.CreateSshSessionRequest + (*CreateSshSessionResponse)(nil), // 12: openshell.v1.CreateSshSessionResponse + (*RevokeSshSessionRequest)(nil), // 13: openshell.v1.RevokeSshSessionRequest + (*RevokeSshSessionResponse)(nil), // 14: openshell.v1.RevokeSshSessionResponse + (*ExecSandboxRequest)(nil), // 15: openshell.v1.ExecSandboxRequest + (*ExecSandboxStdout)(nil), // 16: openshell.v1.ExecSandboxStdout + (*ExecSandboxStderr)(nil), // 17: openshell.v1.ExecSandboxStderr + (*ExecSandboxExit)(nil), // 18: openshell.v1.ExecSandboxExit + (*ExecSandboxEvent)(nil), // 19: openshell.v1.ExecSandboxEvent + (*SshSession)(nil), // 20: openshell.v1.SshSession + (*WatchSandboxRequest)(nil), // 21: openshell.v1.WatchSandboxRequest + (*SandboxStreamEvent)(nil), // 22: openshell.v1.SandboxStreamEvent + (*SandboxLogLine)(nil), // 23: openshell.v1.SandboxLogLine + (*PlatformEvent)(nil), // 24: openshell.v1.PlatformEvent + (*SandboxStreamWarning)(nil), // 25: openshell.v1.SandboxStreamWarning + (*CreateProviderRequest)(nil), // 26: openshell.v1.CreateProviderRequest + (*GetProviderRequest)(nil), // 27: openshell.v1.GetProviderRequest + (*ListProvidersRequest)(nil), // 28: openshell.v1.ListProvidersRequest + (*UpdateProviderRequest)(nil), // 29: openshell.v1.UpdateProviderRequest + (*DeleteProviderRequest)(nil), // 30: openshell.v1.DeleteProviderRequest + (*ProviderResponse)(nil), // 31: openshell.v1.ProviderResponse + (*ListProvidersResponse)(nil), // 32: openshell.v1.ListProvidersResponse + (*DeleteProviderResponse)(nil), // 33: openshell.v1.DeleteProviderResponse + (*GetSandboxProviderEnvironmentRequest)(nil), // 34: openshell.v1.GetSandboxProviderEnvironmentRequest + (*GetSandboxProviderEnvironmentResponse)(nil), // 35: openshell.v1.GetSandboxProviderEnvironmentResponse + (*UpdateSandboxPolicyRequest)(nil), // 36: openshell.v1.UpdateSandboxPolicyRequest + (*UpdateSandboxPolicyResponse)(nil), // 37: openshell.v1.UpdateSandboxPolicyResponse + (*GetSandboxPolicyStatusRequest)(nil), // 38: openshell.v1.GetSandboxPolicyStatusRequest + (*GetSandboxPolicyStatusResponse)(nil), // 39: openshell.v1.GetSandboxPolicyStatusResponse + (*ListSandboxPoliciesRequest)(nil), // 40: openshell.v1.ListSandboxPoliciesRequest + (*ListSandboxPoliciesResponse)(nil), // 41: openshell.v1.ListSandboxPoliciesResponse + (*ReportPolicyStatusRequest)(nil), // 42: openshell.v1.ReportPolicyStatusRequest + (*ReportPolicyStatusResponse)(nil), // 43: openshell.v1.ReportPolicyStatusResponse + (*SandboxPolicyRevision)(nil), // 44: openshell.v1.SandboxPolicyRevision + (*GetSandboxLogsRequest)(nil), // 45: openshell.v1.GetSandboxLogsRequest + (*PushSandboxLogsRequest)(nil), // 46: openshell.v1.PushSandboxLogsRequest + (*PushSandboxLogsResponse)(nil), // 47: openshell.v1.PushSandboxLogsResponse + (*GetSandboxLogsResponse)(nil), // 48: openshell.v1.GetSandboxLogsResponse + (*L7RequestSample)(nil), // 49: openshell.v1.L7RequestSample + (*DenialSummary)(nil), // 50: openshell.v1.DenialSummary + (*PolicyChunk)(nil), // 51: openshell.v1.PolicyChunk + (*DraftPolicyUpdate)(nil), // 52: openshell.v1.DraftPolicyUpdate + (*SubmitPolicyAnalysisRequest)(nil), // 53: openshell.v1.SubmitPolicyAnalysisRequest + (*SubmitPolicyAnalysisResponse)(nil), // 54: openshell.v1.SubmitPolicyAnalysisResponse + (*GetDraftPolicyRequest)(nil), // 55: openshell.v1.GetDraftPolicyRequest + (*GetDraftPolicyResponse)(nil), // 56: openshell.v1.GetDraftPolicyResponse + (*ApproveDraftChunkRequest)(nil), // 57: openshell.v1.ApproveDraftChunkRequest + (*ApproveDraftChunkResponse)(nil), // 58: openshell.v1.ApproveDraftChunkResponse + (*RejectDraftChunkRequest)(nil), // 59: openshell.v1.RejectDraftChunkRequest + (*RejectDraftChunkResponse)(nil), // 60: openshell.v1.RejectDraftChunkResponse + (*ApproveAllDraftChunksRequest)(nil), // 61: openshell.v1.ApproveAllDraftChunksRequest + (*ApproveAllDraftChunksResponse)(nil), // 62: openshell.v1.ApproveAllDraftChunksResponse + (*EditDraftChunkRequest)(nil), // 63: openshell.v1.EditDraftChunkRequest + (*EditDraftChunkResponse)(nil), // 64: openshell.v1.EditDraftChunkResponse + (*UndoDraftChunkRequest)(nil), // 65: openshell.v1.UndoDraftChunkRequest + (*UndoDraftChunkResponse)(nil), // 66: openshell.v1.UndoDraftChunkResponse + (*ClearDraftChunksRequest)(nil), // 67: openshell.v1.ClearDraftChunksRequest + (*ClearDraftChunksResponse)(nil), // 68: openshell.v1.ClearDraftChunksResponse + (*GetDraftHistoryRequest)(nil), // 69: openshell.v1.GetDraftHistoryRequest + (*DraftHistoryEntry)(nil), // 70: openshell.v1.DraftHistoryEntry + (*GetDraftHistoryResponse)(nil), // 71: openshell.v1.GetDraftHistoryResponse + nil, // 72: openshell.v1.ExecSandboxRequest.EnvironmentEntry + nil, // 73: openshell.v1.SandboxLogLine.FieldsEntry + nil, // 74: openshell.v1.PlatformEvent.MetadataEntry + nil, // 75: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + (*SandboxSpec)(nil), // 76: openshell.datamodel.v1.SandboxSpec + (*Sandbox)(nil), // 77: openshell.datamodel.v1.Sandbox + (*Provider)(nil), // 78: openshell.datamodel.v1.Provider + (*SandboxPolicy)(nil), // 79: openshell.sandbox.v1.SandboxPolicy + (*NetworkPolicyRule)(nil), // 80: openshell.sandbox.v1.NetworkPolicyRule + (*GetSandboxPolicyRequest)(nil), // 81: openshell.sandbox.v1.GetSandboxPolicyRequest + (*GetSandboxPolicyResponse)(nil), // 82: openshell.sandbox.v1.GetSandboxPolicyResponse +} +var file_openshell_proto_depIdxs = []int32{ + 1, // 0: openshell.v1.HealthResponse.status:type_name -> openshell.v1.ServiceStatus + 76, // 1: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.datamodel.v1.SandboxSpec + 77, // 2: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.datamodel.v1.Sandbox + 77, // 3: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.datamodel.v1.Sandbox + 72, // 4: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry + 16, // 5: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout + 17, // 6: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr + 18, // 7: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit + 77, // 8: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.datamodel.v1.Sandbox + 23, // 9: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine + 24, // 10: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent + 25, // 11: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning + 52, // 12: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate + 73, // 13: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry + 74, // 14: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry + 78, // 15: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 78, // 16: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 78, // 17: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider + 78, // 18: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 75, // 19: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + 79, // 20: openshell.v1.UpdateSandboxPolicyRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 44, // 21: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision + 44, // 22: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision + 0, // 23: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus + 0, // 24: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus + 79, // 25: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 23, // 26: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine + 23, // 27: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine + 49, // 28: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample + 80, // 29: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 50, // 30: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary + 51, // 31: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk + 51, // 32: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk + 80, // 33: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 70, // 34: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry + 2, // 35: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest + 4, // 36: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest + 5, // 37: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest + 6, // 38: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest + 7, // 39: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest + 11, // 40: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest + 13, // 41: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest + 15, // 42: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest + 26, // 43: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest + 27, // 44: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest + 28, // 45: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest + 29, // 46: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest + 30, // 47: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest + 81, // 48: openshell.v1.OpenShell.GetSandboxPolicy:input_type -> openshell.sandbox.v1.GetSandboxPolicyRequest + 36, // 49: openshell.v1.OpenShell.UpdateSandboxPolicy:input_type -> openshell.v1.UpdateSandboxPolicyRequest + 38, // 50: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest + 40, // 51: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest + 42, // 52: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest + 34, // 53: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest + 45, // 54: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest + 46, // 55: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest + 21, // 56: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest + 53, // 57: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest + 55, // 58: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest + 57, // 59: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest + 59, // 60: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest + 61, // 61: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest + 63, // 62: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest + 65, // 63: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest + 67, // 64: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest + 69, // 65: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest + 3, // 66: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse + 8, // 67: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse + 8, // 68: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse + 9, // 69: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse + 10, // 70: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse + 12, // 71: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse + 14, // 72: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse + 19, // 73: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent + 31, // 74: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse + 31, // 75: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse + 32, // 76: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse + 31, // 77: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse + 33, // 78: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse + 82, // 79: openshell.v1.OpenShell.GetSandboxPolicy:output_type -> openshell.sandbox.v1.GetSandboxPolicyResponse + 37, // 80: openshell.v1.OpenShell.UpdateSandboxPolicy:output_type -> openshell.v1.UpdateSandboxPolicyResponse + 39, // 81: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse + 41, // 82: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse + 43, // 83: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse + 35, // 84: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse + 48, // 85: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse + 47, // 86: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse + 22, // 87: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent + 54, // 88: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse + 56, // 89: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse + 58, // 90: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse + 60, // 91: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse + 62, // 92: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse + 64, // 93: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse + 66, // 94: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse + 68, // 95: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse + 71, // 96: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse + 66, // [66:97] is the sub-list for method output_type + 35, // [35:66] is the sub-list for method input_type + 35, // [35:35] is the sub-list for extension type_name + 35, // [35:35] is the sub-list for extension extendee + 0, // [0:35] is the sub-list for field type_name +} + +func init() { file_openshell_proto_init() } +func file_openshell_proto_init() { + if File_openshell_proto != nil { + return + } + file_datamodel_proto_init() + file_sandbox_proto_init() + file_openshell_proto_msgTypes[17].OneofWrappers = []any{ + (*ExecSandboxEvent_Stdout)(nil), + (*ExecSandboxEvent_Stderr)(nil), + (*ExecSandboxEvent_Exit)(nil), + } + file_openshell_proto_msgTypes[20].OneofWrappers = []any{ + (*SandboxStreamEvent_Sandbox)(nil), + (*SandboxStreamEvent_Log)(nil), + (*SandboxStreamEvent_Event)(nil), + (*SandboxStreamEvent_Warning)(nil), + (*SandboxStreamEvent_DraftPolicyUpdate)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_openshell_proto_rawDesc), len(file_openshell_proto_rawDesc)), + NumEnums: 2, + NumMessages: 74, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_openshell_proto_goTypes, + DependencyIndexes: file_openshell_proto_depIdxs, + EnumInfos: file_openshell_proto_enumTypes, + MessageInfos: file_openshell_proto_msgTypes, + }.Build() + File_openshell_proto = out.File + file_openshell_proto_goTypes = nil + file_openshell_proto_depIdxs = nil +} diff --git a/internal/registry/platforms/openshell/proto/gen/openshell_grpc.pb.go b/internal/registry/platforms/openshell/proto/gen/openshell_grpc.pb.go new file mode 100644 index 00000000..3800b158 --- /dev/null +++ b/internal/registry/platforms/openshell/proto/gen/openshell_grpc.pb.go @@ -0,0 +1,1340 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.6.1 +// - protoc v7.34.0 +// source: openshell.proto + +package gen + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + OpenShell_Health_FullMethodName = "/openshell.v1.OpenShell/Health" + OpenShell_CreateSandbox_FullMethodName = "/openshell.v1.OpenShell/CreateSandbox" + OpenShell_GetSandbox_FullMethodName = "/openshell.v1.OpenShell/GetSandbox" + OpenShell_ListSandboxes_FullMethodName = "/openshell.v1.OpenShell/ListSandboxes" + OpenShell_DeleteSandbox_FullMethodName = "/openshell.v1.OpenShell/DeleteSandbox" + OpenShell_CreateSshSession_FullMethodName = "/openshell.v1.OpenShell/CreateSshSession" + OpenShell_RevokeSshSession_FullMethodName = "/openshell.v1.OpenShell/RevokeSshSession" + OpenShell_ExecSandbox_FullMethodName = "/openshell.v1.OpenShell/ExecSandbox" + OpenShell_CreateProvider_FullMethodName = "/openshell.v1.OpenShell/CreateProvider" + OpenShell_GetProvider_FullMethodName = "/openshell.v1.OpenShell/GetProvider" + OpenShell_ListProviders_FullMethodName = "/openshell.v1.OpenShell/ListProviders" + OpenShell_UpdateProvider_FullMethodName = "/openshell.v1.OpenShell/UpdateProvider" + OpenShell_DeleteProvider_FullMethodName = "/openshell.v1.OpenShell/DeleteProvider" + OpenShell_GetSandboxPolicy_FullMethodName = "/openshell.v1.OpenShell/GetSandboxPolicy" + OpenShell_UpdateSandboxPolicy_FullMethodName = "/openshell.v1.OpenShell/UpdateSandboxPolicy" + OpenShell_GetSandboxPolicyStatus_FullMethodName = "/openshell.v1.OpenShell/GetSandboxPolicyStatus" + OpenShell_ListSandboxPolicies_FullMethodName = "/openshell.v1.OpenShell/ListSandboxPolicies" + OpenShell_ReportPolicyStatus_FullMethodName = "/openshell.v1.OpenShell/ReportPolicyStatus" + OpenShell_GetSandboxProviderEnvironment_FullMethodName = "/openshell.v1.OpenShell/GetSandboxProviderEnvironment" + OpenShell_GetSandboxLogs_FullMethodName = "/openshell.v1.OpenShell/GetSandboxLogs" + OpenShell_PushSandboxLogs_FullMethodName = "/openshell.v1.OpenShell/PushSandboxLogs" + OpenShell_WatchSandbox_FullMethodName = "/openshell.v1.OpenShell/WatchSandbox" + OpenShell_SubmitPolicyAnalysis_FullMethodName = "/openshell.v1.OpenShell/SubmitPolicyAnalysis" + OpenShell_GetDraftPolicy_FullMethodName = "/openshell.v1.OpenShell/GetDraftPolicy" + OpenShell_ApproveDraftChunk_FullMethodName = "/openshell.v1.OpenShell/ApproveDraftChunk" + OpenShell_RejectDraftChunk_FullMethodName = "/openshell.v1.OpenShell/RejectDraftChunk" + OpenShell_ApproveAllDraftChunks_FullMethodName = "/openshell.v1.OpenShell/ApproveAllDraftChunks" + OpenShell_EditDraftChunk_FullMethodName = "/openshell.v1.OpenShell/EditDraftChunk" + OpenShell_UndoDraftChunk_FullMethodName = "/openshell.v1.OpenShell/UndoDraftChunk" + OpenShell_ClearDraftChunks_FullMethodName = "/openshell.v1.OpenShell/ClearDraftChunks" + OpenShell_GetDraftHistory_FullMethodName = "/openshell.v1.OpenShell/GetDraftHistory" +) + +// OpenShellClient is the client API for OpenShell service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// OpenShell service provides sandbox, provider, and runtime management capabilities. +type OpenShellClient interface { + // Check the health of the service. + Health(ctx context.Context, in *HealthRequest, opts ...grpc.CallOption) (*HealthResponse, error) + // Create a new sandbox. + CreateSandbox(ctx context.Context, in *CreateSandboxRequest, opts ...grpc.CallOption) (*SandboxResponse, error) + // Fetch a sandbox by name. + GetSandbox(ctx context.Context, in *GetSandboxRequest, opts ...grpc.CallOption) (*SandboxResponse, error) + // List sandboxes. + ListSandboxes(ctx context.Context, in *ListSandboxesRequest, opts ...grpc.CallOption) (*ListSandboxesResponse, error) + // Delete a sandbox by name. + DeleteSandbox(ctx context.Context, in *DeleteSandboxRequest, opts ...grpc.CallOption) (*DeleteSandboxResponse, error) + // Create a short-lived SSH session for a sandbox. + CreateSshSession(ctx context.Context, in *CreateSshSessionRequest, opts ...grpc.CallOption) (*CreateSshSessionResponse, error) + // Revoke a previously issued SSH session. + RevokeSshSession(ctx context.Context, in *RevokeSshSessionRequest, opts ...grpc.CallOption) (*RevokeSshSessionResponse, error) + // Execute a command in a ready sandbox and stream output. + ExecSandbox(ctx context.Context, in *ExecSandboxRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ExecSandboxEvent], error) + // Create a provider. + CreateProvider(ctx context.Context, in *CreateProviderRequest, opts ...grpc.CallOption) (*ProviderResponse, error) + // Fetch a provider by name. + GetProvider(ctx context.Context, in *GetProviderRequest, opts ...grpc.CallOption) (*ProviderResponse, error) + // List providers. + ListProviders(ctx context.Context, in *ListProvidersRequest, opts ...grpc.CallOption) (*ListProvidersResponse, error) + // Update an existing provider by name. + UpdateProvider(ctx context.Context, in *UpdateProviderRequest, opts ...grpc.CallOption) (*ProviderResponse, error) + // Delete a provider by name. + DeleteProvider(ctx context.Context, in *DeleteProviderRequest, opts ...grpc.CallOption) (*DeleteProviderResponse, error) + // Get sandbox policy by id (called by sandbox entrypoint and poll loop). + GetSandboxPolicy(ctx context.Context, in *GetSandboxPolicyRequest, opts ...grpc.CallOption) (*GetSandboxPolicyResponse, error) + // Update sandbox policy on a live sandbox. + UpdateSandboxPolicy(ctx context.Context, in *UpdateSandboxPolicyRequest, opts ...grpc.CallOption) (*UpdateSandboxPolicyResponse, error) + // Get the load status of a specific policy version. + GetSandboxPolicyStatus(ctx context.Context, in *GetSandboxPolicyStatusRequest, opts ...grpc.CallOption) (*GetSandboxPolicyStatusResponse, error) + // List policy history for a sandbox. + ListSandboxPolicies(ctx context.Context, in *ListSandboxPoliciesRequest, opts ...grpc.CallOption) (*ListSandboxPoliciesResponse, error) + // Report policy load result (called by sandbox after reload attempt). + ReportPolicyStatus(ctx context.Context, in *ReportPolicyStatusRequest, opts ...grpc.CallOption) (*ReportPolicyStatusResponse, error) + // Get provider environment for a sandbox (called by sandbox supervisor at startup). + GetSandboxProviderEnvironment(ctx context.Context, in *GetSandboxProviderEnvironmentRequest, opts ...grpc.CallOption) (*GetSandboxProviderEnvironmentResponse, error) + // Fetch recent sandbox logs (one-shot). + GetSandboxLogs(ctx context.Context, in *GetSandboxLogsRequest, opts ...grpc.CallOption) (*GetSandboxLogsResponse, error) + // Push sandbox supervisor logs to the server (client-streaming). + PushSandboxLogs(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[PushSandboxLogsRequest, PushSandboxLogsResponse], error) + // Watch a sandbox and stream updates. + // + // This stream can include: + // - Sandbox status snapshots (phase/status) + // - OpenShell server process logs correlated by sandbox_id + // - Platform events correlated to the sandbox + WatchSandbox(ctx context.Context, in *WatchSandboxRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[SandboxStreamEvent], error) + // Submit denial analysis results from sandbox (summaries + proposed chunks). + SubmitPolicyAnalysis(ctx context.Context, in *SubmitPolicyAnalysisRequest, opts ...grpc.CallOption) (*SubmitPolicyAnalysisResponse, error) + // Get draft policy recommendations for a sandbox. + GetDraftPolicy(ctx context.Context, in *GetDraftPolicyRequest, opts ...grpc.CallOption) (*GetDraftPolicyResponse, error) + // Approve a single draft policy chunk (merges into active policy). + ApproveDraftChunk(ctx context.Context, in *ApproveDraftChunkRequest, opts ...grpc.CallOption) (*ApproveDraftChunkResponse, error) + // Reject a single draft policy chunk. + RejectDraftChunk(ctx context.Context, in *RejectDraftChunkRequest, opts ...grpc.CallOption) (*RejectDraftChunkResponse, error) + // Approve all pending draft chunks (skips security-flagged unless forced). + ApproveAllDraftChunks(ctx context.Context, in *ApproveAllDraftChunksRequest, opts ...grpc.CallOption) (*ApproveAllDraftChunksResponse, error) + // Edit a pending draft chunk in-place (e.g. narrow allowed_ips). + EditDraftChunk(ctx context.Context, in *EditDraftChunkRequest, opts ...grpc.CallOption) (*EditDraftChunkResponse, error) + // Reverse an approval (remove merged rule from active policy). + UndoDraftChunk(ctx context.Context, in *UndoDraftChunkRequest, opts ...grpc.CallOption) (*UndoDraftChunkResponse, error) + // Clear all pending draft chunks for a sandbox. + ClearDraftChunks(ctx context.Context, in *ClearDraftChunksRequest, opts ...grpc.CallOption) (*ClearDraftChunksResponse, error) + // Get decision history for a sandbox's draft policy. + GetDraftHistory(ctx context.Context, in *GetDraftHistoryRequest, opts ...grpc.CallOption) (*GetDraftHistoryResponse, error) +} + +type openShellClient struct { + cc grpc.ClientConnInterface +} + +func NewOpenShellClient(cc grpc.ClientConnInterface) OpenShellClient { + return &openShellClient{cc} +} + +func (c *openShellClient) Health(ctx context.Context, in *HealthRequest, opts ...grpc.CallOption) (*HealthResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(HealthResponse) + err := c.cc.Invoke(ctx, OpenShell_Health_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) CreateSandbox(ctx context.Context, in *CreateSandboxRequest, opts ...grpc.CallOption) (*SandboxResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SandboxResponse) + err := c.cc.Invoke(ctx, OpenShell_CreateSandbox_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) GetSandbox(ctx context.Context, in *GetSandboxRequest, opts ...grpc.CallOption) (*SandboxResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SandboxResponse) + err := c.cc.Invoke(ctx, OpenShell_GetSandbox_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) ListSandboxes(ctx context.Context, in *ListSandboxesRequest, opts ...grpc.CallOption) (*ListSandboxesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListSandboxesResponse) + err := c.cc.Invoke(ctx, OpenShell_ListSandboxes_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) DeleteSandbox(ctx context.Context, in *DeleteSandboxRequest, opts ...grpc.CallOption) (*DeleteSandboxResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteSandboxResponse) + err := c.cc.Invoke(ctx, OpenShell_DeleteSandbox_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) CreateSshSession(ctx context.Context, in *CreateSshSessionRequest, opts ...grpc.CallOption) (*CreateSshSessionResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateSshSessionResponse) + err := c.cc.Invoke(ctx, OpenShell_CreateSshSession_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) RevokeSshSession(ctx context.Context, in *RevokeSshSessionRequest, opts ...grpc.CallOption) (*RevokeSshSessionResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(RevokeSshSessionResponse) + err := c.cc.Invoke(ctx, OpenShell_RevokeSshSession_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) ExecSandbox(ctx context.Context, in *ExecSandboxRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ExecSandboxEvent], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &OpenShell_ServiceDesc.Streams[0], OpenShell_ExecSandbox_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[ExecSandboxRequest, ExecSandboxEvent]{ClientStream: stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type OpenShell_ExecSandboxClient = grpc.ServerStreamingClient[ExecSandboxEvent] + +func (c *openShellClient) CreateProvider(ctx context.Context, in *CreateProviderRequest, opts ...grpc.CallOption) (*ProviderResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ProviderResponse) + err := c.cc.Invoke(ctx, OpenShell_CreateProvider_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) GetProvider(ctx context.Context, in *GetProviderRequest, opts ...grpc.CallOption) (*ProviderResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ProviderResponse) + err := c.cc.Invoke(ctx, OpenShell_GetProvider_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) ListProviders(ctx context.Context, in *ListProvidersRequest, opts ...grpc.CallOption) (*ListProvidersResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListProvidersResponse) + err := c.cc.Invoke(ctx, OpenShell_ListProviders_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) UpdateProvider(ctx context.Context, in *UpdateProviderRequest, opts ...grpc.CallOption) (*ProviderResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ProviderResponse) + err := c.cc.Invoke(ctx, OpenShell_UpdateProvider_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) DeleteProvider(ctx context.Context, in *DeleteProviderRequest, opts ...grpc.CallOption) (*DeleteProviderResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteProviderResponse) + err := c.cc.Invoke(ctx, OpenShell_DeleteProvider_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) GetSandboxPolicy(ctx context.Context, in *GetSandboxPolicyRequest, opts ...grpc.CallOption) (*GetSandboxPolicyResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetSandboxPolicyResponse) + err := c.cc.Invoke(ctx, OpenShell_GetSandboxPolicy_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) UpdateSandboxPolicy(ctx context.Context, in *UpdateSandboxPolicyRequest, opts ...grpc.CallOption) (*UpdateSandboxPolicyResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateSandboxPolicyResponse) + err := c.cc.Invoke(ctx, OpenShell_UpdateSandboxPolicy_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) GetSandboxPolicyStatus(ctx context.Context, in *GetSandboxPolicyStatusRequest, opts ...grpc.CallOption) (*GetSandboxPolicyStatusResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetSandboxPolicyStatusResponse) + err := c.cc.Invoke(ctx, OpenShell_GetSandboxPolicyStatus_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) ListSandboxPolicies(ctx context.Context, in *ListSandboxPoliciesRequest, opts ...grpc.CallOption) (*ListSandboxPoliciesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListSandboxPoliciesResponse) + err := c.cc.Invoke(ctx, OpenShell_ListSandboxPolicies_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) ReportPolicyStatus(ctx context.Context, in *ReportPolicyStatusRequest, opts ...grpc.CallOption) (*ReportPolicyStatusResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ReportPolicyStatusResponse) + err := c.cc.Invoke(ctx, OpenShell_ReportPolicyStatus_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) GetSandboxProviderEnvironment(ctx context.Context, in *GetSandboxProviderEnvironmentRequest, opts ...grpc.CallOption) (*GetSandboxProviderEnvironmentResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetSandboxProviderEnvironmentResponse) + err := c.cc.Invoke(ctx, OpenShell_GetSandboxProviderEnvironment_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) GetSandboxLogs(ctx context.Context, in *GetSandboxLogsRequest, opts ...grpc.CallOption) (*GetSandboxLogsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetSandboxLogsResponse) + err := c.cc.Invoke(ctx, OpenShell_GetSandboxLogs_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) PushSandboxLogs(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[PushSandboxLogsRequest, PushSandboxLogsResponse], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &OpenShell_ServiceDesc.Streams[1], OpenShell_PushSandboxLogs_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[PushSandboxLogsRequest, PushSandboxLogsResponse]{ClientStream: stream} + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type OpenShell_PushSandboxLogsClient = grpc.ClientStreamingClient[PushSandboxLogsRequest, PushSandboxLogsResponse] + +func (c *openShellClient) WatchSandbox(ctx context.Context, in *WatchSandboxRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[SandboxStreamEvent], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &OpenShell_ServiceDesc.Streams[2], OpenShell_WatchSandbox_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[WatchSandboxRequest, SandboxStreamEvent]{ClientStream: stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type OpenShell_WatchSandboxClient = grpc.ServerStreamingClient[SandboxStreamEvent] + +func (c *openShellClient) SubmitPolicyAnalysis(ctx context.Context, in *SubmitPolicyAnalysisRequest, opts ...grpc.CallOption) (*SubmitPolicyAnalysisResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SubmitPolicyAnalysisResponse) + err := c.cc.Invoke(ctx, OpenShell_SubmitPolicyAnalysis_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) GetDraftPolicy(ctx context.Context, in *GetDraftPolicyRequest, opts ...grpc.CallOption) (*GetDraftPolicyResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetDraftPolicyResponse) + err := c.cc.Invoke(ctx, OpenShell_GetDraftPolicy_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) ApproveDraftChunk(ctx context.Context, in *ApproveDraftChunkRequest, opts ...grpc.CallOption) (*ApproveDraftChunkResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ApproveDraftChunkResponse) + err := c.cc.Invoke(ctx, OpenShell_ApproveDraftChunk_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) RejectDraftChunk(ctx context.Context, in *RejectDraftChunkRequest, opts ...grpc.CallOption) (*RejectDraftChunkResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(RejectDraftChunkResponse) + err := c.cc.Invoke(ctx, OpenShell_RejectDraftChunk_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) ApproveAllDraftChunks(ctx context.Context, in *ApproveAllDraftChunksRequest, opts ...grpc.CallOption) (*ApproveAllDraftChunksResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ApproveAllDraftChunksResponse) + err := c.cc.Invoke(ctx, OpenShell_ApproveAllDraftChunks_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) EditDraftChunk(ctx context.Context, in *EditDraftChunkRequest, opts ...grpc.CallOption) (*EditDraftChunkResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(EditDraftChunkResponse) + err := c.cc.Invoke(ctx, OpenShell_EditDraftChunk_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) UndoDraftChunk(ctx context.Context, in *UndoDraftChunkRequest, opts ...grpc.CallOption) (*UndoDraftChunkResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UndoDraftChunkResponse) + err := c.cc.Invoke(ctx, OpenShell_UndoDraftChunk_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) ClearDraftChunks(ctx context.Context, in *ClearDraftChunksRequest, opts ...grpc.CallOption) (*ClearDraftChunksResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ClearDraftChunksResponse) + err := c.cc.Invoke(ctx, OpenShell_ClearDraftChunks_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) GetDraftHistory(ctx context.Context, in *GetDraftHistoryRequest, opts ...grpc.CallOption) (*GetDraftHistoryResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetDraftHistoryResponse) + err := c.cc.Invoke(ctx, OpenShell_GetDraftHistory_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// OpenShellServer is the server API for OpenShell service. +// All implementations must embed UnimplementedOpenShellServer +// for forward compatibility. +// +// OpenShell service provides sandbox, provider, and runtime management capabilities. +type OpenShellServer interface { + // Check the health of the service. + Health(context.Context, *HealthRequest) (*HealthResponse, error) + // Create a new sandbox. + CreateSandbox(context.Context, *CreateSandboxRequest) (*SandboxResponse, error) + // Fetch a sandbox by name. + GetSandbox(context.Context, *GetSandboxRequest) (*SandboxResponse, error) + // List sandboxes. + ListSandboxes(context.Context, *ListSandboxesRequest) (*ListSandboxesResponse, error) + // Delete a sandbox by name. + DeleteSandbox(context.Context, *DeleteSandboxRequest) (*DeleteSandboxResponse, error) + // Create a short-lived SSH session for a sandbox. + CreateSshSession(context.Context, *CreateSshSessionRequest) (*CreateSshSessionResponse, error) + // Revoke a previously issued SSH session. + RevokeSshSession(context.Context, *RevokeSshSessionRequest) (*RevokeSshSessionResponse, error) + // Execute a command in a ready sandbox and stream output. + ExecSandbox(*ExecSandboxRequest, grpc.ServerStreamingServer[ExecSandboxEvent]) error + // Create a provider. + CreateProvider(context.Context, *CreateProviderRequest) (*ProviderResponse, error) + // Fetch a provider by name. + GetProvider(context.Context, *GetProviderRequest) (*ProviderResponse, error) + // List providers. + ListProviders(context.Context, *ListProvidersRequest) (*ListProvidersResponse, error) + // Update an existing provider by name. + UpdateProvider(context.Context, *UpdateProviderRequest) (*ProviderResponse, error) + // Delete a provider by name. + DeleteProvider(context.Context, *DeleteProviderRequest) (*DeleteProviderResponse, error) + // Get sandbox policy by id (called by sandbox entrypoint and poll loop). + GetSandboxPolicy(context.Context, *GetSandboxPolicyRequest) (*GetSandboxPolicyResponse, error) + // Update sandbox policy on a live sandbox. + UpdateSandboxPolicy(context.Context, *UpdateSandboxPolicyRequest) (*UpdateSandboxPolicyResponse, error) + // Get the load status of a specific policy version. + GetSandboxPolicyStatus(context.Context, *GetSandboxPolicyStatusRequest) (*GetSandboxPolicyStatusResponse, error) + // List policy history for a sandbox. + ListSandboxPolicies(context.Context, *ListSandboxPoliciesRequest) (*ListSandboxPoliciesResponse, error) + // Report policy load result (called by sandbox after reload attempt). + ReportPolicyStatus(context.Context, *ReportPolicyStatusRequest) (*ReportPolicyStatusResponse, error) + // Get provider environment for a sandbox (called by sandbox supervisor at startup). + GetSandboxProviderEnvironment(context.Context, *GetSandboxProviderEnvironmentRequest) (*GetSandboxProviderEnvironmentResponse, error) + // Fetch recent sandbox logs (one-shot). + GetSandboxLogs(context.Context, *GetSandboxLogsRequest) (*GetSandboxLogsResponse, error) + // Push sandbox supervisor logs to the server (client-streaming). + PushSandboxLogs(grpc.ClientStreamingServer[PushSandboxLogsRequest, PushSandboxLogsResponse]) error + // Watch a sandbox and stream updates. + // + // This stream can include: + // - Sandbox status snapshots (phase/status) + // - OpenShell server process logs correlated by sandbox_id + // - Platform events correlated to the sandbox + WatchSandbox(*WatchSandboxRequest, grpc.ServerStreamingServer[SandboxStreamEvent]) error + // Submit denial analysis results from sandbox (summaries + proposed chunks). + SubmitPolicyAnalysis(context.Context, *SubmitPolicyAnalysisRequest) (*SubmitPolicyAnalysisResponse, error) + // Get draft policy recommendations for a sandbox. + GetDraftPolicy(context.Context, *GetDraftPolicyRequest) (*GetDraftPolicyResponse, error) + // Approve a single draft policy chunk (merges into active policy). + ApproveDraftChunk(context.Context, *ApproveDraftChunkRequest) (*ApproveDraftChunkResponse, error) + // Reject a single draft policy chunk. + RejectDraftChunk(context.Context, *RejectDraftChunkRequest) (*RejectDraftChunkResponse, error) + // Approve all pending draft chunks (skips security-flagged unless forced). + ApproveAllDraftChunks(context.Context, *ApproveAllDraftChunksRequest) (*ApproveAllDraftChunksResponse, error) + // Edit a pending draft chunk in-place (e.g. narrow allowed_ips). + EditDraftChunk(context.Context, *EditDraftChunkRequest) (*EditDraftChunkResponse, error) + // Reverse an approval (remove merged rule from active policy). + UndoDraftChunk(context.Context, *UndoDraftChunkRequest) (*UndoDraftChunkResponse, error) + // Clear all pending draft chunks for a sandbox. + ClearDraftChunks(context.Context, *ClearDraftChunksRequest) (*ClearDraftChunksResponse, error) + // Get decision history for a sandbox's draft policy. + GetDraftHistory(context.Context, *GetDraftHistoryRequest) (*GetDraftHistoryResponse, error) + mustEmbedUnimplementedOpenShellServer() +} + +// UnimplementedOpenShellServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedOpenShellServer struct{} + +func (UnimplementedOpenShellServer) Health(context.Context, *HealthRequest) (*HealthResponse, error) { + return nil, status.Error(codes.Unimplemented, "method Health not implemented") +} +func (UnimplementedOpenShellServer) CreateSandbox(context.Context, *CreateSandboxRequest) (*SandboxResponse, error) { + return nil, status.Error(codes.Unimplemented, "method CreateSandbox not implemented") +} +func (UnimplementedOpenShellServer) GetSandbox(context.Context, *GetSandboxRequest) (*SandboxResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetSandbox not implemented") +} +func (UnimplementedOpenShellServer) ListSandboxes(context.Context, *ListSandboxesRequest) (*ListSandboxesResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ListSandboxes not implemented") +} +func (UnimplementedOpenShellServer) DeleteSandbox(context.Context, *DeleteSandboxRequest) (*DeleteSandboxResponse, error) { + return nil, status.Error(codes.Unimplemented, "method DeleteSandbox not implemented") +} +func (UnimplementedOpenShellServer) CreateSshSession(context.Context, *CreateSshSessionRequest) (*CreateSshSessionResponse, error) { + return nil, status.Error(codes.Unimplemented, "method CreateSshSession not implemented") +} +func (UnimplementedOpenShellServer) RevokeSshSession(context.Context, *RevokeSshSessionRequest) (*RevokeSshSessionResponse, error) { + return nil, status.Error(codes.Unimplemented, "method RevokeSshSession not implemented") +} +func (UnimplementedOpenShellServer) ExecSandbox(*ExecSandboxRequest, grpc.ServerStreamingServer[ExecSandboxEvent]) error { + return status.Error(codes.Unimplemented, "method ExecSandbox not implemented") +} +func (UnimplementedOpenShellServer) CreateProvider(context.Context, *CreateProviderRequest) (*ProviderResponse, error) { + return nil, status.Error(codes.Unimplemented, "method CreateProvider not implemented") +} +func (UnimplementedOpenShellServer) GetProvider(context.Context, *GetProviderRequest) (*ProviderResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetProvider not implemented") +} +func (UnimplementedOpenShellServer) ListProviders(context.Context, *ListProvidersRequest) (*ListProvidersResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ListProviders not implemented") +} +func (UnimplementedOpenShellServer) UpdateProvider(context.Context, *UpdateProviderRequest) (*ProviderResponse, error) { + return nil, status.Error(codes.Unimplemented, "method UpdateProvider not implemented") +} +func (UnimplementedOpenShellServer) DeleteProvider(context.Context, *DeleteProviderRequest) (*DeleteProviderResponse, error) { + return nil, status.Error(codes.Unimplemented, "method DeleteProvider not implemented") +} +func (UnimplementedOpenShellServer) GetSandboxPolicy(context.Context, *GetSandboxPolicyRequest) (*GetSandboxPolicyResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetSandboxPolicy not implemented") +} +func (UnimplementedOpenShellServer) UpdateSandboxPolicy(context.Context, *UpdateSandboxPolicyRequest) (*UpdateSandboxPolicyResponse, error) { + return nil, status.Error(codes.Unimplemented, "method UpdateSandboxPolicy not implemented") +} +func (UnimplementedOpenShellServer) GetSandboxPolicyStatus(context.Context, *GetSandboxPolicyStatusRequest) (*GetSandboxPolicyStatusResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetSandboxPolicyStatus not implemented") +} +func (UnimplementedOpenShellServer) ListSandboxPolicies(context.Context, *ListSandboxPoliciesRequest) (*ListSandboxPoliciesResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ListSandboxPolicies not implemented") +} +func (UnimplementedOpenShellServer) ReportPolicyStatus(context.Context, *ReportPolicyStatusRequest) (*ReportPolicyStatusResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ReportPolicyStatus not implemented") +} +func (UnimplementedOpenShellServer) GetSandboxProviderEnvironment(context.Context, *GetSandboxProviderEnvironmentRequest) (*GetSandboxProviderEnvironmentResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetSandboxProviderEnvironment not implemented") +} +func (UnimplementedOpenShellServer) GetSandboxLogs(context.Context, *GetSandboxLogsRequest) (*GetSandboxLogsResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetSandboxLogs not implemented") +} +func (UnimplementedOpenShellServer) PushSandboxLogs(grpc.ClientStreamingServer[PushSandboxLogsRequest, PushSandboxLogsResponse]) error { + return status.Error(codes.Unimplemented, "method PushSandboxLogs not implemented") +} +func (UnimplementedOpenShellServer) WatchSandbox(*WatchSandboxRequest, grpc.ServerStreamingServer[SandboxStreamEvent]) error { + return status.Error(codes.Unimplemented, "method WatchSandbox not implemented") +} +func (UnimplementedOpenShellServer) SubmitPolicyAnalysis(context.Context, *SubmitPolicyAnalysisRequest) (*SubmitPolicyAnalysisResponse, error) { + return nil, status.Error(codes.Unimplemented, "method SubmitPolicyAnalysis not implemented") +} +func (UnimplementedOpenShellServer) GetDraftPolicy(context.Context, *GetDraftPolicyRequest) (*GetDraftPolicyResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetDraftPolicy not implemented") +} +func (UnimplementedOpenShellServer) ApproveDraftChunk(context.Context, *ApproveDraftChunkRequest) (*ApproveDraftChunkResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ApproveDraftChunk not implemented") +} +func (UnimplementedOpenShellServer) RejectDraftChunk(context.Context, *RejectDraftChunkRequest) (*RejectDraftChunkResponse, error) { + return nil, status.Error(codes.Unimplemented, "method RejectDraftChunk not implemented") +} +func (UnimplementedOpenShellServer) ApproveAllDraftChunks(context.Context, *ApproveAllDraftChunksRequest) (*ApproveAllDraftChunksResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ApproveAllDraftChunks not implemented") +} +func (UnimplementedOpenShellServer) EditDraftChunk(context.Context, *EditDraftChunkRequest) (*EditDraftChunkResponse, error) { + return nil, status.Error(codes.Unimplemented, "method EditDraftChunk not implemented") +} +func (UnimplementedOpenShellServer) UndoDraftChunk(context.Context, *UndoDraftChunkRequest) (*UndoDraftChunkResponse, error) { + return nil, status.Error(codes.Unimplemented, "method UndoDraftChunk not implemented") +} +func (UnimplementedOpenShellServer) ClearDraftChunks(context.Context, *ClearDraftChunksRequest) (*ClearDraftChunksResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ClearDraftChunks not implemented") +} +func (UnimplementedOpenShellServer) GetDraftHistory(context.Context, *GetDraftHistoryRequest) (*GetDraftHistoryResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetDraftHistory not implemented") +} +func (UnimplementedOpenShellServer) mustEmbedUnimplementedOpenShellServer() {} +func (UnimplementedOpenShellServer) testEmbeddedByValue() {} + +// UnsafeOpenShellServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to OpenShellServer will +// result in compilation errors. +type UnsafeOpenShellServer interface { + mustEmbedUnimplementedOpenShellServer() +} + +func RegisterOpenShellServer(s grpc.ServiceRegistrar, srv OpenShellServer) { + // If the following call panics, it indicates UnimplementedOpenShellServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&OpenShell_ServiceDesc, srv) +} + +func _OpenShell_Health_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(HealthRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).Health(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_Health_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).Health(ctx, req.(*HealthRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_CreateSandbox_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateSandboxRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).CreateSandbox(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_CreateSandbox_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).CreateSandbox(ctx, req.(*CreateSandboxRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_GetSandbox_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSandboxRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).GetSandbox(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_GetSandbox_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).GetSandbox(ctx, req.(*GetSandboxRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_ListSandboxes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListSandboxesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).ListSandboxes(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_ListSandboxes_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).ListSandboxes(ctx, req.(*ListSandboxesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_DeleteSandbox_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteSandboxRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).DeleteSandbox(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_DeleteSandbox_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).DeleteSandbox(ctx, req.(*DeleteSandboxRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_CreateSshSession_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateSshSessionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).CreateSshSession(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_CreateSshSession_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).CreateSshSession(ctx, req.(*CreateSshSessionRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_RevokeSshSession_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RevokeSshSessionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).RevokeSshSession(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_RevokeSshSession_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).RevokeSshSession(ctx, req.(*RevokeSshSessionRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_ExecSandbox_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(ExecSandboxRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(OpenShellServer).ExecSandbox(m, &grpc.GenericServerStream[ExecSandboxRequest, ExecSandboxEvent]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type OpenShell_ExecSandboxServer = grpc.ServerStreamingServer[ExecSandboxEvent] + +func _OpenShell_CreateProvider_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateProviderRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).CreateProvider(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_CreateProvider_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).CreateProvider(ctx, req.(*CreateProviderRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_GetProvider_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetProviderRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).GetProvider(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_GetProvider_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).GetProvider(ctx, req.(*GetProviderRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_ListProviders_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListProvidersRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).ListProviders(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_ListProviders_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).ListProviders(ctx, req.(*ListProvidersRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_UpdateProvider_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateProviderRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).UpdateProvider(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_UpdateProvider_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).UpdateProvider(ctx, req.(*UpdateProviderRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_DeleteProvider_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteProviderRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).DeleteProvider(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_DeleteProvider_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).DeleteProvider(ctx, req.(*DeleteProviderRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_GetSandboxPolicy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSandboxPolicyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).GetSandboxPolicy(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_GetSandboxPolicy_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).GetSandboxPolicy(ctx, req.(*GetSandboxPolicyRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_UpdateSandboxPolicy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateSandboxPolicyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).UpdateSandboxPolicy(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_UpdateSandboxPolicy_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).UpdateSandboxPolicy(ctx, req.(*UpdateSandboxPolicyRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_GetSandboxPolicyStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSandboxPolicyStatusRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).GetSandboxPolicyStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_GetSandboxPolicyStatus_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).GetSandboxPolicyStatus(ctx, req.(*GetSandboxPolicyStatusRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_ListSandboxPolicies_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListSandboxPoliciesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).ListSandboxPolicies(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_ListSandboxPolicies_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).ListSandboxPolicies(ctx, req.(*ListSandboxPoliciesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_ReportPolicyStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ReportPolicyStatusRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).ReportPolicyStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_ReportPolicyStatus_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).ReportPolicyStatus(ctx, req.(*ReportPolicyStatusRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_GetSandboxProviderEnvironment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSandboxProviderEnvironmentRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).GetSandboxProviderEnvironment(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_GetSandboxProviderEnvironment_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).GetSandboxProviderEnvironment(ctx, req.(*GetSandboxProviderEnvironmentRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_GetSandboxLogs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSandboxLogsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).GetSandboxLogs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_GetSandboxLogs_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).GetSandboxLogs(ctx, req.(*GetSandboxLogsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_PushSandboxLogs_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(OpenShellServer).PushSandboxLogs(&grpc.GenericServerStream[PushSandboxLogsRequest, PushSandboxLogsResponse]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type OpenShell_PushSandboxLogsServer = grpc.ClientStreamingServer[PushSandboxLogsRequest, PushSandboxLogsResponse] + +func _OpenShell_WatchSandbox_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(WatchSandboxRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(OpenShellServer).WatchSandbox(m, &grpc.GenericServerStream[WatchSandboxRequest, SandboxStreamEvent]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type OpenShell_WatchSandboxServer = grpc.ServerStreamingServer[SandboxStreamEvent] + +func _OpenShell_SubmitPolicyAnalysis_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SubmitPolicyAnalysisRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).SubmitPolicyAnalysis(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_SubmitPolicyAnalysis_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).SubmitPolicyAnalysis(ctx, req.(*SubmitPolicyAnalysisRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_GetDraftPolicy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetDraftPolicyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).GetDraftPolicy(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_GetDraftPolicy_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).GetDraftPolicy(ctx, req.(*GetDraftPolicyRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_ApproveDraftChunk_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ApproveDraftChunkRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).ApproveDraftChunk(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_ApproveDraftChunk_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).ApproveDraftChunk(ctx, req.(*ApproveDraftChunkRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_RejectDraftChunk_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RejectDraftChunkRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).RejectDraftChunk(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_RejectDraftChunk_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).RejectDraftChunk(ctx, req.(*RejectDraftChunkRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_ApproveAllDraftChunks_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ApproveAllDraftChunksRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).ApproveAllDraftChunks(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_ApproveAllDraftChunks_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).ApproveAllDraftChunks(ctx, req.(*ApproveAllDraftChunksRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_EditDraftChunk_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(EditDraftChunkRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).EditDraftChunk(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_EditDraftChunk_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).EditDraftChunk(ctx, req.(*EditDraftChunkRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_UndoDraftChunk_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UndoDraftChunkRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).UndoDraftChunk(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_UndoDraftChunk_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).UndoDraftChunk(ctx, req.(*UndoDraftChunkRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_ClearDraftChunks_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ClearDraftChunksRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).ClearDraftChunks(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_ClearDraftChunks_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).ClearDraftChunks(ctx, req.(*ClearDraftChunksRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_GetDraftHistory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetDraftHistoryRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).GetDraftHistory(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_GetDraftHistory_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).GetDraftHistory(ctx, req.(*GetDraftHistoryRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// OpenShell_ServiceDesc is the grpc.ServiceDesc for OpenShell service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var OpenShell_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "openshell.v1.OpenShell", + HandlerType: (*OpenShellServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Health", + Handler: _OpenShell_Health_Handler, + }, + { + MethodName: "CreateSandbox", + Handler: _OpenShell_CreateSandbox_Handler, + }, + { + MethodName: "GetSandbox", + Handler: _OpenShell_GetSandbox_Handler, + }, + { + MethodName: "ListSandboxes", + Handler: _OpenShell_ListSandboxes_Handler, + }, + { + MethodName: "DeleteSandbox", + Handler: _OpenShell_DeleteSandbox_Handler, + }, + { + MethodName: "CreateSshSession", + Handler: _OpenShell_CreateSshSession_Handler, + }, + { + MethodName: "RevokeSshSession", + Handler: _OpenShell_RevokeSshSession_Handler, + }, + { + MethodName: "CreateProvider", + Handler: _OpenShell_CreateProvider_Handler, + }, + { + MethodName: "GetProvider", + Handler: _OpenShell_GetProvider_Handler, + }, + { + MethodName: "ListProviders", + Handler: _OpenShell_ListProviders_Handler, + }, + { + MethodName: "UpdateProvider", + Handler: _OpenShell_UpdateProvider_Handler, + }, + { + MethodName: "DeleteProvider", + Handler: _OpenShell_DeleteProvider_Handler, + }, + { + MethodName: "GetSandboxPolicy", + Handler: _OpenShell_GetSandboxPolicy_Handler, + }, + { + MethodName: "UpdateSandboxPolicy", + Handler: _OpenShell_UpdateSandboxPolicy_Handler, + }, + { + MethodName: "GetSandboxPolicyStatus", + Handler: _OpenShell_GetSandboxPolicyStatus_Handler, + }, + { + MethodName: "ListSandboxPolicies", + Handler: _OpenShell_ListSandboxPolicies_Handler, + }, + { + MethodName: "ReportPolicyStatus", + Handler: _OpenShell_ReportPolicyStatus_Handler, + }, + { + MethodName: "GetSandboxProviderEnvironment", + Handler: _OpenShell_GetSandboxProviderEnvironment_Handler, + }, + { + MethodName: "GetSandboxLogs", + Handler: _OpenShell_GetSandboxLogs_Handler, + }, + { + MethodName: "SubmitPolicyAnalysis", + Handler: _OpenShell_SubmitPolicyAnalysis_Handler, + }, + { + MethodName: "GetDraftPolicy", + Handler: _OpenShell_GetDraftPolicy_Handler, + }, + { + MethodName: "ApproveDraftChunk", + Handler: _OpenShell_ApproveDraftChunk_Handler, + }, + { + MethodName: "RejectDraftChunk", + Handler: _OpenShell_RejectDraftChunk_Handler, + }, + { + MethodName: "ApproveAllDraftChunks", + Handler: _OpenShell_ApproveAllDraftChunks_Handler, + }, + { + MethodName: "EditDraftChunk", + Handler: _OpenShell_EditDraftChunk_Handler, + }, + { + MethodName: "UndoDraftChunk", + Handler: _OpenShell_UndoDraftChunk_Handler, + }, + { + MethodName: "ClearDraftChunks", + Handler: _OpenShell_ClearDraftChunks_Handler, + }, + { + MethodName: "GetDraftHistory", + Handler: _OpenShell_GetDraftHistory_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "ExecSandbox", + Handler: _OpenShell_ExecSandbox_Handler, + ServerStreams: true, + }, + { + StreamName: "PushSandboxLogs", + Handler: _OpenShell_PushSandboxLogs_Handler, + ClientStreams: true, + }, + { + StreamName: "WatchSandbox", + Handler: _OpenShell_WatchSandbox_Handler, + ServerStreams: true, + }, + }, + Metadata: "openshell.proto", +} diff --git a/internal/registry/platforms/openshell/proto/gen/sandbox.pb.go b/internal/registry/platforms/openshell/proto/gen/sandbox.pb.go new file mode 100644 index 00000000..c3a46922 --- /dev/null +++ b/internal/registry/platforms/openshell/proto/gen/sandbox.pb.go @@ -0,0 +1,872 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v7.34.0 +// source: sandbox.proto + +package gen + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Sandbox security policy configuration. +type SandboxPolicy struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Policy version. + Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + // Filesystem access policy. + Filesystem *FilesystemPolicy `protobuf:"bytes,2,opt,name=filesystem,proto3" json:"filesystem,omitempty"` + // Landlock configuration. + Landlock *LandlockPolicy `protobuf:"bytes,3,opt,name=landlock,proto3" json:"landlock,omitempty"` + // Process execution policy. + Process *ProcessPolicy `protobuf:"bytes,4,opt,name=process,proto3" json:"process,omitempty"` + // Network access policies keyed by name (e.g. "claude_code", "gitlab"). + NetworkPolicies map[string]*NetworkPolicyRule `protobuf:"bytes,5,rep,name=network_policies,json=networkPolicies,proto3" json:"network_policies,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxPolicy) Reset() { + *x = SandboxPolicy{} + mi := &file_sandbox_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxPolicy) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxPolicy) ProtoMessage() {} + +func (x *SandboxPolicy) ProtoReflect() protoreflect.Message { + mi := &file_sandbox_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SandboxPolicy.ProtoReflect.Descriptor instead. +func (*SandboxPolicy) Descriptor() ([]byte, []int) { + return file_sandbox_proto_rawDescGZIP(), []int{0} +} + +func (x *SandboxPolicy) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *SandboxPolicy) GetFilesystem() *FilesystemPolicy { + if x != nil { + return x.Filesystem + } + return nil +} + +func (x *SandboxPolicy) GetLandlock() *LandlockPolicy { + if x != nil { + return x.Landlock + } + return nil +} + +func (x *SandboxPolicy) GetProcess() *ProcessPolicy { + if x != nil { + return x.Process + } + return nil +} + +func (x *SandboxPolicy) GetNetworkPolicies() map[string]*NetworkPolicyRule { + if x != nil { + return x.NetworkPolicies + } + return nil +} + +// Filesystem access policy. +type FilesystemPolicy struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Automatically include the workdir as read-write. + IncludeWorkdir bool `protobuf:"varint,1,opt,name=include_workdir,json=includeWorkdir,proto3" json:"include_workdir,omitempty"` + // Read-only directory allow list. + ReadOnly []string `protobuf:"bytes,2,rep,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` + // Read-write directory allow list. + ReadWrite []string `protobuf:"bytes,3,rep,name=read_write,json=readWrite,proto3" json:"read_write,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *FilesystemPolicy) Reset() { + *x = FilesystemPolicy{} + mi := &file_sandbox_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *FilesystemPolicy) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FilesystemPolicy) ProtoMessage() {} + +func (x *FilesystemPolicy) ProtoReflect() protoreflect.Message { + mi := &file_sandbox_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FilesystemPolicy.ProtoReflect.Descriptor instead. +func (*FilesystemPolicy) Descriptor() ([]byte, []int) { + return file_sandbox_proto_rawDescGZIP(), []int{1} +} + +func (x *FilesystemPolicy) GetIncludeWorkdir() bool { + if x != nil { + return x.IncludeWorkdir + } + return false +} + +func (x *FilesystemPolicy) GetReadOnly() []string { + if x != nil { + return x.ReadOnly + } + return nil +} + +func (x *FilesystemPolicy) GetReadWrite() []string { + if x != nil { + return x.ReadWrite + } + return nil +} + +// Landlock policy configuration. +type LandlockPolicy struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Compatibility mode (e.g. "best_effort", "hard_requirement"). + Compatibility string `protobuf:"bytes,1,opt,name=compatibility,proto3" json:"compatibility,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LandlockPolicy) Reset() { + *x = LandlockPolicy{} + mi := &file_sandbox_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LandlockPolicy) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LandlockPolicy) ProtoMessage() {} + +func (x *LandlockPolicy) ProtoReflect() protoreflect.Message { + mi := &file_sandbox_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LandlockPolicy.ProtoReflect.Descriptor instead. +func (*LandlockPolicy) Descriptor() ([]byte, []int) { + return file_sandbox_proto_rawDescGZIP(), []int{2} +} + +func (x *LandlockPolicy) GetCompatibility() string { + if x != nil { + return x.Compatibility + } + return "" +} + +// Process execution policy. +type ProcessPolicy struct { + state protoimpl.MessageState `protogen:"open.v1"` + // User name to run the sandboxed process as. + RunAsUser string `protobuf:"bytes,1,opt,name=run_as_user,json=runAsUser,proto3" json:"run_as_user,omitempty"` + // Group name to run the sandboxed process as. + RunAsGroup string `protobuf:"bytes,2,opt,name=run_as_group,json=runAsGroup,proto3" json:"run_as_group,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProcessPolicy) Reset() { + *x = ProcessPolicy{} + mi := &file_sandbox_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProcessPolicy) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProcessPolicy) ProtoMessage() {} + +func (x *ProcessPolicy) ProtoReflect() protoreflect.Message { + mi := &file_sandbox_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProcessPolicy.ProtoReflect.Descriptor instead. +func (*ProcessPolicy) Descriptor() ([]byte, []int) { + return file_sandbox_proto_rawDescGZIP(), []int{3} +} + +func (x *ProcessPolicy) GetRunAsUser() string { + if x != nil { + return x.RunAsUser + } + return "" +} + +func (x *ProcessPolicy) GetRunAsGroup() string { + if x != nil { + return x.RunAsGroup + } + return "" +} + +// A named network access policy rule. +type NetworkPolicyRule struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Human-readable name for this policy rule. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Allowed endpoint (host:port) pairs. + Endpoints []*NetworkEndpoint `protobuf:"bytes,2,rep,name=endpoints,proto3" json:"endpoints,omitempty"` + // Allowed binary identities. + Binaries []*NetworkBinary `protobuf:"bytes,3,rep,name=binaries,proto3" json:"binaries,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetworkPolicyRule) Reset() { + *x = NetworkPolicyRule{} + mi := &file_sandbox_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetworkPolicyRule) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetworkPolicyRule) ProtoMessage() {} + +func (x *NetworkPolicyRule) ProtoReflect() protoreflect.Message { + mi := &file_sandbox_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NetworkPolicyRule.ProtoReflect.Descriptor instead. +func (*NetworkPolicyRule) Descriptor() ([]byte, []int) { + return file_sandbox_proto_rawDescGZIP(), []int{4} +} + +func (x *NetworkPolicyRule) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *NetworkPolicyRule) GetEndpoints() []*NetworkEndpoint { + if x != nil { + return x.Endpoints + } + return nil +} + +func (x *NetworkPolicyRule) GetBinaries() []*NetworkBinary { + if x != nil { + return x.Binaries + } + return nil +} + +// A network endpoint (host + port) with optional L7 inspection config. +type NetworkEndpoint struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Hostname or host glob pattern. Exact match is case-insensitive. + // Glob patterns use "." as delimiter: "*.example.com" matches a single + // subdomain label, "**.example.com" matches across labels. + Host string `protobuf:"bytes,1,opt,name=host,proto3" json:"host,omitempty"` + // Single port (backwards compat). Use `ports` for multiple ports. + // Mutually exclusive with `ports` — if both are set, `ports` takes precedence. + Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"` + // Application protocol for L7 inspection: "rest", "sql", or "" (L4-only). + Protocol string `protobuf:"bytes,3,opt,name=protocol,proto3" json:"protocol,omitempty"` + // TLS handling: "terminate" or "passthrough" (default). + Tls string `protobuf:"bytes,4,opt,name=tls,proto3" json:"tls,omitempty"` + // Enforcement mode: "enforce" or "audit" (default). + Enforcement string `protobuf:"bytes,5,opt,name=enforcement,proto3" json:"enforcement,omitempty"` + // Access preset shorthand: "read-only", "read-write", "full". + // Mutually exclusive with rules. + Access string `protobuf:"bytes,6,opt,name=access,proto3" json:"access,omitempty"` + // Explicit L7 rules (mutually exclusive with access). + Rules []*L7Rule `protobuf:"bytes,7,rep,name=rules,proto3" json:"rules,omitempty"` + // Allowed resolved IP addresses or CIDR ranges for this endpoint. + // When non-empty, the SSRF internal-IP check is replaced by an allowlist check: + // - If host is also set: domain must resolve to an IP in this list. + // - If host is empty: any domain is allowed as long as it resolves to an IP in this list. + // + // Supports exact IPs ("10.0.5.20") and CIDR notation ("10.0.5.0/24"). + // Loopback (127.0.0.0/8) and link-local (169.254.0.0/16) are always blocked + // regardless of this field. + AllowedIps []string `protobuf:"bytes,8,rep,name=allowed_ips,json=allowedIps,proto3" json:"allowed_ips,omitempty"` + // Multiple ports. When non-empty, this endpoint covers all listed ports. + // If `port` is set and `ports` is empty, `port` is normalized to `ports: [port]`. + // If both are set, `ports` takes precedence. + Ports []uint32 `protobuf:"varint,9,rep,packed,name=ports,proto3" json:"ports,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetworkEndpoint) Reset() { + *x = NetworkEndpoint{} + mi := &file_sandbox_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetworkEndpoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetworkEndpoint) ProtoMessage() {} + +func (x *NetworkEndpoint) ProtoReflect() protoreflect.Message { + mi := &file_sandbox_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NetworkEndpoint.ProtoReflect.Descriptor instead. +func (*NetworkEndpoint) Descriptor() ([]byte, []int) { + return file_sandbox_proto_rawDescGZIP(), []int{5} +} + +func (x *NetworkEndpoint) GetHost() string { + if x != nil { + return x.Host + } + return "" +} + +func (x *NetworkEndpoint) GetPort() uint32 { + if x != nil { + return x.Port + } + return 0 +} + +func (x *NetworkEndpoint) GetProtocol() string { + if x != nil { + return x.Protocol + } + return "" +} + +func (x *NetworkEndpoint) GetTls() string { + if x != nil { + return x.Tls + } + return "" +} + +func (x *NetworkEndpoint) GetEnforcement() string { + if x != nil { + return x.Enforcement + } + return "" +} + +func (x *NetworkEndpoint) GetAccess() string { + if x != nil { + return x.Access + } + return "" +} + +func (x *NetworkEndpoint) GetRules() []*L7Rule { + if x != nil { + return x.Rules + } + return nil +} + +func (x *NetworkEndpoint) GetAllowedIps() []string { + if x != nil { + return x.AllowedIps + } + return nil +} + +func (x *NetworkEndpoint) GetPorts() []uint32 { + if x != nil { + return x.Ports + } + return nil +} + +// An L7 policy rule (allow-only). +type L7Rule struct { + state protoimpl.MessageState `protogen:"open.v1"` + Allow *L7Allow `protobuf:"bytes,1,opt,name=allow,proto3" json:"allow,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *L7Rule) Reset() { + *x = L7Rule{} + mi := &file_sandbox_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *L7Rule) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*L7Rule) ProtoMessage() {} + +func (x *L7Rule) ProtoReflect() protoreflect.Message { + mi := &file_sandbox_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use L7Rule.ProtoReflect.Descriptor instead. +func (*L7Rule) Descriptor() ([]byte, []int) { + return file_sandbox_proto_rawDescGZIP(), []int{6} +} + +func (x *L7Rule) GetAllow() *L7Allow { + if x != nil { + return x.Allow + } + return nil +} + +// Allowed action definition for L7 rules. +type L7Allow struct { + state protoimpl.MessageState `protogen:"open.v1"` + // HTTP method (REST): GET, POST, etc. or "*" for any. + Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"` + // URL path glob pattern (REST): "/repos/**", "**" for any. + Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` + // SQL command (SQL): SELECT, INSERT, etc. or "*" for any. + Command string `protobuf:"bytes,3,opt,name=command,proto3" json:"command,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *L7Allow) Reset() { + *x = L7Allow{} + mi := &file_sandbox_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *L7Allow) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*L7Allow) ProtoMessage() {} + +func (x *L7Allow) ProtoReflect() protoreflect.Message { + mi := &file_sandbox_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use L7Allow.ProtoReflect.Descriptor instead. +func (*L7Allow) Descriptor() ([]byte, []int) { + return file_sandbox_proto_rawDescGZIP(), []int{7} +} + +func (x *L7Allow) GetMethod() string { + if x != nil { + return x.Method + } + return "" +} + +func (x *L7Allow) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +func (x *L7Allow) GetCommand() string { + if x != nil { + return x.Command + } + return "" +} + +// A binary identity for network policy matching. +type NetworkBinary struct { + state protoimpl.MessageState `protogen:"open.v1"` + Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` + // Deprecated: the harness concept has been removed. This field is ignored. + // + // Deprecated: Marked as deprecated in sandbox.proto. + Harness bool `protobuf:"varint,2,opt,name=harness,proto3" json:"harness,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetworkBinary) Reset() { + *x = NetworkBinary{} + mi := &file_sandbox_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetworkBinary) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetworkBinary) ProtoMessage() {} + +func (x *NetworkBinary) ProtoReflect() protoreflect.Message { + mi := &file_sandbox_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NetworkBinary.ProtoReflect.Descriptor instead. +func (*NetworkBinary) Descriptor() ([]byte, []int) { + return file_sandbox_proto_rawDescGZIP(), []int{8} +} + +func (x *NetworkBinary) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +// Deprecated: Marked as deprecated in sandbox.proto. +func (x *NetworkBinary) GetHarness() bool { + if x != nil { + return x.Harness + } + return false +} + +// Request to get sandbox policy by sandbox ID. +type GetSandboxPolicyRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The sandbox ID. + SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetSandboxPolicyRequest) Reset() { + *x = GetSandboxPolicyRequest{} + mi := &file_sandbox_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetSandboxPolicyRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSandboxPolicyRequest) ProtoMessage() {} + +func (x *GetSandboxPolicyRequest) ProtoReflect() protoreflect.Message { + mi := &file_sandbox_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSandboxPolicyRequest.ProtoReflect.Descriptor instead. +func (*GetSandboxPolicyRequest) Descriptor() ([]byte, []int) { + return file_sandbox_proto_rawDescGZIP(), []int{9} +} + +func (x *GetSandboxPolicyRequest) GetSandboxId() string { + if x != nil { + return x.SandboxId + } + return "" +} + +// Response containing sandbox policy. +type GetSandboxPolicyResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The sandbox policy configuration. + Policy *SandboxPolicy `protobuf:"bytes,1,opt,name=policy,proto3" json:"policy,omitempty"` + // Current policy version (monotonically increasing per sandbox). + Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` + // SHA-256 hash of the serialized policy payload. + PolicyHash string `protobuf:"bytes,3,opt,name=policy_hash,json=policyHash,proto3" json:"policy_hash,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetSandboxPolicyResponse) Reset() { + *x = GetSandboxPolicyResponse{} + mi := &file_sandbox_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetSandboxPolicyResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSandboxPolicyResponse) ProtoMessage() {} + +func (x *GetSandboxPolicyResponse) ProtoReflect() protoreflect.Message { + mi := &file_sandbox_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSandboxPolicyResponse.ProtoReflect.Descriptor instead. +func (*GetSandboxPolicyResponse) Descriptor() ([]byte, []int) { + return file_sandbox_proto_rawDescGZIP(), []int{10} +} + +func (x *GetSandboxPolicyResponse) GetPolicy() *SandboxPolicy { + if x != nil { + return x.Policy + } + return nil +} + +func (x *GetSandboxPolicyResponse) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *GetSandboxPolicyResponse) GetPolicyHash() string { + if x != nil { + return x.PolicyHash + } + return "" +} + +var File_sandbox_proto protoreflect.FileDescriptor + +const file_sandbox_proto_rawDesc = "" + + "\n" + + "\rsandbox.proto\x12\x14openshell.sandbox.v1\"\xc4\x03\n" + + "\rSandboxPolicy\x12\x18\n" + + "\aversion\x18\x01 \x01(\rR\aversion\x12F\n" + + "\n" + + "filesystem\x18\x02 \x01(\v2&.openshell.sandbox.v1.FilesystemPolicyR\n" + + "filesystem\x12@\n" + + "\blandlock\x18\x03 \x01(\v2$.openshell.sandbox.v1.LandlockPolicyR\blandlock\x12=\n" + + "\aprocess\x18\x04 \x01(\v2#.openshell.sandbox.v1.ProcessPolicyR\aprocess\x12c\n" + + "\x10network_policies\x18\x05 \x03(\v28.openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntryR\x0fnetworkPolicies\x1ak\n" + + "\x14NetworkPoliciesEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12=\n" + + "\x05value\x18\x02 \x01(\v2'.openshell.sandbox.v1.NetworkPolicyRuleR\x05value:\x028\x01\"w\n" + + "\x10FilesystemPolicy\x12'\n" + + "\x0finclude_workdir\x18\x01 \x01(\bR\x0eincludeWorkdir\x12\x1b\n" + + "\tread_only\x18\x02 \x03(\tR\breadOnly\x12\x1d\n" + + "\n" + + "read_write\x18\x03 \x03(\tR\treadWrite\"6\n" + + "\x0eLandlockPolicy\x12$\n" + + "\rcompatibility\x18\x01 \x01(\tR\rcompatibility\"Q\n" + + "\rProcessPolicy\x12\x1e\n" + + "\vrun_as_user\x18\x01 \x01(\tR\trunAsUser\x12 \n" + + "\frun_as_group\x18\x02 \x01(\tR\n" + + "runAsGroup\"\xad\x01\n" + + "\x11NetworkPolicyRule\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12C\n" + + "\tendpoints\x18\x02 \x03(\v2%.openshell.sandbox.v1.NetworkEndpointR\tendpoints\x12?\n" + + "\bbinaries\x18\x03 \x03(\v2#.openshell.sandbox.v1.NetworkBinaryR\bbinaries\"\x8c\x02\n" + + "\x0fNetworkEndpoint\x12\x12\n" + + "\x04host\x18\x01 \x01(\tR\x04host\x12\x12\n" + + "\x04port\x18\x02 \x01(\rR\x04port\x12\x1a\n" + + "\bprotocol\x18\x03 \x01(\tR\bprotocol\x12\x10\n" + + "\x03tls\x18\x04 \x01(\tR\x03tls\x12 \n" + + "\venforcement\x18\x05 \x01(\tR\venforcement\x12\x16\n" + + "\x06access\x18\x06 \x01(\tR\x06access\x122\n" + + "\x05rules\x18\a \x03(\v2\x1c.openshell.sandbox.v1.L7RuleR\x05rules\x12\x1f\n" + + "\vallowed_ips\x18\b \x03(\tR\n" + + "allowedIps\x12\x14\n" + + "\x05ports\x18\t \x03(\rR\x05ports\"=\n" + + "\x06L7Rule\x123\n" + + "\x05allow\x18\x01 \x01(\v2\x1d.openshell.sandbox.v1.L7AllowR\x05allow\"O\n" + + "\aL7Allow\x12\x16\n" + + "\x06method\x18\x01 \x01(\tR\x06method\x12\x12\n" + + "\x04path\x18\x02 \x01(\tR\x04path\x12\x18\n" + + "\acommand\x18\x03 \x01(\tR\acommand\"A\n" + + "\rNetworkBinary\x12\x12\n" + + "\x04path\x18\x01 \x01(\tR\x04path\x12\x1c\n" + + "\aharness\x18\x02 \x01(\bB\x02\x18\x01R\aharness\"8\n" + + "\x17GetSandboxPolicyRequest\x12\x1d\n" + + "\n" + + "sandbox_id\x18\x01 \x01(\tR\tsandboxId\"\x92\x01\n" + + "\x18GetSandboxPolicyResponse\x12;\n" + + "\x06policy\x18\x01 \x01(\v2#.openshell.sandbox.v1.SandboxPolicyR\x06policy\x12\x18\n" + + "\aversion\x18\x02 \x01(\rR\aversion\x12\x1f\n" + + "\vpolicy_hash\x18\x03 \x01(\tR\n" + + "policyHashb\x06proto3" + +var ( + file_sandbox_proto_rawDescOnce sync.Once + file_sandbox_proto_rawDescData []byte +) + +func file_sandbox_proto_rawDescGZIP() []byte { + file_sandbox_proto_rawDescOnce.Do(func() { + file_sandbox_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_sandbox_proto_rawDesc), len(file_sandbox_proto_rawDesc))) + }) + return file_sandbox_proto_rawDescData +} + +var file_sandbox_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_sandbox_proto_goTypes = []any{ + (*SandboxPolicy)(nil), // 0: openshell.sandbox.v1.SandboxPolicy + (*FilesystemPolicy)(nil), // 1: openshell.sandbox.v1.FilesystemPolicy + (*LandlockPolicy)(nil), // 2: openshell.sandbox.v1.LandlockPolicy + (*ProcessPolicy)(nil), // 3: openshell.sandbox.v1.ProcessPolicy + (*NetworkPolicyRule)(nil), // 4: openshell.sandbox.v1.NetworkPolicyRule + (*NetworkEndpoint)(nil), // 5: openshell.sandbox.v1.NetworkEndpoint + (*L7Rule)(nil), // 6: openshell.sandbox.v1.L7Rule + (*L7Allow)(nil), // 7: openshell.sandbox.v1.L7Allow + (*NetworkBinary)(nil), // 8: openshell.sandbox.v1.NetworkBinary + (*GetSandboxPolicyRequest)(nil), // 9: openshell.sandbox.v1.GetSandboxPolicyRequest + (*GetSandboxPolicyResponse)(nil), // 10: openshell.sandbox.v1.GetSandboxPolicyResponse + nil, // 11: openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry +} +var file_sandbox_proto_depIdxs = []int32{ + 1, // 0: openshell.sandbox.v1.SandboxPolicy.filesystem:type_name -> openshell.sandbox.v1.FilesystemPolicy + 2, // 1: openshell.sandbox.v1.SandboxPolicy.landlock:type_name -> openshell.sandbox.v1.LandlockPolicy + 3, // 2: openshell.sandbox.v1.SandboxPolicy.process:type_name -> openshell.sandbox.v1.ProcessPolicy + 11, // 3: openshell.sandbox.v1.SandboxPolicy.network_policies:type_name -> openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry + 5, // 4: openshell.sandbox.v1.NetworkPolicyRule.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint + 8, // 5: openshell.sandbox.v1.NetworkPolicyRule.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 6, // 6: openshell.sandbox.v1.NetworkEndpoint.rules:type_name -> openshell.sandbox.v1.L7Rule + 7, // 7: openshell.sandbox.v1.L7Rule.allow:type_name -> openshell.sandbox.v1.L7Allow + 0, // 8: openshell.sandbox.v1.GetSandboxPolicyResponse.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 4, // 9: openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry.value:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 10, // [10:10] is the sub-list for method output_type + 10, // [10:10] is the sub-list for method input_type + 10, // [10:10] is the sub-list for extension type_name + 10, // [10:10] is the sub-list for extension extendee + 0, // [0:10] is the sub-list for field type_name +} + +func init() { file_sandbox_proto_init() } +func file_sandbox_proto_init() { + if File_sandbox_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_sandbox_proto_rawDesc), len(file_sandbox_proto_rawDesc)), + NumEnums: 0, + NumMessages: 12, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_sandbox_proto_goTypes, + DependencyIndexes: file_sandbox_proto_depIdxs, + MessageInfos: file_sandbox_proto_msgTypes, + }.Build() + File_sandbox_proto = out.File + file_sandbox_proto_goTypes = nil + file_sandbox_proto_depIdxs = nil +} diff --git a/internal/registry/platforms/openshell/proto/inference.proto b/internal/registry/platforms/openshell/proto/inference.proto new file mode 100644 index 00000000..a15f4b84 --- /dev/null +++ b/internal/registry/platforms/openshell/proto/inference.proto @@ -0,0 +1,114 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package openshell.inference.v1; + +option java_multiple_files = true; +option java_package = "com.anthropic.openshell.inference.v1"; + +// Inference service provides cluster inference configuration and bundle delivery. +service Inference { + // Return the resolved inference route bundle for sandbox-local execution. + rpc GetInferenceBundle(GetInferenceBundleRequest) + returns (GetInferenceBundleResponse); + + // Set cluster-level inference configuration. + // + // This controls how requests sent to `inference.local` are routed. + rpc SetClusterInference(SetClusterInferenceRequest) + returns (SetClusterInferenceResponse); + + // Get cluster-level inference configuration. + rpc GetClusterInference(GetClusterInferenceRequest) + returns (GetClusterInferenceResponse); + +} + +// Persisted cluster inference configuration. +// +// Only `provider_name` and `model_id` are stored; endpoint, protocols, +// credentials, and auth style are resolved from the provider at bundle time. +message ClusterInferenceConfig { + // Provider record name backing this route. + string provider_name = 1; + // Model identifier to force on generation calls. + string model_id = 2; +} + +// Storage envelope for the managed cluster inference route. +message InferenceRoute { + string id = 1; + ClusterInferenceConfig config = 2; + // Object name ("inference.local" for the user-facing route, + // "sandbox-system" for the sandbox system-level route). + string name = 3; + // Monotonic version incremented on every update. + uint64 version = 4; +} + +message SetClusterInferenceRequest { + // Provider record name to use for credentials + endpoint mapping. + string provider_name = 1; + // Model identifier to force on generation calls. + string model_id = 2; + // Route name to target. Empty string defaults to "inference.local" (user-facing). + // Use "sandbox-system" for the sandbox system-level inference route. + string route_name = 3; + // Verify the resolved upstream endpoint synchronously before persistence. + bool verify = 4; + // Skip synchronous endpoint validation before persistence. + bool no_verify = 5; +} + +message ValidatedEndpoint { + string url = 1; + string protocol = 2; +} + +message SetClusterInferenceResponse { + string provider_name = 1; + string model_id = 2; + uint64 version = 3; + // Route name that was configured. + string route_name = 4; + // Whether endpoint verification ran as part of this request. + bool validation_performed = 5; + // The concrete endpoints that were probed during validation, when available. + repeated ValidatedEndpoint validated_endpoints = 6; +} + +message GetClusterInferenceRequest { + // Route name to query. Empty string defaults to "inference.local" (user-facing). + // Use "sandbox-system" for the sandbox system-level inference route. + string route_name = 1; +} + +message GetClusterInferenceResponse { + string provider_name = 1; + string model_id = 2; + uint64 version = 3; + // Route name that was queried. + string route_name = 4; +} + +message GetInferenceBundleRequest {} + +// A single resolved route ready for sandbox-local execution. +message ResolvedRoute { + string name = 1; + string base_url = 2; + repeated string protocols = 3; + string api_key = 4; + string model_id = 5; + string provider_type = 6; +} + +message GetInferenceBundleResponse { + repeated ResolvedRoute routes = 1; + // Opaque revision tag for cache freshness checks. + string revision = 2; + // Timestamp (epoch ms) when this bundle was generated. + int64 generated_at_ms = 3; +} diff --git a/internal/registry/platforms/openshell/proto/openshell.proto b/internal/registry/platforms/openshell/proto/openshell.proto new file mode 100644 index 00000000..ad93848d --- /dev/null +++ b/internal/registry/platforms/openshell/proto/openshell.proto @@ -0,0 +1,827 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package openshell.v1; + +import "datamodel.proto"; +import "sandbox.proto"; + +option java_multiple_files = true; +option java_package = "com.anthropic.openshell.v1"; + +// OpenShell service provides sandbox, provider, and runtime management capabilities. +service OpenShell { + // Check the health of the service. + rpc Health(HealthRequest) returns (HealthResponse); + + // Create a new sandbox. + rpc CreateSandbox(CreateSandboxRequest) returns (SandboxResponse); + + // Fetch a sandbox by name. + rpc GetSandbox(GetSandboxRequest) returns (SandboxResponse); + + // List sandboxes. + rpc ListSandboxes(ListSandboxesRequest) returns (ListSandboxesResponse); + + // Delete a sandbox by name. + rpc DeleteSandbox(DeleteSandboxRequest) returns (DeleteSandboxResponse); + + // Create a short-lived SSH session for a sandbox. + rpc CreateSshSession(CreateSshSessionRequest) returns (CreateSshSessionResponse); + + // Revoke a previously issued SSH session. + rpc RevokeSshSession(RevokeSshSessionRequest) returns (RevokeSshSessionResponse); + + // Execute a command in a ready sandbox and stream output. + rpc ExecSandbox(ExecSandboxRequest) returns (stream ExecSandboxEvent); + + // Create a provider. + rpc CreateProvider(CreateProviderRequest) returns (ProviderResponse); + + // Fetch a provider by name. + rpc GetProvider(GetProviderRequest) returns (ProviderResponse); + + // List providers. + rpc ListProviders(ListProvidersRequest) returns (ListProvidersResponse); + + // Update an existing provider by name. + rpc UpdateProvider(UpdateProviderRequest) returns (ProviderResponse); + + // Delete a provider by name. + rpc DeleteProvider(DeleteProviderRequest) returns (DeleteProviderResponse); + + // Get sandbox policy by id (called by sandbox entrypoint and poll loop). + rpc GetSandboxPolicy(openshell.sandbox.v1.GetSandboxPolicyRequest) + returns (openshell.sandbox.v1.GetSandboxPolicyResponse); + + // Update sandbox policy on a live sandbox. + rpc UpdateSandboxPolicy(UpdateSandboxPolicyRequest) + returns (UpdateSandboxPolicyResponse); + + // Get the load status of a specific policy version. + rpc GetSandboxPolicyStatus(GetSandboxPolicyStatusRequest) + returns (GetSandboxPolicyStatusResponse); + + // List policy history for a sandbox. + rpc ListSandboxPolicies(ListSandboxPoliciesRequest) + returns (ListSandboxPoliciesResponse); + + // Report policy load result (called by sandbox after reload attempt). + rpc ReportPolicyStatus(ReportPolicyStatusRequest) + returns (ReportPolicyStatusResponse); + + // Get provider environment for a sandbox (called by sandbox supervisor at startup). + rpc GetSandboxProviderEnvironment(GetSandboxProviderEnvironmentRequest) + returns (GetSandboxProviderEnvironmentResponse); + + // Fetch recent sandbox logs (one-shot). + rpc GetSandboxLogs(GetSandboxLogsRequest) returns (GetSandboxLogsResponse); + + // Push sandbox supervisor logs to the server (client-streaming). + rpc PushSandboxLogs(stream PushSandboxLogsRequest) returns (PushSandboxLogsResponse); + + // Watch a sandbox and stream updates. + // + // This stream can include: + // - Sandbox status snapshots (phase/status) + // - OpenShell server process logs correlated by sandbox_id + // - Platform events correlated to the sandbox + rpc WatchSandbox(WatchSandboxRequest) returns (stream SandboxStreamEvent); + + // --------------------------------------------------------------------------- + // Draft policy recommendation RPCs + // --------------------------------------------------------------------------- + + // Submit denial analysis results from sandbox (summaries + proposed chunks). + rpc SubmitPolicyAnalysis(SubmitPolicyAnalysisRequest) + returns (SubmitPolicyAnalysisResponse); + + // Get draft policy recommendations for a sandbox. + rpc GetDraftPolicy(GetDraftPolicyRequest) returns (GetDraftPolicyResponse); + + // Approve a single draft policy chunk (merges into active policy). + rpc ApproveDraftChunk(ApproveDraftChunkRequest) + returns (ApproveDraftChunkResponse); + + // Reject a single draft policy chunk. + rpc RejectDraftChunk(RejectDraftChunkRequest) + returns (RejectDraftChunkResponse); + + // Approve all pending draft chunks (skips security-flagged unless forced). + rpc ApproveAllDraftChunks(ApproveAllDraftChunksRequest) + returns (ApproveAllDraftChunksResponse); + + // Edit a pending draft chunk in-place (e.g. narrow allowed_ips). + rpc EditDraftChunk(EditDraftChunkRequest) returns (EditDraftChunkResponse); + + // Reverse an approval (remove merged rule from active policy). + rpc UndoDraftChunk(UndoDraftChunkRequest) returns (UndoDraftChunkResponse); + + // Clear all pending draft chunks for a sandbox. + rpc ClearDraftChunks(ClearDraftChunksRequest) + returns (ClearDraftChunksResponse); + + // Get decision history for a sandbox's draft policy. + rpc GetDraftHistory(GetDraftHistoryRequest) returns (GetDraftHistoryResponse); +} + +// Health check request. +message HealthRequest {} + +// Health check response. +message HealthResponse { + // Service status. + ServiceStatus status = 1; + + // Service version. + string version = 2; +} + +// Create sandbox request. +message CreateSandboxRequest { + openshell.datamodel.v1.SandboxSpec spec = 1; + // Optional user-supplied sandbox name. When empty the server generates one. + string name = 2; +} + +// Get sandbox request. +message GetSandboxRequest { + // Sandbox name (canonical lookup key). + string name = 1; +} + +// List sandboxes request. +message ListSandboxesRequest { + uint32 limit = 1; + uint32 offset = 2; +} + +// Delete sandbox request. +message DeleteSandboxRequest { + // Sandbox name (canonical lookup key). + string name = 1; +} + +// Sandbox response. +message SandboxResponse { + openshell.datamodel.v1.Sandbox sandbox = 1; +} + +// List sandboxes response. +message ListSandboxesResponse { + repeated openshell.datamodel.v1.Sandbox sandboxes = 1; +} + +// Delete sandbox response. +message DeleteSandboxResponse { + bool deleted = 1; +} + +// Create SSH session request. +message CreateSshSessionRequest { + // Sandbox id. + string sandbox_id = 1; +} + +// Create SSH session response. +message CreateSshSessionResponse { + // Sandbox id. + string sandbox_id = 1; + + // Session token for the gateway tunnel. + string token = 2; + + // Gateway host for SSH proxy connection. + string gateway_host = 3; + + // Gateway port for SSH proxy connection. + uint32 gateway_port = 4; + + // Gateway scheme (http or https). + string gateway_scheme = 5; + + // HTTP path for the CONNECT/upgrade endpoint. + string connect_path = 6; + + // Optional host key fingerprint. + string host_key_fingerprint = 7; + + // Expiry timestamp in milliseconds since epoch. 0 means no expiry. + int64 expires_at_ms = 8; +} + +// Revoke SSH session request. +message RevokeSshSessionRequest { + // Session token to revoke. + string token = 1; +} + +// Revoke SSH session response. +message RevokeSshSessionResponse { + // True when a session was revoked. + bool revoked = 1; +} + +// Execute command request. +message ExecSandboxRequest { + // Sandbox id. + string sandbox_id = 1; + + // Command and arguments. + repeated string command = 2; + + // Optional working directory. + string workdir = 3; + + // Optional environment overrides. + map environment = 4; + + // Optional timeout in seconds. 0 means no timeout. + uint32 timeout_seconds = 5; + + // Optional stdin payload passed to the command. + bytes stdin = 6; +} + +// One stdout chunk from a sandbox exec. +message ExecSandboxStdout { + bytes data = 1; +} + +// One stderr chunk from a sandbox exec. +message ExecSandboxStderr { + bytes data = 1; +} + +// Final exit status for a sandbox exec. +message ExecSandboxExit { + int32 exit_code = 1; +} + +// One event in a sandbox exec stream. +message ExecSandboxEvent { + oneof payload { + ExecSandboxStdout stdout = 1; + ExecSandboxStderr stderr = 2; + ExecSandboxExit exit = 3; + } +} + +// SSH session record stored in persistence. +message SshSession { + // Unique id (token). + string id = 1; + + // Sandbox id. + string sandbox_id = 2; + + // Session token. + string token = 3; + + // Creation timestamp in milliseconds since epoch. + int64 created_at_ms = 4; + + // Revoked flag. + bool revoked = 5; + + // Human-friendly name (auto-generated if not provided). + string name = 6; + + // Expiry timestamp in milliseconds since epoch. 0 means no expiry + // (backward-compatible default for sessions created before this field existed). + int64 expires_at_ms = 7; +} + +// Watch sandbox request. +message WatchSandboxRequest { + // Sandbox id. + string id = 1; + + // Stream sandbox status snapshots. + bool follow_status = 2; + + // Stream openshell-server process logs correlated to this sandbox. + bool follow_logs = 3; + + // Stream platform events correlated to this sandbox. + bool follow_events = 4; + + // Replay the last N log lines (best-effort) before following. + uint32 log_tail_lines = 5; + + // Replay the last N platform events (best-effort) before following. + uint32 event_tail = 6; + + // Stop streaming once the sandbox reaches a terminal phase (READY or ERROR). + bool stop_on_terminal = 7; + + // Only include log lines with timestamp >= this value (milliseconds since epoch). + // 0 means no time filter. Applies to both tail replay and live streaming. + int64 log_since_ms = 8; + + // Filter by log source (e.g. "gateway", "sandbox"). Empty means all sources. + repeated string log_sources = 9; + + // Minimum log level to include (e.g. "INFO", "WARN", "ERROR"). Empty means all levels. + string log_min_level = 10; +} + +// One event in a sandbox watch stream. +message SandboxStreamEvent { + oneof payload { + // Latest sandbox snapshot. + openshell.datamodel.v1.Sandbox sandbox = 1; + // One server log line/event. + SandboxLogLine log = 2; + // One platform event. + PlatformEvent event = 3; + // Warning from the server (e.g. missed messages due to lag). + SandboxStreamWarning warning = 4; + // Draft policy update notification. + DraftPolicyUpdate draft_policy_update = 5; + } +} + +// Log line correlated to a sandbox. +message SandboxLogLine { + string sandbox_id = 1; + int64 timestamp_ms = 2; + string level = 3; + string target = 4; + string message = 5; + // Log source: "gateway" (server-side) or "sandbox" (supervisor). + // Empty is treated as "gateway" for backward compatibility. + string source = 6; + // Structured key-value fields from the tracing event (e.g. dst_host, action). + map fields = 7; +} + +// Platform event correlated to a sandbox. +message PlatformEvent { + // Event timestamp in milliseconds since epoch. + int64 timestamp_ms = 1; + // Event source (e.g. "kubernetes", "docker", "process"). + string source = 2; + // Event type/severity (e.g. "Normal", "Warning"). + string type = 3; + // Short reason code (e.g. "Started", "Pulled", "Failed"). + string reason = 4; + // Human-readable event message. + string message = 5; + // Optional metadata as key-value pairs. + map metadata = 6; +} + +message SandboxStreamWarning { + string message = 1; +} + +// Create provider request. +message CreateProviderRequest { + openshell.datamodel.v1.Provider provider = 1; +} + +// Get provider request. +message GetProviderRequest { + string name = 1; +} + +// List providers request. +message ListProvidersRequest { + uint32 limit = 1; + uint32 offset = 2; +} + +// Update provider request. +message UpdateProviderRequest { + openshell.datamodel.v1.Provider provider = 1; +} + +// Delete provider request. +message DeleteProviderRequest { + string name = 1; +} + +// Provider response. +message ProviderResponse { + openshell.datamodel.v1.Provider provider = 1; +} + +// List providers response. +message ListProvidersResponse { + repeated openshell.datamodel.v1.Provider providers = 1; +} + +// Delete provider response. +message DeleteProviderResponse { + bool deleted = 1; +} + +// Get sandbox provider environment request. +message GetSandboxProviderEnvironmentRequest { + // The sandbox ID. + string sandbox_id = 1; +} + +// Get sandbox provider environment response. +message GetSandboxProviderEnvironmentResponse { + // Provider credential environment variables. + map environment = 1; +} + +// --------------------------------------------------------------------------- +// Policy update messages +// --------------------------------------------------------------------------- + +// Update sandbox policy request. +message UpdateSandboxPolicyRequest { + // Sandbox name (canonical lookup key). + string name = 1; + // The new policy to apply. Only network_policies and inference fields may + // differ from the create-time policy; static fields (filesystem, landlock, + // process) must match version 1 or the request is rejected. + openshell.sandbox.v1.SandboxPolicy policy = 2; +} + +// Update sandbox policy response. +message UpdateSandboxPolicyResponse { + // Assigned policy version (monotonically increasing per sandbox). + uint32 version = 1; + // SHA-256 hash of the serialized policy payload. + string policy_hash = 2; +} + +// Get sandbox policy status request. +message GetSandboxPolicyStatusRequest { + // Sandbox name (canonical lookup key). + string name = 1; + // The specific policy version to query. 0 means latest. + uint32 version = 2; +} + +// Get sandbox policy status response. +message GetSandboxPolicyStatusResponse { + // The queried policy revision. + SandboxPolicyRevision revision = 1; + // The currently active (loaded) policy version for this sandbox. + uint32 active_version = 2; +} + +// List sandbox policies request. +message ListSandboxPoliciesRequest { + // Sandbox name (canonical lookup key). + string name = 1; + uint32 limit = 2; + uint32 offset = 3; +} + +// List sandbox policies response. +message ListSandboxPoliciesResponse { + repeated SandboxPolicyRevision revisions = 1; +} + +// Report policy load status (called by sandbox runtime after reload attempt). +message ReportPolicyStatusRequest { + // Sandbox id. + string sandbox_id = 1; + // The policy version that was attempted. + uint32 version = 2; + // Load result status. + PolicyStatus status = 3; + // Error message if status is FAILED. + string load_error = 4; +} + +// Report policy status response. +message ReportPolicyStatusResponse {} + +// A versioned policy revision with metadata. +message SandboxPolicyRevision { + // Policy version (monotonically increasing per sandbox). + uint32 version = 1; + // SHA-256 hash of the serialized policy payload. + string policy_hash = 2; + // Load status of this revision. + PolicyStatus status = 3; + // Error message if status is FAILED. + string load_error = 4; + // Milliseconds since epoch when this revision was created. + int64 created_at_ms = 5; + // Milliseconds since epoch when this revision was loaded by the sandbox. + int64 loaded_at_ms = 6; + // The full policy (only populated when explicitly requested). + openshell.sandbox.v1.SandboxPolicy policy = 7; +} + +// Policy load status. +enum PolicyStatus { + POLICY_STATUS_UNSPECIFIED = 0; + // Server received the update; sandbox has not yet loaded it. + POLICY_STATUS_PENDING = 1; + // Sandbox successfully applied this policy version. + POLICY_STATUS_LOADED = 2; + // Sandbox attempted to apply but failed; LKG policy remains active. + POLICY_STATUS_FAILED = 3; + // A newer version was persisted before the sandbox loaded this one. + POLICY_STATUS_SUPERSEDED = 4; +} + +// --------------------------------------------------------------------------- +// Sandbox logs messages +// --------------------------------------------------------------------------- + +// Get sandbox logs request (one-shot fetch). +message GetSandboxLogsRequest { + // Sandbox id. + string sandbox_id = 1; + // Maximum number of log lines to return. 0 means use default (2000). + uint32 lines = 2; + // Only include logs with timestamp >= this value (ms since epoch). 0 means no filter. + int64 since_ms = 3; + // Filter by log source (e.g. "gateway", "sandbox"). Empty means all sources. + repeated string sources = 4; + // Minimum log level to include (e.g. "INFO", "WARN", "ERROR"). Empty means all levels. + string min_level = 5; +} + +// Batch of log lines pushed from sandbox to server. +message PushSandboxLogsRequest { + // The sandbox ID. + string sandbox_id = 1; + // Log lines to ingest. + repeated SandboxLogLine logs = 2; +} + +// Push sandbox logs response. +message PushSandboxLogsResponse {} + +// Get sandbox logs response. +message GetSandboxLogsResponse { + // Log lines in chronological order. + repeated SandboxLogLine logs = 1; + // Total number of lines in the server's buffer for this sandbox. + uint32 buffer_total = 2; +} + +// --------------------------------------------------------------------------- +// Service status +// --------------------------------------------------------------------------- + +// Service status enum. +enum ServiceStatus { + SERVICE_STATUS_UNSPECIFIED = 0; + SERVICE_STATUS_HEALTHY = 1; + SERVICE_STATUS_DEGRADED = 2; + SERVICE_STATUS_UNHEALTHY = 3; +} + +// --------------------------------------------------------------------------- +// Draft policy recommendation messages +// --------------------------------------------------------------------------- + +// Observed HTTP method+path pattern from L7 inspection. +message L7RequestSample { + // HTTP method: GET, POST, PUT, DELETE, etc. + string method = 1; + // HTTP path: /v1/models, /repos/myorg/issues + string path = 2; + // L7 decision: "audit" or "deny" (allowed requests not collected). + string decision = 3; + // Number of times this (method, path) was observed. + uint32 count = 4; +} + +// Structured denial summary from sandbox aggregator. +message DenialSummary { + // Sandbox ID that produced this summary. + string sandbox_id = 1; + // Denied destination host. + string host = 2; + // Denied destination port. + uint32 port = 3; + // Binary that attempted the connection. + string binary = 4; + // Process ancestor chain. + repeated string ancestors = 5; + // Denial reason from OPA evaluation. + string deny_reason = 6; + // First denial timestamp (ms since epoch). + int64 first_seen_ms = 7; + // Most recent denial timestamp (ms since epoch). + int64 last_seen_ms = 8; + // Number of denials in the current window. + uint32 count = 9; + // Events dropped during aggregator cooldown. + uint32 suppressed_count = 10; + // Cumulative lifetime count (never resets). + uint32 total_count = 11; + // Distinct cmdline strings observed (sanitized of credentials). + repeated string sample_cmdlines = 12; + // SHA-256 of the binary for audit trail. + string binary_sha256 = 13; + // True if emitted by stale-flush rather than threshold. + bool persistent = 14; + // Denial category: "l4_deny", "l7_deny", "l7_audit", "ssrf". + string denial_stage = 15; + // Observed HTTP request patterns (from L7 inspection). + repeated L7RequestSample l7_request_samples = 16; + // True if L7 inspection was active during observation window. + bool l7_inspection_active = 17; +} + +// A proposed policy rule with rationale and approval status. +message PolicyChunk { + // Unique chunk identifier. + string id = 1; + // Approval status: "pending", "approved", "rejected". + string status = 2; + // Proposed network_policies map key. + string rule_name = 3; + // The proposed network policy rule. + openshell.sandbox.v1.NetworkPolicyRule proposed_rule = 4; + // Human-readable explanation of why this rule is proposed. + string rationale = 5; + // Security concerns flagged by analysis (empty if none). + string security_notes = 6; + // Analysis confidence (0.0-1.0). 0 for mechanistic mode. + float confidence = 7; + // IDs of denial summaries that led to this chunk. + repeated string denial_summary_ids = 8; + // Creation timestamp (ms since epoch). + int64 created_at_ms = 9; + // When the user approved/rejected (ms since epoch). 0 if undecided. + int64 decided_at_ms = 10; + // Recommendation stage: "initial" or "refined" (progressive L7 visibility). + string stage = 11; + // For stage="refined": the initial chunk this replaces. + string supersedes_chunk_id = 12; + // How many times this endpoint has been seen across denial flush cycles. + int32 hit_count = 13; + // First time this endpoint was proposed (ms since epoch). + int64 first_seen_ms = 14; + // Most recent time this endpoint was re-proposed (ms since epoch). + int64 last_seen_ms = 15; + // Binary path that triggered the denial (denormalized for display convenience). + string binary = 16; +} + +// Notification that the draft policy was updated. +message DraftPolicyUpdate { + // Current draft version. + uint64 draft_version = 1; + // Number of new chunks added in this update. + uint32 new_chunks = 2; + // Total pending chunks awaiting approval. + uint32 total_pending = 3; + // Brief description of what changed. + string summary = 4; +} + +// Submit analysis results from sandbox to gateway. +message SubmitPolicyAnalysisRequest { + // Aggregated denial summaries. + repeated DenialSummary summaries = 1; + // Proposed policy chunks (validated by sandbox OPA engine). + repeated PolicyChunk proposed_chunks = 2; + // Analysis mode: "mechanistic" or "llm". + string analysis_mode = 3; + // Sandbox name. + string name = 4; +} + +message SubmitPolicyAnalysisResponse { + // Number of chunks accepted by the gateway. + uint32 accepted_chunks = 1; + // Number of chunks rejected by gateway validation. + uint32 rejected_chunks = 2; + // Reasons for each rejected chunk. + repeated string rejection_reasons = 3; +} + +// Get draft policy for a sandbox. +message GetDraftPolicyRequest { + // Sandbox name. + string name = 1; + // Optional status filter: "pending", "approved", "rejected", or "" for all. + string status_filter = 2; +} + +message GetDraftPolicyResponse { + // Draft policy chunks. + repeated PolicyChunk chunks = 1; + // LLM-generated summary of all analysis (empty in mechanistic mode). + string rolling_summary = 2; + // Current draft version. + uint64 draft_version = 3; + // When the last analysis completed (ms since epoch). + int64 last_analyzed_at_ms = 4; +} + +// Approve a single draft chunk. +message ApproveDraftChunkRequest { + // Sandbox name. + string name = 1; + // Chunk ID to approve. + string chunk_id = 2; +} + +message ApproveDraftChunkResponse { + // New policy version after merge. + uint32 policy_version = 1; + // SHA-256 hash of the new policy. + string policy_hash = 2; +} + +// Reject a single draft chunk. +message RejectDraftChunkRequest { + // Sandbox name. + string name = 1; + // Chunk ID to reject. + string chunk_id = 2; + // Optional reason for rejection (fed to LLM context in future analysis). + string reason = 3; +} + +message RejectDraftChunkResponse {} + +// Approve all pending chunks. +message ApproveAllDraftChunksRequest { + // Sandbox name. + string name = 1; + // Include chunks with security_notes (default false: skips them). + bool include_security_flagged = 2; +} + +message ApproveAllDraftChunksResponse { + // New policy version after merge. + uint32 policy_version = 1; + // SHA-256 hash of the new policy. + string policy_hash = 2; + // Number of chunks approved. + uint32 chunks_approved = 3; + // Number of chunks skipped (security-flagged). + uint32 chunks_skipped = 4; +} + +// Edit a pending chunk in-place. +message EditDraftChunkRequest { + // Sandbox name. + string name = 1; + // Chunk ID to edit. + string chunk_id = 2; + // The modified rule (replaces existing proposed_rule). + openshell.sandbox.v1.NetworkPolicyRule proposed_rule = 3; +} + +message EditDraftChunkResponse {} + +// Reverse an approval (remove merged rule from active policy). +message UndoDraftChunkRequest { + // Sandbox name. + string name = 1; + // Chunk ID to undo. + string chunk_id = 2; +} + +message UndoDraftChunkResponse { + // New policy version after removal. + uint32 policy_version = 1; + // SHA-256 hash of the updated policy. + string policy_hash = 2; +} + +// Clear all pending draft chunks for a sandbox. +message ClearDraftChunksRequest { + // Sandbox name. + string name = 1; +} + +message ClearDraftChunksResponse { + // Number of chunks cleared. + uint32 chunks_cleared = 1; +} + +// Get decision history for a sandbox's draft policy. +message GetDraftHistoryRequest { + // Sandbox name. + string name = 1; +} + +message DraftHistoryEntry { + // Event timestamp (ms since epoch). + int64 timestamp_ms = 1; + // Event type: "denial_detected", "analysis_cycle", "approved", + // "rejected", "edited", "undone", "cleared". + string event_type = 2; + // Human-readable description. + string description = 3; + // Associated chunk ID (if applicable). + string chunk_id = 4; +} + +message GetDraftHistoryResponse { + // Chronological decision history. + repeated DraftHistoryEntry entries = 1; +} diff --git a/internal/registry/platforms/openshell/proto/sandbox.proto b/internal/registry/platforms/openshell/proto/sandbox.proto new file mode 100644 index 00000000..01925fbe --- /dev/null +++ b/internal/registry/platforms/openshell/proto/sandbox.proto @@ -0,0 +1,126 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package openshell.sandbox.v1; + +// Sandbox security policy configuration. +message SandboxPolicy { + // Policy version. + uint32 version = 1; + // Filesystem access policy. + FilesystemPolicy filesystem = 2; + // Landlock configuration. + LandlockPolicy landlock = 3; + // Process execution policy. + ProcessPolicy process = 4; + // Network access policies keyed by name (e.g. "claude_code", "gitlab"). + map network_policies = 5; +} + +// Filesystem access policy. +message FilesystemPolicy { + // Automatically include the workdir as read-write. + bool include_workdir = 1; + // Read-only directory allow list. + repeated string read_only = 2; + // Read-write directory allow list. + repeated string read_write = 3; +} + +// Landlock policy configuration. +message LandlockPolicy { + // Compatibility mode (e.g. "best_effort", "hard_requirement"). + string compatibility = 1; +} + +// Process execution policy. +message ProcessPolicy { + // User name to run the sandboxed process as. + string run_as_user = 1; + // Group name to run the sandboxed process as. + string run_as_group = 2; +} + +// A named network access policy rule. +message NetworkPolicyRule { + // Human-readable name for this policy rule. + string name = 1; + // Allowed endpoint (host:port) pairs. + repeated NetworkEndpoint endpoints = 2; + // Allowed binary identities. + repeated NetworkBinary binaries = 3; +} + +// A network endpoint (host + port) with optional L7 inspection config. +message NetworkEndpoint { + // Hostname or host glob pattern. Exact match is case-insensitive. + // Glob patterns use "." as delimiter: "*.example.com" matches a single + // subdomain label, "**.example.com" matches across labels. + string host = 1; + // Single port (backwards compat). Use `ports` for multiple ports. + // Mutually exclusive with `ports` — if both are set, `ports` takes precedence. + uint32 port = 2; + // Application protocol for L7 inspection: "rest", "sql", or "" (L4-only). + string protocol = 3; + // TLS handling: "terminate" or "passthrough" (default). + string tls = 4; + // Enforcement mode: "enforce" or "audit" (default). + string enforcement = 5; + // Access preset shorthand: "read-only", "read-write", "full". + // Mutually exclusive with rules. + string access = 6; + // Explicit L7 rules (mutually exclusive with access). + repeated L7Rule rules = 7; + // Allowed resolved IP addresses or CIDR ranges for this endpoint. + // When non-empty, the SSRF internal-IP check is replaced by an allowlist check: + // - If host is also set: domain must resolve to an IP in this list. + // - If host is empty: any domain is allowed as long as it resolves to an IP in this list. + // Supports exact IPs ("10.0.5.20") and CIDR notation ("10.0.5.0/24"). + // Loopback (127.0.0.0/8) and link-local (169.254.0.0/16) are always blocked + // regardless of this field. + repeated string allowed_ips = 8; + // Multiple ports. When non-empty, this endpoint covers all listed ports. + // If `port` is set and `ports` is empty, `port` is normalized to `ports: [port]`. + // If both are set, `ports` takes precedence. + repeated uint32 ports = 9; +} + +// An L7 policy rule (allow-only). +message L7Rule { + L7Allow allow = 1; +} + +// Allowed action definition for L7 rules. +message L7Allow { + // HTTP method (REST): GET, POST, etc. or "*" for any. + string method = 1; + // URL path glob pattern (REST): "/repos/**", "**" for any. + string path = 2; + // SQL command (SQL): SELECT, INSERT, etc. or "*" for any. + string command = 3; +} + +// A binary identity for network policy matching. +message NetworkBinary { + string path = 1; + // Deprecated: the harness concept has been removed. This field is ignored. + bool harness = 2 [deprecated = true]; +} + +// Request to get sandbox policy by sandbox ID. +message GetSandboxPolicyRequest { + // The sandbox ID. + string sandbox_id = 1; +} + +// Response containing sandbox policy. +message GetSandboxPolicyResponse { + // The sandbox policy configuration. + SandboxPolicy policy = 1; + // Current policy version (monotonically increasing per sandbox). + uint32 version = 2; + // SHA-256 hash of the serialized policy payload. + string policy_hash = 3; +} diff --git a/internal/registry/platforms/openshell/provider_config.go b/internal/registry/platforms/openshell/provider_config.go new file mode 100644 index 00000000..f2034fec --- /dev/null +++ b/internal/registry/platforms/openshell/provider_config.go @@ -0,0 +1,7 @@ +package openshell + +// OpenShellProviderConfig holds provider-level configuration for the OpenShell platform. +type OpenShellProviderConfig struct { + GatewayName string `json:"gatewayName,omitempty"` + InferenceProviders []string `json:"inferenceProviders,omitempty"` +} diff --git a/internal/registry/registry_app.go b/internal/registry/registry_app.go index 1bee94e2..77128fda 100644 --- a/internal/registry/registry_app.go +++ b/internal/registry/registry_app.go @@ -15,6 +15,7 @@ import ( "github.com/agentregistry-dev/agentregistry/internal/registry/platforms/kubernetes" "github.com/agentregistry-dev/agentregistry/internal/registry/platforms/local" + "github.com/agentregistry-dev/agentregistry/internal/registry/platforms/openshell" "github.com/modelcontextprotocol/go-sdk/mcp" mcpregistry "github.com/agentregistry-dev/agentregistry/internal/mcp/registryserver" @@ -133,6 +134,7 @@ func App(_ context.Context, opts ...types.AppOptions) error { deploymentPlatforms := map[string]types.DeploymentPlatformAdapter{ "local": local.NewLocalDeploymentAdapter(registryService, cfg.RuntimeDir, cfg.AgentGatewayPort), "kubernetes": kubernetes.NewKubernetesDeploymentAdapter(registryService), + "openshell": openshell.NewOpenShellDeploymentAdapter(registryService, nil), } maps.Copy(deploymentPlatforms, options.DeploymentPlatforms) diff --git a/ui/components/deploy-server-dialog.tsx b/ui/components/deploy-server-dialog.tsx index 5a0fc5bf..0967a2d2 100644 --- a/ui/components/deploy-server-dialog.tsx +++ b/ui/components/deploy-server-dialog.tsx @@ -1,12 +1,20 @@ "use client" -import { useState } from "react" +import { useEffect, useState } from "react" import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Separator } from "@/components/ui/separator" -import { deployServer as deployServerApi, type ServerResponse } from "@/lib/admin-api" +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select" +import { deployServer as deployServerApi, listProviders, type ServerResponse, type Provider } from "@/lib/admin-api" +import { platformDisplayName } from "@/lib/platform-display" import { Play, Plus, X, Loader2 } from "lucide-react" interface DeployServerDialogProps { @@ -23,6 +31,20 @@ export function DeployServerDialog({ open, onOpenChange, server, onDeploySuccess const [config, setConfig] = useState>({}) const [newKey, setNewKey] = useState("") const [newValue, setNewValue] = useState("") + const [providers, setProviders] = useState([]) + const [providerId, setProviderId] = useState("local") + + useEffect(() => { + if (open) { + listProviders({ throwOnError: false }) + .then(({ data }) => { + if (data?.providers?.length) { + setProviders(data.providers) + } + }) + .catch(() => {}) + } + }, [open]) const handleAddConfig = () => { if (newKey.trim() && newValue.trim()) { @@ -44,14 +66,14 @@ export function DeployServerDialog({ open, onOpenChange, server, onDeploySuccess try { setDeploying(true) setError(null) - + await deployServerApi({ body: { serverName: server.server.name, version: server.server.version, env: config, preferRemote: false, - providerId: "local", + providerId, }, throwOnError: true, }) @@ -61,6 +83,7 @@ export function DeployServerDialog({ open, onOpenChange, server, onDeploySuccess onOpenChange(false) setSuccess(false) setConfig({}) + setProviderId("local") onDeploySuccess?.() }, 1500) } catch (err) { @@ -76,6 +99,7 @@ export function DeployServerDialog({ open, onOpenChange, server, onDeploySuccess setError(null) setSuccess(false) setConfig({}) + setProviderId("local") setNewKey("") setNewValue("") } @@ -117,6 +141,25 @@ export function DeployServerDialog({ open, onOpenChange, server, onDeploySuccess + {/* Deploy Target */} + {providers.length > 0 && ( +
+ + +
+ )} + {/* Configuration */}
@@ -220,4 +263,3 @@ export function DeployServerDialog({ open, onOpenChange, server, onDeploySuccess ) } - diff --git a/ui/lib/platform-display.ts b/ui/lib/platform-display.ts new file mode 100644 index 00000000..73f11c75 --- /dev/null +++ b/ui/lib/platform-display.ts @@ -0,0 +1,13 @@ +const PLATFORM_DISPLAY: Record = { + local: { label: "Local", description: "Docker Compose on this machine" }, + kubernetes: { label: "Kubernetes", description: "Kubernetes cluster" }, + openshell: { label: "OpenShell", description: "Secure sandboxed runtime" }, +} + +export function platformDisplayName(platform: string): string { + return PLATFORM_DISPLAY[platform]?.label ?? platform +} + +export function platformDescription(platform: string): string { + return PLATFORM_DISPLAY[platform]?.description ?? "" +} From e1e2bd97209c1aa0606ee31f19aafe91e1070189 Mon Sep 17 00:00:00 2001 From: Peter Jausovec Date: Fri, 20 Mar 2026 14:08:34 -0700 Subject: [PATCH 2/5] wip Signed-off-by: Peter Jausovec --- .../adk/python/templates/Dockerfile.tmpl | 12 + internal/daemon/docker-compose.yml | 2 +- .../registry/platforms/openshell/client.go | 38 +++ .../platforms/openshell/deployment_adapter.go | 74 ++++- .../openshell/deployment_adapter_test.go | 228 ++++++++++++++- ui/components/deploy-dialog.tsx | 75 ++--- ui/components/deploy-server-dialog.tsx | 265 ------------------ 7 files changed, 371 insertions(+), 323 deletions(-) delete mode 100644 ui/components/deploy-server-dialog.tsx diff --git a/internal/cli/agent/frameworks/adk/python/templates/Dockerfile.tmpl b/internal/cli/agent/frameworks/adk/python/templates/Dockerfile.tmpl index 5f3cbe29..8e9122e5 100644 --- a/internal/cli/agent/frameworks/adk/python/templates/Dockerfile.tmpl +++ b/internal/cli/agent/frameworks/adk/python/templates/Dockerfile.tmpl @@ -14,6 +14,18 @@ COPY .python-version .python-version RUN uv sync +# OpenShell sandbox requirements: iproute2 for network namespace setup, +# iptables for network bypass detection, and a sandbox user/group. +# The kagent-adk image is Wolfi-based, so packages come from the Wolfi OS repo. +USER root +RUN apk add --no-cache \ + --repository https://packages.wolfi.dev/os \ + --allow-untrusted \ + iproute2 iptables && \ + addgroup -S sandbox && adduser -S -G sandbox -s /bin/sh sandbox +USER sandbox + +ENV PATH="/sbin:/usr/sbin:$PATH" ENV OTEL_SERVICE_NAME={{.Name}} CMD ["{{.Name}}"] diff --git a/internal/daemon/docker-compose.yml b/internal/daemon/docker-compose.yml index 80bc9a84..1707779b 100644 --- a/internal/daemon/docker-compose.yml +++ b/internal/daemon/docker-compose.yml @@ -64,7 +64,7 @@ services: # Mount kubeconfig as read-only source; the entrypoint rewrites it for Docker networking - ~/.kube/config:/root/.kube/config.orig:ro # Mount OpenShell mTLS certs for gateway authentication - - ~/.config/openshell/gateways/ar-dev/mtls:/root/.config/openshell/mtls:ro + - ~/.config/openshell/gateways/${OPENSHELL_GATEWAY_NAME:-openshell}/mtls:/root/.config/openshell/mtls:ro depends_on: postgres: condition: service_healthy diff --git a/internal/registry/platforms/openshell/client.go b/internal/registry/platforms/openshell/client.go index 1e902884..57c3a3c6 100644 --- a/internal/registry/platforms/openshell/client.go +++ b/internal/registry/platforms/openshell/client.go @@ -16,6 +16,12 @@ import ( "google.golang.org/grpc/credentials/insecure" ) +// ProviderInfo holds the identity and type of an OpenShell inference provider. +type ProviderInfo struct { + Name string + Type string +} + // Client is the interface for interacting with an OpenShell gateway. type Client interface { CreateSandbox(ctx context.Context, opts CreateSandboxOpts) (*SandboxInfo, error) @@ -24,6 +30,8 @@ type Client interface { DeleteSandbox(ctx context.Context, name string) error GetSandboxLogs(ctx context.Context, sandboxID string) ([]string, error) HealthCheck(ctx context.Context) error + ListProviders(ctx context.Context) ([]ProviderInfo, error) + EnsureProvider(ctx context.Context, name, providerType string, credentials map[string]string) error Close() error } @@ -214,6 +222,36 @@ func (c *grpcClient) HealthCheck(ctx context.Context) error { return nil } +func (c *grpcClient) ListProviders(ctx context.Context) ([]ProviderInfo, error) { + resp, err := c.client.ListProviders(ctx, &pb.ListProvidersRequest{}) + if err != nil { + return nil, fmt.Errorf("list providers: %w", err) + } + result := make([]ProviderInfo, len(resp.GetProviders())) + for i, p := range resp.GetProviders() { + result[i] = ProviderInfo{Name: p.GetName(), Type: p.GetType()} + } + return result, nil +} + +func (c *grpcClient) EnsureProvider(ctx context.Context, name, providerType string, credentials map[string]string) error { + _, err := c.client.GetProvider(ctx, &pb.GetProviderRequest{Name: name}) + if err == nil { + return nil + } + _, err = c.client.CreateProvider(ctx, &pb.CreateProviderRequest{ + Provider: &pb.Provider{ + Name: name, + Type: providerType, + Credentials: credentials, + }, + }) + if err != nil { + return fmt.Errorf("create openshell provider %s: %w", name, err) + } + return nil +} + func (c *grpcClient) Close() error { if c.conn != nil { return c.conn.Close() diff --git a/internal/registry/platforms/openshell/deployment_adapter.go b/internal/registry/platforms/openshell/deployment_adapter.go index e696be5f..b4f11433 100644 --- a/internal/registry/platforms/openshell/deployment_adapter.go +++ b/internal/registry/platforms/openshell/deployment_adapter.go @@ -22,6 +22,26 @@ const ( sandboxPhaseError = "SANDBOX_PHASE_ERROR" ) +// openshellProviderMapping maps agent model-provider slugs to their +// corresponding OpenShell provider type and credential env vars. +// Supported OpenShell types: claude, codex, generic, github, gitlab, +// nvidia, openai, opencode. +// See https://docs.nvidia.com/openshell/latest/sandboxes/manage-providers.html +type openshellProviderSpec struct { + Type string // OpenShell provider type + CredentialKeys []string // env var names that carry API credentials +} + +var openshellProviderMapping = map[string]openshellProviderSpec{ + "anthropic": {Type: "claude", CredentialKeys: []string{"ANTHROPIC_API_KEY", "CLAUDE_API_KEY"}}, + "openai": {Type: "openai", CredentialKeys: []string{"OPENAI_API_KEY"}}, + "nvidia": {Type: "nvidia", CredentialKeys: []string{"NVIDIA_API_KEY"}}, + "google": {Type: "generic", CredentialKeys: []string{"GOOGLE_API_KEY", "GEMINI_API_KEY"}}, + "gemini": {Type: "generic", CredentialKeys: []string{"GOOGLE_API_KEY", "GEMINI_API_KEY"}}, + "mistral": {Type: "generic", CredentialKeys: []string{"MISTRAL_API_KEY"}}, + "cohere": {Type: "generic", CredentialKeys: []string{"COHERE_API_KEY"}}, +} + type openshellDeploymentAdapter struct { registry service.RegistryService client Client @@ -69,22 +89,26 @@ func (a *openshellDeploymentAdapter) SupportedResourceTypes() []string { } func (a *openshellDeploymentAdapter) Deploy(ctx context.Context, req *models.Deployment) (*models.DeploymentActionResult, error) { + if err := utils.ValidateDeploymentRequest(req, false); err != nil { + return nil, err + } slog.Info("openshell: deploy started", "server", req.ServerName, "provider", req.ProviderID) client, err := a.getClient() if err != nil { return nil, err } slog.Info("openshell: client ready") - if err := utils.ValidateDeploymentRequest(req, false); err != nil { - return nil, err - } sandboxName := sandboxNameForDeployment(req) image, env, providers, err := a.resolveDeploymentSpec(ctx, req) if err != nil { return nil, err } - slog.Info("openshell: resolved spec", "sandbox", sandboxName, "image", image) + slog.Info("openshell: resolved spec", "sandbox", sandboxName, "image", image, "providers", providers) + + if err := a.ensureProviders(ctx, client, providers, env); err != nil { + return nil, err + } opts := CreateSandboxOpts{ Name: sandboxName, @@ -176,13 +200,53 @@ func (a *openshellDeploymentAdapter) resolveDeploymentSpec( if rErr != nil { return "", nil, nil, rErr } - return resolved.Agent.Deployment.Image, mergeEnv(deployment.Env, resolved.Agent.Deployment.Env), nil, nil + mergedEnv := mergeEnv(deployment.Env, resolved.Agent.Deployment.Env) + modelProvider := mergedEnv["MODEL_PROVIDER"] + if modelProvider != "" { + providers = append(providers, strings.ToLower(modelProvider)) + } + return resolved.Agent.Deployment.Image, mergedEnv, providers, nil default: return "", nil, nil, fmt.Errorf("invalid resource type %q: %w", deployment.ResourceType, database.ErrInvalidInput) } } +// ensureProviders makes sure every named inference provider exists on the +// gateway, creating it with credentials extracted from env if necessary. +func (a *openshellDeploymentAdapter) ensureProviders(ctx context.Context, client Client, providers []string, env map[string]string) error { + for _, name := range providers { + spec := resolveProviderSpec(name) + creds := extractProviderCredentials(spec, env) + slog.Info("openshell: ensuring provider", "provider", name, "openshell_type", spec.Type, "has_credentials", len(creds) > 0) + if err := client.EnsureProvider(ctx, name, spec.Type, creds); err != nil { + return fmt.Errorf("ensure openshell provider %s: %w", name, err) + } + } + return nil +} + +// resolveProviderSpec returns the OpenShell provider spec for a model provider +// slug. Unknown providers fall back to the "generic" type. +func resolveProviderSpec(provider string) openshellProviderSpec { + if spec, ok := openshellProviderMapping[provider]; ok { + return spec + } + return openshellProviderSpec{Type: "generic"} +} + +// extractProviderCredentials looks up known API-key env vars for a provider +// spec and returns them as a credentials map suitable for OpenShell. +func extractProviderCredentials(spec openshellProviderSpec, env map[string]string) map[string]string { + creds := make(map[string]string) + for _, key := range spec.CredentialKeys { + if v, exists := env[key]; exists && v != "" { + creds[key] = v + } + } + return creds +} + // waitForReady polls GetSandbox until the sandbox reaches the Ready phase or times out. func (a *openshellDeploymentAdapter) waitForReady(ctx context.Context, client Client, sandboxName string) error { deadline := time.Now().Add(sandboxReadyTimeout) diff --git a/internal/registry/platforms/openshell/deployment_adapter_test.go b/internal/registry/platforms/openshell/deployment_adapter_test.go index 8dc4c263..52a518c1 100644 --- a/internal/registry/platforms/openshell/deployment_adapter_test.go +++ b/internal/registry/platforms/openshell/deployment_adapter_test.go @@ -14,12 +14,14 @@ import ( // mockClient implements Client for testing. type mockClient struct { - createFn func(ctx context.Context, opts CreateSandboxOpts) (*SandboxInfo, error) - getFn func(ctx context.Context, name string) (*SandboxInfo, error) - listFn func(ctx context.Context) ([]SandboxInfo, error) - deleteFn func(ctx context.Context, name string) error - logsFn func(ctx context.Context, name string) ([]string, error) - healthFn func(ctx context.Context) error + createFn func(ctx context.Context, opts CreateSandboxOpts) (*SandboxInfo, error) + getFn func(ctx context.Context, name string) (*SandboxInfo, error) + listFn func(ctx context.Context) ([]SandboxInfo, error) + deleteFn func(ctx context.Context, name string) error + logsFn func(ctx context.Context, name string) ([]string, error) + healthFn func(ctx context.Context) error + listProvidersFn func(ctx context.Context) ([]ProviderInfo, error) + ensureProvFn func(ctx context.Context, name, provType string, creds map[string]string) error } func (m *mockClient) CreateSandbox(ctx context.Context, opts CreateSandboxOpts) (*SandboxInfo, error) { @@ -64,16 +66,35 @@ func (m *mockClient) HealthCheck(ctx context.Context) error { return nil } +func (m *mockClient) ListProviders(ctx context.Context) ([]ProviderInfo, error) { + if m.listProvidersFn != nil { + return m.listProvidersFn(ctx) + } + return nil, nil +} + +func (m *mockClient) EnsureProvider(ctx context.Context, name, provType string, creds map[string]string) error { + if m.ensureProvFn != nil { + return m.ensureProvFn(ctx, name, provType, creds) + } + return nil +} + func (m *mockClient) Close() error { return nil } func newTestRegistry() *servicetesting.FakeRegistry { + return newTestRegistryWithProvider("anthropic") +} + +func newTestRegistryWithProvider(modelProvider string) *servicetesting.FakeRegistry { registry := servicetesting.NewFakeRegistry() registry.GetAgentByNameAndVersionFn = func(_ context.Context, name, version string) (*models.AgentResponse, error) { return &models.AgentResponse{ Agent: models.AgentJSON{ AgentManifest: models.AgentManifest{ - Name: name, - Image: "test-agent-image:latest", + Name: name, + Image: "test-agent-image:latest", + ModelProvider: modelProvider, }, Version: version, }, @@ -413,3 +434,194 @@ func TestDeploy_CreateSandboxError(t *testing.T) { t.Fatal("expected error from CreateSandbox failure") } } + +func TestDeploy_Agent_EnsuresProvider(t *testing.T) { + var ensuredName, ensuredType string + var ensuredCreds map[string]string + var createdProviders []string + + client := &mockClient{ + ensureProvFn: func(_ context.Context, name, provType string, creds map[string]string) error { + ensuredName = name + ensuredType = provType + ensuredCreds = creds + return nil + }, + createFn: func(_ context.Context, opts CreateSandboxOpts) (*SandboxInfo, error) { + createdProviders = opts.Providers + return &SandboxInfo{ID: "sb-1", Name: opts.Name, Phase: "SANDBOX_PHASE_PROVISIONING"}, nil + }, + } + + adapter := NewOpenShellDeploymentAdapter(newTestRegistry(), client) + + deployment := &models.Deployment{ + ID: "dep-prov", + ServerName: "my-agent", + Version: "1.0.0", + ResourceType: "agent", + ProviderID: "openshell-default", + Env: map[string]string{"ANTHROPIC_API_KEY": "sk-test-123"}, + } + + result, err := adapter.Deploy(context.Background(), deployment) + if err != nil { + t.Fatalf("Deploy() error = %v", err) + } + if result.Status != models.DeploymentStatusDeployed { + t.Errorf("status = %q, want %q", result.Status, models.DeploymentStatusDeployed) + } + if ensuredName != "anthropic" { + t.Errorf("ensured provider name = %q, want %q", ensuredName, "anthropic") + } + if ensuredType != "claude" { + t.Errorf("ensured provider type = %q, want %q (OpenShell type for anthropic)", ensuredType, "claude") + } + if ensuredCreds["ANTHROPIC_API_KEY"] != "sk-test-123" { + t.Errorf("ensured creds = %v, want ANTHROPIC_API_KEY=sk-test-123", ensuredCreds) + } + if len(createdProviders) != 1 || createdProviders[0] != "anthropic" { + t.Errorf("sandbox providers = %v, want [anthropic]", createdProviders) + } +} + +func TestDeploy_Agent_NoProviderWhenModelProviderEmpty(t *testing.T) { + var ensureCalled bool + client := &mockClient{ + ensureProvFn: func(_ context.Context, _, _ string, _ map[string]string) error { + ensureCalled = true + return nil + }, + } + + adapter := NewOpenShellDeploymentAdapter(newTestRegistryWithProvider(""), client) + + deployment := &models.Deployment{ + ID: "dep-noprov", + ServerName: "my-agent", + Version: "1.0.0", + ResourceType: "agent", + ProviderID: "openshell-default", + } + + _, err := adapter.Deploy(context.Background(), deployment) + if err != nil { + t.Fatalf("Deploy() error = %v", err) + } + if ensureCalled { + t.Error("EnsureProvider should not be called when model provider is empty") + } +} + +func TestDeploy_Agent_EnsureProviderError(t *testing.T) { + client := &mockClient{ + ensureProvFn: func(_ context.Context, _, _ string, _ map[string]string) error { + return fmt.Errorf("gateway unreachable") + }, + } + + adapter := NewOpenShellDeploymentAdapter(newTestRegistry(), client) + + deployment := &models.Deployment{ + ID: "dep-enserr", + ServerName: "my-agent", + Version: "1.0.0", + ResourceType: "agent", + ProviderID: "openshell-default", + Env: map[string]string{"ANTHROPIC_API_KEY": "sk-test"}, + } + + _, err := adapter.Deploy(context.Background(), deployment) + if err == nil { + t.Fatal("expected error from EnsureProvider failure") + } +} + +func TestExtractProviderCredentials(t *testing.T) { + tests := []struct { + name string + provider string + env map[string]string + wantKeys []string + }{ + { + name: "anthropic with key", + provider: "anthropic", + env: map[string]string{"ANTHROPIC_API_KEY": "sk-123", "OTHER": "val"}, + wantKeys: []string{"ANTHROPIC_API_KEY"}, + }, + { + name: "openai with key", + provider: "openai", + env: map[string]string{"OPENAI_API_KEY": "sk-456"}, + wantKeys: []string{"OPENAI_API_KEY"}, + }, + { + name: "google with gemini key", + provider: "google", + env: map[string]string{"GEMINI_API_KEY": "gem-789"}, + wantKeys: []string{"GEMINI_API_KEY"}, + }, + { + name: "unknown provider falls back to generic", + provider: "custom-llm", + env: map[string]string{"CUSTOM_KEY": "val"}, + wantKeys: nil, + }, + { + name: "known provider but no matching env var", + provider: "anthropic", + env: map[string]string{"SOME_OTHER_KEY": "val"}, + wantKeys: nil, + }, + { + name: "empty env var value ignored", + provider: "anthropic", + env: map[string]string{"ANTHROPIC_API_KEY": ""}, + wantKeys: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + spec := resolveProviderSpec(tt.provider) + creds := extractProviderCredentials(spec, tt.env) + if len(tt.wantKeys) == 0 { + if len(creds) != 0 { + t.Errorf("expected empty creds, got %v", creds) + } + return + } + for _, key := range tt.wantKeys { + if _, ok := creds[key]; !ok { + t.Errorf("expected key %q in creds %v", key, creds) + } + } + }) + } +} + +func TestResolveProviderSpec(t *testing.T) { + tests := []struct { + provider string + wantType string + }{ + {"anthropic", "claude"}, + {"openai", "openai"}, + {"nvidia", "nvidia"}, + {"google", "generic"}, + {"gemini", "generic"}, + {"mistral", "generic"}, + {"cohere", "generic"}, + {"unknown-provider", "generic"}, + } + + for _, tt := range tests { + t.Run(tt.provider, func(t *testing.T) { + spec := resolveProviderSpec(tt.provider) + if spec.Type != tt.wantType { + t.Errorf("resolveProviderSpec(%q).Type = %q, want %q", tt.provider, spec.Type, tt.wantType) + } + }) + } +} diff --git a/ui/components/deploy-dialog.tsx b/ui/components/deploy-dialog.tsx index 39b155d8..5ea0ed13 100644 --- a/ui/components/deploy-dialog.tsx +++ b/ui/components/deploy-dialog.tsx @@ -12,7 +12,8 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select" -import { deployServer as deployServerApi, getHealthV0, type ServerResponse, type AgentResponse } from "@/lib/admin-api" +import { deployServer as deployServerApi, listProviders, type ServerResponse, type AgentResponse, type Provider } from "@/lib/admin-api" +import { platformDisplayName, platformDescription } from "@/lib/platform-display" import { Play, Plus, X, Loader2, CheckCircle } from "lucide-react" type DeployResourceType = "mcp" | "agent" @@ -26,21 +27,6 @@ interface DeployDialogProps { onDeploySuccess?: () => void } -interface ProviderOption { - id: string - label: string - description: string -} - -const DOCKER_PROVIDERS: ProviderOption[] = [ - { id: "local", label: "Local (Docker)", description: "Deploy as a Docker container on this machine" }, - { id: "kubernetes-default", label: "Kubernetes", description: "Deploy to the connected Kubernetes cluster" }, -] - -const KUBERNETES_PROVIDERS: ProviderOption[] = [ - { id: "kubernetes-default", label: "Kubernetes", description: "Deploy to the local Kubernetes cluster" }, -] - export function DeployDialog({ open, onOpenChange, resourceType, server, agent, onDeploySuccess }: DeployDialogProps) { const [deploying, setDeploying] = useState(false) const [error, setError] = useState(null) @@ -48,35 +34,31 @@ export function DeployDialog({ open, onOpenChange, resourceType, server, agent, const [config, setConfig] = useState>({}) const [newKey, setNewKey] = useState("") const [newValue, setNewValue] = useState("") - const [providerId, setProviderId] = useState("local") + const [providerId, setProviderId] = useState("") const [namespace, setNamespace] = useState("") - const [platformMode, setPlatformMode] = useState("docker") - const [loadingPlatform, setLoadingPlatform] = useState(true) + const [providers, setProviders] = useState([]) + const [loadingProviders, setLoadingProviders] = useState(true) const keyInputRef = useRef(null) - const availableProviders = platformMode === "kubernetes" ? KUBERNETES_PROVIDERS : DOCKER_PROVIDERS - useEffect(() => { if (open) { - fetchPlatformMode() + fetchProviders() } }, [open]) - useEffect(() => { - if (platformMode === "kubernetes") { - setProviderId("kubernetes-default") - } - }, [platformMode]) - - const fetchPlatformMode = async () => { + const fetchProviders = async () => { try { - setLoadingPlatform(true) - const { data } = await getHealthV0({ throwOnError: true }) - setPlatformMode(data.platform_mode || "docker") + setLoadingProviders(true) + const { data } = await listProviders({ throwOnError: true }) + const available = data.providers ?? [] + setProviders(available) + if (available.length > 0 && !available.some(p => p.id === providerId)) { + setProviderId(available[0].id) + } } catch { - setPlatformMode("docker") + setProviders([]) } finally { - setLoadingPlatform(false) + setLoadingProviders(false) } } @@ -92,7 +74,8 @@ export function DeployDialog({ open, onOpenChange, resourceType, server, agent, ? (server?.server.title || server?.server.name) : agent?.agent.name - const isKubernetesProvider = providerId.startsWith("kubernetes") + const selectedProvider = providers.find(p => p.id === providerId) + const isKubernetesProvider = selectedProvider?.platform === "kubernetes" const handleAddConfig = () => { if (newKey.trim() && newValue.trim()) { @@ -152,7 +135,7 @@ export function DeployDialog({ open, onOpenChange, resourceType, server, agent, setConfig({}) setNewKey("") setNewValue("") - setProviderId("local") + setProviderId("") setNamespace("") } @@ -203,11 +186,13 @@ export function DeployDialog({ open, onOpenChange, resourceType, server, agent, {/* Provider Selection */}
- {loadingPlatform ? ( + {loadingProviders ? (
+ ) : providers.length === 0 ? ( +

No deployment providers configured.

) : ( <> -

- {availableProviders.find(p => p.id === providerId)?.description} -

+ {selectedProvider && ( +

+ {platformDescription(selectedProvider.platform)} +

+ )} )}
@@ -349,7 +336,7 @@ export function DeployDialog({ open, onOpenChange, resourceType, server, agent, - -
- ))} -
- )} - - {/* Add new config */} -
-
-
- setNewKey(e.target.value)} - onKeyDown={(e) => { - if (e.key === "Enter" && newKey && newValue) { - handleAddConfig() - } - }} - /> -
-
- setNewValue(e.target.value)} - onKeyDown={(e) => { - if (e.key === "Enter" && newKey && newValue) { - handleAddConfig() - } - }} - /> -
-
- -
- - - {error && ( -
-

{error}

-
- )} - - {/* Actions */} -
- - -
- - )} - - - ) -} From e46479e831d7660d161fd77ccd2cbe0511235e8d Mon Sep 17 00:00:00 2001 From: Peter Jausovec Date: Fri, 20 Mar 2026 16:38:10 -0700 Subject: [PATCH 3/5] wip Signed-off-by: Peter Jausovec --- .../registry/platforms/openshell/client.go | 43 +++++-- .../platforms/openshell/client_test.go | 91 +++++++++++++++ .../platforms/openshell/deployment_adapter.go | 65 ++++++++++- .../openshell/deployment_adapter_test.go | 32 +++++ .../openshell/kagent_network_policies.go | 109 ++++++++++++++++++ .../openshell/kagent_network_policies_test.go | 101 ++++++++++++++++ .../openshell/kagent_sandbox_policy.go | 28 +++++ .../openshell/pod_template_command.go | 84 ++++++++++++++ 8 files changed, 544 insertions(+), 9 deletions(-) create mode 100644 internal/registry/platforms/openshell/kagent_network_policies.go create mode 100644 internal/registry/platforms/openshell/kagent_network_policies_test.go create mode 100644 internal/registry/platforms/openshell/kagent_sandbox_policy.go create mode 100644 internal/registry/platforms/openshell/pod_template_command.go diff --git a/internal/registry/platforms/openshell/client.go b/internal/registry/platforms/openshell/client.go index 57c3a3c6..40fe623d 100644 --- a/internal/registry/platforms/openshell/client.go +++ b/internal/registry/platforms/openshell/client.go @@ -42,6 +42,8 @@ type CreateSandboxOpts struct { Env map[string]string Providers []string // OpenShell provider names to attach GPU bool + Policy *pb.SandboxPolicy + Command []string // optional workload container command (merged via template.pod_template) } // SandboxInfo holds the status of a sandbox. @@ -153,17 +155,42 @@ func NewGRPCClientFromEndpoint(endpoint string, tlsCfg *tls.Config) (Client, err }, nil } +func buildSandboxSpec(opts CreateSandboxOpts) (*pb.SandboxSpec, error) { + tmpl := &pb.SandboxTemplate{Image: opts.Image} + // Also set template.environment for API completeness; the gateway still applies "sleep infinity" + // to the pod unless pod_template patches containers[].env (see podTemplatePatchForCommand). + if opts.Env != nil { + if v := strings.TrimSpace(opts.Env[openshellSandboxCommandEnv]); v != "" { + tmpl.Environment = map[string]string{openshellSandboxCommandEnv: v} + } + } + if len(opts.Command) > 0 { + podPatch, err := podTemplatePatchForCommand(opts.Image, opts.Command) + if err != nil { + return nil, err + } + tmpl.PodTemplate = podPatch + } + spec := &pb.SandboxSpec{ + Environment: opts.Env, + Providers: opts.Providers, + Gpu: opts.GPU, + Template: tmpl, + } + if opts.Policy != nil { + spec.Policy = opts.Policy + } + return spec, nil +} + func (c *grpcClient) CreateSandbox(ctx context.Context, opts CreateSandboxOpts) (*SandboxInfo, error) { + spec, err := buildSandboxSpec(opts) + if err != nil { + return nil, err + } resp, err := c.client.CreateSandbox(ctx, &pb.CreateSandboxRequest{ Name: opts.Name, - Spec: &pb.SandboxSpec{ - Environment: opts.Env, - Providers: opts.Providers, - Gpu: opts.GPU, - Template: &pb.SandboxTemplate{ - Image: opts.Image, - }, - }, + Spec: spec, }) if err != nil { return nil, fmt.Errorf("create sandbox: %w", err) diff --git a/internal/registry/platforms/openshell/client_test.go b/internal/registry/platforms/openshell/client_test.go index 831ac246..9a795d1f 100644 --- a/internal/registry/platforms/openshell/client_test.go +++ b/internal/registry/platforms/openshell/client_test.go @@ -146,6 +146,97 @@ func TestCreateSandboxOptsMapping(t *testing.T) { } } +func TestBuildSandboxSpec_SetsTemplateEnvironmentForWorkload(t *testing.T) { + want := "kagent-adk run --host 0.0.0.0 --port 9999 myagent --local" + spec, err := buildSandboxSpec(CreateSandboxOpts{ + Image: "docker.io/example:latest", + Env: map[string]string{openshellSandboxCommandEnv: want}, + Command: []string{"kagent-adk", "run", "--help"}, + }) + if err != nil { + t.Fatal(err) + } + tmpl := spec.GetTemplate() + if tmpl == nil { + t.Fatal("nil template") + } + if got := tmpl.GetEnvironment()[openshellSandboxCommandEnv]; got != want { + t.Errorf("template.environment[%s] = %q, want %q", openshellSandboxCommandEnv, got, want) + } +} + +func TestPodTemplatePatchForCommand(t *testing.T) { + st, err := podTemplatePatchForCommand("ghcr.io/example/agent:latest", []string{"kagent-adk", "run", "--help"}) + if err != nil { + t.Fatal(err) + } + if st == nil { + t.Fatal("expected non-nil struct") + } + specVal := st.GetFields()["spec"] + if specVal == nil { + t.Fatal("missing spec") + } + spec := specVal.GetStructValue() + if spec == nil { + t.Fatal("spec not a struct") + } + containersVal := spec.GetFields()["containers"] + if containersVal == nil { + t.Fatal("missing containers") + } + list := containersVal.GetListValue() + if list == nil || len(list.GetValues()) == 0 { + t.Fatal("expected containers list") + } + c0 := list.GetValues()[0].GetStructValue() + if c0.GetFields()["name"].GetStringValue() != "sandbox" { + t.Errorf("container name = %q", c0.GetFields()["name"].GetStringValue()) + } + if c0.GetFields()["image"].GetStringValue() != "ghcr.io/example/agent:latest" { + t.Errorf("container image = %q", c0.GetFields()["image"].GetStringValue()) + } + argsList := c0.GetFields()["args"].GetListValue() + if argsList == nil || len(argsList.GetValues()) != 3 { + t.Fatalf("args = %v, want 3 elements", argsList) + } + if argsList.GetValues()[0].GetStringValue() != "kagent-adk" || + argsList.GetValues()[1].GetStringValue() != "run" || + argsList.GetValues()[2].GetStringValue() != "--help" { + t.Errorf("args = %v", argsList.GetValues()) + } + envList := c0.GetFields()["env"].GetListValue() + if envList == nil || len(envList.GetValues()) != 1 { + t.Fatalf("env list = %v, want 1 entry for OPENSHELL_SANDBOX_COMMAND", envList) + } + ev := envList.GetValues()[0].GetStructValue().GetFields() + if ev["name"].GetStringValue() != openshellSandboxCommandEnv { + t.Errorf("env name = %q", ev["name"].GetStringValue()) + } + if want := "kagent-adk run --help"; ev["value"].GetStringValue() != want { + t.Errorf("env value = %q, want %q", ev["value"].GetStringValue(), want) + } + scVal := c0.GetFields()["securityContext"] + if scVal == nil { + t.Fatal("missing securityContext") + } + sc := scVal.GetStructValue() + if sc.GetFields()["runAsUser"].GetNumberValue() != 0 { + t.Errorf("runAsUser = %v, want 0", sc.GetFields()["runAsUser"].GetNumberValue()) + } + addList := sc.GetFields()["capabilities"].GetStructValue().GetFields()["add"].GetListValue() + if addList == nil || len(addList.GetValues()) != 4 { + t.Fatalf("capabilities.add = %v, want 4 caps", addList) + } +} + +func TestPodTemplatePatchForCommand_RequiresImage(t *testing.T) { + _, err := podTemplatePatchForCommand("", []string{"sh", "-c", "true"}) + if err == nil { + t.Fatal("expected error for empty image") + } +} + func TestNewGRPCClientFromEndpoint_Insecure(t *testing.T) { client, err := NewGRPCClientFromEndpoint("localhost:0", nil) if err != nil { diff --git a/internal/registry/platforms/openshell/deployment_adapter.go b/internal/registry/platforms/openshell/deployment_adapter.go index b4f11433..e6f4a761 100644 --- a/internal/registry/platforms/openshell/deployment_adapter.go +++ b/internal/registry/platforms/openshell/deployment_adapter.go @@ -20,6 +20,12 @@ const ( // Phase enum string values from the generated proto. sandboxPhaseReady = "SANDBOX_PHASE_READY" sandboxPhaseError = "SANDBOX_PHASE_ERROR" + // openshellKagentForwardPort is the in-sandbox port for kagent-adk HTTP; users forward this from the host. + openshellKagentForwardPort = 9999 + // openshellSandboxCommandEnv is the env var the supervisor reads to exec the workload; the + // container entrypoint remains /opt/openshell/bin/openshell-sandbox (setting container.command + // in a pod patch does not replace that). + openshellSandboxCommandEnv = "OPENSHELL_SANDBOX_COMMAND" ) // openshellProviderMapping maps agent model-provider slugs to their @@ -106,6 +112,17 @@ func (a *openshellDeploymentAdapter) Deploy(ctx context.Context, req *models.Dep } slog.Info("openshell: resolved spec", "sandbox", sandboxName, "image", image, "providers", providers) + resourceType := strings.ToLower(strings.TrimSpace(req.ResourceType)) + + if resourceType == "agent" { + agentName := strings.TrimSpace(req.ServerName) + env = mergeEnv(env, map[string]string{ + "KAGENT_URL": "placeholder", + "KAGENT_NAME": agentName, + "KAGENT_NAMESPACE": "placeholder", + }) + } + if err := a.ensureProviders(ctx, client, providers, env); err != nil { return nil, err } @@ -116,6 +133,16 @@ func (a *openshellDeploymentAdapter) Deploy(ctx context.Context, req *models.Dep Env: env, Providers: providers, } + if resourceType == "agent" { + agentName := strings.TrimSpace(req.ServerName) + modelProvider := strings.TrimSpace(env["MODEL_PROVIDER"]) + cmd := kagentADKOpenshellCommand(agentName, openshellKagentForwardPort) + opts.Policy = kagentADKSandboxPolicy(modelProvider) + opts.Command = cmd + opts.Env = mergeEnv(opts.Env, map[string]string{ + openshellSandboxCommandEnv: joinOpenshellSandboxWorkload(cmd), + }) + } slog.Info("openshell: calling CreateSandbox") if _, err := client.CreateSandbox(ctx, opts); err != nil { @@ -127,7 +154,26 @@ func (a *openshellDeploymentAdapter) Deploy(ctx context.Context, req *models.Dep return nil, err } - return &models.DeploymentActionResult{Status: models.DeploymentStatusDeployed}, nil + result := &models.DeploymentActionResult{Status: models.DeploymentStatusDeployed} + if resourceType == "agent" { + forwardCLI := fmt.Sprintf("openshell forward start %d %s", openshellKagentForwardPort, sandboxName) + slog.Info("openshell: agent sandbox ready — forward this port from your machine to reach the agent", + "command", forwardCLI, + "sandbox", sandboxName, + "port", openshellKagentForwardPort, + ) + meta, mErr := models.UnmarshalFrom(map[string]any{ + "openshellSandboxName": sandboxName, + "openshellForwardPort": openshellKagentForwardPort, + "openshellForwardCLI": forwardCLI, + }) + if mErr != nil { + slog.Warn("openshell: could not build provider metadata", "error", mErr) + } else { + result.ProviderMetadata = meta + } + } + return result, nil } func (a *openshellDeploymentAdapter) Undeploy(_ context.Context, deployment *models.Deployment) error { @@ -295,3 +341,20 @@ func mergeEnv(base, override map[string]string) map[string]string { } return result } + +// joinOpenshellSandboxWorkload formats argv for OPENSHELL_SANDBOX_COMMAND (space-separated, like +// the default "sleep infinity"). Agent names must not contain spaces. +func joinOpenshellSandboxWorkload(argv []string) string { + return strings.Join(argv, " ") +} + +// kagentADKOpenshellCommand is the process OpenShell runs inside the agent image (see kagent-adk CLI). +func kagentADKOpenshellCommand(agentName string, port int) []string { + return []string{ + "kagent-adk", "run", + "--host", "0.0.0.0", + "--port", fmt.Sprintf("%d", port), + agentName, + "--local", + } +} diff --git a/internal/registry/platforms/openshell/deployment_adapter_test.go b/internal/registry/platforms/openshell/deployment_adapter_test.go index 52a518c1..4b00b21c 100644 --- a/internal/registry/platforms/openshell/deployment_adapter_test.go +++ b/internal/registry/platforms/openshell/deployment_adapter_test.go @@ -137,12 +137,36 @@ func TestDeploy_Agent_CallsCreateSandbox(t *testing.T) { if result.Status != models.DeploymentStatusDeployed { t.Errorf("status = %q, want %q", result.Status, models.DeploymentStatusDeployed) } + if result.ProviderMetadata == nil || result.ProviderMetadata["openshellForwardCLI"] == nil { + t.Errorf("expected openshell ProviderMetadata with forward CLI, got %#v", result.ProviderMetadata) + } if createdOpts.Image != "test-agent-image:latest" { t.Errorf("image = %q, want %q", createdOpts.Image, "test-agent-image:latest") } if createdOpts.Name == "" { t.Error("sandbox name should not be empty") } + if createdOpts.Policy == nil || createdOpts.Policy.GetProcess().GetRunAsUser() != "sandbox" { + t.Errorf("expected default sandbox policy with run_as_user sandbox, got policy=%v", createdOpts.Policy) + } + np := createdOpts.Policy.GetNetworkPolicies() + rule, ok := np["anthropic_api"] + if !ok || rule == nil || len(rule.GetEndpoints()) == 0 || rule.GetEndpoints()[0].GetHost() != "api.anthropic.com" { + t.Errorf("anthropic agent should get api.anthropic.com egress, got network_policies=%v", np) + } + if len(createdOpts.Command) < 2 || createdOpts.Command[0] != "kagent-adk" || createdOpts.Command[1] != "run" { + t.Errorf("command = %v, want kagent-adk run ...", createdOpts.Command) + } + if createdOpts.Env["KAGENT_URL"] != "placeholder" || createdOpts.Env["KAGENT_NAMESPACE"] != "placeholder" { + t.Errorf("KAGENT env = %#v, want placeholder URL/namespace", createdOpts.Env) + } + if createdOpts.Env["KAGENT_NAME"] != "my-agent" { + t.Errorf("KAGENT_NAME = %q, want my-agent", createdOpts.Env["KAGENT_NAME"]) + } + wantWorkload := "kagent-adk run --host 0.0.0.0 --port 9999 my-agent --local" + if got := createdOpts.Env["OPENSHELL_SANDBOX_COMMAND"]; got != wantWorkload { + t.Errorf("OPENSHELL_SANDBOX_COMMAND = %q, want %q", got, wantWorkload) + } } func TestDeploy_MCP_CallsCreateSandbox(t *testing.T) { @@ -487,7 +511,12 @@ func TestDeploy_Agent_EnsuresProvider(t *testing.T) { func TestDeploy_Agent_NoProviderWhenModelProviderEmpty(t *testing.T) { var ensureCalled bool + var createdOpts CreateSandboxOpts client := &mockClient{ + createFn: func(_ context.Context, opts CreateSandboxOpts) (*SandboxInfo, error) { + createdOpts = opts + return &SandboxInfo{ID: "sb-1", Name: opts.Name, Phase: "SANDBOX_PHASE_PROVISIONING"}, nil + }, ensureProvFn: func(_ context.Context, _, _ string, _ map[string]string) error { ensureCalled = true return nil @@ -511,6 +540,9 @@ func TestDeploy_Agent_NoProviderWhenModelProviderEmpty(t *testing.T) { if ensureCalled { t.Error("EnsureProvider should not be called when model provider is empty") } + if _, ok := createdOpts.Policy.GetNetworkPolicies()["gemini_api"]; !ok { + t.Errorf("empty MODEL_PROVIDER should default to Gemini network policy, got %#v", createdOpts.Policy.GetNetworkPolicies()) + } } func TestDeploy_Agent_EnsureProviderError(t *testing.T) { diff --git a/internal/registry/platforms/openshell/kagent_network_policies.go b/internal/registry/platforms/openshell/kagent_network_policies.go new file mode 100644 index 00000000..081a71d3 --- /dev/null +++ b/internal/registry/platforms/openshell/kagent_network_policies.go @@ -0,0 +1,109 @@ +package openshell + +import ( + "log/slog" + "strings" + + pb "github.com/agentregistry-dev/agentregistry/internal/registry/platforms/openshell/proto/gen" +) + +// kagentADKNetworkBinaryAllowlist is the set of process paths allowed to use the +// model-provider egress rules (kagent-adk + venv python). +// +// The venv's python3 is usually a symlink to a standalone CPython under /python/ +// (python-build-standalone style: cpython--linux--gnu). OpenShell matches the +// resolved realpath, so we list common arch triples for the same Python micro version. +// Extra entries are harmless; missing entries cause L7 proxy denials for that image. +// Bump the cpython-* paths when the kagent-adk base image changes Python version. +func kagentADKNetworkBinaryAllowlist() []*pb.NetworkBinary { + const pyVer = "3.13.12" + return []*pb.NetworkBinary{ + {Path: "/.kagent/.venv/bin/kagent-adk"}, + {Path: "/.kagent/.venv/bin/python3"}, + {Path: "/python/cpython-" + pyVer + "-linux-aarch64-gnu/bin/python3.13"}, + {Path: "/python/cpython-" + pyVer + "-linux-x86_64-gnu/bin/python3.13"}, + } +} + +func kagentRESTEndpoint(host string, rules []*pb.L7Rule) *pb.NetworkEndpoint { + return &pb.NetworkEndpoint{ + Host: host, + Port: 443, + Protocol: "rest", + Tls: "terminate", + Enforcement: "enforce", + Rules: rules, + } +} + +// POST /v1/** — OpenAI-compatible and many REST inference APIs. +var kagentL7PostV1Star = []*pb.L7Rule{ + {Allow: &pb.L7Allow{Method: "POST", Path: "/v1/**"}}, +} + +// Google Generative Language API (Gemini). +var kagentL7GeminiPaths = []*pb.L7Rule{ + {Allow: &pb.L7Allow{Method: "POST", Path: "/v1beta/**"}}, + {Allow: &pb.L7Allow{Method: "POST", Path: "/v1/**"}}, +} + +// kagentNetworkPoliciesForModelProvider returns OpenShell network_policies entries for +// the agent manifest's model provider slug (MODEL_PROVIDER). Keys are stable policy map keys. +// Supported slugs align with openshellProviderMapping in deployment_adapter.go where applicable. +// +// Empty modelProvider defaults to Google Gemini API rules (previous single-policy behavior). +// Unknown slugs log a warning and return no egress rules so policy failures are visible; +// extend the switch or use a registered provider slug from openshellProviderMapping. +func kagentNetworkPoliciesForModelProvider(modelProvider string) map[string]*pb.NetworkPolicyRule { + p := strings.ToLower(strings.TrimSpace(modelProvider)) + if p == "" { + slog.Info("openshell: MODEL_PROVIDER empty; using Gemini (Google AI) API network policy") + p = "google" + } + + bin := kagentADKNetworkBinaryAllowlist() + + switch p { + case "google", "gemini": + return map[string]*pb.NetworkPolicyRule{ + "gemini_api": { + Name: "gemini-api", + Endpoints: []*pb.NetworkEndpoint{kagentRESTEndpoint("generativelanguage.googleapis.com", kagentL7GeminiPaths)}, + Binaries: bin, + }, + } + + case "anthropic": + return map[string]*pb.NetworkPolicyRule{ + "anthropic_api": { + Name: "anthropic-api", + Endpoints: []*pb.NetworkEndpoint{kagentRESTEndpoint("api.anthropic.com", kagentL7PostV1Star)}, + Binaries: bin, + }, + } + + case "openai": + return map[string]*pb.NetworkPolicyRule{ + "openai_api": { + Name: "openai-api", + Endpoints: []*pb.NetworkEndpoint{kagentRESTEndpoint("api.openai.com", kagentL7PostV1Star)}, + Binaries: bin, + }, + } + + case "nvidia": + return map[string]*pb.NetworkPolicyRule{ + "nvidia_api": { + Name: "nvidia-api", + Endpoints: []*pb.NetworkEndpoint{kagentRESTEndpoint("integrate.api.nvidia.com", kagentL7PostV1Star)}, + Binaries: bin, + }, + } + + default: + slog.Warn("openshell: no built-in network policy for model provider; sandbox may block model API egress", + "model_provider", modelProvider, + ) + return map[string]*pb.NetworkPolicyRule{} + } +} diff --git a/internal/registry/platforms/openshell/kagent_network_policies_test.go b/internal/registry/platforms/openshell/kagent_network_policies_test.go new file mode 100644 index 00000000..3f858c81 --- /dev/null +++ b/internal/registry/platforms/openshell/kagent_network_policies_test.go @@ -0,0 +1,101 @@ +package openshell + +import ( + "strings" + "testing" +) + +func TestKagentNetworkPoliciesForModelProvider(t *testing.T) { + tests := []struct { + provider string + wantKey string + wantHost string + empty bool + }{ + {"google", "gemini_api", "generativelanguage.googleapis.com", false}, + {"GEMINI", "gemini_api", "generativelanguage.googleapis.com", false}, + {"anthropic", "anthropic_api", "api.anthropic.com", false}, + {"openai", "openai_api", "api.openai.com", false}, + {"nvidia", "nvidia_api", "integrate.api.nvidia.com", false}, + {"", "gemini_api", "generativelanguage.googleapis.com", false}, + {"unknown-custom", "", "", true}, + } + + for _, tt := range tests { + name := tt.provider + if name == "" { + name = "(empty)" + } + t.Run(name, func(t *testing.T) { + got := kagentNetworkPoliciesForModelProvider(tt.provider) + if tt.empty { + if len(got) != 0 { + t.Fatalf("expected no policies, got %d", len(got)) + } + return + } + rule, ok := got[tt.wantKey] + if !ok || rule == nil { + t.Fatalf("missing policy key %q, got %v", tt.wantKey, got) + } + if len(rule.GetEndpoints()) == 0 { + t.Fatal("no endpoints") + } + if h := rule.GetEndpoints()[0].GetHost(); h != tt.wantHost { + t.Errorf("host = %q, want %q", h, tt.wantHost) + } + if len(rule.GetBinaries()) == 0 { + t.Error("expected non-empty binaries allowlist") + } + }) + } +} + +func TestKagentNetworkPoliciesForModelProvider_TrimsAndLowercases(t *testing.T) { + got := kagentNetworkPoliciesForModelProvider(" OpenAI ") + rule := got["openai_api"] + if rule == nil { + t.Fatal("expected openai_api") + } + if rule.GetEndpoints()[0].GetHost() != "api.openai.com" { + t.Errorf("host = %q", rule.GetEndpoints()[0].GetHost()) + } +} + +func TestKagentADKNetworkBinaryAllowlist_ArchPaths(t *testing.T) { + bin := kagentADKNetworkBinaryAllowlist() + if len(bin) < 4 { + t.Fatalf("want at least 4 binary paths, got %d", len(bin)) + } + paths := make([]string, len(bin)) + for i, b := range bin { + paths[i] = b.GetPath() + } + joined := strings.Join(paths, " ") + if !strings.Contains(joined, "aarch64-gnu") || !strings.Contains(joined, "x86_64-gnu") { + t.Fatalf("expected aarch64 and x86_64 cpython paths, got %v", paths) + } +} + +func TestKagentRESTEndpoint(t *testing.T) { + ep := kagentRESTEndpoint("example.com", kagentL7PostV1Star) + if ep.GetHost() != "example.com" || ep.GetPort() != 443 { + t.Fatalf("endpoint: %+v", ep) + } + if ep.GetProtocol() != "rest" || ep.GetTls() != "terminate" || ep.GetEnforcement() != "enforce" { + t.Errorf("unexpected TLS/protocol/enforcement: %+v", ep) + } + if len(ep.GetRules()) != 1 || ep.GetRules()[0].GetAllow().GetPath() != "/v1/**" { + t.Errorf("rules: %+v", ep.GetRules()) + } +} + +func TestKagentL7GeminiPaths(t *testing.T) { + if len(kagentL7GeminiPaths) != 2 { + t.Fatalf("gemini rules count = %d", len(kagentL7GeminiPaths)) + } + paths := kagentL7GeminiPaths[0].GetAllow().GetPath() + "," + kagentL7GeminiPaths[1].GetAllow().GetPath() + if !strings.Contains(paths, "/v1beta/") || !strings.Contains(paths, "/v1/") { + t.Errorf("paths = %s", paths) + } +} diff --git a/internal/registry/platforms/openshell/kagent_sandbox_policy.go b/internal/registry/platforms/openshell/kagent_sandbox_policy.go new file mode 100644 index 00000000..d5cef56f --- /dev/null +++ b/internal/registry/platforms/openshell/kagent_sandbox_policy.go @@ -0,0 +1,28 @@ +package openshell + +import ( + pb "github.com/agentregistry-dev/agentregistry/internal/registry/platforms/openshell/proto/gen" +) + +// kagentADKSandboxPolicy returns the default OpenShell policy for kagent-adk agents. +// modelProvider is the agent manifest MODEL_PROVIDER slug; egress rules are chosen via +// kagentNetworkPoliciesForModelProvider (see kagent_network_policies.go). +// Process identity is fixed to sandbox/sandbox to match OpenShell + kagent-adk image docs. +func kagentADKSandboxPolicy(modelProvider string) *pb.SandboxPolicy { + return &pb.SandboxPolicy{ + Version: 1, + Filesystem: &pb.FilesystemPolicy{ + IncludeWorkdir: true, + ReadOnly: []string{ + "/usr", "/lib", "/proc", "/dev/urandom", "/app", "/etc", "/var/log", + }, + ReadWrite: []string{"/sandbox", "/tmp", "/dev/null"}, + }, + Landlock: &pb.LandlockPolicy{Compatibility: "best_effort"}, + Process: &pb.ProcessPolicy{ + RunAsUser: "sandbox", + RunAsGroup: "sandbox", + }, + NetworkPolicies: kagentNetworkPoliciesForModelProvider(modelProvider), + } +} diff --git a/internal/registry/platforms/openshell/pod_template_command.go b/internal/registry/platforms/openshell/pod_template_command.go new file mode 100644 index 00000000..403558aa --- /dev/null +++ b/internal/registry/platforms/openshell/pod_template_command.go @@ -0,0 +1,84 @@ +package openshell + +import ( + "fmt" + "strings" + + "google.golang.org/protobuf/types/known/structpb" +) + +// defaultOpenshellWorkloadContainer is the K8s container name OpenShell uses for the +// agent workload; the pod patch merges image, args, env, and securityContext into this container. +const defaultOpenshellWorkloadContainer = "sandbox" + +// openshellSandboxContainerSecurityContext matches the workload container securityContext +// OpenShell applies for `openshell sandbox create --from Dockerfile` (supervisor needs +// these caps for ip netns / veth / iptables before the child drops privileges). +func openshellSandboxContainerSecurityContext() map[string]interface{} { + return map[string]interface{}{ + "runAsUser": int64(0), + "capabilities": map[string]interface{}{ + "add": []interface{}{ + "SYS_ADMIN", + "NET_ADMIN", + "SYS_PTRACE", + "SYSLOG", + }, + }, + } +} + +// podTemplatePatchForCommand builds a pod_template patch for the workload container: image, +// securityContext, container args, and OPENSHELL_SANDBOX_COMMAND env. +// +// Per OpenShell supervisor behavior, workload resolution order is: (1) argv after the entrypoint +// (Kubernetes container `args` — what `openshell sandbox create … -- ` sets), (2) +// OPENSHELL_SANDBOX_COMMAND (server default "sleep infinity"), (3) /bin/bash. We set both `args` +// and the env var so gateways that merge pod specs in different orders still run kagent-adk. +// +// SandboxSpec.environment / SandboxTemplate.environment alone do not replace the server’s default +// pod env; pod_template on the workload container does. +// +// The command parameter must be non-empty so agent deploys still take this code path when BYO +// image + kagent workload are used. +// +// BYO-image CreateSandbox sandboxes may omit the same securityContext as CLI --from +// flows; without SYS_ADMIN/NET_ADMIN the supervisor fails creating the network namespace. +func podTemplatePatchForCommand(image string, command []string) (*structpb.Struct, error) { + containerName := defaultOpenshellWorkloadContainer + if strings.TrimSpace(image) == "" { + return nil, fmt.Errorf("container image is required for pod command patch") + } + if len(command) == 0 { + return nil, fmt.Errorf("command must be non-empty") + } + argVals := make([]interface{}, len(command)) + for i, c := range command { + argVals[i] = c + } + workload := strings.Join(command, " ") + raw := map[string]interface{}{ + "spec": map[string]interface{}{ + "containers": []interface{}{ + map[string]interface{}{ + "name": containerName, + "image": image, + // Same as CLI trailing args after `--`; supervisor prefers these over OPENSHELL_SANDBOX_COMMAND. + "args": argVals, + "env": []interface{}{ + map[string]interface{}{ + "name": openshellSandboxCommandEnv, + "value": workload, + }, + }, + "securityContext": openshellSandboxContainerSecurityContext(), + }, + }, + }, + } + st, err := structpb.NewStruct(raw) + if err != nil { + return nil, fmt.Errorf("pod template struct: %w", err) + } + return st, nil +} From 708f46c83df48f935d38a6506f2671caaf531f42 Mon Sep 17 00:00:00 2001 From: Peter Jausovec Date: Sun, 22 Mar 2026 11:08:03 +0100 Subject: [PATCH 4/5] wip Signed-off-by: Peter Jausovec --- internal/cli/deployment/create.go | 22 +++++++ .../platforms/openshell/deployment_adapter.go | 1 + .../openshell/pod_template_command.go | 61 +++++++++++-------- 3 files changed, 59 insertions(+), 25 deletions(-) diff --git a/internal/cli/deployment/create.go b/internal/cli/deployment/create.go index 26a4592d..6a9c8034 100644 --- a/internal/cli/deployment/create.go +++ b/internal/cli/deployment/create.go @@ -9,6 +9,7 @@ import ( cliCommon "github.com/agentregistry-dev/agentregistry/internal/cli/common" cliUtils "github.com/agentregistry-dev/agentregistry/internal/cli/utils" "github.com/agentregistry-dev/agentregistry/pkg/models" + "github.com/agentregistry-dev/agentregistry/pkg/printer" "github.com/spf13/cobra" ) @@ -139,6 +140,7 @@ func createAgentDeployment(name, version string, envMap map[string]string, provi return fmt.Errorf("failed to deploy agent: %w", err) } fmt.Printf("Agent '%s' version '%s' deployed to local provider (providerId=%s)\n", deployment.ServerName, deployment.Version, providerID) + printOpenShellAgentForwardHint(deployment) return nil } @@ -159,6 +161,7 @@ func createAgentDeployment(name, version string, envMap map[string]string, provi ns = "(default)" } fmt.Printf("Agent '%s' version '%s' deployed to providerId=%s in namespace '%s'\n", deployment.ServerName, deployment.Version, providerID, ns) + printOpenShellAgentForwardHint(deployment) return nil } @@ -225,3 +228,22 @@ func buildAgentDeployConfig(manifest *models.AgentManifest, envOverrides map[str return config } + +// printOpenShellAgentForwardHint prints the openshell forward command when the adapter +// stored it in providerMetadata (slog alone only reaches server logs). +func printOpenShellAgentForwardHint(d *models.Deployment) { + if d == nil || len(d.ProviderMetadata) == 0 { + return + } + raw, ok := d.ProviderMetadata["openshellForwardCLI"] + if !ok || raw == nil { + return + } + s := strings.TrimSpace(fmt.Sprint(raw)) + if s == "" { + return + } + printer.PrintInfo("") + printer.PrintSuccess("OpenShell: forward this port from your machine to reach the agent") + printer.PrintInfo(" " + s) +} diff --git a/internal/registry/platforms/openshell/deployment_adapter.go b/internal/registry/platforms/openshell/deployment_adapter.go index e6f4a761..dd2d4381 100644 --- a/internal/registry/platforms/openshell/deployment_adapter.go +++ b/internal/registry/platforms/openshell/deployment_adapter.go @@ -157,6 +157,7 @@ func (a *openshellDeploymentAdapter) Deploy(ctx context.Context, req *models.Dep result := &models.DeploymentActionResult{Status: models.DeploymentStatusDeployed} if resourceType == "agent" { forwardCLI := fmt.Sprintf("openshell forward start %d %s", openshellKagentForwardPort, sandboxName) + // User-facing hint is persisted on providerMetadata (arctl prints it); slog is for server logs only. slog.Info("openshell: agent sandbox ready — forward this port from your machine to reach the agent", "command", forwardCLI, "sandbox", sandboxName, diff --git a/internal/registry/platforms/openshell/pod_template_command.go b/internal/registry/platforms/openshell/pod_template_command.go index 403558aa..47c0d43b 100644 --- a/internal/registry/platforms/openshell/pod_template_command.go +++ b/internal/registry/platforms/openshell/pod_template_command.go @@ -1,10 +1,12 @@ package openshell import ( + "encoding/json" "fmt" "strings" "google.golang.org/protobuf/types/known/structpb" + corev1 "k8s.io/api/core/v1" ) // defaultOpenshellWorkloadContainer is the K8s container name OpenShell uses for the @@ -14,11 +16,12 @@ const defaultOpenshellWorkloadContainer = "sandbox" // openshellSandboxContainerSecurityContext matches the workload container securityContext // OpenShell applies for `openshell sandbox create --from Dockerfile` (supervisor needs // these caps for ip netns / veth / iptables before the child drops privileges). -func openshellSandboxContainerSecurityContext() map[string]interface{} { - return map[string]interface{}{ - "runAsUser": int64(0), - "capabilities": map[string]interface{}{ - "add": []interface{}{ +func openshellSandboxContainerSecurityContext() *corev1.SecurityContext { + u := int64(0) + return &corev1.SecurityContext{ + RunAsUser: &u, + Capabilities: &corev1.Capabilities{ + Add: []corev1.Capability{ "SYS_ADMIN", "NET_ADMIN", "SYS_PTRACE", @@ -45,38 +48,46 @@ func openshellSandboxContainerSecurityContext() map[string]interface{} { // BYO-image CreateSandbox sandboxes may omit the same securityContext as CLI --from // flows; without SYS_ADMIN/NET_ADMIN the supervisor fails creating the network namespace. func podTemplatePatchForCommand(image string, command []string) (*structpb.Struct, error) { - containerName := defaultOpenshellWorkloadContainer if strings.TrimSpace(image) == "" { return nil, fmt.Errorf("container image is required for pod command patch") } if len(command) == 0 { return nil, fmt.Errorf("command must be non-empty") } - argVals := make([]interface{}, len(command)) - for i, c := range command { - argVals[i] = c - } + + args := append([]string(nil), command...) workload := strings.Join(command, " ") - raw := map[string]interface{}{ - "spec": map[string]interface{}{ - "containers": []interface{}{ - map[string]interface{}{ - "name": containerName, - "image": image, - // Same as CLI trailing args after `--`; supervisor prefers these over OPENSHELL_SANDBOX_COMMAND. - "args": argVals, - "env": []interface{}{ - map[string]interface{}{ - "name": openshellSandboxCommandEnv, - "value": workload, - }, + + pod := &corev1.Pod{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: defaultOpenshellWorkloadContainer, + Image: image, + Args: args, + Env: []corev1.EnvVar{ + {Name: openshellSandboxCommandEnv, Value: workload}, }, - "securityContext": openshellSandboxContainerSecurityContext(), + SecurityContext: openshellSandboxContainerSecurityContext(), }, }, }, } - st, err := structpb.NewStruct(raw) + return podToStructPB(pod) +} + +// podToStructPB converts a Kubernetes Pod to protobuf Struct for SandboxTemplate.pod_template. +// JSON is the stable interchange format between k8s.io/api types and structpb. +func podToStructPB(pod *corev1.Pod) (*structpb.Struct, error) { + data, err := json.Marshal(pod) + if err != nil { + return nil, fmt.Errorf("marshal pod: %w", err) + } + var root map[string]interface{} + if err := json.Unmarshal(data, &root); err != nil { + return nil, fmt.Errorf("unmarshal pod json: %w", err) + } + st, err := structpb.NewStruct(root) if err != nil { return nil, fmt.Errorf("pod template struct: %w", err) } From af9c627740f209bc74fa426688723f759bc11d19 Mon Sep 17 00:00:00 2001 From: Peter Jausovec Date: Sun, 22 Mar 2026 12:12:34 +0100 Subject: [PATCH 5/5] pr feedback Signed-off-by: Peter Jausovec --- internal/registry/api/server.go | 52 +------------------ .../registry/platforms/openshell/client.go | 14 +---- .../platforms/openshell/deployment_adapter.go | 48 ++++++++--------- .../openshell/deployment_adapter_test.go | 43 ++++++--------- 4 files changed, 43 insertions(+), 114 deletions(-) diff --git a/internal/registry/api/server.go b/internal/registry/api/server.go index 31f96d03..a72707ff 100644 --- a/internal/registry/api/server.go +++ b/internal/registry/api/server.go @@ -25,7 +25,6 @@ import ( var embeddedUI embed.FS // createUIHandler creates an HTTP handler for serving the embedded UI files -// with SPA-aware routing for Next.js static export func createUIHandler() (http.Handler, error) { // Extract the ui/dist subdirectory from the embedded filesystem uiFS, err := fs.Sub(embeddedUI, "ui/dist") @@ -33,55 +32,8 @@ func createUIHandler() (http.Handler, error) { return nil, err } - httpFS := http.FS(uiFS) - fileServer := http.FileServer(httpFS) - - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - path := r.URL.Path - - // Try the exact path first (handles static assets like .js, .css, etc.) - if f, err := httpFS.Open(path); err == nil { - f.Close() - // Check if it's a file (not a directory) — serve it directly - if stat, err := f.(interface{ Stat() (fs.FileInfo, error) }).Stat(); err == nil && !stat.IsDir() { - fileServer.ServeHTTP(w, r) - return - } - } - - // For paths without extensions (route requests), try {path}.html - // This handles Next.js static export where /deployed -> deployed.html - cleanPath := strings.TrimSuffix(path, "/") - if cleanPath != "" && !strings.Contains(cleanPath[strings.LastIndex(cleanPath, "/")+1:], ".") { - htmlPath := cleanPath + ".html" - if f, err := httpFS.Open(htmlPath); err == nil { - f.Close() - r.URL.Path = htmlPath - fileServer.ServeHTTP(w, r) - return - } - } - - // Try {path}/index.html for directory-style routes - indexPath := strings.TrimSuffix(path, "/") + "/index.html" - if f, err := httpFS.Open(indexPath); err == nil { - f.Close() - r.URL.Path = indexPath - fileServer.ServeHTTP(w, r) - return - } - - // Fall back to /index.html for client-side routing - if f, err := httpFS.Open("/index.html"); err == nil { - f.Close() - r.URL.Path = "/index.html" - fileServer.ServeHTTP(w, r) - return - } - - // Nothing found - http.NotFound(w, r) - }), nil + // Create a file server for the UI + return http.FileServer(http.FS(uiFS)), nil } // TrailingSlashMiddleware redirects requests with trailing slashes to their canonical form diff --git a/internal/registry/platforms/openshell/client.go b/internal/registry/platforms/openshell/client.go index 40fe623d..733b3d28 100644 --- a/internal/registry/platforms/openshell/client.go +++ b/internal/registry/platforms/openshell/client.go @@ -28,7 +28,6 @@ type Client interface { GetSandbox(ctx context.Context, name string) (*SandboxInfo, error) ListSandboxes(ctx context.Context) ([]SandboxInfo, error) DeleteSandbox(ctx context.Context, name string) error - GetSandboxLogs(ctx context.Context, sandboxID string) ([]string, error) HealthCheck(ctx context.Context) error ListProviders(ctx context.Context) ([]ProviderInfo, error) EnsureProvider(ctx context.Context, name, providerType string, credentials map[string]string) error @@ -44,6 +43,7 @@ type CreateSandboxOpts struct { GPU bool Policy *pb.SandboxPolicy Command []string // optional workload container command (merged via template.pod_template) + LogLevel string } // SandboxInfo holds the status of a sandbox. @@ -226,18 +226,6 @@ func (c *grpcClient) DeleteSandbox(ctx context.Context, name string) error { return nil } -func (c *grpcClient) GetSandboxLogs(ctx context.Context, sandboxID string) ([]string, error) { - resp, err := c.client.GetSandboxLogs(ctx, &pb.GetSandboxLogsRequest{SandboxId: sandboxID}) - if err != nil { - return nil, fmt.Errorf("get sandbox logs %s: %w", sandboxID, err) - } - lines := make([]string, len(resp.GetLogs())) - for i, entry := range resp.GetLogs() { - lines[i] = entry.GetMessage() - } - return lines, nil -} - func (c *grpcClient) HealthCheck(ctx context.Context) error { resp, err := c.client.Health(ctx, &pb.HealthRequest{}) if err != nil { diff --git a/internal/registry/platforms/openshell/deployment_adapter.go b/internal/registry/platforms/openshell/deployment_adapter.go index dd2d4381..c04df66f 100644 --- a/internal/registry/platforms/openshell/deployment_adapter.go +++ b/internal/registry/platforms/openshell/deployment_adapter.go @@ -144,17 +144,25 @@ func (a *openshellDeploymentAdapter) Deploy(ctx context.Context, req *models.Dep }) } - slog.Info("openshell: calling CreateSandbox") - if _, err := client.CreateSandbox(ctx, opts); err != nil { + slog.Info("openshell: calling CreateSandbox", "sandbox_name", sandboxName) + created, err := client.CreateSandbox(ctx, opts) + if err != nil { return nil, fmt.Errorf("create openshell sandbox: %w", err) } - slog.Info("openshell: sandbox created, waiting for ready") + slog.Info("openshell: CreateSandbox returned — waiting for ready", + "sandbox_id", strings.TrimSpace(created.ID), + "sandbox_name", sandboxName, + "phase", created.Phase, + ) if err := a.waitForReady(ctx, client, sandboxName); err != nil { return nil, err } result := &models.DeploymentActionResult{Status: models.DeploymentStatusDeployed} + metaMap := map[string]any{ + "openshellSandboxName": sandboxName, + } if resourceType == "agent" { forwardCLI := fmt.Sprintf("openshell forward start %d %s", openshellKagentForwardPort, sandboxName) // User-facing hint is persisted on providerMetadata (arctl prints it); slog is for server logs only. @@ -163,21 +171,19 @@ func (a *openshellDeploymentAdapter) Deploy(ctx context.Context, req *models.Dep "sandbox", sandboxName, "port", openshellKagentForwardPort, ) - meta, mErr := models.UnmarshalFrom(map[string]any{ - "openshellSandboxName": sandboxName, - "openshellForwardPort": openshellKagentForwardPort, - "openshellForwardCLI": forwardCLI, - }) - if mErr != nil { - slog.Warn("openshell: could not build provider metadata", "error", mErr) - } else { - result.ProviderMetadata = meta - } + metaMap["openshellForwardPort"] = openshellKagentForwardPort + metaMap["openshellForwardCLI"] = forwardCLI + } + meta, mErr := models.UnmarshalFrom(metaMap) + if mErr != nil { + slog.Warn("openshell: could not build provider metadata", "error", mErr) + } else { + result.ProviderMetadata = meta } return result, nil } -func (a *openshellDeploymentAdapter) Undeploy(_ context.Context, deployment *models.Deployment) error { +func (a *openshellDeploymentAdapter) Undeploy(ctx context.Context, deployment *models.Deployment) error { client, err := a.getClient() if err != nil { return err @@ -186,7 +192,7 @@ func (a *openshellDeploymentAdapter) Undeploy(_ context.Context, deployment *mod return err } - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + ctx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() sandboxName := sandboxNameForDeployment(deployment) @@ -196,16 +202,8 @@ func (a *openshellDeploymentAdapter) Undeploy(_ context.Context, deployment *mod return nil } -func (a *openshellDeploymentAdapter) GetLogs(ctx context.Context, deployment *models.Deployment) ([]string, error) { - client, err := a.getClient() - if err != nil { - return nil, err - } - if deployment == nil { - return nil, fmt.Errorf("deployment is required: %w", database.ErrInvalidInput) - } - sandboxName := sandboxNameForDeployment(deployment) - return client.GetSandboxLogs(ctx, sandboxName) +func (a *openshellDeploymentAdapter) GetLogs(_ context.Context, _ *models.Deployment) ([]string, error) { + return nil, utils.ErrDeploymentNotSupported } func (a *openshellDeploymentAdapter) Cancel(ctx context.Context, deployment *models.Deployment) error { diff --git a/internal/registry/platforms/openshell/deployment_adapter_test.go b/internal/registry/platforms/openshell/deployment_adapter_test.go index 4b00b21c..d24d59aa 100644 --- a/internal/registry/platforms/openshell/deployment_adapter_test.go +++ b/internal/registry/platforms/openshell/deployment_adapter_test.go @@ -2,10 +2,12 @@ package openshell import ( "context" + "errors" "fmt" "testing" platformtypes "github.com/agentregistry-dev/agentregistry/internal/registry/platforms/types" + "github.com/agentregistry-dev/agentregistry/internal/registry/platforms/utils" servicetesting "github.com/agentregistry-dev/agentregistry/internal/registry/service/testing" "github.com/agentregistry-dev/agentregistry/pkg/models" apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" @@ -18,7 +20,6 @@ type mockClient struct { getFn func(ctx context.Context, name string) (*SandboxInfo, error) listFn func(ctx context.Context) ([]SandboxInfo, error) deleteFn func(ctx context.Context, name string) error - logsFn func(ctx context.Context, name string) ([]string, error) healthFn func(ctx context.Context) error listProvidersFn func(ctx context.Context) ([]ProviderInfo, error) ensureProvFn func(ctx context.Context, name, provType string, creds map[string]string) error @@ -52,13 +53,6 @@ func (m *mockClient) DeleteSandbox(ctx context.Context, name string) error { return nil } -func (m *mockClient) GetSandboxLogs(ctx context.Context, name string) ([]string, error) { - if m.logsFn != nil { - return m.logsFn(ctx, name) - } - return nil, nil -} - func (m *mockClient) HealthCheck(ctx context.Context) error { if m.healthFn != nil { return m.healthFn(ctx) @@ -140,6 +134,9 @@ func TestDeploy_Agent_CallsCreateSandbox(t *testing.T) { if result.ProviderMetadata == nil || result.ProviderMetadata["openshellForwardCLI"] == nil { t.Errorf("expected openshell ProviderMetadata with forward CLI, got %#v", result.ProviderMetadata) } + if got, _ := result.ProviderMetadata["openshellSandboxName"].(string); got == "" { + t.Errorf("openshellSandboxName should be set, got %#v", result.ProviderMetadata["openshellSandboxName"]) + } if createdOpts.Image != "test-agent-image:latest" { t.Errorf("image = %q, want %q", createdOpts.Image, "test-agent-image:latest") } @@ -214,6 +211,12 @@ func TestDeploy_MCP_CallsCreateSandbox(t *testing.T) { if createdOpts.Name == "" { t.Error("sandbox name should not be empty") } + if result.ProviderMetadata == nil { + t.Fatal("expected ProviderMetadata for MCP deploy") + } + if got, _ := result.ProviderMetadata["openshellSandboxName"].(string); got == "" { + t.Errorf("openshellSandboxName should be set, got %#v", result.ProviderMetadata["openshellSandboxName"]) + } } func TestUndeploy_CallsDeleteSandbox(t *testing.T) { @@ -243,29 +246,17 @@ func TestUndeploy_CallsDeleteSandbox(t *testing.T) { } } -func TestGetLogs_ReturnsLogLines(t *testing.T) { - client := &mockClient{ - logsFn: func(_ context.Context, _ string) ([]string, error) { - return []string{"line1", "line2", "line3"}, nil - }, - } - - adapter := NewOpenShellDeploymentAdapter(newTestRegistry(), client) - - deployment := &models.Deployment{ +func TestGetLogs_NotSupported(t *testing.T) { + adapter := NewOpenShellDeploymentAdapter(newTestRegistry(), &mockClient{}) + _, err := adapter.GetLogs(context.Background(), &models.Deployment{ ID: "dep-logs", ServerName: "my-agent", Version: "1.0.0", ResourceType: "agent", ProviderID: "openshell-default", - } - - logs, err := adapter.GetLogs(context.Background(), deployment) - if err != nil { - t.Fatalf("GetLogs() error = %v", err) - } - if len(logs) != 3 { - t.Errorf("log lines = %d, want 3", len(logs)) + }) + if !errors.Is(err, utils.ErrDeploymentNotSupported) { + t.Fatalf("GetLogs() error = %v, want %v", err, utils.ErrDeploymentNotSupported) } }