// 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 settings by id (called by sandbox entrypoint and poll loop). rpc GetSandboxConfig(openshell.sandbox.v1.GetSandboxConfigRequest) returns (openshell.sandbox.v1.GetSandboxConfigResponse); // Get gateway-global settings. rpc GetGatewayConfig(openshell.sandbox.v1.GetGatewayConfigRequest) returns (openshell.sandbox.v1.GetGatewayConfigResponse); // Update settings or policy at sandbox or global scope. rpc UpdateConfig(UpdateConfigRequest) returns (UpdateConfigResponse); // 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 UpdateConfigRequest { // Sandbox name (canonical lookup key). Required for sandbox-scoped updates. // Not required when `global=true`. string name = 1; // The new policy to apply. // // Sandbox scope (`global=false`): // - only network_policies and inference fields may differ from create-time // policy; static fields must match version 1. // // Global scope (`global=true`): // - applies to all sandboxes in full (no merge). openshell.sandbox.v1.SandboxPolicy policy = 2; // Optional single setting key to mutate. string setting_key = 3; // Setting value for upsert operations. openshell.sandbox.v1.SettingValue setting_value = 4; // Delete the setting key from scope. // Sandbox-scoped deletes are rejected; only global delete is supported. bool delete_setting = 5; // Apply mutation at gateway-global scope. bool global = 6; } // Update sandbox policy response. message UpdateConfigResponse { // Assigned policy version (monotonically increasing per sandbox). uint32 version = 1; // SHA-256 hash of the serialized policy payload. string policy_hash = 2; // Settings revision for the scope that was modified. uint64 settings_revision = 3; // True when a setting delete operation removed an existing key. bool deleted = 4; } // Get sandbox policy status request. message GetSandboxPolicyStatusRequest { // Sandbox name (canonical lookup key). Ignored when global is true. string name = 1; // The specific policy version to query. 0 means latest. uint32 version = 2; // Query global policy revisions instead of a sandbox-scoped one. bool global = 3; } // 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). Ignored when global is true. string name = 1; uint32 limit = 2; uint32 offset = 3; // List global policy revisions instead of sandbox-scoped ones. bool global = 4; } // 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; }