diff --git a/.agents/skills/debug-openshell-cluster/SKILL.md b/.agents/skills/debug-openshell-cluster/SKILL.md
index 62512792c..9d16be2d8 100644
--- a/.agents/skills/debug-openshell-cluster/SKILL.md
+++ b/.agents/skills/debug-openshell-cluster/SKILL.md
@@ -210,9 +210,13 @@ Common findings:
host's IPv4 default route. Rootless pasta uses the private source address
selected by that route; rootful Podman uses the bridge gateway address.
- Callback discovery reports that the requested address equals the primary
- listener: configure a distinct primary address. For Podman Machine, keep the
- IPv4 loopback callback separate by using an IPv6-loopback primary such as
- `[::1]:17670`.
+ listener: configure a distinct primary address. For Podman Machine, bind the
+ primary listener to IPv6 loopback, for example
+ `bind_address = "[::1]:17670"`, and register the CLI endpoint as
+ `https://localhost:17670`. The generated certificate includes `localhost`,
+ while a raw `https://[::1]:17670` endpoint can fail TLS setup with
+ `invalid dns name`. This leaves `127.0.0.1:17670` available for the
+ callback-only listener.
- Rootless slirp4netns, another named helper, or missing helper metadata
requires an explicitly remote `grpc_endpoint`. An explicit `host_gateway_ip`
cannot bypass slirp4netns host-loopback isolation. Do not work around
diff --git a/.github/workflows/branch-checks.yml b/.github/workflows/branch-checks.yml
index fccdfd1bb..53f467ff7 100644
--- a/.github/workflows/branch-checks.yml
+++ b/.github/workflows/branch-checks.yml
@@ -218,6 +218,25 @@ jobs:
- name: Test
run: mise run test:python
+ go:
+ name: Go SDK
+ needs: pr_metadata
+ if: needs.pr_metadata.outputs.should_run == 'true'
+ runs-on: linux-amd64-cpu8
+ container:
+ image: ghcr.io/nvidia/openshell/ci:latest
+ credentials:
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ steps:
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+
+ - name: Install tools
+ run: mise install --locked
+
+ - name: Lint, build, test, proto-check
+ run: mise run go:ci
+
markdown:
name: Markdown
needs: pr_metadata
diff --git a/.gitignore b/.gitignore
index 40307c7a1..b6df45ef1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -64,6 +64,7 @@ pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
+coverage.out
htmlcov/
.tox/
.nox/
diff --git a/AGENTS.md b/AGENTS.md
index f2a9f486f..7e494a7b5 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -204,6 +204,15 @@ ocsf_emit!(event);
- `mise run e2e` — End-to-end tests against a running gateway. Run for infrastructure, sandbox, or policy changes.
- `mise run ci` — Full local CI (lint + compile/type checks + tests). Run before opening a PR.
+## Go SDK (`sdk/go/`)
+
+- The Go SDK lives in `sdk/go/` with module path `github.com/NVIDIA/OpenShell/sdk/go`.
+- Run `mise run go:ci` for the full SDK CI pipeline (lint, build, test, proto-check, docs-check).
+- Proto bindings are generated with `mise run go:proto:gen` from the `.proto` files in `proto/`.
+- Domain types in `sdk/go/openshell/v1/types/` must not import proto packages.
+- Converters in `sdk/go/openshell/v1/internal/converter/` deep-copy slices and maps at boundaries.
+- Tests use bufconn for in-process gRPC and testify for assertions.
+
## Python
- Always use `uv` for Python commands (e.g., `uv pip install`, `uv run`, `uv venv`)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 22592c435..64b9d85b0 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -434,6 +434,7 @@ Bazel does not yet cover `mise run gateway`, `mise run sandbox`, `mise run e2e`,
| --------------- | --------------------------------------------- |
| `crates/` | Rust crates |
| `python/` | Python SDK and bindings |
+| `sdk/go/` | Go SDK (types, gRPC clients, converters) |
| `proto/` | Protocol buffer definitions |
| `tasks/` | `mise` task definitions and build scripts |
| `deploy/` | Dockerfiles, Helm chart, Kubernetes manifests |
diff --git a/Cargo.lock b/Cargo.lock
index e6224b335..2b2d256b9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -127,7 +127,7 @@ version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
dependencies = [
- "windows-sys 0.61.2",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -138,7 +138,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
dependencies = [
"anstyle",
"once_cell_polyfill",
- "windows-sys 0.61.2",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -1356,15 +1356,16 @@ dependencies = [
[[package]]
name = "curve25519-dalek"
-version = "5.0.0-rc.0"
+version = "5.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f359e08ca85e7bd759e1fd933ff2bccd81864c60a8fba0e259c7f822b0924bf"
+checksum = "b5eed333089e2e1c1ac8c6c0398e5e2497b4c9926ca6d0365ed1e099afa5bc23"
dependencies = [
"cfg-if",
"cpufeatures 0.3.0",
"curve25519-dalek-derive",
"digest 0.11.2",
"fiat-crypto",
+ "rand_core 0.10.1",
"rustc_version",
"subtle",
"zeroize",
@@ -1615,9 +1616,9 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
[[package]]
name = "ecdsa"
-version = "0.17.0-rc.18"
+version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54fb064faabbee66e1fc8e5c5a9458d4269dc2d8b638fe86a425adb2510d1a96"
+checksum = "c0681a4fc24c767085329728d8dfba959af91228aa4610cca4f8ce317ba46ae0"
dependencies = [
"der 0.8.0",
"digest 0.11.2",
@@ -1640,9 +1641,9 @@ dependencies = [
[[package]]
name = "ed25519-dalek"
-version = "3.0.0-rc.0"
+version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b011170fe4f04665565b4110afef66774fe9ffff278f3eb5b81cc73d26e27d60"
+checksum = "6ebaa1a2bf1290ab3bfe5a7b771d050ebffab2711c19a81691c683a5144a25de"
dependencies = [
"curve25519-dalek",
"ed25519",
@@ -1665,9 +1666,9 @@ dependencies = [
[[package]]
name = "elliptic-curve"
-version = "0.14.0-rc.33"
+version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "102d3643d30dd8b559613c5cced68317199597fffb278cdc88daa2ef7fafc935"
+checksum = "9d65aa39b3a5c1c9c1b745c9a019234bb7a21b77abcb4f4d266d706e2d577d65"
dependencies = [
"base16ct",
"crypto-bigint",
@@ -1677,7 +1678,6 @@ dependencies = [
"group",
"hkdf 0.13.0",
"hybrid-array",
- "once_cell",
"pem-rfc7468 1.0.0",
"pkcs8 0.11.0",
"rand_core 0.10.1",
@@ -1737,7 +1737,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
- "windows-sys 0.61.2",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -2869,33 +2869,21 @@ dependencies = [
"thiserror 1.0.69",
]
-[[package]]
-name = "jsonwebtoken"
-version = "9.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde"
-dependencies = [
- "base64 0.22.1",
- "js-sys",
- "pem",
- "ring",
- "serde",
- "serde_json",
- "simple_asn1",
-]
-
[[package]]
name = "jsonwebtoken"
version = "10.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0529410abe238729a60b108898784df8984c87f6054c9c4fcacc47e4803c1ce1"
dependencies = [
+ "aws-lc-rs",
"base64 0.22.1",
"getrandom 0.2.17",
"js-sys",
+ "pem",
"serde",
"serde_json",
"signature 2.2.0",
+ "simple_asn1",
]
[[package]]
@@ -3371,7 +3359,7 @@ dependencies = [
"module-lattice",
"pkcs8 0.11.0",
"rand_core 0.10.1",
- "sha3",
+ "sha3 0.11.0",
]
[[package]]
@@ -3467,7 +3455,7 @@ version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
- "windows-sys 0.61.2",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -3588,7 +3576,7 @@ dependencies = [
"futures-util",
"http 1.4.0",
"http-auth",
- "jsonwebtoken 10.3.0",
+ "jsonwebtoken",
"lazy_static",
"oci-spec",
"olpc-cjson",
@@ -4109,7 +4097,7 @@ dependencies = [
"hyper-rustls 0.27.9",
"hyper-util",
"ipnet",
- "jsonwebtoken 9.3.1",
+ "jsonwebtoken",
"k8s-openapi",
"kube",
"metrics",
@@ -4145,6 +4133,7 @@ dependencies = [
"rcgen",
"reqwest 0.12.28",
"ring",
+ "rsa 0.9.10",
"russh",
"rustix 1.1.4",
"rustls 0.23.38",
@@ -4428,9 +4417,9 @@ checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d"
[[package]]
name = "p256"
-version = "0.14.0-rc.10"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41adc63effe99d48837a8cc0e6d7a77e32ae6a07f6000df466178dbc2193093e"
+checksum = "d2c9239b2dbc807adbbe147e8cf72ea7450c3a0aabe62cb8e75ff4ec22e1f72a"
dependencies = [
"ecdsa",
"elliptic-curve",
@@ -4441,9 +4430,9 @@ dependencies = [
[[package]]
name = "p384"
-version = "0.14.0-rc.10"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bd5333afa5ae0347f39e6a0f2c9c155da431583fd71fe5555bd0521b4ccaf02"
+checksum = "d17b851e6b3e378ab4ecb07fa2ed23f4d15f075735f8fec9fa1e7bdce5f8301f"
dependencies = [
"ecdsa",
"elliptic-curve",
@@ -4455,9 +4444,9 @@ dependencies = [
[[package]]
name = "p521"
-version = "0.14.0-rc.10"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3a5297f53dc16d35909060ba3032cff7867e8809f01e273ff325579d5f0ceae"
+checksum = "4ad64cc32c2dc466317c12ee5853e61f159f9eab1fe7efade0395dc2e7b43449"
dependencies = [
"base16ct",
"ecdsa",
@@ -4848,11 +4837,15 @@ dependencies = [
[[package]]
name = "primeorder"
-version = "0.14.0-rc.10"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d2793f22b9b6fd11ef3ac1d59bf003c2573593e4968702341605c2748fd90bf"
+checksum = "5c9f42978c78a00e3d68f69fc03e57a234debae69da4020a4fb588fcdcd07b06"
dependencies = [
"elliptic-curve",
+ "once_cell",
+ "primefield",
+ "serdect",
+ "wnaf",
]
[[package]]
@@ -5355,12 +5348,12 @@ dependencies = [
[[package]]
name = "rfc6979"
-version = "0.5.0"
+version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5236ce872cac07e0fb3969b0cbf468c7d2f37d432f1b627dcb7b8d34563fb0c3"
+checksum = "b4a459cddafb3fe76b31fd8f1108007566c40301feb64dc7b54656eb7388172b"
dependencies = [
+ "crypto-bigint",
"hmac 0.13.0",
- "subtle",
]
[[package]]
@@ -5430,9 +5423,9 @@ dependencies = [
[[package]]
name = "russh"
-version = "0.61.2"
+version = "0.62.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbf893f64684e58da8a68d56a5e84d1cf0440226274c515770fe267707a7d0b0"
+checksum = "da7c230e0ed9cbeb92fbad6c8848985d6df2a1464c0dc247a021abd666e9005e"
dependencies = [
"aes",
"aws-lc-rs",
@@ -5487,7 +5480,7 @@ dependencies = [
"sec1",
"sha1 0.11.0",
"sha2 0.11.0",
- "sha3",
+ "sha3 0.12.0",
"signature 3.0.0",
"spki 0.8.0",
"ssh-encoding",
@@ -5502,9 +5495,9 @@ dependencies = [
[[package]]
name = "russh-cryptovec"
-version = "0.61.0"
+version = "0.62.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "443f6bbcfacb34a1aab2b12b99bf08e0c63abdc5a0db261901365df9d57fff51"
+checksum = "3aec6cb630dbe85d72ffd7bcd95f07e1bd69f9f270ee8adfa1afe443a6331438"
dependencies = [
"log",
"nix 0.31.3",
@@ -5583,7 +5576,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys 0.12.1",
- "windows-sys 0.61.2",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -5663,7 +5656,7 @@ dependencies = [
"security-framework",
"security-framework-sys",
"webpki-root-certs",
- "windows-sys 0.61.2",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -6047,6 +6040,17 @@ dependencies = [
"keccak",
]
+[[package]]
+name = "sha3"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc9bad02c26382724b2d2692c6f179285e4b54eeecd7968f52a50059c3c11759"
+dependencies = [
+ "digest 0.11.2",
+ "keccak",
+ "sponge-cursor",
+]
+
[[package]]
name = "sharded-slab"
version = "0.1.7"
@@ -6182,7 +6186,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
dependencies = [
"libc",
- "windows-sys 0.61.2",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -6242,6 +6246,12 @@ dependencies = [
"der 0.8.0",
]
+[[package]]
+name = "sponge-cursor"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a0219bd7d979d58245a4f41f695e1ac9f8befdffadd7f61f1bae9e39abc6620"
+
[[package]]
name = "sqlx"
version = "0.8.6"
@@ -6432,17 +6442,15 @@ dependencies = [
[[package]]
name = "ssh-cipher"
-version = "0.3.0-rc.9"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10db6f219196a8528f9ec904d9d45cdad692d65b0e57e72be4dedd1c5fddce36"
+checksum = "d801accda99469cde6d73da741422610fdf6508a72d9a69d1b55cb241c720597"
dependencies = [
"aead",
"aes",
"aes-gcm",
- "cbc",
"chacha20",
"cipher",
- "ctr",
"ctutils",
"des",
"poly1305",
@@ -6452,9 +6460,9 @@ dependencies = [
[[package]]
name = "ssh-encoding"
-version = "0.3.0-rc.9"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7abf34aa716da5d5b4c496936d042ea282ab392092cd68a72ef6a8863ff8c96a"
+checksum = "7b54d0ed0498daf3f78d82e00e28c8eec9d75a067c4cfbcc7a0f7d0f4077749e"
dependencies = [
"base64ct",
"bytes",
@@ -6467,9 +6475,9 @@ dependencies = [
[[package]]
name = "ssh-key"
-version = "0.7.0-rc.10"
+version = "0.7.0-rc.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45735ce3dea95690e4a9e414c4cfde7f79835063c3dcd35881df85a84118e74b"
+checksum = "f9a32fae177b74a22aa9c5b01bf7e68b33545be32d9e381e248058d2adc15ce3"
dependencies = [
"argon2",
"bcrypt-pbkdf",
@@ -6647,9 +6655,9 @@ dependencies = [
[[package]]
name = "tar"
-version = "0.4.45"
+version = "0.4.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973"
+checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840"
dependencies = [
"filetime",
"libc",
@@ -6675,7 +6683,7 @@ dependencies = [
"getrandom 0.4.2",
"once_cell",
"rustix 1.1.4",
- "windows-sys 0.61.2",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -6711,7 +6719,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874"
dependencies = [
"rustix 1.1.4",
- "windows-sys 0.61.2",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -7708,7 +7716,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
- "windows-sys 0.61.2",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -8250,6 +8258,17 @@ dependencies = [
"wasmparser",
]
+[[package]]
+name = "wnaf"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab12e7090f27e2ffd9322651492942d50c2926094af30601e1964337db39daf1"
+dependencies = [
+ "ff",
+ "group",
+ "hybrid-array",
+]
+
[[package]]
name = "writeable"
version = "0.6.3"
diff --git a/Cargo.toml b/Cargo.toml
index 9d801570e..26c1f72f1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -102,7 +102,7 @@ base64 = "0.22"
# Crypto / Auth
sha2 = "0.10"
rand = "0.9"
-jsonwebtoken = "9"
+jsonwebtoken = { version = "10", features = ["aws_lc_rs"] }
getrandom = "0.3"
ring = "0.17"
spiffe = { version = "0.15", default-features = false, features = ["workload-api-jwt", "tracing"] }
diff --git a/MODULE.bazel b/MODULE.bazel
index 5946d072f..d54b7ba40 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -6,6 +6,56 @@ bazel_dep(name = "rules_cc", version = "0.2.20")
bazel_dep(name = "rules_proto", version = "7.1.0")
bazel_dep(name = "protobuf", version = "34.0.bcr.1")
+bazel_lib_toolchains = use_extension("@bazel_lib//lib:extensions.bzl", "toolchains")
+bazel_lib_toolchains.zstd()
+use_repo(bazel_lib_toolchains, "zstd_toolchains")
+
+register_toolchains("@zstd_toolchains//:all")
+
+http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+http_archive(
+ name = "vm_runtime_darwin_aarch64",
+ build_file_content = """
+exports_files([
+ "gvproxy",
+ "libkrun.dylib",
+ "libkrunfw.5.dylib",
+ "umoci",
+])
+""",
+ integrity = "sha256-KSAKryBFZiytwYwXB0CR++u4tGlA5ficf7X/nen7qQE=",
+ urls = ["https://github.com/NVIDIA/OpenShell/releases/download/vm-runtime/vm-runtime-darwin-aarch64.tar.zst"],
+)
+
+http_archive(
+ name = "vm_runtime_linux_aarch64",
+ build_file_content = """
+exports_files([
+ "gvproxy",
+ "libkrun.so",
+ "libkrunfw.so.5",
+ "umoci",
+])
+""",
+ integrity = "sha256-zn0P4NtEKp7Euy44HfQ3YoBNijF2VWFTaLLsase+Y1A=",
+ urls = ["https://github.com/NVIDIA/OpenShell/releases/download/vm-runtime/vm-runtime-linux-aarch64.tar.zst"],
+)
+
+http_archive(
+ name = "vm_runtime_linux_x86_64",
+ build_file_content = """
+exports_files([
+ "gvproxy",
+ "libkrun.so",
+ "libkrunfw.so.5",
+ "umoci",
+])
+""",
+ integrity = "sha256-urdMjarDN5WJ6eCmpddlcnEn2v3qp28D7+e6PtyhPr0=",
+ urls = ["https://github.com/NVIDIA/OpenShell/releases/download/vm-runtime/vm-runtime-linux-x86_64.tar.zst"],
+)
+
include("//bazel/annotations:aws-lc-sys.MODULE.bazel")
include("//bazel/annotations:z3-sys.MODULE.bazel")
include("//bazel/annotations:zstd-sys.MODULE.bazel")
diff --git a/README.md b/README.md
index 3d5aeb6fb..4b8c37015 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,12 @@
-# 
+
+
+
+
+
+
+
+
+
[](https://github.com/NVIDIA/OpenShell/blob/main/LICENSE)
[](https://pypi.org/project/openshell/)
diff --git a/bazel/BUILD.bazel b/bazel/BUILD.bazel
index 8d61bb55c..ceba7d2e2 100644
--- a/bazel/BUILD.bazel
+++ b/bazel/BUILD.bazel
@@ -1 +1,4 @@
-exports_files(["cargo_version.bzl"])
+exports_files([
+ "cargo_version.bzl",
+ "vm_runtime.bzl",
+])
diff --git a/bazel/releases/BUILD.bazel b/bazel/releases/BUILD.bazel
index e424cef40..bc859ed16 100644
--- a/bazel/releases/BUILD.bazel
+++ b/bazel/releases/BUILD.bazel
@@ -44,6 +44,7 @@ platform_transition_binary(
binary = "//crates/openshell-sandbox:openshell-sandbox-bin",
tags = ["manual"],
target_platform = "@rules_rs//rs/platforms:x86_64-unknown-linux-musl",
+ visibility = ["//visibility:public"],
)
platform_transition_binary(
@@ -52,6 +53,7 @@ platform_transition_binary(
binary = "//crates/openshell-sandbox:openshell-sandbox-bin",
tags = ["manual"],
target_platform = "@rules_rs//rs/platforms:aarch64-unknown-linux-musl",
+ visibility = ["//visibility:public"],
)
platform_transition_binary(
diff --git a/bazel/vm-runtime/BUILD.bazel b/bazel/vm-runtime/BUILD.bazel
new file mode 100644
index 000000000..073bcf047
--- /dev/null
+++ b/bazel/vm-runtime/BUILD.bazel
@@ -0,0 +1,72 @@
+load("//bazel:vm_runtime.bzl", "vm_runtime_bundle")
+
+config_setting(
+ name = "darwin_aarch64",
+ constraint_values = [
+ "@platforms//cpu:aarch64",
+ "@platforms//os:osx",
+ ],
+)
+
+config_setting(
+ name = "linux_aarch64",
+ constraint_values = [
+ "@platforms//cpu:aarch64",
+ "@platforms//os:linux",
+ ],
+)
+
+config_setting(
+ name = "linux_x86_64",
+ constraint_values = [
+ "@platforms//cpu:x86_64",
+ "@platforms//os:linux",
+ ],
+)
+
+vm_runtime_bundle(
+ name = "runtime",
+ gvproxy = select({
+ ":darwin_aarch64": "@vm_runtime_darwin_aarch64//:gvproxy",
+ ":linux_aarch64": "@vm_runtime_linux_aarch64//:gvproxy",
+ ":linux_x86_64": "@vm_runtime_linux_x86_64//:gvproxy",
+ }),
+ libkrun = select({
+ ":darwin_aarch64": "@vm_runtime_darwin_aarch64//:libkrun.dylib",
+ ":linux_aarch64": "@vm_runtime_linux_aarch64//:libkrun.so",
+ ":linux_x86_64": "@vm_runtime_linux_x86_64//:libkrun.so",
+ }),
+ libkrun_name = select({
+ ":darwin_aarch64": "libkrun.dylib",
+ ":linux_aarch64": "libkrun.so",
+ ":linux_x86_64": "libkrun.so",
+ }),
+ libkrunfw = select({
+ ":darwin_aarch64": "@vm_runtime_darwin_aarch64//:libkrunfw.5.dylib",
+ ":linux_aarch64": "@vm_runtime_linux_aarch64//:libkrunfw.so.5",
+ ":linux_x86_64": "@vm_runtime_linux_x86_64//:libkrunfw.so.5",
+ }),
+ libkrunfw_name = select({
+ ":darwin_aarch64": "libkrunfw.5.dylib",
+ ":linux_aarch64": "libkrunfw.so.5",
+ ":linux_x86_64": "libkrunfw.so.5",
+ }),
+ supervisor = select({
+ ":darwin_aarch64": "//bazel/releases:openshell_sandbox_linux_aarch64",
+ ":linux_aarch64": "//bazel/releases:openshell_sandbox_linux_aarch64",
+ ":linux_x86_64": "//bazel/releases:openshell_sandbox_linux_x86_64",
+ }),
+ tags = ["manual"],
+ target_compatible_with = select({
+ ":darwin_aarch64": [],
+ ":linux_aarch64": [],
+ ":linux_x86_64": [],
+ "//conditions:default": ["@platforms//:incompatible"],
+ }),
+ umoci = select({
+ ":darwin_aarch64": "@vm_runtime_darwin_aarch64//:umoci",
+ ":linux_aarch64": "@vm_runtime_linux_aarch64//:umoci",
+ ":linux_x86_64": "@vm_runtime_linux_x86_64//:umoci",
+ }),
+ visibility = ["//visibility:public"],
+)
diff --git a/bazel/vm_runtime.bzl b/bazel/vm_runtime.bzl
new file mode 100644
index 000000000..1f611fd44
--- /dev/null
+++ b/bazel/vm_runtime.bzl
@@ -0,0 +1,46 @@
+"""Rules for staging the embedded openshell-driver-vm runtime."""
+
+_ZSTD_TOOLCHAIN = "@bazel_lib//lib:zstd_toolchain_type"
+
+def _vm_runtime_bundle_impl(ctx):
+ output = ctx.actions.declare_directory(ctx.label.name)
+ zstd = ctx.toolchains[_ZSTD_TOOLCHAIN].zstdinfo.binary
+
+ resources = [
+ (ctx.file.libkrun, ctx.attr.libkrun_name),
+ (ctx.file.libkrunfw, ctx.attr.libkrunfw_name),
+ (ctx.file.gvproxy, "gvproxy"),
+ (ctx.executable.supervisor, "openshell-sandbox"),
+ (ctx.file.umoci, "umoci"),
+ ]
+ commands = ["mkdir -p '{}'".format(output.path)]
+ for source, name in resources:
+ commands.append("'{}' -q -f '{}' -o '{}/{}.zst'".format(
+ zstd.path,
+ source.path,
+ output.path,
+ name,
+ ))
+
+ ctx.actions.run_shell(
+ command = "set -euo pipefail\n{}".format("\n".join(commands)),
+ inputs = [source for source, _ in resources],
+ outputs = [output],
+ tools = [zstd],
+ )
+
+ return [DefaultInfo(files = depset([output]))]
+
+vm_runtime_bundle = rule(
+ implementation = _vm_runtime_bundle_impl,
+ attrs = {
+ "gvproxy": attr.label(allow_single_file = True, mandatory = True),
+ "libkrun": attr.label(allow_single_file = True, mandatory = True),
+ "libkrun_name": attr.string(mandatory = True),
+ "libkrunfw": attr.label(allow_single_file = True, mandatory = True),
+ "libkrunfw_name": attr.string(mandatory = True),
+ "supervisor": attr.label(executable = True, cfg = "target", mandatory = True),
+ "umoci": attr.label(allow_single_file = True, mandatory = True),
+ },
+ toolchains = [_ZSTD_TOOLCHAIN],
+)
diff --git a/buf.yaml b/buf.yaml
new file mode 100644
index 000000000..a9ada8c9e
--- /dev/null
+++ b/buf.yaml
@@ -0,0 +1,31 @@
+# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0
+
+# Repo-level buf module. Declares proto/ as the single module so buf generate,
+# buf lint, buf breaking, and the editor LSP all resolve imports the same way.
+# Code generation lives with each consumer (see sdk/go/buf.gen.yaml,
+# sdk/typescript/buf.gen.yaml); this file owns the module boundary and proto
+# validation policy.
+version: v2
+modules:
+ - path: proto
+lint:
+ use:
+ - STANDARD
+ except:
+ # Flat proto/ layout: all files live in one directory with nested
+ # packages (openshell.v1, openshell.sandbox.v1, ...). Adopting these
+ # would require restructuring the tree into openshell//v1/ and
+ # updating every Rust/Python/TS codegen path and import.
+ - DIRECTORY_SAME_PACKAGE
+ - PACKAGE_DIRECTORY_MATCH
+ # Established API shape: services are unsuffixed (OpenShell, not
+ # OpenShellService) and RPCs reuse shared request/response messages with
+ # short names. Renaming these is a breaking change across the codebase.
+ - RPC_REQUEST_RESPONSE_UNIQUE
+ - RPC_REQUEST_STANDARD_NAME
+ - RPC_RESPONSE_STANDARD_NAME
+ - SERVICE_SUFFIX
+breaking:
+ use:
+ - FILE
diff --git a/crates/openshell-core/src/forward.rs b/crates/openshell-core/src/forward.rs
index 1d97174d9..3b9527bcc 100644
--- a/crates/openshell-core/src/forward.rs
+++ b/crates/openshell-core/src/forward.rs
@@ -745,11 +745,11 @@ pub fn resolve_ssh_gateway(
// Remote cluster: use the remote host but keep the cluster URL port.
return (host.to_string(), cluster_port);
}
- // Both endpoints loopback. The unspecified addresses (0.0.0.0 / ::)
- // are bind-only — they aren't valid connect targets and aren't in TLS
- // cert SANs, so fall back to the cluster URL's host (which the CLI
- // is already using to reach the gateway).
- if gateway_host == "0.0.0.0" || gateway_host == "::" {
+ // Unspecified addresses are bind-only, and tonic cannot use an IPv6
+ // literal as a TLS DNS name. In those cases, keep the cluster URL's
+ // already-reachable authority. Other loopback addresses retain the
+ // gateway-reported host.
+ if matches!(gateway_host, "0.0.0.0" | "::" | "::1") {
return (host.to_string(), cluster_port);
}
return (gateway_host.to_string(), cluster_port);
@@ -1026,6 +1026,13 @@ mod tests {
assert_eq!(port, 443);
}
+ #[test]
+ fn resolve_ssh_gateway_preserves_loopback_tls_authority() {
+ let (host, port) = resolve_ssh_gateway("::1", 8080, "https://localhost:8443");
+ assert_eq!(host, "localhost");
+ assert_eq!(port, 8443);
+ }
+
#[test]
fn resolve_ssh_gateway_swaps_zeros_for_loopback_cluster_host() {
// The gateway binds 0.0.0.0 but advertises that bind address via the
diff --git a/crates/openshell-core/src/proto/mod.rs b/crates/openshell-core/src/proto/mod.rs
index 4a9e11715..7a0f87c83 100644
--- a/crates/openshell-core/src/proto/mod.rs
+++ b/crates/openshell-core/src/proto/mod.rs
@@ -46,16 +46,20 @@ pub mod compute {
pub use super::generated::openshell::compute::v1;
}
+#[allow(
+ clippy::all,
+ clippy::pedantic,
+ clippy::nursery,
+ dead_code,
+ unused_imports,
+ unused_qualifications,
+ rust_2018_idioms
+)]
pub mod credentials {
- #[allow(
- clippy::all,
- clippy::pedantic,
- clippy::nursery,
- dead_code,
- unused_imports,
- unused_qualifications,
- rust_2018_idioms
- )]
+ #[cfg(bazel)]
+ pub use super::generated::openshell::credentials::v1;
+
+ #[cfg(not(bazel))]
pub mod v1 {
include!(concat!(env!("OUT_DIR"), "/openshell.credentials.v1.rs"));
}
diff --git a/crates/openshell-driver-db-credstore/BUILD.bazel b/crates/openshell-driver-db-credstore/BUILD.bazel
new file mode 100644
index 000000000..ec5e01f7f
--- /dev/null
+++ b/crates/openshell-driver-db-credstore/BUILD.bazel
@@ -0,0 +1,27 @@
+load("@crates//:defs.bzl", "aliases", "all_crate_deps")
+load("@rules_rs//rs:rust_library.bzl", "rust_library")
+load("@rules_rs//rs:rust_test.bzl", "rust_test")
+load("@rules_rust//rust:defs.bzl", "rustfmt_test")
+
+rust_library(
+ name = "openshell-driver-db-credstore",
+ srcs = glob(["src/**/*.rs"]),
+ aliases = aliases(),
+ visibility = ["//visibility:public"],
+ deps = all_crate_deps(normal = True),
+)
+
+rust_test(
+ name = "openshell-driver-db-credstore_test",
+ crate = ":openshell-driver-db-credstore",
+ deps = all_crate_deps(normal_dev = True),
+)
+
+rustfmt_test(
+ name = "rustfmt_test",
+ targets = [
+ ":openshell-driver-db-credstore",
+ ":openshell-driver-db-credstore_test",
+ ],
+ visibility = ["//crates:__pkg__"],
+)
diff --git a/crates/openshell-driver-kubernetes-secrets/BUILD.bazel b/crates/openshell-driver-kubernetes-secrets/BUILD.bazel
new file mode 100644
index 000000000..383932b55
--- /dev/null
+++ b/crates/openshell-driver-kubernetes-secrets/BUILD.bazel
@@ -0,0 +1,41 @@
+load("@crates//:defs.bzl", "aliases", "all_crate_deps")
+load("@rules_rs//rs:rust_binary.bzl", "rust_binary")
+load("@rules_rs//rs:rust_library.bzl", "rust_library")
+load("@rules_rs//rs:rust_test.bzl", "rust_test")
+load("@rules_rust//rust:defs.bzl", "rustfmt_test")
+
+rust_library(
+ name = "openshell-driver-kubernetes-secrets",
+ srcs = glob(
+ ["src/**/*.rs"],
+ exclude = ["src/main.rs"],
+ ),
+ aliases = aliases(),
+ visibility = ["//visibility:public"],
+ deps = all_crate_deps(normal = True),
+)
+
+rust_binary(
+ name = "openshell-driver-kubernetes-secrets_bin",
+ srcs = ["src/main.rs"],
+ aliases = aliases(),
+ binary_name = "openshell-driver-kubernetes-secrets",
+ visibility = ["//visibility:public"],
+ deps = all_crate_deps(normal = True) + [":openshell-driver-kubernetes-secrets"],
+)
+
+rust_test(
+ name = "openshell-driver-kubernetes-secrets_test",
+ crate = ":openshell-driver-kubernetes-secrets",
+ deps = all_crate_deps(normal_dev = True),
+)
+
+rustfmt_test(
+ name = "rustfmt_test",
+ targets = [
+ ":openshell-driver-kubernetes-secrets",
+ ":openshell-driver-kubernetes-secrets_bin",
+ ":openshell-driver-kubernetes-secrets_test",
+ ],
+ visibility = ["//crates:__pkg__"],
+)
diff --git a/crates/openshell-driver-vault/BUILD.bazel b/crates/openshell-driver-vault/BUILD.bazel
new file mode 100644
index 000000000..3743e911b
--- /dev/null
+++ b/crates/openshell-driver-vault/BUILD.bazel
@@ -0,0 +1,41 @@
+load("@crates//:defs.bzl", "aliases", "all_crate_deps")
+load("@rules_rs//rs:rust_binary.bzl", "rust_binary")
+load("@rules_rs//rs:rust_library.bzl", "rust_library")
+load("@rules_rs//rs:rust_test.bzl", "rust_test")
+load("@rules_rust//rust:defs.bzl", "rustfmt_test")
+
+rust_library(
+ name = "openshell-driver-vault",
+ srcs = glob(
+ ["src/**/*.rs"],
+ exclude = ["src/main.rs"],
+ ),
+ aliases = aliases(),
+ visibility = ["//visibility:public"],
+ deps = all_crate_deps(normal = True),
+)
+
+rust_binary(
+ name = "openshell-driver-vault_bin",
+ srcs = ["src/main.rs"],
+ aliases = aliases(),
+ binary_name = "openshell-driver-vault",
+ visibility = ["//visibility:public"],
+ deps = all_crate_deps(normal = True) + [":openshell-driver-vault"],
+)
+
+rust_test(
+ name = "openshell-driver-vault_test",
+ crate = ":openshell-driver-vault",
+ deps = all_crate_deps(normal_dev = True),
+)
+
+rustfmt_test(
+ name = "rustfmt_test",
+ targets = [
+ ":openshell-driver-vault",
+ ":openshell-driver-vault_bin",
+ ":openshell-driver-vault_test",
+ ],
+ visibility = ["//crates:__pkg__"],
+)
diff --git a/crates/openshell-driver-vm/BUILD.bazel b/crates/openshell-driver-vm/BUILD.bazel
new file mode 100644
index 000000000..d433b7842
--- /dev/null
+++ b/crates/openshell-driver-vm/BUILD.bazel
@@ -0,0 +1,74 @@
+load("@crates//:defs.bzl", "aliases", "all_crate_deps")
+load("@rules_rs//rs:rust_binary.bzl", "rust_binary")
+load("@rules_rs//rs:rust_library.bzl", "rust_library")
+load("@rules_rs//rs:rust_test.bzl", "rust_test")
+load("@rules_rust//rust:defs.bzl", "rustfmt_test")
+load("@workspace_version//:version.bzl", "WORKSPACE_VERSION")
+
+VM_RUNTIME = "//bazel/vm-runtime:runtime"
+
+VM_RUNTIME_ENV = {
+ "OUT_DIR": "$(execpath //bazel/vm-runtime:runtime)",
+}
+
+rust_library(
+ name = "openshell-driver-vm",
+ srcs = glob(
+ ["src/**/*.rs"],
+ exclude = ["src/main.rs"],
+ ),
+ aliases = aliases(),
+ compile_data = [
+ "scripts/openshell-vm-sandbox-init.sh",
+ VM_RUNTIME,
+ ],
+ crate_features = ["telemetry"],
+ rustc_env = VM_RUNTIME_ENV,
+ version = WORKSPACE_VERSION,
+ visibility = ["//visibility:public"],
+ deps = all_crate_deps(normal = True),
+)
+
+rust_binary(
+ name = "openshell-driver-vm_bin",
+ srcs = ["src/main.rs"],
+ aliases = aliases(),
+ binary_name = "openshell-driver-vm",
+ version = WORKSPACE_VERSION,
+ visibility = ["//visibility:public"],
+ deps = all_crate_deps(normal = True) + [":openshell-driver-vm"],
+)
+
+rust_test(
+ name = "openshell-driver-vm_lib_test",
+ compile_data = [
+ "scripts/openshell-vm-sandbox-init.sh",
+ VM_RUNTIME,
+ ],
+ crate = ":openshell-driver-vm",
+ crate_features = ["telemetry"],
+ rustc_env = VM_RUNTIME_ENV,
+ deps = all_crate_deps(normal_dev = True),
+)
+
+rust_test(
+ name = "openshell-driver-vm_bin_test",
+ srcs = ["src/main.rs"],
+ aliases = aliases(),
+ version = WORKSPACE_VERSION,
+ deps = all_crate_deps(
+ normal = True,
+ normal_dev = True,
+ ) + [":openshell-driver-vm"],
+)
+
+rustfmt_test(
+ name = "rustfmt_test",
+ targets = [
+ ":openshell-driver-vm",
+ ":openshell-driver-vm_bin",
+ ":openshell-driver-vm_bin_test",
+ ":openshell-driver-vm_lib_test",
+ ],
+ visibility = ["//crates:__pkg__"],
+)
diff --git a/crates/openshell-sandbox/BUILD.bazel b/crates/openshell-sandbox/BUILD.bazel
index 3b4c74b96..dac448831 100644
--- a/crates/openshell-sandbox/BUILD.bazel
+++ b/crates/openshell-sandbox/BUILD.bazel
@@ -12,7 +12,10 @@ rust_library(
exclude = ["src/main.rs"],
),
aliases = aliases(),
- crate_features = ["telemetry"],
+ crate_features = [
+ "bundled-ca-roots",
+ "telemetry",
+ ],
version = WORKSPACE_VERSION,
visibility = ["//visibility:public"],
deps = all_crate_deps(normal = True),
@@ -33,7 +36,10 @@ rust_test(
name = "openshell-sandbox_lib_test",
compile_data = ["//crates/openshell-supervisor-network:sandbox-policy-rego"],
crate = ":openshell-sandbox",
- crate_features = ["telemetry"],
+ crate_features = [
+ "bundled-ca-roots",
+ "telemetry",
+ ],
deps = all_crate_deps(normal_dev = True),
)
diff --git a/crates/openshell-server/Cargo.toml b/crates/openshell-server/Cargo.toml
index 7182d0f70..e158edda4 100644
--- a/crates/openshell-server/Cargo.toml
+++ b/crates/openshell-server/Cargo.toml
@@ -106,7 +106,7 @@ async-trait = "0.1"
url = { workspace = true }
glob = { workspace = true }
hex = "0.4"
-russh = "0.61"
+russh = "0.62"
rand = { workspace = true }
petname = "2"
ipnet = "2"
@@ -128,6 +128,8 @@ test-support = []
[dev-dependencies]
hyper-rustls = { version = "0.27", default-features = false, features = ["native-tokio", "http1", "tls12", "logging", "ring"] }
rcgen = { version = "0.13", features = ["crypto", "pem"] }
+rsa = { version = "0.9", features = ["pem"] }
+base64 = { workspace = true }
tokio-tungstenite = { workspace = true }
futures-util = "0.3"
wiremock = "0.6"
diff --git a/crates/openshell-server/src/auth/oidc.rs b/crates/openshell-server/src/auth/oidc.rs
index cbe83ff06..fd599b501 100644
--- a/crates/openshell-server/src/auth/oidc.rs
+++ b/crates/openshell-server/src/auth/oidc.rs
@@ -510,4 +510,256 @@ mod tests {
let scopes = claims.extract_scopes("scope");
assert!(scopes.is_empty());
}
+
+ // -----------------------------------------------------------------------
+ // RS256 verification through the real JWKS path
+ //
+ // The tests above only cover claim extraction from an already-trusted
+ // payload. These sign real RS256 tokens and push them through
+ // `JwksCache::new` + `validate_token`, so the JWKS `n`/`e` decoding and the
+ // RSA signature check are exercised against whichever crypto backend
+ // `jsonwebtoken` is built with — a backend swap is otherwise invisible to
+ // the test suite.
+ // -----------------------------------------------------------------------
+
+ const TEST_KID: &str = "test-signing-key";
+ const TEST_AUDIENCE: &str = "openshell-cli";
+
+ /// One RSA key per test binary. Key generation dominates the runtime of
+ /// these tests and the key carries no meaning beyond being valid.
+ static TEST_RSA_KEY: std::sync::LazyLock =
+ std::sync::LazyLock::new(TestRsaKey::generate);
+
+ struct TestRsaKey {
+ private_pem: String,
+ modulus_b64: String,
+ exponent_b64: String,
+ }
+
+ impl TestRsaKey {
+ fn generate() -> Self {
+ use base64::Engine as _;
+ use rsa::pkcs1::EncodeRsaPrivateKey as _;
+ use rsa::traits::PublicKeyParts as _;
+
+ let private = rsa::RsaPrivateKey::new(&mut rsa::rand_core::OsRng, 2048)
+ .expect("generate RSA test key");
+ let b64 = base64::engine::general_purpose::URL_SAFE_NO_PAD;
+ Self {
+ private_pem: private
+ .to_pkcs1_pem(rsa::pkcs1::LineEnding::LF)
+ .expect("encode RSA private key as PEM")
+ .to_string(),
+ modulus_b64: b64.encode(private.n().to_bytes_be()),
+ exponent_b64: b64.encode(private.e().to_bytes_be()),
+ }
+ }
+ }
+
+ fn now_secs() -> i64 {
+ i64::try_from(
+ std::time::SystemTime::now()
+ .duration_since(std::time::UNIX_EPOCH)
+ .expect("system clock is after the unix epoch")
+ .as_secs(),
+ )
+ .expect("current time fits in i64")
+ }
+
+ /// Sign `claims` with the test key, tagging the header with `kid`.
+ fn mint_rs256(claims: &serde_json::Value, kid: &str) -> String {
+ let mut header = jsonwebtoken::Header::new(Algorithm::RS256);
+ header.kid = Some(kid.to_owned());
+ let key = jsonwebtoken::EncodingKey::from_rsa_pem(TEST_RSA_KEY.private_pem.as_bytes())
+ .expect("load RSA signing key");
+ jsonwebtoken::encode(&header, claims, &key).expect("sign RS256 token")
+ }
+
+ fn claims_for(issuer: &str, audience: &str, exp: i64) -> serde_json::Value {
+ serde_json::json!({
+ "sub": "user-42",
+ "preferred_username": "ada",
+ "iss": issuer,
+ "aud": audience,
+ "exp": exp,
+ "scope": "openid profile sandbox:write",
+ "realm_access": { "roles": ["openshell-user"] },
+ })
+ }
+
+ /// Serve an OIDC discovery document and a JWKS carrying the test key, then
+ /// build a cache against them the same way production does.
+ async fn cache_with_mock_issuer(server: &wiremock::MockServer) -> JwksCache {
+ use wiremock::matchers::{method, path};
+ use wiremock::{Mock, ResponseTemplate};
+
+ let issuer = server.uri();
+ Mock::given(method("GET"))
+ .and(path("/.well-known/openid-configuration"))
+ .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
+ "issuer": issuer,
+ "jwks_uri": format!("{issuer}/jwks"),
+ })))
+ .mount(server)
+ .await;
+ Mock::given(method("GET"))
+ .and(path("/jwks"))
+ .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
+ "keys": [{
+ "kid": TEST_KID,
+ "kty": "RSA",
+ "n": TEST_RSA_KEY.modulus_b64,
+ "e": TEST_RSA_KEY.exponent_b64,
+ }],
+ })))
+ .mount(server)
+ .await;
+
+ JwksCache::new(&OidcConfig {
+ issuer,
+ audience: TEST_AUDIENCE.to_owned(),
+ jwks_ttl_secs: 3600,
+ roles_claim: "realm_access.roles".to_owned(),
+ admin_role: "openshell-admin".to_owned(),
+ user_role: "openshell-user".to_owned(),
+ scopes_claim: "scope".to_owned(),
+ })
+ .await
+ .expect("cache should build from the mock issuer")
+ }
+
+ #[tokio::test]
+ async fn rs256_token_signed_by_jwks_key_is_accepted() {
+ let server = wiremock::MockServer::start().await;
+ let cache = cache_with_mock_issuer(&server).await;
+
+ let token = mint_rs256(
+ &claims_for(&server.uri(), TEST_AUDIENCE, now_secs() + 3600),
+ TEST_KID,
+ );
+ let identity = cache
+ .validate_token(&token)
+ .await
+ .expect("a correctly signed token must be accepted");
+
+ assert_eq!(identity.subject, "user-42");
+ assert_eq!(identity.display_name.as_deref(), Some("ada"));
+ assert_eq!(identity.roles, vec!["openshell-user".to_owned()]);
+ assert_eq!(identity.scopes, vec!["sandbox:write".to_owned()]);
+ assert_eq!(identity.provider, IdentityProvider::Oidc);
+ }
+
+ #[tokio::test]
+ async fn rs256_token_with_tampered_payload_is_rejected() {
+ let server = wiremock::MockServer::start().await;
+ let cache = cache_with_mock_issuer(&server).await;
+
+ let exp = now_secs() + 3600;
+ let token = mint_rs256(&claims_for(&server.uri(), TEST_AUDIENCE, exp), TEST_KID);
+
+ // Keep the header and signature but swap in a payload that escalates
+ // the subject: only the RSA check stands between this and an identity.
+ let segments: Vec<&str> = token.split('.').collect();
+ assert_eq!(segments.len(), 3, "a JWT has three segments");
+ let mut forged_claims = claims_for(&server.uri(), TEST_AUDIENCE, exp);
+ forged_claims["sub"] = serde_json::json!("root");
+ let forged_payload = {
+ use base64::Engine as _;
+ base64::engine::general_purpose::URL_SAFE_NO_PAD
+ .encode(serde_json::to_vec(&forged_claims).expect("serialize forged claims"))
+ };
+ let forged = format!("{}.{forged_payload}.{}", segments[0], segments[2]);
+
+ cache
+ .validate_token(&forged)
+ .await
+ .expect_err("a swapped payload must fail the signature check");
+ }
+
+ #[tokio::test]
+ async fn rs256_token_signed_by_unrelated_key_is_rejected() {
+ let server = wiremock::MockServer::start().await;
+ let cache = cache_with_mock_issuer(&server).await;
+
+ let other = TestRsaKey::generate();
+ let mut header = jsonwebtoken::Header::new(Algorithm::RS256);
+ header.kid = Some(TEST_KID.to_owned());
+ let token = jsonwebtoken::encode(
+ &header,
+ &claims_for(&server.uri(), TEST_AUDIENCE, now_secs() + 3600),
+ &jsonwebtoken::EncodingKey::from_rsa_pem(other.private_pem.as_bytes())
+ .expect("load unrelated signing key"),
+ )
+ .expect("sign with unrelated key");
+
+ cache
+ .validate_token(&token)
+ .await
+ .expect_err("a token signed by a key outside the JWKS must be rejected");
+ }
+
+ #[tokio::test]
+ async fn rs256_expired_token_is_rejected() {
+ let server = wiremock::MockServer::start().await;
+ let cache = cache_with_mock_issuer(&server).await;
+
+ // Beyond the 60s default leeway.
+ let token = mint_rs256(
+ &claims_for(&server.uri(), TEST_AUDIENCE, now_secs() - 3600),
+ TEST_KID,
+ );
+
+ cache
+ .validate_token(&token)
+ .await
+ .expect_err("an expired token must be rejected");
+ }
+
+ #[tokio::test]
+ async fn rs256_token_from_other_issuer_is_rejected() {
+ let server = wiremock::MockServer::start().await;
+ let cache = cache_with_mock_issuer(&server).await;
+
+ let token = mint_rs256(
+ &claims_for("https://evil.example.com", TEST_AUDIENCE, now_secs() + 3600),
+ TEST_KID,
+ );
+
+ cache
+ .validate_token(&token)
+ .await
+ .expect_err("a token from another issuer must be rejected");
+ }
+
+ #[tokio::test]
+ async fn rs256_token_for_other_audience_is_rejected() {
+ let server = wiremock::MockServer::start().await;
+ let cache = cache_with_mock_issuer(&server).await;
+
+ let token = mint_rs256(
+ &claims_for(&server.uri(), "some-other-client", now_secs() + 3600),
+ TEST_KID,
+ );
+
+ cache
+ .validate_token(&token)
+ .await
+ .expect_err("a token minted for another audience must be rejected");
+ }
+
+ #[tokio::test]
+ async fn rs256_token_with_unknown_kid_is_rejected() {
+ let server = wiremock::MockServer::start().await;
+ let cache = cache_with_mock_issuer(&server).await;
+
+ let token = mint_rs256(
+ &claims_for(&server.uri(), TEST_AUDIENCE, now_secs() + 3600),
+ "rotated-away-key",
+ );
+
+ cache
+ .validate_token(&token)
+ .await
+ .expect_err("a token naming a kid absent from the JWKS must be rejected");
+ }
}
diff --git a/crates/openshell-supervisor-middleware/src/remote.rs b/crates/openshell-supervisor-middleware/src/remote.rs
index 378dac3ec..30ea5a74b 100644
--- a/crates/openshell-supervisor-middleware/src/remote.rs
+++ b/crates/openshell-supervisor-middleware/src/remote.rs
@@ -16,6 +16,8 @@ use tonic::{Request, Response, Status};
use crate::MIDDLEWARE_GRPC_MESSAGE_BYTES;
const CONNECT_TIMEOUT: Duration = Duration::from_secs(5);
+const HTTP2_KEEP_ALIVE_INTERVAL: Duration = Duration::from_secs(10);
+const HTTP2_KEEP_ALIVE_TIMEOUT: Duration = Duration::from_secs(20);
#[derive(Clone)]
pub struct RemoteMiddlewareService {
@@ -30,7 +32,12 @@ impl RemoteMiddlewareService {
format!(
"middleware registration '{registration_name}' has an invalid grpc_endpoint"
)
- })?;
+ })?
+ .http2_keep_alive_interval(HTTP2_KEEP_ALIVE_INTERVAL)
+ .keep_alive_while_idle(true)
+ .keep_alive_timeout(HTTP2_KEEP_ALIVE_TIMEOUT)
+ .http2_adaptive_window(true);
+
if grpc_endpoint.starts_with("https://") {
endpoint = endpoint
.tls_config(ClientTlsConfig::new().with_enabled_roots())
@@ -39,6 +46,7 @@ impl RemoteMiddlewareService {
format!("middleware registration '{registration_name}' could not configure TLS")
})?;
}
+
let channel = endpoint
.connect_timeout(CONNECT_TIMEOUT)
.connect()
@@ -49,6 +57,7 @@ impl RemoteMiddlewareService {
"middleware registration '{registration_name}' could not connect to {grpc_endpoint}"
)
})?;
+
Ok(Self {
client: SupervisorMiddlewareClient::new(channel)
.max_decoding_message_size(MIDDLEWARE_GRPC_MESSAGE_BYTES)
diff --git a/crates/openshell-supervisor-network/BUILD.bazel b/crates/openshell-supervisor-network/BUILD.bazel
index fe3673a6b..851b71958 100644
--- a/crates/openshell-supervisor-network/BUILD.bazel
+++ b/crates/openshell-supervisor-network/BUILD.bazel
@@ -14,6 +14,7 @@ rust_library(
srcs = glob(["src/**/*.rs"]),
aliases = aliases(),
compile_data = glob(["data/**/*"]),
+ crate_features = ["bundled-ca-roots"],
visibility = ["//visibility:public"],
deps = all_crate_deps(normal = True),
)
@@ -22,6 +23,7 @@ rust_test(
name = "openshell-supervisor-network_test",
compile_data = glob(["testdata/**/*"]),
crate = ":openshell-supervisor-network",
+ crate_features = ["bundled-ca-roots"],
deps = all_crate_deps(normal_dev = True),
)
diff --git a/crates/openshell-supervisor-process/Cargo.toml b/crates/openshell-supervisor-process/Cargo.toml
index 575923d4c..7b9188758 100644
--- a/crates/openshell-supervisor-process/Cargo.toml
+++ b/crates/openshell-supervisor-process/Cargo.toml
@@ -21,7 +21,7 @@ hex = "0.4"
miette = { workspace = true }
nix = { workspace = true }
rand = "0.10"
-russh = "0.61"
+russh = "0.62"
serde_json = { workspace = true }
sha2 = { workspace = true }
tokio = { workspace = true }
diff --git a/crates/openshell-supervisor-process/src/ssh.rs b/crates/openshell-supervisor-process/src/ssh.rs
index 127fc4944..0649cff97 100644
--- a/crates/openshell-supervisor-process/src/ssh.rs
+++ b/crates/openshell-supervisor-process/src/ssh.rs
@@ -20,9 +20,9 @@ use openshell_core::provider_credentials::ProviderCredentialState;
use openshell_ocsf::{
ActionId, ActivityId, DispositionId, SeverityId, SshActivityBuilder, StatusId, ocsf_emit,
};
-use russh::ChannelId;
use russh::keys::{Algorithm, PrivateKey};
-use russh::server::{Auth, Handle, Session};
+use russh::server::{Auth, ChannelOpenHandle, Handle, Session};
+use russh::{ChannelId, ChannelOpenFailure};
use std::collections::HashMap;
use std::io::{Read, Write};
use std::os::fd::{AsRawFd, RawFd};
@@ -297,10 +297,12 @@ impl russh::server::Handler for SshHandler {
async fn channel_open_session(
&mut self,
channel: russh::Channel,
+ reply: ChannelOpenHandle,
_session: &mut Session,
- ) -> Result {
+ ) -> Result<(), Self::Error> {
self.channels.insert(channel.id(), ChannelState::default());
- Ok(true)
+ reply.accept().await;
+ Ok(())
}
/// Clean up per-channel state when the channel is closed.
@@ -324,8 +326,9 @@ impl russh::server::Handler for SshHandler {
port_to_connect: u32,
_originator_address: &str,
_originator_port: u32,
+ reply: ChannelOpenHandle,
_session: &mut Session,
- ) -> Result {
+ ) -> Result<(), Self::Error> {
// Validate port range before truncating u32 -> u16. The SSH protocol
// uses u32 for ports, but valid TCP ports are 0-65535. Without this
// check, port 65537 truncates to port 1 (privileged).
@@ -339,7 +342,10 @@ impl russh::server::Handler for SshHandler {
"direct-tcpip rejected: port {port_to_connect} exceeds valid TCP range for host {host_to_connect}"
))
.build());
- return Ok(false);
+ reply
+ .reject(ChannelOpenFailure::AdministrativelyProhibited)
+ .await;
+ return Ok(());
}
// Only allow forwarding to loopback destinations to prevent the
@@ -354,7 +360,10 @@ impl russh::server::Handler for SshHandler {
"direct-tcpip rejected: non-loopback destination {host_to_connect}:{port_to_connect}"
))
.build());
- return Ok(false);
+ reply
+ .reject(ChannelOpenFailure::AdministrativelyProhibited)
+ .await;
+ return Ok(());
}
let host = host_to_connect.to_string();
@@ -363,6 +372,10 @@ impl russh::server::Handler for SshHandler {
let port = u16::try_from(port_to_connect).unwrap_or(u16::MAX);
let netns_fd = self.netns_fd;
+ // Confirm the channel before spawning: the task below writes to it, and
+ // the peer must see the open-confirmation first.
+ reply.accept().await;
+
tokio::spawn(async move {
let addr = format!("{host}:{port}");
let tcp = match connect_in_netns(&addr, netns_fd).await {
@@ -387,7 +400,7 @@ impl russh::server::Handler for SshHandler {
let _ = tokio::io::copy_bidirectional(&mut channel_stream, &mut tcp_stream).await;
});
- Ok(true)
+ Ok(())
}
async fn pty_request(
@@ -1951,4 +1964,178 @@ mod tests {
"resolved-identity-ok"
);
}
+
+ // -----------------------------------------------------------------------
+ // direct-tcpip authorization wiring (SEC-007)
+ //
+ // The `loopback_host_*` tests above cover the predicate in isolation.
+ // These drive the real `russh::server::Handler` over an in-memory duplex
+ // so the deny path itself is covered: channel-open authorization travels
+ // through a reply handle rather than the handler's return value, so a
+ // handler that never rejects anything still type-checks and still passes
+ // every predicate test.
+ // -----------------------------------------------------------------------
+
+ struct AcceptAnyServerKey;
+
+ impl russh::client::Handler for AcceptAnyServerKey {
+ type Error = russh::Error;
+
+ async fn check_server_key(
+ &mut self,
+ _server_public_key: &russh::keys::PublicKey,
+ ) -> Result {
+ Ok(true)
+ }
+ }
+
+ fn forwarding_test_policy() -> SandboxPolicy {
+ use openshell_core::policy::{
+ FilesystemPolicy, LandlockPolicy, NetworkPolicy, ProcessPolicy,
+ };
+
+ SandboxPolicy {
+ version: 0,
+ filesystem: FilesystemPolicy::default(),
+ network: NetworkPolicy::default(),
+ landlock: LandlockPolicy::default(),
+ process: ProcessPolicy {
+ run_as_user: None,
+ run_as_group: None,
+ },
+ }
+ }
+
+ /// Serve `SshHandler` on one end of an in-memory duplex and return an
+ /// authenticated client handle for the other end.
+ ///
+ /// The handler gets `netns_fd: None` so `connect_in_netns` performs a plain
+ /// TCP connect, making the forwarding path reachable without a network
+ /// namespace.
+ async fn authenticated_test_client() -> russh::client::Handle {
+ // Scoped so the `!Send` ThreadRng is dropped before the first await.
+ let host_key = {
+ let mut rng = rand::rng();
+ PrivateKey::random(&mut rng, Algorithm::Ed25519).expect("host key")
+ };
+ let mut server_config = russh::server::Config {
+ auth_rejection_time: Duration::from_millis(1),
+ ..Default::default()
+ };
+ server_config.keys.push(host_key);
+
+ let handler = SshHandler::new(
+ forwarding_test_policy(),
+ ResolvedWorkspace::default(),
+ None,
+ None,
+ None,
+ ProviderCredentialState::from_child_env_snapshot(0, HashMap::new()),
+ HashMap::new(),
+ ResolvedProcessIdentity::default(),
+ ProcessEnforcementMode::NetworkOnly,
+ );
+
+ let (server_stream, client_stream) = tokio::io::duplex(64 * 1024);
+ tokio::spawn(async move {
+ if let Ok(session) =
+ russh::server::run_stream(Arc::new(server_config), server_stream, handler).await
+ {
+ let _ = session.await;
+ }
+ });
+
+ let mut client = russh::client::connect_stream(
+ Arc::new(russh::client::Config::default()),
+ client_stream,
+ AcceptAnyServerKey,
+ )
+ .await
+ .expect("SSH handshake should complete over the duplex");
+
+ let auth = client
+ .authenticate_none("sandbox")
+ .await
+ .expect("auth_none should not error");
+ assert!(
+ matches!(auth, russh::client::AuthResult::Success),
+ "sandbox SSH server accepts the none auth method"
+ );
+
+ client
+ }
+
+ #[tokio::test]
+ async fn direct_tcpip_rejects_non_loopback_destination() {
+ let client = authenticated_test_client().await;
+
+ let err = client
+ .channel_open_direct_tcpip("10.0.0.1", 80, "127.0.0.1", 0)
+ .await
+ .expect_err("forwarding to a non-loopback host must be refused");
+
+ assert!(
+ matches!(
+ err,
+ russh::Error::ChannelOpenFailure(ChannelOpenFailure::AdministrativelyProhibited)
+ ),
+ "expected AdministrativelyProhibited, got {err:?}"
+ );
+ }
+
+ #[tokio::test]
+ async fn direct_tcpip_rejects_port_above_tcp_range() {
+ let client = authenticated_test_client().await;
+
+ // 65_537 truncates to port 1 when cast to u16, so the guard has to
+ // reject it before the cast rather than forward to a privileged port.
+ let err = client
+ .channel_open_direct_tcpip("127.0.0.1", 65_537, "127.0.0.1", 0)
+ .await
+ .expect_err("a port outside the TCP range must be refused");
+
+ assert!(
+ matches!(
+ err,
+ russh::Error::ChannelOpenFailure(ChannelOpenFailure::AdministrativelyProhibited)
+ ),
+ "expected AdministrativelyProhibited, got {err:?}"
+ );
+ }
+
+ #[tokio::test]
+ async fn direct_tcpip_forwards_to_loopback_listener() {
+ use tokio::io::{AsyncReadExt, AsyncWriteExt};
+
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:0")
+ .await
+ .expect("bind loopback echo listener");
+ let port = listener.local_addr().expect("listener address").port();
+ tokio::spawn(async move {
+ if let Ok((mut socket, _)) = listener.accept().await {
+ let mut buf = [0u8; 64];
+ if let Ok(n) = socket.read(&mut buf).await
+ && n > 0
+ {
+ let _ = socket.write_all(&buf[..n]).await;
+ }
+ }
+ });
+
+ let client = authenticated_test_client().await;
+ let channel = client
+ .channel_open_direct_tcpip("127.0.0.1", u32::from(port), "127.0.0.1", 0)
+ .await
+ .expect("forwarding to a loopback listener must be allowed");
+
+ let mut stream = channel.into_stream();
+ stream.write_all(b"ping").await.expect("write to channel");
+
+ let mut echoed = [0u8; 4];
+ tokio::time::timeout(Duration::from_secs(10), stream.read_exact(&mut echoed))
+ .await
+ .expect("relayed response should arrive before the timeout")
+ .expect("read from channel");
+ assert_eq!(&echoed, b"ping", "bytes round-trip through the tunnel");
+ }
}
diff --git a/crates/openshell-vfio/BUILD.bazel b/crates/openshell-vfio/BUILD.bazel
index 1e08c0bb9..0ec5f0679 100644
--- a/crates/openshell-vfio/BUILD.bazel
+++ b/crates/openshell-vfio/BUILD.bazel
@@ -9,6 +9,7 @@ rust_library(
srcs = glob(["src/**/*.rs"]),
aliases = aliases(),
target_compatible_with = ["@platforms//os:linux"],
+ visibility = ["//visibility:public"],
deps = all_crate_deps(normal = True),
)
diff --git a/docs/brand/assets/openshell-banner-dark.png b/docs/brand/assets/openshell-banner-dark.png
new file mode 100644
index 000000000..6c7d11f6e
Binary files /dev/null and b/docs/brand/assets/openshell-banner-dark.png differ
diff --git a/docs/brand/assets/openshell-banner-light.png b/docs/brand/assets/openshell-banner-light.png
new file mode 100644
index 000000000..c2a951a7d
Binary files /dev/null and b/docs/brand/assets/openshell-banner-light.png differ
diff --git a/docs/reference/sandbox-compute-drivers.mdx b/docs/reference/sandbox-compute-drivers.mdx
index 17e13d2cf..a8a9d164a 100644
--- a/docs/reference/sandbox-compute-drivers.mdx
+++ b/docs/reference/sandbox-compute-drivers.mdx
@@ -114,8 +114,10 @@ reflection, inference-route management, and HTTP requests. A
is expected for those requests. The gateway fails startup if a callback
requirement resolves to the exact primary listener address because one socket
cannot preserve both authorization scopes. For the IPv4-loopback callback used
-by Podman Machine, bind the primary listener to a distinct address such as
-`[::1]:17670`.
+by Podman Machine, set `bind_address = "[::1]:17670"` for the primary listener
+and register `https://localhost:17670` as the CLI endpoint. The hostname matches
+the generated certificate and avoids the TLS transport error produced by a raw
+IPv6-literal endpoint. Do not broaden the primary listener to `0.0.0.0`.
## Docker Driver
diff --git a/e2e/with-podman-gateway.sh b/e2e/with-podman-gateway.sh
index 8c598c88f..cd52e007a 100755
--- a/e2e/with-podman-gateway.sh
+++ b/e2e/with-podman-gateway.sh
@@ -386,6 +386,16 @@ export OPENSHELL_E2E_GATEWAY_CA_CERT="${PKI_DIR}/ca.crt"
HOST_PORT=$(e2e_pick_port)
HEALTH_PORT=$(e2e_pick_port)
+if [ "$(uname -s)" = "Darwin" ]; then
+ # Podman Machine reserves IPv4 loopback for its callback-only listener.
+ PRIMARY_BIND_IP="::1"
+ CLI_ENDPOINT_HOST="localhost"
+ HEALTH_ENDPOINT_HOST="[::1]"
+else
+ PRIMARY_BIND_IP="127.0.0.1"
+ CLI_ENDPOINT_HOST="127.0.0.1"
+ HEALTH_ENDPOINT_HOST="127.0.0.1"
+fi
STATE_DIR="${WORKDIR}/state"
mkdir -p "${STATE_DIR}"
export XDG_STATE_HOME="${STATE_DIR}"
@@ -415,11 +425,11 @@ toml_string() {
GATEWAY_CONFIG="${STATE_DIR}/gateway.toml"
-# Start from the RPM default template so this e2e test exercises the same
-# TOML config path that RPM users get on first start. The template leaves
-# bind_address unset and sets compute_drivers = ["podman"], so this test
-# exercises the built-in loopback listener plus the callback listener
-# requested by the Podman driver.
+# Start from the RPM default template so this e2e test exercises the same TOML
+# config path that RPM users get on first start. The template leaves
+# bind_address unset and sets compute_drivers = ["podman"]. On Podman Machine,
+# the driver reserves IPv4 loopback for its callback-only listener, so the
+# primary listener uses IPv6 loopback. Native Linux keeps the IPv4 default.
#
# We append the driver-specific table and override the port via CLI flag
# (CLI > TOML in the merge precedence) so the test can use an ephemeral port.
@@ -458,8 +468,9 @@ cp "${ROOT}/deploy/rpm/gateway.toml.default" "${GATEWAY_CONFIG}"
GATEWAY_ARGS=(
--config "${GATEWAY_CONFIG}"
- # compute_drivers comes from the RPM template, while bind_address uses the
- # built-in loopback default. Override only the port for ephemeral selection.
+ # compute_drivers comes from the RPM template. Override the loopback address
+ # and port so Podman Machine can keep its IPv4 callback listener distinct.
+ --bind-address "${PRIMARY_BIND_IP}"
--port "${HOST_PORT}"
--health-port "${HEALTH_PORT}"
--tls-cert "${PKI_DIR}/server/tls.crt"
@@ -495,10 +506,10 @@ printf '%s\n' "${GATEWAY_PID}" >"${GATEWAY_PID_FILE}"
GATEWAY_NAME="openshell-e2e-podman-${HOST_PORT}"
if [ "${OIDC_MODE}" = "1" ]; then
- CLI_GATEWAY_ENDPOINT="https://127.0.0.1:${HOST_PORT}"
+ CLI_GATEWAY_ENDPOINT="https://${CLI_ENDPOINT_HOST}:${HOST_PORT}"
export OPENSHELL_E2E_OIDC_GATEWAY_ENDPOINT="${CLI_GATEWAY_ENDPOINT}"
else
- CLI_GATEWAY_ENDPOINT="https://127.0.0.1:${HOST_PORT}"
+ CLI_GATEWAY_ENDPOINT="https://${CLI_ENDPOINT_HOST}:${HOST_PORT}"
e2e_register_mtls_gateway \
"${XDG_CONFIG_HOME}" \
"${GATEWAY_NAME}" \
@@ -524,7 +535,8 @@ while [ "${elapsed}" -lt "${timeout}" ]; do
echo "ERROR: openshell-gateway exited before becoming healthy"
exit 1
fi
- if curl -sf "http://127.0.0.1:${HEALTH_PORT}/healthz" >/dev/null 2>&1; then
+ # Keep this loopback probe direct even when ::1 is absent from NO_PROXY.
+ if curl --noproxy '*' -sf "http://${HEALTH_ENDPOINT_HOST}:${HEALTH_PORT}/healthz" >/dev/null 2>&1; then
echo "Gateway healthy after ${elapsed}s."
break
fi
diff --git a/mise.lock b/mise.lock
index 5dc2cc25f..74067b6cf 100644
--- a/mise.lock
+++ b/mise.lock
@@ -1,5 +1,27 @@
# @generated - this file is auto-generated by `mise lock` https://mise.en.dev/dev-tools/mise-lock.html
+[[tools.buf]]
+version = "1.72.0"
+backend = "aqua:bufbuild/buf"
+
+[tools.buf."platforms.linux-arm64"]
+checksum = "sha256:7641bd7e06a37a54cbb8c789f53465899def96196ab5c08057432f781a15d517"
+url = "https://github.com/bufbuild/buf/releases/download/v1.72.0/buf-Linux-aarch64.tar.gz"
+url_api = "https://api.github.com/repos/bufbuild/buf/releases/assets/480772526"
+provenance = "minisign"
+
+[tools.buf."platforms.linux-x64"]
+checksum = "sha256:a9c6186cf6fcf062b247345e1b7b12c26f580c1b2a4bbf4d3fe080abf85ceee8"
+url = "https://github.com/bufbuild/buf/releases/download/v1.72.0/buf-Linux-x86_64.tar.gz"
+url_api = "https://api.github.com/repos/bufbuild/buf/releases/assets/480772583"
+provenance = "minisign"
+
+[tools.buf."platforms.macos-arm64"]
+checksum = "sha256:be040ae0ca381103dfda68a36738695c4db3e48de8e91412acdc3d991f39b91e"
+url = "https://github.com/bufbuild/buf/releases/download/v1.72.0/buf-Darwin-arm64.tar.gz"
+url_api = "https://api.github.com/repos/bufbuild/buf/releases/assets/480772487"
+provenance = "minisign"
+
[[tools."github:EmbarkStudios/cargo-about"]]
version = "0.8.4"
backend = "github:EmbarkStudios/cargo-about"
@@ -104,6 +126,38 @@ checksum = "sha256:29caf036bdbb4e6f07afea31706b6f386cb5a4db9a46a3a8b462b9b78157e
url = "https://github.com/rust-cross/cargo-zigbuild/releases/download/v0.22.3/cargo-zigbuild-aarch64-apple-darwin.tar.xz"
url_api = "https://api.github.com/repos/rust-cross/cargo-zigbuild/releases/assets/405676922"
+[[tools.go]]
+version = "1.26.5"
+backend = "core:go"
+
+[tools.go."platforms.linux-arm64"]
+checksum = "sha256:fe4789e92b1f33358680864bbe8704289e7bb5fc207d80623c308935bd696d49"
+url = "https://dl.google.com/go/go1.26.5.linux-arm64.tar.gz"
+
+[tools.go."platforms.linux-x64"]
+checksum = "sha256:5c2c3b16caefa1d968a94c1daca04a7ca301a496d9b086e17ad77bb81393f053"
+url = "https://dl.google.com/go/go1.26.5.linux-amd64.tar.gz"
+
+[tools.go."platforms.macos-arm64"]
+checksum = "sha256:efb87ff28af9a188d0536ef5d42e63dd52ba8263cd7344a993cc48dd11dedb6a"
+url = "https://dl.google.com/go/go1.26.5.darwin-arm64.tar.gz"
+
+[[tools."go:github.com/golangci/golangci-lint/v2/cmd/golangci-lint"]]
+version = "2.12.2"
+backend = "go:github.com/golangci/golangci-lint/v2/cmd/golangci-lint"
+
+[[tools."go:golang.org/x/tools/cmd/goimports"]]
+version = "0.48.0"
+backend = "go:golang.org/x/tools/cmd/goimports"
+
+[[tools."go:google.golang.org/grpc/cmd/protoc-gen-go-grpc"]]
+version = "1.6.2"
+backend = "go:google.golang.org/grpc/cmd/protoc-gen-go-grpc"
+
+[[tools."go:google.golang.org/protobuf/cmd/protoc-gen-go"]]
+version = "1.36.11"
+backend = "go:google.golang.org/protobuf/cmd/protoc-gen-go"
+
[[tools.helm]]
version = "4.2.0"
backend = "aqua:helm/helm"
@@ -127,14 +181,17 @@ backend = "aqua:norwoodj/helm-docs"
[tools.helm-docs."platforms.linux-arm64"]
checksum = "sha256:c3787212332386dcd122debef7848feb165aa701467ae3e3442df7638f3ac4e4"
url = "https://github.com/norwoodj/helm-docs/releases/download/v1.14.2/helm-docs_1.14.2_Linux_arm64.tar.gz"
+url_api = "https://api.github.com/repos/norwoodj/helm-docs/releases/assets/178327216"
[tools.helm-docs."platforms.linux-x64"]
checksum = "sha256:a8cf72ada34fad93285ba2a452b38bdc5bd52cc9a571236244ec31022928d6cc"
url = "https://github.com/norwoodj/helm-docs/releases/download/v1.14.2/helm-docs_1.14.2_Linux_x86_64.tar.gz"
+url_api = "https://api.github.com/repos/norwoodj/helm-docs/releases/assets/178327210"
[tools.helm-docs."platforms.macos-arm64"]
checksum = "sha256:2d8399db5b33d240d5f8985241bcf5483563150b968e3229823822979f3e4b8b"
url = "https://github.com/norwoodj/helm-docs/releases/download/v1.14.2/helm-docs_1.14.2_Darwin_arm64.tar.gz"
+url_api = "https://api.github.com/repos/norwoodj/helm-docs/releases/assets/178327215"
[[tools.k3d]]
version = "5.8.3"
@@ -143,14 +200,17 @@ backend = "aqua:k3d-io/k3d"
[tools.k3d."platforms.linux-arm64"]
checksum = "sha256:0b8110f2229631af7402fb828259330985918b08fefd38b7f1b788a1c8687216"
url = "https://github.com/k3d-io/k3d/releases/download/v5.8.3/k3d-linux-arm64"
+url_api = "https://api.github.com/repos/k3d-io/k3d/releases/assets/229450023"
[tools.k3d."platforms.linux-x64"]
checksum = "sha256:dbaa79a76ace7f4ca230a1ff41dc7d8a5036a8ad0309e9c54f9bf3836dbe853e"
url = "https://github.com/k3d-io/k3d/releases/download/v5.8.3/k3d-linux-amd64"
+url_api = "https://api.github.com/repos/k3d-io/k3d/releases/assets/229450045"
[tools.k3d."platforms.macos-arm64"]
checksum = "sha256:8da468daa7dc7cf7cdd4735f90a9bb05179fa27858250f62e3d8cdf5b5ca0698"
url = "https://github.com/k3d-io/k3d/releases/download/v5.8.3/k3d-darwin-arm64"
+url_api = "https://api.github.com/repos/k3d-io/k3d/releases/assets/229450067"
[[tools.kubectl]]
version = "1.36.1"
@@ -195,14 +255,17 @@ backend = "aqua:protocolbuffers/protobuf/protoc"
[tools.protoc."platforms.linux-arm64"]
checksum = "sha256:2594ff4fcae8cb57310d394d0961b236190ad9c5efbfdf1f597ea471d424fe79"
url = "https://github.com/protocolbuffers/protobuf/releases/download/v29.6/protoc-29.6-linux-aarch_64.zip"
+url_api = "https://api.github.com/repos/protocolbuffers/protobuf/releases/assets/350795076"
[tools.protoc."platforms.linux-x64"]
checksum = "sha256:48785a926e73ffa3f68e2f22b14e7b849620c7a1d36809ac9249a5495e280323"
url = "https://github.com/protocolbuffers/protobuf/releases/download/v29.6/protoc-29.6-linux-x86_64.zip"
+url_api = "https://api.github.com/repos/protocolbuffers/protobuf/releases/assets/350795083"
[tools.protoc."platforms.macos-arm64"]
checksum = "sha256:b9576b5fa1a1ef3fe13a8c91d9d8204b46545759bea5ae155cd6ba2ea4cdaeed"
url = "https://github.com/protocolbuffers/protobuf/releases/download/v29.6/protoc-29.6-osx-aarch_64.zip"
+url_api = "https://api.github.com/repos/protocolbuffers/protobuf/releases/assets/350795082"
[[tools.python]]
version = "3.14.5"
@@ -251,16 +314,19 @@ backend = "aqua:astral-sh/uv"
[tools.uv."platforms.linux-arm64"]
checksum = "sha256:55bd1c1c10ec8b95a8c184f5e18b566703c6ab105f0fc118aaa4d748aabf28e4"
url = "https://github.com/astral-sh/uv/releases/download/0.10.12/uv-aarch64-unknown-linux-musl.tar.gz"
+url_api = "https://api.github.com/repos/astral-sh/uv/releases/assets/377491942"
provenance = "github-attestations"
[tools.uv."platforms.linux-x64"]
checksum = "sha256:adccf40b5d1939a5e0093081ec2307ea24235adf7c2d96b122c561fa37711c46"
url = "https://github.com/astral-sh/uv/releases/download/0.10.12/uv-x86_64-unknown-linux-musl.tar.gz"
+url_api = "https://api.github.com/repos/astral-sh/uv/releases/assets/377491998"
provenance = "github-attestations"
[tools.uv."platforms.macos-arm64"]
checksum = "sha256:ae738b5661a900579ec621d3918c0ef17bdec0da2a8a6d8b161137cd15f25414"
url = "https://github.com/astral-sh/uv/releases/download/0.10.12/uv-aarch64-apple-darwin.tar.gz"
+url_api = "https://api.github.com/repos/astral-sh/uv/releases/assets/377491929"
provenance = "github-attestations"
[[tools.zig]]
diff --git a/mise.toml b/mise.toml
index da0c9cbfc..ac29a927b 100644
--- a/mise.toml
+++ b/mise.toml
@@ -25,6 +25,12 @@ node = "24.15.0"
kubectl = "1.36.1"
uv = "0.10.12"
protoc = "29.6"
+go = "1.26"
+"go:github.com/golangci/golangci-lint/v2/cmd/golangci-lint" = "2.12"
+"go:google.golang.org/protobuf/cmd/protoc-gen-go" = "1.36.11"
+"go:google.golang.org/grpc/cmd/protoc-gen-go-grpc" = "1.6.2"
+"go:golang.org/x/tools/cmd/goimports" = "0.48.0"
+buf = "1.72.0"
helm = "4.2.0"
helm-docs = "1.14.2"
skaffold = "2.20.0"
diff --git a/rfc/0005-sandbox-proxy-egress-adapter/README.md b/rfc/0005-sandbox-proxy-egress-adapter/README.md
new file mode 100644
index 000000000..c0a43849e
--- /dev/null
+++ b/rfc/0005-sandbox-proxy-egress-adapter/README.md
@@ -0,0 +1,589 @@
+---
+authors:
+ - "@johntmyers"
+state: review
+links:
+ - https://github.com/NVIDIA/OpenShell/issues/1107
+ - https://github.com/NVIDIA/OpenShell/pull/2155
+ - https://github.com/NVIDIA/OpenShell/pull/1083
+ - https://github.com/NVIDIA/OpenShell/pull/1151
+ - https://github.com/NVIDIA/OpenShell/pull/1286
+ - https://github.com/NVIDIA/OpenShell/pull/1511
+ - https://github.com/NVIDIA/OpenShell/pull/1738
+ - https://github.com/NVIDIA/OpenShell/pull/2027
+ - https://github.com/NVIDIA/OpenShell/pull/1865
+ - https://github.com/NVIDIA/OpenShell/pull/1938
+---
+
+# RFC 0005 - Sandbox Proxy Egress Adapter Model
+
+
+
+## Summary
+
+Refactor sandbox egress around shared authorization, destination-validation,
+and relay boundaries. CONNECT, forward HTTP, native TCP capture, policy DNS,
+`inference.local`, `policy.local`, and metadata loopback become narrow adapters
+that translate userland entry points into common runtime intents. Policy
+evaluation, destination validation, supervisor middleware, credential
+injection, request-body rewrite, WebSocket handling, protocol processing, and
+upstream dialing happen behind shared boundaries.
+
+The RFC describes the complete forward-looking architecture. It is designed
+to land incrementally across multiple pull requests. The first milestone only
+restructures CONNECT and forward HTTP, extracts shared primitives, and
+preserves every current user-facing feature and enforcement behavior. Later
+milestones add policy DNS, transparent TCP capture, native protocol processors,
+and optional deployment shapes on top of those boundaries.
+
+The codebase has already moved in this direction by splitting networking into
+`openshell-supervisor-network` and process/netns work into
+`openshell-supervisor-process`. This RFC proposes the next internal boundary:
+make proxy entry mechanisms pluggable without duplicating authorization,
+destination validation, or relay behavior.
+
+Supporting detail lives in:
+
+- [Current shape appendix](current-shape.md)
+- [Technical design appendix](technical-design.md)
+- [Implementation plan](implementation-plan.md)
+
+## Motivation
+
+The sandbox proxy supports several connection surfaces: explicit CONNECT,
+forward HTTP, local inference and policy APIs, metadata loopback, TLS
+termination, REST, GraphQL, JSON-RPC, MCP, and WebSocket inspection,
+credential injection, supervisor middleware, and nftables-backed bypass
+detection. These features are valuable, but changes to policy and enforcement
+still tend to touch multiple entry paths.
+
+The risk is asymmetric enforcement. A security fix can be added to CONNECT and
+missed in forward HTTP; endpoint metadata can be selected differently from the
+logged policy; a credential path can gain request-body or WebSocket support
+without the same behavior existing in another relay mode.
+
+The target shape separates three concerns:
+
+- **Adapters** describe how userland reached the networking component.
+- **Authorization** decides whether the egress is allowed and what endpoint
+ behavior applies.
+- **Relays** own bytes, credentials, protocol parsing, and upstream dialing.
+
+The first milestone targets the current embedded/network-only supervisor
+runtime and preserves its existing user-facing behavior while the internal
+seams move. The same boundaries then support policy DNS and transparent TCP,
+native protocol processing, and future deployment modes without duplicating
+authorization or relay logic.
+
+## Non-goals
+
+- Replace CONNECT with forward proxy as the only explicit proxy mode.
+- Add SOCKS support.
+- Add HTTP/2 L7 parsing in this refactor. Inspected HTTP paths should continue
+ to reject unsupported h2c upgrades instead of silently upgrading to raw
+ traffic.
+- Redesign provider credential storage.
+- Reintroduce iptables as the sandbox packet filtering backend.
+- Use eBPF connect hooks for transparent capture. Native TCP capture needs a
+ userland proxy in the byte stream for TLS termination and protocol parsing.
+- Add policy-declared supervisor-proxied host-local endpoints. Issue
+ [#1633](https://github.com/NVIDIA/OpenShell/issues/1633) can consume these
+ boundaries in separate feature work.
+- Change the existing endpoint-only runtime's process-identity semantics during
+ the compatibility refactor. Future identity-less deployment modes require an
+ explicit capability contract and cannot inherit endpoint-only behavior by
+ accident.
+
+## Proposal
+
+### Migration Big Rocks
+
+1. **Transport and local-service adapters.** CONNECT, forward HTTP,
+ transparent TCP, policy DNS, `inference.local`, `policy.local`, and metadata
+ loopback become small adapters. They parse their surface and produce either
+ an egress intent, a local response, or a DNS answer. They do not duplicate
+ policy evaluation.
+2. **Egress intent and decision.** Shared authorization evaluates L4 policy and
+ endpoint selection once per connection intent and returns one decision
+ containing the matched policy, matched endpoint, optional process identity
+ evidence used for evaluation, allowed IP metadata, TLS behavior, protocol
+ enforcement, and credential injection and middleware plans.
+3. **Relays.** Relays receive an authorized destination connector, not an
+ already-open upstream socket. HTTP relays evaluate every request before
+ upstream write. TCP relays copy bytes for L4-only endpoints or hand the
+ stream to a protocol processor when endpoint policy requires native protocol
+ enforcement.
+
+The first implementation milestone populates a compatibility
+`EgressDecision` through the existing separate queries so type extraction does
+not change behavior. That transitional envelope is not the target single
+authorization result. Generation-consistent materialization and deterministic
+endpoint selection cut over separately after shadow comparison, before later
+transport adapters depend on the result.
+
+### Unified Adapter Flow
+
+```mermaid
+flowchart TD
+ User["Userland payload / harness"]
+
+ subgraph ExplicitProxy["Explicit proxy listener"]
+ ProxyBytes["HTTP proxy bytes"]
+ IsConnect{"CONNECT request?"}
+ Connect["CONNECT adapter"]
+ Forward["Forward HTTP adapter"]
+ ProxyBytes --> IsConnect
+ IsConnect -- Yes --> Connect
+ IsConnect -- No --> Forward
+ end
+
+ subgraph NativeTcp["Policy DNS + native TCP"]
+ NameLookup["Userland DNS lookup"]
+ PolicyDns["Policy DNS adapter"]
+ DnsEligible{"Eligible native TCP
policy endpoint?"}
+ DnsDeny["Local DNS refusal
no upstream lookup"]
+ TrustedDns["Trusted upstream lookup
and destination filtering"]
+ DnsMapping["Synthetic IP + active mapping
to validated real addresses"]
+ DnsAnswer["Return synthetic IP"]
+ NativeConnect["Userland connect(synthetic_ip:port)"]
+ TcpAdapter["Transparent TCP adapter
recover mapping"]
+ NameLookup --> PolicyDns
+ PolicyDns --> DnsEligible
+ DnsEligible -- No --> DnsDeny
+ DnsEligible -- Yes --> TrustedDns
+ TrustedDns --> DnsMapping
+ DnsMapping --> DnsAnswer
+ DnsAnswer --> NativeConnect
+ NativeConnect --> TcpAdapter
+ end
+
+ subgraph LocalApis["Sandbox-local services"]
+ InferenceReq["Request to inference.local"]
+ PolicyReq["Request to policy.local"]
+ MetadataReq["Request to metadata loopback"]
+ InferenceAdapter["Inference local adapter"]
+ PolicyAdapter["Policy local adapter"]
+ MetadataAdapter["Metadata loopback adapter"]
+ InferenceReq --> InferenceAdapter
+ PolicyReq --> PolicyAdapter
+ MetadataReq --> MetadataAdapter
+ end
+
+ subgraph Shared["Shared external egress pipeline"]
+ Intent["EgressIntent"]
+ Auth["Authorize and select endpoint"]
+ Decision["EgressDecision"]
+ Validate["Resolve or consume pinned destination
and validate"]
+ Relay["Relay"]
+ Deny["Adapter-specific deny response"]
+ Intent --> Auth
+ Auth --> Allowed{"Allowed?"}
+ Allowed -- No --> Deny
+ Allowed -- Yes --> Decision
+ Decision --> Validate
+ Validate --> Relay
+ end
+
+ User --> ProxyBytes
+ User --> NameLookup
+ User --> NativeConnect
+ User --> InferenceReq
+ User --> PolicyReq
+ User --> MetadataReq
+
+ Connect --> Intent
+ Forward --> Intent
+ TcpAdapter --> Intent
+ InferenceAdapter --> InferenceResp["Local inference response"]
+ PolicyAdapter --> PolicyResp["Local policy response"]
+ MetadataAdapter --> MetadataResp["Local metadata credential response"]
+```
+
+Each adapter still owns its response shape. If authorization denies a CONNECT
+intent, the CONNECT adapter returns a tunnel denial. If forward HTTP is denied,
+the forward adapter returns an HTTP denial. If policy DNS refuses a name, it
+returns the appropriate DNS response. The shared layer decides the outcome;
+the adapter renders it for its protocol.
+
+### Relay Flow
+
+```mermaid
+flowchart TD
+ Start["Authorized egress + destination connector"]
+ Start --> FirstReq{"Forward HTTP adapter
already has first request?"}
+
+ FirstReq -- Yes --> ForwardEnforcement{"Endpoint enforcement"}
+ ForwardEnforcement -- "None or HTTP" --> HttpReq["Parsed HTTP request"]
+ ForwardEnforcement -- "Protocol processor" --> BadForward["Deny: HTTP request for native protocol endpoint"]
+
+ FirstReq -- No --> Prepare["Prepare readable client stream"]
+ Prepare --> TlsPolicy{"TLS handling enabled?"}
+ TlsPolicy -- No --> Readable["Client stream"]
+ TlsPolicy -- Yes --> Peek["Peek client bytes"]
+ Peek --> Tls{"TLS ClientHello?"}
+ Tls -- Yes --> Terminate["Shared TLS terminator"]
+ Tls -- No --> Readable
+ Terminate --> Readable
+
+ Readable --> Enforce{"Endpoint enforcement"}
+ Enforce -- "None" --> Sniff{"HTTP request detected?"}
+ Sniff -- Yes --> ParseHttp["Parse HTTP request"]
+ Sniff -- No --> TcpRelay["TcpRelay
connect upstream and copy bytes"]
+ ParseHttp --> HttpReq
+
+ Enforce -- "HTTP" --> MustHttp{"HTTP request detected?"}
+ MustHttp -- Yes --> ParseHttp
+ MustHttp -- No --> DenyHttp["Deny: expected HTTP"]
+
+ Enforce -- "Protocol processor" --> Processor["TcpRelay hands stream to protocol processor"]
+ Processor --> ProcessorOwns["Processor owns message loop
and calls connector when allowed"]
+
+ subgraph HttpLoop["HTTP relay request loop"]
+ HttpReq --> HttpMode{"HTTP endpoint policy?"}
+ HttpMode -- "L4-only HTTP" --> ReqAllowed["Request admitted by connection decision"]
+ HttpMode -- "REST / GraphQL / JSON-RPC / MCP / WebSocket" --> ReqPolicy{"Request policy allowed?"}
+ ReqPolicy -- No --> ReqDeny["Local HTTP deny
no upstream write"]
+ ReqPolicy -- Yes --> ReqAllowed
+ ReqAllowed --> Middleware{"Supervisor middleware
configured?"}
+ Middleware -- Yes --> MwEval["Run HTTP_REQUEST / PRE_CREDENTIALS middleware"]
+ Middleware -- No --> Creds["Resolve static placeholders
and token grants"]
+ MwEval --> MwAllowed{"Middleware allowed?"}
+ MwAllowed -- No --> MwDeny["Local middleware deny
no credential injection"]
+ MwAllowed -- Yes --> Recheck["Re-parse transformed protocol body
and re-evaluate request policy"]
+ Recheck --> PostMwAllowed{"Allowed under endpoint
enforcement mode?"}
+ PostMwAllowed -- No --> PostMwDeny["Local policy deny
no credential injection"]
+ PostMwAllowed -- Yes --> Creds
+ Creds --> Rewrite["Inject credentials into configured slots"]
+ Rewrite --> HttpDial["Connect or reuse upstream"]
+ HttpDial --> HttpResponse["Write request and relay response"]
+ HttpResponse --> Upgrade{"101 WebSocket upgrade?"}
+ Upgrade -- No --> NextReq{"Another HTTP request
on this connection?"}
+ NextReq -- Yes --> HttpReq
+ NextReq -- No --> Done["HTTP relay done"]
+ Upgrade -- Yes --> WsInspect{"WebSocket inspection
or rewrite configured?"}
+ WsInspect -- No --> RawUpgrade["Raw upgraded stream"]
+ WsInspect -- Yes --> WsRelay["WebSocket relay
text-frame rewrite / message policy"]
+ end
+```
+
+Read this as two phases. The top half chooses the relay shape from the adapter
+surface and endpoint enforcement. The `HTTP relay request loop` only receives a
+parsed HTTP request. Supervisor middleware is not another policy funnel; it is
+an optional request-path hook after HTTP policy allows the request and before
+OpenShell-managed credential injection. When middleware changes a request
+body, the relay re-parses body-dependent protocol inputs and re-evaluates
+request policy before credential injection or upstream write.
+
+Relay rules:
+
+- HTTP credential injection happens in both HTTP modes: L4-only HTTP and
+ HTTP-inspected.
+- HTTP-inspected endpoints include `rest`, `graphql`, `json-rpc`, `mcp`, and
+ `websocket`. JSON-RPC and MCP are HTTP L7 protocols, not native TCP protocol
+ processors.
+- Supervisor middleware is a typed relay hook. V1 middleware runs on parsed
+ HTTP requests at `HTTP_REQUEST / PRE_CREDENTIALS`, after network and request
+ policy admit the request and before OpenShell injects credentials.
+- Middleware can allow, deny, replace the bounded request body, add approved
+ headers, and emit audit-safe findings/metadata. External middleware must not
+ receive OpenShell-managed credentials.
+- Middleware mutation cannot bypass request policy. After a body replacement,
+ the relay re-parses and re-evaluates body-dependent GraphQL, JSON-RPC, and MCP
+ policy inputs before credential injection or upstream write. A policy
+ mismatch follows the endpoint's configured enforcement mode; a malformed or
+ unclassifiable transformed protocol body fails closed even in audit mode.
+- Credential injection includes static placeholder rewrite and endpoint-bound
+ dynamic token grants. Token grants run after policy allow and before upstream
+ write; failures deny without forwarding the request.
+- Middleware-transformed content must not create a new path for resolving
+ OpenShell credential placeholders unless the middleware hook is explicitly
+ trusted as credential-capable. The safe default is to fail closed on newly
+ introduced reserved placeholders before credential injection.
+- Static credential rewrite covers request target, query, headers, opt-in REST
+ request bodies, and opt-in client-to-server WebSocket text frames.
+- HTTP L7 policy is evaluated before upstream write for each request. JSON-RPC
+ and MCP evaluation parse bounded JSON-RPC-over-HTTP bodies; MCP adds
+ tool-aware selectors for `tools/call`.
+- WebSocket upgrade policy is evaluated as HTTP first. After an allowed `101`
+ upgrade, the WebSocket relay owns frame parsing when text-frame credential
+ rewrite, WebSocket transport policy, GraphQL-over-WebSocket policy, or safe
+ compression handling is configured. Other upgraded streams remain raw.
+- Forward HTTP must stay in the shared HTTP relay loop or in an equivalent
+ guarded single-request relay. It must not evaluate one request and then
+ switch to raw bidirectional copy.
+- `protocol: tcp` or an omitted protocol means L4 authorization plus byte copy,
+ except that HTTP-looking streams may still use HTTP credential injection.
+- Future native protocol processors, such as Redis, Postgres, or MySQL, own the
+ full message loop and can parse multiple commands or queries on one TCP
+ session. A processor may be in-tree, middleware-backed, or a combination
+ where in-tree framing exposes typed middleware hooks.
+
+### Adapter Responsibilities
+
+CONNECT remains the generic explicit proxy mode for HTTPS and arbitrary TCP.
+The CONNECT adapter parses `CONNECT host:port` into an `EgressIntent`, asks the
+shared authorization boundary for an `EgressDecision`, returns the tunnel-ready
+response only after the connection is allowed, and then hands the tunnel to the
+relay. The upstream connection is opened by the HTTP relay or protocol
+processor when payload policy allows it. The compatibility milestone preserves
+the current raw-relay dial point until the processor boundary exists.
+
+Forward HTTP is compatibility for clients that send absolute-form HTTP
+requests. The adapter parses the first request, rewrites proxy framing only at
+the relay boundary, rejects `https://` absolute-form requests, rejects
+unsupported h2c upgrades on inspected routes, and either stays in a shared HTTP
+request loop or forces `Connection: close` for a guarded single request.
+
+Transparent TCP is for native clients that do not know they are using a proxy.
+It depends on policy DNS and nftables capture. For a policy-eligible native TCP
+name, policy DNS returns a supervisor-owned synthetic IP and creates an active
+mapping from that IP to the normalized name, matched endpoint, allowed ports,
+and validated real addresses. Userland later calls
+`connect(synthetic_ip:port)`, nftables redirects the traffic to a userland
+listener, and the TCP adapter recovers the synthetic destination and exact
+mapping before building an intent.
+
+Policy DNS replaces static `/etc/hosts` snapshots for native TCP names. It is
+query-driven. It first checks whether the normalized name matches an endpoint
+whose transport and protocol contract enables native TCP through policy DNS. A
+name without such an endpoint receives a local policy-denial DNS response,
+normally `REFUSED`, and is never sent to upstream DNS. An eligible name is
+resolved through trusted DNS, and every returned address is filtered through
+destination and SSRF controls before the adapter atomically publishes the
+mapping and capture state and returns the synthetic IP to userland.
+
+The later connect still runs through normal authorization. The connector may
+dial only the validated real addresses pinned in the unexpired mapping; it must
+not perform an unrelated fresh resolution or treat a direct connection to one
+of those real IPs as correlated. Process identity remains independent
+authorization evidence evaluated at connect time, not the mechanism that joins
+the DNS request to the TCP connection.
+
+Local service adapters stay outside the normal external egress relay:
+`inference.local` routes chat, completion, model discovery, embeddings, and
+provider-specific inference traffic through the router with local limits;
+`policy.local` exposes current policy, denial summaries, proposal submission,
+and proposal wait routes; metadata loopback serves provider metadata
+credentials to SDKs that bypass HTTP proxy variables.
+
+### Network Enforcement Substrate
+
+Current main uses nftables for sandbox bypass enforcement. It accepts
+proxy-bound traffic, loopback, and established flows, then rejects and
+optionally logs other TCP/UDP traffic for the bypass monitor. That is current
+enforcement, not native TCP capture.
+
+```mermaid
+flowchart TD
+ Packet["Userland packet"] --> ProxyDest{"Proxy destination?"}
+ ProxyDest -- Yes --> AcceptProxy["nftables accept"]
+ ProxyDest -- No --> Capture{"Active synthetic-IP
capture match?"}
+ Capture -- Yes --> Redirect["nftables redirect/TPROXY to transparent adapter"]
+ Capture -- No --> Reject["nftables log + reject bypass"]
+ Reject --> Monitor["Bypass monitor emits OCSF"]
+```
+
+Transparent TCP extends this nftables model with explicit capture rules that
+run before the reject path and are scoped to unexpired synthetic-IP mappings.
+The sandbox resolver points to policy DNS, while direct external DNS traffic
+continues to the reject path. DNS-over-HTTPS is ordinary HTTPS egress and
+requires its own allowed endpoint. Transparent capture does not add a parallel
+iptables path. The compatibility milestone leaves the current table unchanged;
+capture arrives in a later feature phase.
+
+### Deployment Modes
+
+| Mode | Shape | Status |
+|------|-------|--------|
+| Embedded supervisor | `openshell-sandbox` orchestrates `openshell-supervisor-network` and `openshell-supervisor-process` | Current |
+| Network-only supervisor | Networking, policy, proxy, local services, and background tasks run without a payload process leaf | Current runtime mode |
+| Standalone proxy binary | Supervisor launches networking as a separate process with explicit APIs | Future packaging/API work |
+| Sidecar proxy | Proxy runs outside the payload container but inside the sandbox boundary | Future isolation mode |
+
+A pluggable proxy must expose the right userland surfaces, implement the
+gateway APIs it needs, and prove equivalent policy enforcement through tests.
+If supervisor middleware is configured, the proxy runtime must also receive the
+effective middleware service registry, validate and refresh bindings, enforce
+`fail_open` and `fail_closed`, buffer within configured caps, invoke middleware
+on the request path, and emit middleware OCSF events.
+
+Process identity is mode-dependent. Embedded supervisor mode normally requires
+successful workload process, binary, and ancestor resolution; a lookup failure
+continues to deny. A trusted runtime can explicitly select the existing
+endpoint-only mode, in which identity is recorded as intentionally unavailable
+and policy evaluation keeps its current endpoint-only semantics. The refactor
+must not represent either case as a fabricated empty identity or accidentally
+convert a lookup failure into endpoint-only evaluation.
+
+Future standalone and sidecar modes must advertise identity capability. A mode
+without local identity needs an explicit unavailable-identity contract and
+policy validation for binary/path predicates; it does not automatically inherit
+endpoint-only semantics. The nftables rules that force, capture, or reject
+userland traffic remain owned by the sandbox network boundary even if the proxy
+process later moves into a standalone binary or sidecar.
+
+### Migration And Operational Contract
+
+Mechanical adapter, destination, and relay extractions ship as isolated,
+revertible changes without a permanent feature flag. The deterministic
+authorization result is different: it first runs beside the legacy queries in
+shadow mode, reports audit-safe mismatches through internal telemetry, and
+retains the legacy evaluator through the cutover observation window.
+
+Policy DNS, transparent TCP, native processors, and alternate deployment modes
+land only after the shared authorization and relay contracts are authoritative.
+Each is a separate, feature-bearing pull request or series with its own
+capability gating, migration, telemetry, and rollback plan; they are not bundled
+into the compatibility-only refactor.
+
+Adapter response bytes and OCSF event class, action, disposition, severity,
+status, destination, actor, firewall rule, message, and status detail are
+compatibility surfaces. Moving code does not justify changing them. Performance
+is also measured at each phase; fewer OPA evaluations are a target to verify,
+not an unmeasured claim.
+
+## Implementation plan
+
+The detailed migration plan lives in [implementation-plan.md](implementation-plan.md).
+The intended order is:
+
+1. Lock down current responses, OCSF events, policy outcomes, credential
+ behavior, upstream-dial timing, and local-service behavior with regression
+ coverage.
+2. Introduce compatibility `EgressIntent` and `EgressDecision` envelopes while
+ preserving current lookup precedence and failure defaults.
+3. Centralize destination validation behind an unopened connector.
+4. Materialize one generation-consistent authorization decision, compare it
+ against the legacy queries, then cut over deterministic endpoint selection
+ and fail-closed metadata handling as an independently reviewable step.
+5. Consolidate HTTP request-loop, credential, WebSocket, and middleware relay
+ behavior in separately shippable subphases.
+6. Consolidate TLS handling and existing raw TCP relay selection.
+7. Preserve current local-service boundaries and remove compatibility plumbing.
+8. Add the native protocol-processor dispatch contract, then add protocol
+ implementations as independently reviewed features.
+9. Add policy DNS state and transparent TCP capture with mandatory
+ DNS-answer-to-connect correlation and separate mapping generations.
+10. Define capability-checked standalone or sidecar runtime contracts and
+ complete cleanup after each boundary is in use.
+
+Steps 1 through 7 are the compatibility foundation and may themselves span
+several pull requests. Steps 8 through 10 are later feature milestones; their
+presence in this RFC defines the direction without adding them to the initial
+refactor branch.
+
+## Risks
+
+- Tightening L7 and TLS metadata failures from fail-open to deny may expose
+ latent policy or Rego errors. `allowed_ips` and SSRF validation already fail
+ more conservatively; tests must cover each query independently.
+- Deterministic endpoint selection may change ambiguous overlapping policies.
+ The new decision must shadow the legacy queries and report mismatches before
+ any semantic cutover.
+- Token grants add a runtime dependency on SPIFFE Workload API and token
+ endpoints. Failures should remain fail-closed and sanitized.
+- Transparent TCP capture adds network-namespace interception and mutable DNS
+ mapping state. Synthetic address allocation must coexist with runtime
+ networks, avoid premature reuse, prevent unrelated bare-IP connections from
+ inheriting DNS authorization, and fail closed across policy or mapping
+ generation changes.
+- Sidecar or standalone modes may intentionally lack process identity.
+ Binary/path-scoped policy needs an advertised identity capability and policy
+ validation; missing identity cannot silently broaden an allow.
+- Metadata loopback and `policy.local` expand sandbox-local control surfaces
+ and need strict route validation, body limits, redaction, and authentication
+ boundaries.
+- Provider-composed policy rules use a reserved namespace. Decisions and logs
+ must distinguish provider-derived policy from user-authored policy without
+ exposing provider rules as editable sandbox proposals.
+- Supervisor middleware adds a synchronous request-path dependency. Body caps,
+ timeout behavior, registry reloads, and `fail_open` choices must be visible
+ in telemetry so operators can diagnose whether content inspection ran.
+- Moving OCSF emission sites can accidentally change event class, action,
+ disposition, severity, message, or actor/destination fields. Adapter response
+ shapes and OCSF schemas are compatibility requirements, not cleanup targets.
+- New decision/context objects add per-connection allocations on a hot path.
+ Performance claims require before/after measurements of OPA evaluation count,
+ allocation volume, and connection/request latency.
+- Structural phases back out by reverting their isolated commits. The
+ deterministic-decision cutover must retain the legacy evaluator long enough
+ for shadow comparison and immediate rollback; a permanent feature flag is not
+ required for the purely mechanical phases.
+
+## Alternatives
+
+### Keep patching each entry path
+
+This has the lowest short-term cost but keeps security behavior duplicated
+across CONNECT, forward HTTP, and local services. It also makes future TCP
+application protocol support harder because each parser must be wired through
+multiple entry mechanisms.
+
+### Replace CONNECT with forward proxy
+
+Forward proxy only covers plaintext absolute-form HTTP requests. It is not a
+replacement for HTTPS tunnels, WebSocket tunnels, or arbitrary TCP clients.
+CONNECT should remain the generic explicit proxy mode.
+
+### Build only transparent TCP
+
+Transparent TCP helps native clients but does not replace explicit proxy
+support used by common HTTP tooling. It also requires the shared authorization,
+destination, and relay boundaries plus policy DNS and nftables capture before
+it can safely preserve endpoint identity. For that reason it is a later phase
+of this RFC, not the first implementation change.
+
+### Return real addresses from policy DNS
+
+Returning validated real addresses avoids a synthetic address pool, but the
+later TCP connection carries only an IP and port. Two policy names can share
+the same real address and port, and a direct bare-IP connection is
+indistinguishable from one caused by the earlier lookup. Process identity does
+not solve shared resolvers, caches, cross-process handoff, or two names resolved
+by the same process. The proposal therefore uses a synthetic address as the
+correlation handle and keeps process identity as separate authorization
+evidence.
+
+## Prior art
+
+The current `openshell-supervisor-network` split is the immediate prior step:
+it already separates proxy, OPA, L7, inference routing, policy-local routes,
+TLS, and token grants from process supervision.
+
+The current `openshell-supervisor-process` netns and bypass monitor are the
+packet-enforcement substrate. Transparent TCP extends that nftables model in a
+later phase rather than creating a second firewall path.
+
+The existing L7 relay is the behavioral prior art for this RFC. It already
+proves per-request HTTP evaluation, GraphQL parsing, JSON-RPC/MCP body
+inspection, WebSocket frame handling, request-body rewrite, and token-grant
+injection can live behind relay boundaries.
+
+RFC 0009 supervisor middleware is the extension prior art. It defines
+`HTTP_REQUEST / PRE_CREDENTIALS` as a supervisor-owned hook that can inspect,
+deny, or transform admitted HTTP requests before credentials are injected. RFC
+0005 should place that hook inside the shared relay rather than making each
+adapter wire middleware separately.
+
+## Open questions
+
+1. Should overlapping endpoint metadata be rejected at policy load time, or
+ should one documented policy/endpoint precedence key select the complete
+ decision? The initial compatibility refactor does not choose between them.
+2. What mismatch-free observation window is sufficient before the
+ deterministic decision replaces the legacy endpoint queries?
+3. Should metadata loopback be modeled as an adapter inside
+ `openshell-supervisor-network`, or remain orchestrated by `openshell-sandbox`
+ with shared credential/provider helpers?
+4. What TTL cap should policy DNS use, and should policy reload immediately
+ invalidate all active mappings or permit a bounded drain period that cannot
+ authorize new connections?
+5. Which non-routable synthetic IPv4 and IPv6 ranges can each runtime reserve,
+ and what quarantine period prevents address reuse while stale DNS answers
+ may remain cached?
+6. Which original-destination mechanism and nftables redirect mode should each
+ supported runtime use while keeping capture rules ahead of bypass rejection?
+7. Which identity capabilities must standalone and sidecar runtimes advertise
+ before the gateway accepts binary/path-scoped policy for them?
diff --git a/rfc/0005-sandbox-proxy-egress-adapter/current-shape.md b/rfc/0005-sandbox-proxy-egress-adapter/current-shape.md
new file mode 100644
index 000000000..340c7933c
--- /dev/null
+++ b/rfc/0005-sandbox-proxy-egress-adapter/current-shape.md
@@ -0,0 +1,286 @@
+# Current Shape Appendix
+
+This appendix records the current proxy shape and the review findings that
+motivate the adapter model. The main RFC intentionally keeps these details out
+of the direction document.
+
+## Current Runtime Split
+
+The proxy is no longer only a large module inside `openshell-sandbox`.
+Current main has three relevant runtime owners:
+
+```mermaid
+flowchart TD
+ Sandbox["openshell-sandbox
orchestrator"]
+ Network["openshell-supervisor-network
proxy, OPA, L7, TLS, inference,
policy.local, token grants"]
+ Process["openshell-supervisor-process
process leaf, SSH, netns,
nftables, bypass monitor"]
+ Denials["Denial/activity aggregators"]
+ Gateway["Gateway policy/provider APIs"]
+
+ Sandbox --> Network
+ Sandbox --> Process
+ Network --> Denials
+ Process --> Denials
+ Sandbox --> Gateway
+ Network --> Gateway
+```
+
+`openshell-sandbox` creates the shared network namespace, owns denial/activity
+channels, starts the policy poll loop, starts networking, starts the metadata
+loopback server when needed, and then optionally starts the process leaf. If
+`process_enabled` is false, the supervisor can run in network-only mode and
+keep networking/background tasks alive until shutdown.
+
+`openshell-supervisor-network` owns the explicit proxy listener, OPA engine
+integration, L7 enforcement, TLS termination, inference routing, policy-local
+routes, identity cache, provider credential injection, and token grants.
+
+`openshell-supervisor-process` owns process execution, SSH, network namespace
+helpers, nftables bypass rules, and the bypass monitor that turns nftables LOG
+entries into OCSF events.
+
+In embedded supervisor mode, the network leaf normally uses process metadata
+resolved by the process/orchestrator side for binary-scoped policy and OCSF
+context. Current runtime configuration can instead select endpoint-only policy
+evaluation. The adapter model must preserve that intentional mode separately
+from an identity lookup failure; the latter continues to deny when binary
+identity is required.
+
+## Current Userland-Facing Surfaces
+
+The networking surface currently includes:
+
+- CONNECT proxy traffic for HTTPS and generic TCP tunnels.
+- Forward HTTP proxy traffic for absolute-form HTTP requests.
+- `inference.local` for local inference routing.
+- `policy.local` for current policy, denial summaries, proposal submission,
+ and proposal wait routes.
+- GCE metadata loopback for SDKs that bypass HTTP proxy variables.
+- nftables bypass enforcement for direct TCP/UDP egress that does not enter
+ the proxy.
+- OPA/Rego policy and endpoint metadata lookups.
+- DNS resolution and endpoint validation for CONNECT and forward HTTP egress.
+- Static provider credential injection and redaction.
+- Endpoint-bound dynamic token grant injection.
+- Opt-in REST request-body credential rewrite.
+- L7 REST, GraphQL, JSON-RPC, MCP, WebSocket, and
+ GraphQL-over-WebSocket enforcement.
+
+The issue is not that these features exist. The issue is that entry mechanisms,
+policy evaluation, endpoint metadata lookup, credential injection, and byte
+relay decisions are still interleaved.
+
+## Current CONNECT Shape
+
+```mermaid
+flowchart TD
+ Client["Client CONNECT host:port"] --> Parse["Parse CONNECT target"]
+ Parse --> L4["Evaluate network policy"]
+ L4 --> Allowed{"Allowed?"}
+ Allowed -- No --> Deny["CONNECT denial"]
+ Allowed -- Yes --> Meta["Query endpoint metadata"]
+ Meta --> Config{"L7, TLS, or credential config?"}
+ Config -- No --> Tunnel["Return tunnel-ready response"]
+ Config -- Yes --> Tunnel
+ Tunnel --> Inspect["Inspect tunneled bytes when possible"]
+ Inspect --> Relay["HTTP/WebSocket/TCP relay selection"]
+ Relay --> Inject["Middleware, static credentials, and token grants if configured"]
+ Inject --> Upstream["Open upstream when relay policy allows"]
+```
+
+CONNECT is still the strongest entry shape because the tunnel relay can keep
+parsing HTTP requests on long-lived connections and enforce request policy per
+request.
+
+## Current Forward HTTP Shape
+
+```mermaid
+flowchart TD
+ Client["Absolute-form HTTP request"] --> Parse["Parse first request"]
+ Parse --> L4["Evaluate network policy"]
+ L4 --> Allowed{"Allowed?"}
+ Allowed -- No --> Deny["HTTP denial"]
+ Allowed -- Yes --> L7{"Matching L7 endpoint?"}
+ L7 -- Yes --> Eval["Evaluate REST/GraphQL/JSON-RPC/MCP/WebSocket policy"]
+ Eval --> Guard["Reject unsupported h2c upgrade when inspected"]
+ Guard --> Rewrite["Rewrite to origin-form + configured credentials"]
+ L7 -- No --> Rewrite
+ Rewrite --> Token["Apply token grant if endpoint-bound"]
+ Token --> Close["Force Connection: close except WebSocket upgrade"]
+ Close --> Upstream["Open upstream"]
+ Upstream --> Relay["Guarded HTTP relay / upgrade relay"]
+```
+
+Latest main no longer has the old raw-copy-after-first-request shape for
+ordinary forward HTTP. It rewrites ordinary requests with `Connection: close`,
+uses guarded HTTP relay helpers for body handling, rejects inspected h2c
+upgrades, injects token grants, and sends allowed WebSocket upgrades through
+the upgrade relay. That is a narrower surface than the historical bidirectional
+copy, but it is still orchestrated separately from the CONNECT relay path.
+
+## Current Local Service Shape
+
+```mermaid
+flowchart TD
+ Request["Request to local name"] --> Match{"Known local route?"}
+ Match -- "inference.local" --> Inference["Inference route adapter"]
+ Match -- "policy.local" --> Policy["Policy local adapter"]
+ Match -- "metadata loopback" --> Metadata["Metadata credential server"]
+ Match -- No --> External["Normal egress path"]
+ Inference --> InferenceResp["Local inference response"]
+ Policy --> PolicyResp["Local policy response"]
+ Metadata --> MetadataResp["Metadata response"]
+```
+
+`inference.local` now covers buffered and streaming inference shapes including
+chat/completion routes, model discovery, embeddings, and provider-specific
+routes. `policy.local` supports the agentic approval loop: agents can submit
+narrow proposals and wait on approval/reload before retrying. Metadata
+loopback exists for provider credentials consumed by SDKs that do not honor
+HTTP proxy variables.
+
+These are userland-facing network surfaces. They should stay distinct from
+external egress while still fitting the adapter model.
+
+## Adjacent In-Flight Supervisor Middleware Shape
+
+PRs #1738 and #2027 propose supervisor middleware as an HTTP request hook in
+the proxy relay. That work is adjacent to this RFC rather than a separate entry
+adapter.
+
+```mermaid
+flowchart TD
+ Req["Parsed admitted HTTP request"] --> Policy["Network and request policy already allowed"]
+ Policy --> Hook["HTTP_REQUEST / PRE_CREDENTIALS middleware"]
+ Hook --> Outcome{"Middleware outcome"}
+ Outcome -- "deny" --> Deny["Local deny, no credential injection"]
+ Outcome -- "allow / mutate" --> Recheck["Re-parse transformed body and re-evaluate policy"]
+ Recheck --> Allowed{"Allowed under endpoint enforcement mode?"}
+ Allowed -- "no" --> PolicyDeny["Local policy deny, no credential injection"]
+ Allowed -- "yes" --> Creds["Credential injection"]
+ Creds --> Upstream["Upstream write"]
+```
+
+The proposed middleware chain is selected by admitted destination host, runs in
+deterministic order, buffers bounded request bodies, applies `fail_open` or
+`fail_closed`, emits audit-safe findings, and runs before OpenShell-managed
+credentials are injected. Middleware-transformed GraphQL, JSON-RPC, and MCP
+bodies are re-parsed and re-evaluated before credential injection or upstream
+write, so a mutation cannot bypass request policy. Policy mismatches retain the
+endpoint's audit or enforce behavior, while malformed transformed protocol
+bodies fail closed in either mode. Middleware can inspect WebSocket upgrade
+requests because they are HTTP requests, but it does not inspect post-upgrade
+WebSocket frames in v1.
+
+RFC 0005 should account for this by treating middleware as part of the shared
+request processing plan. CONNECT and forward HTTP should not each learn how to
+select and invoke middleware independently.
+
+## Current Network Namespace Enforcement
+
+```mermaid
+flowchart TD
+ Start["Process in sandbox network namespace"] --> Dest{"Destination"}
+ Dest -- "Proxy host_ip:port" --> Proxy["Accept to sandbox proxy"]
+ Dest -- "Loopback" --> Loopback["Accept loopback"]
+ Dest -- "Established/related" --> Established["Accept response packet"]
+ Dest -- "Other TCP/UDP" --> Reject["nftables log + reject"]
+ Reject --> Monitor["Bypass monitor reads dmesg"]
+ Monitor --> OCSF["OCSF network + detection events"]
+```
+
+The process leaf installs an `inet` nftables filter table for bypass
+enforcement. The table accepts proxy-bound traffic, loopback, and established
+flows, then rejects and optionally logs other TCP/UDP traffic. It does not
+currently redirect native TCP connections into the proxy.
+
+## Findings To Preserve
+
+### Invariant: forward proxy must not relay unevaluated follow-on HTTP bytes
+
+The historical forward path evaluated at most the first absolute-form request,
+rewrote it, then switched to bidirectional copy. Bytes already buffered after
+the first header block, or later pipelined requests on the same client/upstream
+connection, could reach upstream without the CONNECT L7 relay's per-request
+parser/evaluator.
+
+Latest main mitigates this by forcing ordinary forward HTTP to one request per
+connection and by using guarded relay helpers. The adapter model should
+preserve the invariant either by keeping forward HTTP single-request/close or
+by passing the first parsed request into a shared HTTP relay loop.
+
+### Endpoint config is not tied to deterministic matched policy
+
+The policy name used for L4 authorization and logging is the lexicographically
+smallest matching policy. L7 candidates are collected independently and later
+selected by request-path specificity. TLS and `allowed_ips` use the first
+extended endpoint config returned by a separate query. Exact-declared-host is
+another independent existential query. With overlapping host, port, and binary
+rules, those results can describe different endpoints and policies on the same
+connection.
+
+The adapter model requires authorization to return one decision with one
+deterministic matched endpoint.
+
+### Policy materialization can span generations
+
+The L4 decision, L7 route, TLS mode, `allowed_ips`, and exact-declared-host
+signal are materialized through separate engine calls. The L7 route records a
+generation for its tunnel evaluator, but the sibling metadata queries are not
+all asserted against the L4 decision generation. A reload during setup can
+therefore assemble one logical connection decision from different policy
+generations.
+
+The target decision carries one top-level policy generation. Every
+policy-derived field must be evaluated from that generation, and relay startup
+must reject a stale decision before an upstream request is written.
+
+### Endpoint metadata query failures should not erase enforcement
+
+Failure behavior is not uniform today. L7 configuration failure becomes no L7
+configuration, and TLS configuration failure becomes automatic TLS handling;
+either can erase intended enforcement. `allowed_ips` and the downstream SSRF
+validation path are already more conservative. The migration must test each
+query independently instead of describing all metadata failures as equivalent.
+
+The adapter model treats endpoint metadata as part of the authorization result.
+Failure to materialize required metadata should deny rather than erase extended
+configuration.
+
+### Destination validation must be shared
+
+Private address checks, `allowed_ips`, exact declared private endpoint trust,
+trusted gateway aliases, SSRF checks, and control-plane port blocks have grown
+over time. They should be centralized so CONNECT and forward HTTP use the same
+resolved-destination rules. Existing local services remain outside normal
+external destination validation.
+
+## Existing Feature Inventory
+
+The refactor should preserve:
+
+- CONNECT explicit proxy support.
+- Forward HTTP explicit proxy support.
+- Network-only supervisor mode.
+- nftables bypass reject/log enforcement.
+- Provider credential injection and redaction.
+- Dynamic token grant injection through SPIFFE-backed provider credentials.
+- Supervisor middleware `HTTP_REQUEST / PRE_CREDENTIALS` when it lands.
+- REST request-body credential rewrite.
+- WebSocket text-frame credential rewrite.
+- REST endpoint method/path policy.
+- GraphQL-over-HTTP policy.
+- JSON-RPC-over-HTTP method policy.
+- MCP Streamable HTTP method and tool policy.
+- WebSocket transport and GraphQL-over-WebSocket policy.
+- h2c rejection on inspected HTTP routes.
+- Inference routing through `inference.local`, including embeddings.
+- Agent-facing policy advisor routes through `policy.local`.
+- GCE metadata loopback for supported provider credentials.
+- Timeout and resource tracking for client, upstream, and local service work.
+- Structured OCSF logging for network and HTTP policy outcomes.
+- SSRF and internal address protections.
+- Exact declared private endpoint handling.
+- Control-plane port protection.
+- `allowed_ips` endpoint restrictions.
+- TLS auto-detection and termination for inspectable client connections.
diff --git a/rfc/0005-sandbox-proxy-egress-adapter/implementation-plan.md b/rfc/0005-sandbox-proxy-egress-adapter/implementation-plan.md
new file mode 100644
index 000000000..5e8a06b74
--- /dev/null
+++ b/rfc/0005-sandbox-proxy-egress-adapter/implementation-plan.md
@@ -0,0 +1,279 @@
+# Implementation Plan
+
+This plan is intentionally separate from the main RFC so the proposal can stay
+direction-focused. The RFC is an incremental roadmap, not one pull request.
+Phases 0 through 7 form the compatibility foundation: they restructure current
+CONNECT, forward HTTP, raw TCP, and local-service behavior without adding a new
+user-facing transport. Phases 8 and later add the forward-looking capabilities
+after the shared contracts are authoritative.
+
+## Phase 0 - Compatibility Baseline
+
+- Cover CONNECT and forward HTTP allow/deny responses, including exact status,
+ headers, and adapter-specific error bodies.
+- Cover forward HTTP pipelining, keep-alive follow-on requests, the current
+ `Connection: close` mitigation, `https://` absolute-form rejection, and h2c
+ rejection on inspected endpoints.
+- Cover the current overlapping-policy outcomes separately for matched policy,
+ L7 route selection, TLS, `allowed_ips`, and exact-declared-host.
+- Inject failures into L7, TLS, `allowed_ips`, and exact-declared-host queries.
+ Record the current fail-open or fail-closed result for each query rather than
+ treating all endpoint metadata errors as equivalent.
+- Cover control-plane ports, cloud metadata, always-blocked addresses, exact
+ declared private endpoints, IP-literal synthesis, trusted gateway aliases,
+ and explicit `allowed_ips` through CONNECT and forward HTTP.
+- Cover identity-required success/failure, unsupported-platform behavior where
+ possible, and intentional endpoint-only evaluation. Prove an empty
+ `exec.path` cannot satisfy binary-scoped policy while identity is required.
+- Cover static credential injection, token grants, REST body rewrite,
+ WebSocket text-frame rewrite and policy, GraphQL, JSON-RPC, and MCP behavior.
+- Cover `inference.local`, `policy.local`, metadata loopback, and unchanged
+ nftables bypass reject/log behavior.
+- Capture stable OCSF event class, activity/action/disposition, severity,
+ status, destination, actor, firewall rule, message, and status detail for
+ representative allow and deny paths.
+- Record a performance baseline for OPA evaluations, per-connection
+ allocations, and CONNECT/forward request latency.
+
+## Phase 1 - Adapters And Compatibility Decision Envelope
+
+- Introduce CONNECT and forward HTTP `EgressIntent` construction inside
+ `openshell-supervisor-network`.
+- Introduce a transitional `EgressDecision` carrying L4 outcome, policy
+ generation, process evidence, and endpoint fields while preserving the
+ current query timing, precedence, and failure defaults.
+- Keep `LookupFailed`/unsupported identity as a denial when identity is
+ required. Keep explicitly configured endpoint-only mode behavior unchanged.
+- Keep adapter-specific responses and OCSF emission at the protocol boundary.
+- Do not claim the transitional decision is one atomic OPA result; document its
+ compatibility hydration until Phase 3 cuts over.
+
+This phase is a mechanical extraction. It must be independently shippable and
+revertible without changing user-visible policy or relay behavior.
+
+## Phase 2 - Shared Destination Validation
+
+- Move DNS resolution, explicit `allowed_ips`, exact declared endpoints,
+ implicit IP-literal handling, trusted gateway aliases, SSRF checks,
+ cloud-metadata blocks, and control-plane-port blocks into one validator.
+- Represent the selected validation mode explicitly instead of passing an
+ ambiguous collection of booleans.
+- Return an unopened `UpstreamConnector` so adapters and relays preserve the
+ current point at which upstream TCP is created.
+- Prove CONNECT and forward HTTP retain their existing denial responses, OCSF
+ fields, and dial timing while using the shared validator.
+
+## Phase 3 - Generation-Consistent Authorization Cutover
+
+- Define either rejection of ambiguous overlapping endpoint metadata or one
+ documented policy/endpoint precedence key before changing enforcement.
+- Add one OPA result that materializes matched policy/source, matched endpoint,
+ destination constraints, TLS, HTTP enforcement, credential plan, and
+ middleware selection from one policy generation.
+- Attach a generation-pinned `TunnelPolicyEngine` to relay context for
+ per-request REST, GraphQL, JSON-RPC, MCP, and WebSocket evaluation. Relays do
+ not rematerialize connection-level endpoint policy.
+- Run the new query in shadow mode beside legacy queries. Emit internal,
+ audit-safe mismatch telemetry without changing existing OCSF network/HTTP
+ events or enforcement.
+- Add reload-race tests proving every materialized field matches the top-level
+ generation and stale decisions stop before upstream request write.
+- Make deterministic selection and fail-closed L7/TLS metadata errors a
+ dedicated cutover only after mismatch cases are understood. Retain the
+ legacy evaluator temporarily for immediate rollback.
+
+This is the only phase that intentionally tightens ambiguous or error behavior;
+it must not be hidden inside the structural refactor commits.
+
+## Phase 4 - Forward HTTP Adapter
+
+- Keep absolute-form parsing and adapter-specific errors at the forward HTTP
+ boundary.
+- Pass the buffered first request into a shared HTTP relay, or retain the
+ guarded single-request/`Connection: close` path until Phase 5a is ready.
+- Preserve `https://` absolute-form rejection and inspected h2c rejection.
+- Preserve the invariant that no unevaluated follow-on request can reach raw
+ bidirectional copy.
+
+## Phase 5 - Relay Consolidation
+
+### Phase 5a - HTTP request loop
+
+- Centralize HTTP parsing and per-request REST, GraphQL, JSON-RPC, and MCP
+ evaluation behind the generation-pinned request-policy handle.
+- Evaluate every request before upstream write and preserve the current rule
+ that a denied request does not create an upstream session.
+- Preserve bounded JSON-RPC/MCP inspection and audit-safe logging that omits
+ params and tool arguments.
+
+### Phase 5b - Credential injection
+
+- Unify static target/query/header rewrite, endpoint-bound token grants, and
+ opt-in REST request-body rewrite after request allow and before upstream
+ write.
+- Preserve buffering limits, supported content types, `Content-Length`
+ recomputation, redaction, token caching, and fail-closed unresolved secrets.
+
+### Phase 5c - WebSocket
+
+- Move allowed upgrades behind the shared relay while preserving raw upgraded
+ passthrough, opt-in text-frame credential rewrite, WebSocket transport policy,
+ GraphQL-over-WebSocket policy, and safe compression behavior.
+
+### Phase 5d - Supervisor middleware
+
+- Land only after the supervisor middleware dependency is available.
+- Run `HTTP_REQUEST / PRE_CREDENTIALS` after request allow and before static or
+ dynamic credential injection.
+- Re-parse middleware-transformed bodies and re-evaluate GraphQL, JSON-RPC, and
+ MCP policy inputs before credential injection or upstream write. Preserve the
+ endpoint's audit or enforce behavior for policy mismatches, and fail closed
+ on malformed transformed protocol bodies in either mode.
+- Preserve ordering, body caps, `fail_open`/`fail_closed`, safe headers,
+ findings, metadata, and rejection of middleware-introduced credential
+ placeholders.
+- Test allowed requests that middleware rewrites into denied GraphQL, JSON-RPC,
+ and MCP operations, including audit-mode forwarding and fail-closed malformed
+ replacements.
+
+Each subphase must be independently testable and shippable; Phase 5 is not a
+single flag-day cutover.
+
+## Phase 6 - Shared TLS And TCP Relay Boundary
+
+- Move client-side TLS detection and termination before the HTTP/raw-TCP relay
+ split without changing handshake, certificate, or upstream-connect timing.
+- Keep endpoint TLS behavior on `EgressDecision` and preserve `tls: skip` as the
+ explicit raw-tunnel path.
+- Use one existing raw `TcpRelay` byte-copy primitive for L4 traffic.
+- Add a protocol-processor dispatch contract without enabling a concrete new
+ protocol in the compatibility milestone.
+- Let processors own their message loop and call the validated connector only
+ when protocol state allows. Permit in-tree, middleware-backed, and hybrid
+ processors with typed middleware operations.
+
+## Phase 7 - Existing Local Services And Cleanup
+
+- Keep `inference.local` as a local adapter with its existing TLS, route,
+ provider-auth, streaming/buffered limit, and OCSF behavior.
+- Keep `policy.local` as a local adapter for current policy, bounded denial
+ summaries, proposals, and proposal wait.
+- Decide whether metadata loopback remains orchestrated by `openshell-sandbox`
+ or moves behind a local adapter boundary; preserve startup/failure behavior
+ either way.
+- Keep the local-routing and destination contracts extensible for issue
+ [#1633](https://github.com/NVIDIA/OpenShell/issues/1633), while leaving its
+ policy surface and host-loopback authorization to separate feature work.
+- Remove compatibility endpoint queries only after Phase 3 is authoritative.
+- Remove duplicated destination/relay plumbing without centralizing
+ adapter-specific response rendering.
+- Update the living architecture documentation once each implemented boundary
+ reflects current code.
+
+Completion of Phase 7 is the compatibility milestone: existing user-facing
+features and capabilities are preserved on the new internal structure. The
+following phases are feature-bearing work and land in separate pull requests or
+series.
+
+## Phase 8 - Policy DNS And Transparent TCP
+
+- Add policy DNS registration for native TCP endpoint names.
+- Reject names that do not match an eligible native TCP endpoint before making
+ an upstream DNS query.
+- Replace static host-file mapping with query-driven synthetic DNS answers.
+ Resolve eligible names through trusted DNS and filter every real address
+ through destination controls.
+- Allocate a supervisor-owned synthetic IP and store the normalized name,
+ endpoint ID, allowed ports, validated real addresses, policy generation,
+ distinct DNS mapping generation, mapping ID, and expiration in active mapping
+ state.
+- Require every captured connect to correlate with the unexpired mapping
+ selected by its synthetic destination and requested port. Do not allow
+ unrelated bare-IP traffic to inherit a policy-DNS decision.
+- Publish mapping and nftables capture updates atomically from the adapter's
+ perspective before returning the synthetic DNS answer.
+- Add nftables REDIRECT/TPROXY capture rules ahead of the bypass reject path;
+ do not add a parallel iptables path.
+- Coordinate capture-rule ownership with
+ `openshell-supervisor-process::netns` and preserve reject/log fallback for
+ unmatched traffic.
+- Recover the original destination, construct a transparent-TCP intent, and run
+ normal generation-consistent authorization and destination validation.
+- Restrict the connector to the mapping's pinned validated real addresses; do
+ not independently re-resolve at connect time.
+- Keep direct external DNS blocked and treat DNS-over-HTTPS as ordinary
+ policy-controlled HTTPS egress.
+- Define synthetic address pools and reuse quarantine, TTL caps, policy-reload
+ invalidation, stale-mapping behavior, and rollback before enabling capture by
+ default.
+
+## Phase 9 - Native Protocol Processors
+
+- Add concrete Redis, Postgres, MySQL, or other processors one protocol at a
+ time, each with a separately reviewed policy schema and operational limits.
+- Keep omitted/`tcp` endpoints on raw L4 byte copy; never infer a native
+ processor from traffic alone.
+- Test multi-message sessions, pre-dial denial, handshake-required dialing,
+ per-command/query evaluation, middleware hooks, timeouts, and redaction.
+- Capability-gate policy that names a processor unavailable in the running
+ proxy build.
+
+## Phase 10 - Runtime Boundary
+
+- Keep embedded and network-only supervisor modes as the migration baseline.
+- Define the proxy runtime API needed for a future standalone binary or
+ sidecar: configured listeners, policy updates, provider credentials, token
+ grants, middleware registry, gateway calls, telemetry, denial/activity
+ events, and shutdown.
+- Advertise process-identity and protocol-processor capabilities. Reject policy
+ that requires unavailable binary/path identity or processor support.
+- Represent intentional runtime identity unavailability separately from the
+ existing endpoint-only mode and from lookup failure.
+- Add gateway capability negotiation if proxy and gateway versions can differ.
+
+## Phase 11 - Final Cleanup
+
+- Remove any compatibility query/evaluator retained for deterministic-decision
+ rollback after its observation window closes.
+- Remove stale static `/etc/hosts`, iptables, or single-process assumptions from
+ proxy design and architecture documentation as the corresponding later phase
+ lands.
+- Keep adapter-specific response rendering and OCSF contracts at their protocol
+ boundaries.
+
+## Testing And Operational Validation
+
+- Unit-test adapter intent construction, response rendering, explicit
+ destination modes, identity evidence, and authorization precedence.
+- Integration-test destination validation across CONNECT and forward HTTP,
+ then reuse the same suite for transparent TCP when Phase 8 lands.
+- Integration-test HTTP keep-alive/pipelining, REST, GraphQL, JSON-RPC, MCP,
+ WebSocket, credentials, token grants, middleware, and TLS/raw-TCP selection.
+- Integration-test `inference.local`, `policy.local`, and metadata loopback body
+ limits, timeouts, redaction, and local denial responses.
+- Compare OCSF fixtures before and after each migration subphase.
+- Exercise policy reload between L4 decision, endpoint materialization, relay
+ startup, and long-lived per-request evaluation.
+- Add protocol-processor harness tests before adding Redis, Postgres, MySQL, or
+ similar enforcement. Each concrete processor adds multi-message, handshake,
+ timeout, denial, redaction, and middleware coverage.
+- Integration-test policy DNS filtering, denial without an upstream query,
+ synthetic answer allocation, TTL and reuse quarantine, distinct mapping
+ generations, policy-reload invalidation, atomic capture-rule updates,
+ original-destination recovery, allowed-port correlation, connector
+ restriction to pinned real addresses, and rejection of unrelated bare-IP
+ connects.
+- Prove two names that resolve to the same real IP and port receive distinct
+ correlations and cannot inherit each other's endpoint policy.
+- Test standalone/sidecar capability negotiation and prove missing identity or
+ processor support fails during policy validation rather than broadening an
+ allow at runtime.
+- Re-run the performance baseline after the compatibility envelope, after the
+ single-decision query, and after relay consolidation. Treat reduced OPA calls
+ as a measured result rather than an assumed benefit.
+- Back out structural phases by reverting their isolated commits. Keep shadow
+ comparison and the legacy evaluator available through the deterministic
+ cutover observation window.
+- Gate later transport/runtime phases independently so disabling policy DNS or
+ transparent capture restores the existing explicit-proxy and bypass-reject
+ behavior without reverting the compatibility foundation.
diff --git a/rfc/0005-sandbox-proxy-egress-adapter/technical-design.md b/rfc/0005-sandbox-proxy-egress-adapter/technical-design.md
new file mode 100644
index 000000000..ea2767b9c
--- /dev/null
+++ b/rfc/0005-sandbox-proxy-egress-adapter/technical-design.md
@@ -0,0 +1,594 @@
+# Technical Design Appendix
+
+This appendix carries implementation-level design details behind the main RFC.
+
+## Existing Runtime Boundary
+
+`openshell-supervisor-network::run::run_networking` is the current networking
+startup boundary. It builds policy-local context, waits for policy binary
+symlink resolution, creates the identity cache, writes the TLS CA, builds TLS
+state, resolves inference routes, wires provider credentials and token grants,
+and starts the proxy. The supervisor middleware work extends this boundary with
+middleware registry construction and reload behavior.
+
+This is a useful outer boundary, but it is not yet the proxy adapter boundary.
+The proxy still needs internal `EgressIntent` and `EgressDecision` boundaries
+so CONNECT, forward HTTP, local routes, and future native TCP capture do not
+duplicate policy and relay orchestration. The first implementation milestone
+wires only current surfaces; later milestones add new adapters to the same
+contract.
+
+## Shared Data Boundaries
+
+### EgressIntent
+
+`EgressIntent` is the normalized description of what userland is trying to do.
+
+It should carry:
+
+- entry transport: CONNECT, forward HTTP, transparent TCP, local HTTP, policy
+ DNS, or metadata loopback;
+- requested destination host/port or captured original IP/port;
+- optional process identity inputs collected by the adapter/runtime;
+- optional first HTTP request for forward proxy traffic;
+- optional local service route;
+- policy generation and, for policy DNS/transparent TCP, a distinct DNS
+ mapping generation and correlation handle.
+
+Adapters build intents. They should not query endpoint metadata, select TLS
+mode, or select relays.
+
+### EgressDecision
+
+`EgressDecision` is the policy result consumed by validation and relay code.
+
+It should carry:
+
+- allow or deny;
+- one top-level policy generation used for every policy-derived field;
+- deterministic matched policy identifier;
+- whether the policy is user-authored, provider-derived, or local-service
+ internal;
+- deterministic matched endpoint identifier and endpoint metadata;
+- process identity availability and any identity fields used for evaluation;
+- destination and allowed IP constraints;
+- TLS behavior;
+- protocol enforcement;
+- credential injection plan;
+- supervisor middleware plan;
+- the request-policy selection needed to create a pinned per-request L7
+ evaluator when HTTP inspection is configured;
+- logging context and denial reason.
+
+Relay code should read this decision. It should not query OPA again for
+endpoint metadata, TLS mode, allowed IPs, credential behavior, middleware
+selection, or relay selection. Long-lived HTTP relays still evaluate each
+request through the generation-pinned L7 evaluator carried in `RelayContext`;
+that is request authorization, not endpoint rematerialization. Later native
+protocol processors use the same pattern with a generation-pinned protocol
+evaluator for per-command or per-query decisions.
+
+## Protocol Enforcement
+
+Use a protocol enforcement value derived from endpoint policy:
+
+| Policy protocol | Enforcement | Relay behavior |
+|-----------------|-------------|----------------|
+| omitted / `tcp` | None | L4 authorization plus byte relay, with optional HTTP sniff for credential injection |
+| `rest` | HTTP | HTTP request parser with REST rules, plus opt-in request-body and WebSocket text-frame credential rewrite |
+| `graphql` | HTTP | HTTP request parser with GraphQL-over-HTTP rules |
+| `json-rpc` | HTTP | HTTP request parser plus bounded JSON-RPC-over-HTTP method inspection |
+| `mcp` | HTTP | HTTP request parser plus bounded MCP Streamable HTTP method/tool inspection |
+| `websocket` | HTTP | HTTP upgrade policy followed by WebSocket frame policy or GraphQL-over-WebSocket policy |
+| future `redis`, `postgres`, `mysql`, ... | Protocol processor | Protocol-specific processor owns framing, middleware hooks, and the message loop |
+
+`protocol: tcp` is effectively the default L4 mode. It should not run native
+protocol processors. Avoid using the term "provider" for processor concepts
+because providers are already a first-class credential and routing domain in
+OpenShell. Concrete native processors land after the shared dispatch contract.
+
+## Suggested Types
+
+The exact Rust shape can evolve, but the boundaries should look like this:
+
+```rust
+enum EgressTransport {
+ Connect,
+ ForwardHttp,
+ TransparentTcp,
+ PolicyDns,
+ LocalHttp,
+ MetadataLoopback,
+}
+
+struct EgressIntent {
+ transport: EgressTransport,
+ destination: RequestedDestination,
+ process: ProcessIdentityEvidence,
+ first_request: Option,
+ local_route: Option,
+ correlation: Option,
+}
+
+struct EgressDecision {
+ policy_generation: PolicyGeneration,
+ outcome: PolicyOutcome,
+ matched_policy: Option,
+ endpoint: Option,
+ process: EvaluatedProcessIdentity,
+ request_processing: RequestProcessingPlan,
+ log_context: EgressLogContext,
+}
+
+enum ProcessIdentityEvidence {
+ Available(ProcessIdentity),
+ Unavailable(ProcessIdentityUnavailableReason),
+}
+
+enum ProcessIdentityUnavailableReason {
+ EndpointOnlyMode,
+ DeclaredRuntimeMode(RuntimeMode),
+ UnsupportedPlatform,
+ LookupFailed,
+}
+
+struct EvaluatedProcessIdentity {
+ evidence: ProcessIdentityEvidence,
+ fields_used: Vec,
+}
+
+struct MatchedPolicy {
+ id: PolicyId,
+ source: PolicySource,
+}
+
+enum PolicySource {
+ User,
+ ProviderDerived,
+ LocalService,
+}
+
+struct MatchedEndpoint {
+ id: EndpointId,
+ destination: DestinationValidationPlan,
+ tls: TlsPolicy,
+ enforcement: ProtocolEnforcement,
+}
+
+struct DestinationValidationPlan {
+ address_authorization: AddressAuthorization,
+}
+
+enum AddressAuthorization {
+ DefaultPublicOnly,
+ ExplicitAllowedIps(Vec),
+ ExactDeclaredHost,
+ ImplicitIpLiteral(IpAddr),
+ TrustedGatewayAlias { expected_ip: IpAddr },
+}
+
+struct RequestProcessingPlan {
+ middleware: SupervisorMiddlewarePlan,
+ credentials: CredentialInjectionPlan,
+}
+
+enum ProtocolEnforcement {
+ None,
+ Http(HttpL7Config),
+ ProtocolProcessor(ProtocolProcessorConfig),
+}
+
+enum HttpL7Protocol {
+ Rest,
+ Graphql,
+ JsonRpc,
+ Mcp,
+ Websocket,
+}
+
+struct HttpL7Config {
+ protocol: HttpL7Protocol,
+ path: EndpointPathScope,
+ allow_encoded_slash: bool,
+ enforcement_mode: L7EnforcementMode,
+ websocket_credential_rewrite: bool,
+ request_body_credential_rewrite: bool,
+ websocket_graphql_policy: bool,
+ graphql_max_body_bytes: usize,
+ json_rpc_max_body_bytes: usize,
+ mcp_strict_tool_names: bool,
+}
+
+struct CredentialInjectionPlan {
+ static_placeholders: StaticPlaceholderPlan,
+ token_grant: Option,
+}
+
+struct StaticPlaceholderPlan {
+ http_target_query_header: bool,
+ rest_request_body: bool,
+ websocket_text_frames: bool,
+}
+
+struct TokenGrantPlan {
+ provider_key: String,
+ auth_style: TokenGrantAuthStyle,
+ token_endpoint: String,
+}
+
+struct SupervisorMiddlewarePlan {
+ stages: Vec,
+ min_body_limit: Option,
+ registry_generation: PolicyGeneration,
+}
+
+struct SupervisorMiddlewareStage {
+ policy_name: String,
+ binding_id: String,
+ operation: MiddlewareOperation,
+ phase: MiddlewarePhase,
+ order: i32,
+ on_error: MiddlewareOnError,
+ config: MiddlewareConfig,
+}
+
+enum MiddlewareOperation {
+ HttpRequest,
+ Future(String),
+}
+
+enum MiddlewarePhase {
+ PreCredentials,
+ Future(String),
+}
+
+struct RelayContext {
+ decision: EgressDecision,
+ request_policy: Option,
+ protocol_policy: Option,
+ connector: UpstreamConnector,
+ deadlines: RelayDeadlines,
+ telemetry: RelayTelemetry,
+}
+
+struct ResolvedEndpointCorrelation {
+ policy_generation: PolicyGeneration,
+ mapping_generation: DnsMappingGeneration,
+ mapping_id: DnsMappingId,
+ synthetic_ip: IpAddr,
+}
+
+struct PinnedRequestPolicy {
+ generation: PolicyGeneration,
+ evaluator: TunnelPolicyEngine,
+}
+
+struct PinnedProtocolPolicy {
+ generation: PolicyGeneration,
+ evaluator: ProtocolPolicyEngine,
+}
+```
+
+`UpstreamConnector` is the relay-owned dial boundary. It encapsulates the
+validated destination and lets relays or processors open an upstream connection
+only after current request or protocol policy allows it.
+
+`DestinationValidationPlan` selects one current validation mode. All modes
+retain control-plane-port and cloud-metadata blocks. Default and explicit IP
+paths retain the always-blocked loopback, link-local, and unspecified-address
+checks. `ImplicitIpLiteral` is synthesized only for an explicitly declared IP
+host. `TrustedGatewayAlias` may accept the one runtime-discovered gateway IP but
+does not become a general private-address exemption.
+
+`policy_generation`, the optional pinned request/protocol evaluators, endpoint
+metadata, and middleware selection must describe one policy snapshot.
+Authorization asserts that every sub-materialization used that generation. If
+the generation changes before relay startup, the adapter receives a
+stale-policy denial rather than a mixed decision.
+
+## Process Identity Availability
+
+Process identity is evidence, not a string to fabricate when lookup fails.
+Embedded mode normally populates binary, PID, ancestry, command-line path, and
+binary hash data. When binary identity is required, `LookupFailed` and
+`UnsupportedPlatform` remain denials. An explicitly configured endpoint-only
+runtime records `Unavailable(EndpointOnlyMode)` and keeps the current
+endpoint-only policy behavior. This RFC does not silently turn one state into
+the other or change the endpoint-only trust contract.
+
+A future standalone or sidecar runtime that intentionally lacks local identity
+uses `DeclaredRuntimeMode`, not `EndpointOnlyMode`, and advertises that
+capability to policy validation. The runtime contract must define binary/path
+predicates as unavailable and reject incompatible policy before traffic starts,
+unless a later accepted policy design specifies a different fail-closed rule.
+
+The decision records identity availability and fields used so OCSF logs and
+deny responses distinguish a binary policy denial, an identity lookup failure,
+and intentional endpoint-only evaluation. Tests must prove an empty synthetic
+`exec.path` cannot satisfy a binary-scoped rule while identity is required.
+Adding new identity-less deployment modes, or changing how binary predicates
+behave in endpoint-only mode, requires the capability work in the later runtime
+phase and cannot be smuggled into the compatibility refactor.
+
+## Current Owners And Proposed Cleanup
+
+| Current owner | Current responsibility | Proposed cleanup |
+|---------------|------------------------|------------------|
+| `openshell-sandbox` | Orchestrator, policy poll loop, denial/activity channels, metadata loopback startup, network-only lifecycle | Keep as orchestration; avoid embedding per-entry proxy policy decisions |
+| `openshell-supervisor-network::run` | Networking startup and handles | Become the stable runtime API for embedded and future standalone modes |
+| `openshell-supervisor-network::proxy` | CONNECT, forward HTTP, local route dispatch, destination validation, denial rendering | Split into adapters, authorization, destination, relay selection, and adapter response rendering |
+| `openshell-supervisor-network::opa` | Policy engine and Rego queries | Return deterministic `EgressDecision` data instead of separate policy and endpoint lookups |
+| `openshell-supervisor-network::l7` | REST, GraphQL, JSON-RPC, MCP, WebSocket, inference helpers, TLS, token grants | Keep as protocol/relay implementation behind shared relay boundaries |
+| `openshell-supervisor-network::policy_local` | `policy.local` state and routes | Model as a local adapter with explicit limits and proposal/wait behavior |
+| `openshell-supervisor-middleware` | Middleware registry, built-ins, service contract, and chain execution | Treat as a relay hook dependency selected by `EgressDecision`, not as adapter-specific policy logic |
+| `openshell-supervisor-process::netns` | nftables bypass rules and namespace helpers | Remain owner of bypass enforcement; coordinate future capture rules with network proxy mappings |
+| `openshell-supervisor-process::bypass_monitor` | nftables LOG parsing and OCSF bypass telemetry | Remain telemetry producer for bypass violations |
+| `openshell-core::secrets` and provider credential state | Static placeholder sources and dynamic credential metadata | Feed credential injection plans; do not leak secrets into decision logs |
+
+## Policy DNS And Resolved TCP State
+
+Policy DNS is query-driven rather than a static `/etc/hosts` snapshot.
+
+1. Policy load registers eligible native TCP endpoint names.
+2. Userland performs a DNS lookup.
+3. Policy DNS checks whether the normalized name matches an endpoint whose
+ transport and protocol contract enables native TCP through policy DNS in the
+ current policy generation.
+4. An ineligible name receives a local policy-denial DNS response without an
+ upstream query.
+5. Policy DNS resolves an eligible name through trusted upstream DNS and
+ filters every answer through endpoint metadata and SSRF controls.
+6. The adapter allocates a supervisor-owned synthetic IP and creates an active
+ mapping containing the synthetic IP, normalized name, endpoint identifier,
+ allowed ports, validated real addresses, policy generation, distinct DNS
+ mapping generation, opaque mapping ID, and expiration.
+7. The adapter publishes the mapping and capture state atomically before
+ returning the synthetic IP to userland with a bounded TTL.
+8. Userland later calls `connect(synthetic_ip:port)`.
+9. Transparent TCP recovers the synthetic original destination and requires an
+ unexpired exact mapping whose allowed ports contain the requested port.
+10. Normal egress authorization and relay selection run against a policy
+ generation consistent with the mapping contract.
+11. The connector dials only a real address pinned in that mapping. It does not
+ re-resolve the name independently at connect time.
+
+The resolved endpoint store is active state produced by policy-eligible lookups
+and consumed by transparent TCP connects. Policy generation and DNS mapping
+generation are separate values: a DNS refresh can replace mappings without a
+policy reload, while a policy reload can invalidate mappings whose endpoint
+contract is no longer current. A captured connection with no mapping, a stale
+mapping, or a mismatched endpoint/port fails closed. An unrelated bare-IP
+connection cannot inherit a policy-DNS authorization merely because it targets
+a real IP present in the mapping store. Synthetic IPs are correlation handles,
+not upstream destinations, and must never be routed directly or reassigned
+while a stale answer could still refer to the prior mapping.
+
+The mapping is sandbox-scoped rather than process-scoped. Process identity is
+looked up and evaluated independently when the captured TCP connection is
+authorized. It is not used to join DNS and TCP because name resolution may be
+cached, delegated to a resolver helper, or consumed by a different process, and
+multiple names resolved by one process may share a real address and port.
+
+## nftables Boundary
+
+Current main uses nftables, not iptables, for sandbox network bypass
+enforcement. The installed `inet` table accepts traffic to the sandbox proxy,
+loopback, and established/related flows, then rejects and optionally logs other
+TCP/UDP traffic. The bypass monitor reads those log lines and emits OCSF
+network and detection events.
+
+Transparent TCP capture builds on this same nftables substrate in a later
+feature phase:
+
+- capture rules run before the generic bypass reject rules;
+- capture rules are scoped to active synthetic-IP and allowed-port mappings;
+- mapping and capture-rule updates are atomic from the adapter's perspective;
+- direct external DNS remains blocked; policy DNS is the sandbox resolver, and
+ DNS-over-HTTPS remains ordinary policy-controlled HTTPS egress;
+- reject/log rules remain the fallback for unmatched TCP/UDP egress;
+- VM or Podman driver nftables rules are infrastructure NAT/isolation and are
+ not the proxy policy enforcement point.
+
+The initial CONNECT/forward refactor does not change the installed table. This
+section defines the consumer contract that the shared adapter and decision
+boundaries must support when transparent capture lands.
+
+## Endpoint Selection And OPA
+
+Today the matched policy name, L7 candidates, first TLS/`allowed_ips` endpoint,
+and exact-declared-host signal are selected through independent rules. OPA/Rego
+should return policy and endpoint metadata through one deterministic
+authorization result. It should not let those fields describe different
+matches.
+
+Two acceptable approaches:
+
+- Reject overlapping endpoint metadata at load or merge time.
+- Define a single deterministic precedence key and use it for both policy name
+ and endpoint metadata.
+
+Endpoint metadata query failures should fail closed when metadata is required
+for the selected endpoint. They should not silently downgrade to L4 behavior.
+The top-level decision generation must also match every policy-derived field;
+reload during materialization yields a stale decision instead of mixing
+generations.
+
+This semantic cutover is separate from introducing the Rust types. The new
+query first runs in shadow mode beside the legacy queries, records audit-safe
+mismatches through internal telemetry, and preserves legacy enforcement. After
+the precedence rule is accepted and mismatch cases are understood, a dedicated
+change switches the authoritative result and retains the legacy evaluator long
+enough for immediate rollback.
+
+Provider-derived policies use a reserved rule-name namespace. The gateway and
+sandbox sync should prevent user-authored `_provider_*` rules, and
+`policy.local` proposal surfaces should not expose provider-derived rules as
+editable user policy. `EgressDecision` should still identify provider-derived
+matches for logging and debugging.
+
+## Credential Injection Boundary
+
+Credential injection belongs in the HTTP/WebSocket relay after policy allow and
+supervisor middleware, and before upstream write.
+
+1. Authorization selects the endpoint and computes a credential injection plan.
+2. Supervisor middleware runs on the admitted request before credentials are
+ visible.
+3. If middleware replaces the body, the relay re-parses body-dependent
+ protocol inputs and re-evaluates request policy.
+4. The HTTP relay resolves credentials only when it still has an allowed
+ request under the endpoint's enforcement mode.
+5. Static placeholder values are resolved and redacted from logs.
+6. Endpoint-bound token grants obtain or reuse a dynamic access token.
+7. The final upstream request or WebSocket frame is rewritten immediately
+ before write.
+
+Both L4-only HTTP and HTTP-inspected paths can inject credentials. The
+difference is whether REST, GraphQL, or WebSocket policy is evaluated before
+the rewrite.
+
+Credential rewrite slots should be explicit:
+
+- request target, query values, and headers for HTTP-family traffic;
+- REST request bodies only when `request_body_credential_rewrite` is enabled;
+- client-to-server WebSocket text frames only when
+ `websocket_credential_rewrite` is enabled;
+- GraphQL-over-WebSocket connection/control messages when they are carried in
+ text frames and the endpoint enables the WebSocket rewrite path;
+- token grant headers for endpoint-bound provider credentials.
+
+Request-body rewrite is REST-only. It should buffer bounded UTF-8 textual
+bodies, including JSON, form-url-encoded, and `text/*`, recompute
+`Content-Length`, preserve unsupported bodies that contain no reserved
+credential markers, and fail closed when a reserved placeholder cannot be
+resolved safely. Binary WebSocket frames are not rewritten.
+
+Token grants are dynamic credential injection. They use provider metadata to
+request a SPIFFE JWT-SVID, exchange it for an OAuth2 access token, cache the
+token, and inject either an `Authorization: Bearer` header or a configured
+custom header. Token grant failures should return a local relay error and must
+not forward the request upstream.
+
+Middleware-transformed content should be treated as untrusted input from a
+credential perspective. External middleware must not receive OpenShell-managed
+credentials, and it should not be able to synthesize new reserved credential
+placeholders that OpenShell later resolves into secrets. Unless a future hook
+is explicitly built-in-only and credential-capable, the relay should fail
+closed or strip newly introduced reserved placeholders before static
+placeholder rewrite and token grant injection.
+
+## Supervisor Middleware Boundary
+
+Supervisor middleware is a typed relay hook, not a replacement for protocol
+framing. The relay or protocol processor must first parse enough structure to
+construct the operation-specific middleware input.
+
+For v1, the operation is `HTTP_REQUEST / PRE_CREDENTIALS`:
+
+1. Network policy, destination validation, and request policy admit the
+ request.
+2. The HTTP relay selects the middleware chain from the request processing
+ plan.
+3. The relay buffers the request body within the smallest selected stage limit.
+4. The chain evaluates in deterministic order.
+5. A deny short-circuits before credential injection or upstream write.
+6. An allow can replace the request body, add approved headers, emit findings,
+ and pass metadata forward.
+7. When the body changes, the relay re-parses and re-evaluates body-dependent
+ request policy inputs.
+8. The transformed request enters credential injection and upstream write only
+ after that re-evaluation admits it under the endpoint's enforcement mode.
+
+The re-evaluation uses the original request method, path, and query because v1
+middleware cannot mutate them. It re-derives the GraphQL operation, JSON-RPC
+method, and MCP method or tool name from the transformed body. A policy mismatch
+preserves the endpoint's audit or enforce behavior. A malformed or
+unclassifiable transformed protocol body fails closed in both modes because the
+relay can no longer prove which operation it would forward.
+
+Middleware selection is independent from the matched endpoint policy. It is a
+request processing plan selected by admitted destination host, order, and
+binding metadata. The decision boundary should materialize it with the same
+policy generation used for endpoint selection so a long-lived tunnel cannot mix
+old endpoint policy with a new middleware registry.
+
+V1 middleware can inspect WebSocket upgrade requests because those are HTTP
+requests. It does not inspect post-upgrade WebSocket frames. A future frame
+hook should be a separate operation such as `WEBSOCKET_MESSAGE /
+BEFORE_FORWARD` owned by the WebSocket relay.
+
+## Protocol Processor Boundary
+
+Protocol processors operate on streams owned by the relay.
+
+- HTTP parsing converts bytes into request metadata, evaluates request policy,
+ runs the `HTTP_REQUEST / PRE_CREDENTIALS` middleware hook when configured,
+ and loops for keep-alive or pipelined requests.
+- JSON-RPC and MCP processing are HTTP L7 processors: they parse bounded
+ JSON-RPC-over-HTTP request bodies after HTTP parsing and before upstream
+ forwarding. Generic JSON-RPC policy matches methods; MCP policy can also
+ match `tools/call` tool names.
+- WebSocket parsing starts only after an allowed HTTP upgrade. It validates the
+ handshake/frame stream and owns client-to-server text-frame inspection when
+ credential rewrite, transport message policy, GraphQL-over-WebSocket policy,
+ or compression handling is configured.
+- Native TCP protocol processors read client and upstream streams as needed and
+ own their message loop.
+- A protocol processor can deny before dialing, dial for a server handshake, or
+ keep evaluating commands or queries throughout the session.
+- A protocol processor may be in-tree, middleware-backed, or a hybrid where
+ in-tree framing exposes typed middleware operations for content evaluation.
+
+HTTP and WebSocket relays receive the generation-pinned request evaluator
+because request policy must continue throughout long-lived sessions. No
+processor rematerializes endpoint, TLS, allowed-IP, credential, or middleware
+selection. This avoids a separate dial-strategy enum: each processor knows
+which protocol milestone is sufficient to call the validated connector.
+
+## Local Service Adapter Boundary
+
+Local services are network surfaces but not normal external egress:
+
+- `inference.local` terminates local client traffic, validates known inference
+ routes, strips caller auth, injects provider routing/auth, and applies
+ streaming or buffered limits based on route type.
+- `policy.local` serves policy snapshots, denial summaries, proposal
+ submission, and proposal wait. It should never expose secrets or provider
+ rules as editable policy.
+- Metadata loopback serves provider metadata credentials for SDKs that bypass
+ HTTP proxy variables. It should use the same provider credential state and
+ redaction discipline as other credential paths.
+
+These adapters may call gateway APIs or local credential helpers, but they
+should not bypass policy and credential invariants that apply to external
+egress.
+
+Issue [#1633](https://github.com/NVIDIA/OpenShell/issues/1633) is a prospective
+consumer of these boundaries, not a feature defined by this RFC. A
+policy-declared host-local endpoint should use an explicit local-routing adapter
+or destination mode; it must not become a general loopback exemption in the
+external destination validator. Its feature design still needs to choose the
+policy surface (reserved hostname versus endpoint flag), define authorization
+before the supervisor connects to host loopback, and specify driver/runtime
+capabilities. That work can reuse `EgressIntent`, adapter-specific responses,
+and the unopened connector boundary without changing this RFC's compatibility
+milestone.
+
+## Timeout And Resource Ownership
+
+| Owner | Resource |
+|-------|----------|
+| Adapter | Client-side parse timeout and adapter-specific deny response |
+| Authorization | OPA deadline and policy evaluation telemetry |
+| Destination validator | DNS timeout, allowed IP checks, SSRF checks, control-plane port checks |
+| TLS terminator | Client TLS handshake timeout and certificate selection |
+| HTTP relay | Per-request read/write deadlines, body caps, request-body rewrite caps, upstream reuse |
+| WebSocket relay | Upgrade validation, frame limits, text-frame rewrite, compression limits, message policy |
+| TCP relay | Byte-copy idle timeout and half-close handling |
+| Protocol processor | Protocol message timeouts, middleware hook timeouts, and processor-specific limits |
+| Local service adapter | Local route body limits, response caps, gateway call timeout |
+| Token grant resolver | SPIFFE Workload API timeout, token endpoint timeout, cache TTL |
+| Middleware runner | Service timeout, body cap, failure policy, registry generation |
+
+Timeouts should be recorded in telemetry at the owner boundary that can explain
+the failure.
diff --git a/scripts/lint-mermaid/package-lock.json b/scripts/lint-mermaid/package-lock.json
index a28a4f295..1fa73b21e 100644
--- a/scripts/lint-mermaid/package-lock.json
+++ b/scripts/lint-mermaid/package-lock.json
@@ -44,42 +44,10 @@
"integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==",
"license": "MIT"
},
- "node_modules/@chevrotain/cst-dts-gen": {
- "version": "12.0.0",
- "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-12.0.0.tgz",
- "integrity": "sha512-fSL4KXjTl7cDgf0B5Rip9Q05BOrYvkJV/RrBTE/bKDN096E4hN/ySpcBK5B24T76dlQ2i32Zc3PAE27jFnFrKg==",
- "license": "Apache-2.0",
- "dependencies": {
- "@chevrotain/gast": "12.0.0",
- "@chevrotain/types": "12.0.0"
- }
- },
- "node_modules/@chevrotain/gast": {
- "version": "12.0.0",
- "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-12.0.0.tgz",
- "integrity": "sha512-1ne/m3XsIT8aEdrvT33so0GUC+wkctpUPK6zU9IlOyJLUbR0rg4G7ZiApiJbggpgPir9ERy3FRjT6T7lpgetnQ==",
- "license": "Apache-2.0",
- "dependencies": {
- "@chevrotain/types": "12.0.0"
- }
- },
- "node_modules/@chevrotain/regexp-to-ast": {
- "version": "12.0.0",
- "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-12.0.0.tgz",
- "integrity": "sha512-p+EW9MaJwgaHguhoqwOtx/FwuGr+DnNn857sXWOi/mClXIkPGl3rn7hGNWvo31HA3vyeQxjqe+H36yZJwYU8cA==",
- "license": "Apache-2.0"
- },
"node_modules/@chevrotain/types": {
- "version": "12.0.0",
- "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-12.0.0.tgz",
- "integrity": "sha512-S+04vjFQKeuYw0/eW3U52LkAHQsB1ASxsPGsLPUyQgrZ2iNNibQrsidruDzjEX2JYfespXMG0eZmXlhA6z7nWA==",
- "license": "Apache-2.0"
- },
- "node_modules/@chevrotain/utils": {
- "version": "12.0.0",
- "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-12.0.0.tgz",
- "integrity": "sha512-lB59uJoaGIfOOL9knQqQRfhl9g7x8/wqFkp13zTdkRu1huG9kg6IJs1O8hqj9rs6h7orGxHJUKb+mX3rPbWGhA==",
- "license": "Apache-2.0"
+ "version": "11.1.2",
+ "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz",
+ "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw=="
},
"node_modules/@csstools/color-helpers": {
"version": "5.1.0",
@@ -209,12 +177,11 @@
}
},
"node_modules/@mermaid-js/parser": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.1.0.tgz",
- "integrity": "sha512-gxK9ZX2+Fex5zu8LhRQoMeMPEHbc73UKZ0FQ54YrQtUxE1VVhMwzeNtKRPAu5aXks4FasbMe4xB4bWrmq6Jlxw==",
- "license": "MIT",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.2.0.tgz",
+ "integrity": "sha512-oYPyv8A4As1yH5Bx+04iQEQxXuIQDe0GKCNSRgao6z8AM9jixXIfP0vsppRLvGf+nKIOb9/LdpWA4YuJiVvESA==",
"dependencies": {
- "langium": "^4.0.0"
+ "@chevrotain/types": "~11.1.2"
}
},
"node_modules/@types/d3": {
@@ -533,34 +500,6 @@
"node": ">= 0.4"
}
},
- "node_modules/chevrotain": {
- "version": "12.0.0",
- "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-12.0.0.tgz",
- "integrity": "sha512-csJvb+6kEiQaqo1woTdSAuOWdN0WTLIydkKrBnS+V5gZz0oqBrp4kQ35519QgK6TpBThiG3V1vNSHlIkv4AglQ==",
- "license": "Apache-2.0",
- "dependencies": {
- "@chevrotain/cst-dts-gen": "12.0.0",
- "@chevrotain/gast": "12.0.0",
- "@chevrotain/regexp-to-ast": "12.0.0",
- "@chevrotain/types": "12.0.0",
- "@chevrotain/utils": "12.0.0"
- },
- "engines": {
- "node": ">=22.0.0"
- }
- },
- "node_modules/chevrotain-allstar": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.4.1.tgz",
- "integrity": "sha512-PvVJm3oGqrveUVW2Vt/eZGeiAIsJszYweUcYwcskg9e+IubNYKKD+rHHem7A6XVO22eDAL+inxNIGAzZ/VIWlA==",
- "license": "MIT",
- "dependencies": {
- "lodash-es": "^4.17.21"
- },
- "peerDependencies": {
- "chevrotain": "^12.0.0"
- }
- },
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -617,10 +556,9 @@
"license": "MIT"
},
"node_modules/cytoscape": {
- "version": "3.33.2",
- "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.2.tgz",
- "integrity": "sha512-sj4HXd3DokGhzZAdjDejGvTPLqlt84vNFN8m7bGsOzDY5DyVcxIb2ejIXat2Iy7HxWhdT/N1oKyheJ5YdpsGuw==",
- "license": "MIT",
+ "version": "3.34.0",
+ "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.34.0.tgz",
+ "integrity": "sha512-62rNSrioXw93uliKFBwjukeQyeWwH2PqDrTac31r2P6464u3AUvTk0xS4LVvT251g7IgkFunrI48ZEZGjywSOg==",
"engines": {
"node": ">=0.10"
}
@@ -1255,17 +1193,21 @@
"node": ">= 0.4"
}
},
+ "node_modules/es-toolkit": {
+ "version": "1.50.0",
+ "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.50.0.tgz",
+ "integrity": "sha512-OyZKhUVvEep9ITEiwHn8GKnMRQIVqoSIX7WnRbkWgJkllCujilqP2rD0u979tkl8wqyc8ICwlc1UBVv/Sl1G6w=="
+ },
"node_modules/form-data": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
- "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
- "license": "MIT",
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz",
+ "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
- "hasown": "^2.0.2",
- "mime-types": "^2.1.12"
+ "hasown": "^2.0.4",
+ "mime-types": "^2.1.35"
},
"engines": {
"node": ">= 6"
@@ -1363,10 +1305,9 @@
}
},
"node_modules/hasown": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz",
- "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==",
- "license": "MIT",
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz",
+ "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==",
"dependencies": {
"function-bind": "^1.1.2"
},
@@ -1509,24 +1450,6 @@
"resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz",
"integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw=="
},
- "node_modules/langium": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/langium/-/langium-4.2.2.tgz",
- "integrity": "sha512-JUshTRAfHI4/MF9dH2WupvjSXyn8JBuUEWazB8ZVJUtXutT0doDlAv1XKbZ1Pb5sMexa8FF4CFBc0iiul7gbUQ==",
- "license": "MIT",
- "dependencies": {
- "@chevrotain/regexp-to-ast": "~12.0.0",
- "chevrotain": "~12.0.0",
- "chevrotain-allstar": "~0.4.1",
- "vscode-languageserver": "~9.0.1",
- "vscode-languageserver-textdocument": "~1.0.11",
- "vscode-uri": "~3.1.0"
- },
- "engines": {
- "node": ">=20.10.0",
- "npm": ">=10.2.3"
- }
- },
"node_modules/layout-base": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz",
@@ -1567,32 +1490,31 @@
}
},
"node_modules/mermaid": {
- "version": "11.14.0",
- "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.14.0.tgz",
- "integrity": "sha512-GSGloRsBs+JINmmhl0JDwjpuezCsHB4WGI4NASHxL3fHo3o/BRXTxhDLKnln8/Q0lRFRyDdEjmk1/d5Sn1Xz8g==",
- "license": "MIT",
+ "version": "11.16.0",
+ "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.16.0.tgz",
+ "integrity": "sha512-Zvm3kbstgdpvIJPPItlL7fppIZ3kibvc1oZIGxdvk9t6UFz6flv+Jw7FtRGKwfcI8OckmH04LqG6LlS6X4B1pA==",
"dependencies": {
- "@braintree/sanitize-url": "^7.1.1",
+ "@braintree/sanitize-url": "^7.1.2",
"@iconify/utils": "^3.0.2",
- "@mermaid-js/parser": "^1.1.0",
+ "@mermaid-js/parser": "^1.2.0",
"@types/d3": "^7.4.3",
"@upsetjs/venn.js": "^2.0.0",
- "cytoscape": "^3.33.1",
+ "cytoscape": "^3.33.3",
"cytoscape-cose-bilkent": "^4.1.0",
"cytoscape-fcose": "^2.2.0",
"d3": "^7.9.0",
"d3-sankey": "^0.12.3",
"dagre-d3-es": "7.0.14",
- "dayjs": "^1.11.19",
- "dompurify": "^3.3.1",
- "katex": "^0.16.25",
+ "dayjs": "^1.11.20",
+ "dompurify": "^3.3.3",
+ "es-toolkit": "^1.45.1",
+ "katex": "^0.16.45",
"khroma": "^2.1.0",
- "lodash-es": "^4.17.23",
"marked": "^16.3.0",
"roughjs": "^4.6.6",
"stylis": "^4.3.6",
"ts-dedent": "^2.2.0",
- "uuid": "^11.1.0"
+ "uuid": "^11.1.0 || ^12 || ^13 || ^14.0.0"
}
},
"node_modules/mime-db": {
@@ -1833,67 +1755,17 @@
"license": "MIT"
},
"node_modules/uuid": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",
- "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==",
+ "version": "14.0.1",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.1.tgz",
+ "integrity": "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
- "license": "MIT",
"bin": {
- "uuid": "dist/esm/bin/uuid"
+ "uuid": "dist-node/bin/uuid"
}
},
- "node_modules/vscode-jsonrpc": {
- "version": "8.2.0",
- "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz",
- "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==",
- "license": "MIT",
- "engines": {
- "node": ">=14.0.0"
- }
- },
- "node_modules/vscode-languageserver": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz",
- "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==",
- "license": "MIT",
- "dependencies": {
- "vscode-languageserver-protocol": "3.17.5"
- },
- "bin": {
- "installServerIntoExtension": "bin/installServerIntoExtension"
- }
- },
- "node_modules/vscode-languageserver-protocol": {
- "version": "3.17.5",
- "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz",
- "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==",
- "license": "MIT",
- "dependencies": {
- "vscode-jsonrpc": "8.2.0",
- "vscode-languageserver-types": "3.17.5"
- }
- },
- "node_modules/vscode-languageserver-textdocument": {
- "version": "1.0.12",
- "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz",
- "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==",
- "license": "MIT"
- },
- "node_modules/vscode-languageserver-types": {
- "version": "3.17.5",
- "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz",
- "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==",
- "license": "MIT"
- },
- "node_modules/vscode-uri": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz",
- "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==",
- "license": "MIT"
- },
"node_modules/w3c-xmlserializer": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
@@ -1951,10 +1823,9 @@
}
},
"node_modules/ws": {
- "version": "8.20.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz",
- "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==",
- "license": "MIT",
+ "version": "8.21.2",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.2.tgz",
+ "integrity": "sha512-54dMVAo4WIe6SKy3vBgN+9bJZqqQ8IMRevAkOLQALhi49qkkQDQfWdAZ8KQlXiEabw88ARXXdUrlvtbKQX+aKw==",
"engines": {
"node": ">=10.0.0"
},
diff --git a/sdk/go/buf.gen.yaml b/sdk/go/buf.gen.yaml
new file mode 100644
index 000000000..40e90d15d
--- /dev/null
+++ b/sdk/go/buf.gen.yaml
@@ -0,0 +1,36 @@
+# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0
+
+# Code generation for the Go SDK. The proto module boundary and validation
+# policy live in the repo-level buf.yaml; this template only drives generation.
+# buf compiles the module with its own compiler and runs protoc-gen-go /
+# protoc-gen-go-grpc from mise-managed binaries. Limited to the client-surface
+# closure (openshell, datamodel, sandbox, options); well-known types resolve
+# through google.golang.org/protobuf and are not generated.
+version: v2
+
+inputs:
+ - directory: ../../proto
+ paths:
+ - ../../proto/openshell.proto
+ - ../../proto/datamodel.proto
+ - ../../proto/sandbox.proto
+ - ../../proto/options.proto
+
+plugins:
+ - local: protoc-gen-go
+ out: .
+ opt:
+ - module=github.com/NVIDIA/OpenShell/sdk/go
+ - Mopenshell.proto=github.com/NVIDIA/OpenShell/sdk/go/proto/openshellv1
+ - Mdatamodel.proto=github.com/NVIDIA/OpenShell/sdk/go/proto/datamodelv1
+ - Msandbox.proto=github.com/NVIDIA/OpenShell/sdk/go/proto/sandboxv1
+ - Moptions.proto=github.com/NVIDIA/OpenShell/sdk/go/proto/optionsv1
+ - local: protoc-gen-go-grpc
+ out: .
+ opt:
+ - module=github.com/NVIDIA/OpenShell/sdk/go
+ - Mopenshell.proto=github.com/NVIDIA/OpenShell/sdk/go/proto/openshellv1
+ - Mdatamodel.proto=github.com/NVIDIA/OpenShell/sdk/go/proto/datamodelv1
+ - Msandbox.proto=github.com/NVIDIA/OpenShell/sdk/go/proto/sandboxv1
+ - Moptions.proto=github.com/NVIDIA/OpenShell/sdk/go/proto/optionsv1
diff --git a/sdk/go/go.mod b/sdk/go/go.mod
new file mode 100644
index 000000000..4a7c16017
--- /dev/null
+++ b/sdk/go/go.mod
@@ -0,0 +1,22 @@
+module github.com/NVIDIA/OpenShell/sdk/go
+
+go 1.24.0
+
+toolchain go1.26.4
+
+require (
+ github.com/stretchr/testify v1.11.1
+ golang.org/x/oauth2 v0.35.0
+ google.golang.org/grpc v1.80.0
+ google.golang.org/protobuf v1.36.11
+)
+
+require (
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
+ golang.org/x/net v0.49.0 // indirect
+ golang.org/x/sys v0.41.0 // indirect
+ golang.org/x/text v0.33.0 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/sdk/go/go.sum b/sdk/go/go.sum
new file mode 100644
index 000000000..5b0f5d005
--- /dev/null
+++ b/sdk/go/go.sum
@@ -0,0 +1,50 @@
+github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
+github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
+github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
+github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
+github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
+go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
+go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
+go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
+go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
+go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
+go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
+go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
+go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
+go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
+go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
+go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
+golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
+golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
+golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=
+golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
+golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
+golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
+golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
+gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
+gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 h1:sNrWoksmOyF5bvJUcnmbeAmQi8baNhqg5IWaI3llQqU=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
+google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
+google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
+google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
+google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/sdk/go/openshell/v1/auth.go b/sdk/go/openshell/v1/auth.go
new file mode 100644
index 000000000..95a7838f0
--- /dev/null
+++ b/sdk/go/openshell/v1/auth.go
@@ -0,0 +1,48 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+)
+
+// AuthProvider supplies per-RPC credentials. It implements the
+// grpc credentials.PerRPCCredentials interface.
+type AuthProvider = types.AuthProvider
+
+type noAuth struct{}
+
+// NoAuth returns an AuthProvider that sends no credentials.
+func NoAuth() AuthProvider {
+ return &noAuth{}
+}
+
+func (n *noAuth) GetRequestMetadata(_ context.Context, _ ...string) (map[string]string, error) {
+ return nil, nil
+}
+
+func (n *noAuth) RequireTransportSecurity() bool {
+ return false
+}
+
+type staticToken struct {
+ token string
+}
+
+// StaticToken returns an AuthProvider that sends a fixed Bearer token.
+func StaticToken(token string) AuthProvider {
+ return &staticToken{token: token}
+}
+
+func (s *staticToken) GetRequestMetadata(_ context.Context, _ ...string) (map[string]string, error) {
+ return map[string]string{
+ "authorization": "Bearer " + s.token,
+ }, nil
+}
+
+func (s *staticToken) RequireTransportSecurity() bool {
+ return true
+}
diff --git a/sdk/go/openshell/v1/auth_extra.go b/sdk/go/openshell/v1/auth_extra.go
new file mode 100644
index 000000000..21a9e9e2c
--- /dev/null
+++ b/sdk/go/openshell/v1/auth_extra.go
@@ -0,0 +1,80 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+ "errors"
+ "maps"
+ "strings"
+
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+)
+
+// extraHeadersAuth wraps a base AuthProvider with additional static headers
+// that are merged into every GetRequestMetadata call. Extra headers take
+// precedence over base headers on key collision (case-insensitive).
+type extraHeadersAuth struct {
+ base types.AuthProvider
+ headers map[string]string // keys already lowercase, empty values filtered out
+}
+
+// WithExtraHeaders wraps base with additional per-RPC headers. Keys are
+// normalized to lowercase per HTTP/2 (RFC 9113). Empty-string values are
+// silently dropped. The headers map is deep-copied at construction time,
+// so later mutations to the caller's map have no effect.
+//
+// Returns an error if base is nil or if headers is nil, empty, or contains
+// only empty-string values.
+func WithExtraHeaders(base AuthProvider, headers map[string]string) (AuthProvider, error) {
+ if base == nil {
+ return nil, errors.New("base auth provider must not be nil")
+ }
+ if len(headers) == 0 {
+ return nil, errors.New("headers must not be nil or empty")
+ }
+
+ // Deep-copy and normalize: lowercase keys, skip empty values.
+ normalized := make(map[string]string, len(headers))
+ for k, v := range headers {
+ if v == "" {
+ continue
+ }
+ normalized[strings.ToLower(k)] = v
+ }
+
+ if len(normalized) == 0 {
+ return nil, errors.New("headers must contain at least one non-empty value")
+ }
+
+ return &extraHeadersAuth{
+ base: base,
+ headers: normalized,
+ }, nil
+}
+
+// GetRequestMetadata merges base metadata with extra headers. Extra headers
+// win on key collision because they are applied after the base metadata.
+func (e *extraHeadersAuth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
+ baseMD, err := e.base.GetRequestMetadata(ctx, uri...)
+ if err != nil {
+ return nil, err
+ }
+
+ // Start with base metadata (may be nil for NoAuth).
+ // Normalize base keys to lowercase for case-insensitive collision.
+ merged := make(map[string]string, len(baseMD)+len(e.headers))
+ for k, v := range baseMD {
+ merged[strings.ToLower(k)] = v
+ }
+ // Extra headers overwrite base on collision.
+ maps.Copy(merged, e.headers)
+
+ return merged, nil
+}
+
+// RequireTransportSecurity delegates to the base auth provider.
+func (e *extraHeadersAuth) RequireTransportSecurity() bool {
+ return e.base.RequireTransportSecurity()
+}
diff --git a/sdk/go/openshell/v1/auth_extra_test.go b/sdk/go/openshell/v1/auth_extra_test.go
new file mode 100644
index 000000000..09bd4d33d
--- /dev/null
+++ b/sdk/go/openshell/v1/auth_extra_test.go
@@ -0,0 +1,177 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+ "errors"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestWithExtraHeaders_NilBase(t *testing.T) {
+ _, err := WithExtraHeaders(nil, map[string]string{"x-key": "val"})
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "base")
+}
+
+func TestWithExtraHeaders_NilHeaders(t *testing.T) {
+ _, err := WithExtraHeaders(NoAuth(), nil)
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "headers")
+}
+
+func TestWithExtraHeaders_EmptyHeaders(t *testing.T) {
+ _, err := WithExtraHeaders(NoAuth(), map[string]string{})
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "headers")
+}
+
+func TestWithExtraHeaders_AllEmptyValues(t *testing.T) {
+ // All values are empty strings, so after filtering, headers map is empty.
+ _, err := WithExtraHeaders(NoAuth(), map[string]string{"x-key": ""})
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "headers")
+}
+
+func TestWithExtraHeaders_MergesWithBase(t *testing.T) {
+ base := StaticToken("my-token")
+ auth, err := WithExtraHeaders(base, map[string]string{
+ "x-proxy-key": "proxy-secret",
+ "x-tenant-id": "acme-corp",
+ })
+ require.NoError(t, err)
+
+ md, err := auth.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+
+ assert.Equal(t, "Bearer my-token", md["authorization"])
+ assert.Equal(t, "proxy-secret", md["x-proxy-key"])
+ assert.Equal(t, "acme-corp", md["x-tenant-id"])
+}
+
+func TestWithExtraHeaders_ExtraPrecedenceOnCollision(t *testing.T) {
+ base := StaticToken("my-token")
+ auth, err := WithExtraHeaders(base, map[string]string{
+ "authorization": "Custom override-token",
+ })
+ require.NoError(t, err)
+
+ md, err := auth.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+
+ // Extra header wins over base.
+ assert.Equal(t, "Custom override-token", md["authorization"])
+}
+
+func TestWithExtraHeaders_CaseInsensitiveCollision(t *testing.T) {
+ base := StaticToken("my-token")
+ // "Authorization" with uppercase should still override "authorization".
+ auth, err := WithExtraHeaders(base, map[string]string{
+ "Authorization": "Custom override-token",
+ })
+ require.NoError(t, err)
+
+ md, err := auth.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+
+ assert.Equal(t, "Custom override-token", md["authorization"])
+}
+
+func TestWithExtraHeaders_EmptyValueSkipped(t *testing.T) {
+ base := StaticToken("my-token")
+ auth, err := WithExtraHeaders(base, map[string]string{
+ "x-proxy-key": "proxy-secret",
+ "x-empty": "", // Should be silently skipped.
+ })
+ require.NoError(t, err)
+
+ md, err := auth.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+
+ assert.Equal(t, "proxy-secret", md["x-proxy-key"])
+ _, hasEmpty := md["x-empty"]
+ assert.False(t, hasEmpty, "empty-string header values should be skipped")
+}
+
+func TestWithExtraHeaders_RequireTransportSecurity_Delegates(t *testing.T) {
+ tests := []struct {
+ name string
+ base AuthProvider
+ expected bool
+ }{
+ {
+ name: "delegates to NoAuth (false)",
+ base: NoAuth(),
+ expected: false,
+ },
+ {
+ name: "delegates to StaticToken (true)",
+ base: StaticToken("tok"),
+ expected: true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ auth, err := WithExtraHeaders(tt.base, map[string]string{"x-key": "val"})
+ require.NoError(t, err)
+ assert.Equal(t, tt.expected, auth.RequireTransportSecurity())
+ })
+ }
+}
+
+func TestWithExtraHeaders_WithNoAuth(t *testing.T) {
+ auth, err := WithExtraHeaders(NoAuth(), map[string]string{
+ "x-proxy-key": "proxy-secret",
+ })
+ require.NoError(t, err)
+
+ md, err := auth.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+
+ // NoAuth returns nil metadata, extra headers should still appear.
+ assert.Equal(t, "proxy-secret", md["x-proxy-key"])
+}
+
+func TestWithExtraHeaders_BaseError_Propagated(t *testing.T) {
+ base := &errAuth{err: errors.New("auth failure")}
+ auth, err := WithExtraHeaders(base, map[string]string{"x-key": "val"})
+ require.NoError(t, err)
+
+ _, err = auth.GetRequestMetadata(context.Background())
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "auth failure")
+}
+
+func TestWithExtraHeaders_DeepCopiesHeaders(t *testing.T) {
+ original := map[string]string{
+ "x-key": "original-value",
+ }
+ auth, err := WithExtraHeaders(NoAuth(), original)
+ require.NoError(t, err)
+
+ // Mutate the original map after construction.
+ original["x-key"] = "mutated-value"
+
+ md, err := auth.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+
+ // The wrapper should use the value at construction time, not the mutated value.
+ assert.Equal(t, "original-value", md["x-key"])
+}
+
+// errAuth is a test helper that always returns an error.
+type errAuth struct {
+ err error
+}
+
+func (e *errAuth) GetRequestMetadata(_ context.Context, _ ...string) (map[string]string, error) {
+ return nil, e.err
+}
+
+func (e *errAuth) RequireTransportSecurity() bool {
+ return false
+}
diff --git a/sdk/go/openshell/v1/auth_refresh.go b/sdk/go/openshell/v1/auth_refresh.go
new file mode 100644
index 000000000..a3cf8b583
--- /dev/null
+++ b/sdk/go/openshell/v1/auth_refresh.go
@@ -0,0 +1,137 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+ "errors"
+ "sync"
+ "time"
+
+ "golang.org/x/oauth2"
+
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+)
+
+const defaultLeeway = 10 * time.Second
+
+var errNilTokenSource = errors.New("openshell: TokenSource must not be nil")
+
+// RefreshOption configures the behavior of RefreshableToken.
+type RefreshOption func(*refreshConfig)
+
+type refreshConfig struct {
+ leeway time.Duration
+ logger types.Logger
+}
+
+func defaultRefreshConfig() refreshConfig {
+ return refreshConfig{
+ leeway: defaultLeeway,
+ }
+}
+
+// WithLeeway sets the duration before token expiry at which a proactive
+// refresh is triggered. Default is 10 seconds.
+func WithLeeway(d time.Duration) RefreshOption {
+ return func(c *refreshConfig) {
+ if d < 0 {
+ d = 0
+ }
+ c.leeway = d
+ }
+}
+
+// WithLogger sets the logger used for stale-token fallback warnings.
+// When not set, warnings are silently dropped.
+func WithLogger(l types.Logger) RefreshOption {
+ return func(c *refreshConfig) {
+ c.logger = l
+ }
+}
+
+type refreshableAuth struct {
+ source oauth2.TokenSource
+ mu sync.RWMutex
+ tok *oauth2.Token
+ leeway time.Duration
+ logger types.Logger
+}
+
+func (r *refreshableAuth) isTokenValid() bool {
+ if r.tok == nil {
+ return false
+ }
+ if r.tok.Expiry.IsZero() {
+ return true
+ }
+ return time.Now().Before(r.tok.Expiry.Add(-r.leeway))
+}
+
+func (r *refreshableAuth) GetRequestMetadata(_ context.Context, _ ...string) (map[string]string, error) {
+ // Fast path: RLock, return cached token if valid.
+ r.mu.RLock()
+ if r.isTokenValid() {
+ tok := r.tok.AccessToken
+ r.mu.RUnlock()
+ return map[string]string{"authorization": "Bearer " + tok}, nil
+ }
+ r.mu.RUnlock()
+
+ // Slow path: Lock, re-check, fetch if still stale.
+ r.mu.Lock()
+ defer r.mu.Unlock()
+
+ if r.isTokenValid() {
+ return map[string]string{"authorization": "Bearer " + r.tok.AccessToken}, nil
+ }
+
+ newTok, err := r.source.Token()
+ if err != nil {
+ if r.tok != nil {
+ if r.logger != nil {
+ r.logger.Error(err, "token refresh failed, using cached token")
+ }
+ return map[string]string{"authorization": "Bearer " + r.tok.AccessToken}, nil
+ }
+ return nil, err
+ }
+
+ if newTok == nil {
+ if r.tok != nil {
+ if r.logger != nil {
+ r.logger.Error(errors.New("token source returned nil token"), "token refresh returned nil, using cached token")
+ }
+ return map[string]string{"authorization": "Bearer " + r.tok.AccessToken}, nil
+ }
+ return nil, errors.New("openshell: token source returned nil token")
+ }
+
+ r.tok = newTok
+ return map[string]string{"authorization": "Bearer " + r.tok.AccessToken}, nil
+}
+
+func (r *refreshableAuth) RequireTransportSecurity() bool {
+ return true
+}
+
+// RefreshableToken returns an AuthProvider that caches tokens from src
+// and refreshes them before expiry. Concurrent callers share a single
+// refresh call (coalesced via RWMutex double-checked locking).
+func RefreshableToken(src oauth2.TokenSource, opts ...RefreshOption) (AuthProvider, error) {
+ if src == nil {
+ return nil, errNilTokenSource
+ }
+
+ cfg := defaultRefreshConfig()
+ for _, o := range opts {
+ o(&cfg)
+ }
+
+ return &refreshableAuth{
+ source: src,
+ leeway: cfg.leeway,
+ logger: cfg.logger,
+ }, nil
+}
diff --git a/sdk/go/openshell/v1/auth_refresh_test.go b/sdk/go/openshell/v1/auth_refresh_test.go
new file mode 100644
index 000000000..451e8e63d
--- /dev/null
+++ b/sdk/go/openshell/v1/auth_refresh_test.go
@@ -0,0 +1,373 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+ "fmt"
+ "sync"
+ "sync/atomic"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "golang.org/x/oauth2"
+)
+
+// mockTokenSource implements oauth2.TokenSource for testing.
+type mockTokenSource struct {
+ mu sync.Mutex
+ tokenFunc func() (*oauth2.Token, error)
+ callCount int
+}
+
+func (m *mockTokenSource) Token() (*oauth2.Token, error) {
+ m.mu.Lock()
+ m.callCount++
+ m.mu.Unlock()
+ return m.tokenFunc()
+}
+
+func (m *mockTokenSource) calls() int {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ return m.callCount
+}
+
+// --- Phase 2 tests: constructor validation ---
+
+func TestRefreshableToken_NilSource(t *testing.T) {
+ _, err := RefreshableToken(nil)
+ require.Error(t, err)
+ assert.Equal(t, "openshell: TokenSource must not be nil", err.Error())
+}
+
+func TestRefreshableToken_ValidSource(t *testing.T) {
+ src := &mockTokenSource{
+ tokenFunc: func() (*oauth2.Token, error) {
+ return &oauth2.Token{AccessToken: "tok", Expiry: time.Now().Add(time.Hour)}, nil
+ },
+ }
+ provider, err := RefreshableToken(src)
+ require.NoError(t, err)
+ assert.NotNil(t, provider)
+}
+
+// --- Phase 3 / US1 tests: automatic token refresh ---
+
+func TestGetRequestMetadata_FirstCallFetchesToken(t *testing.T) {
+ src := &mockTokenSource{
+ tokenFunc: func() (*oauth2.Token, error) {
+ return &oauth2.Token{AccessToken: "fresh-token", Expiry: time.Now().Add(time.Hour)}, nil
+ },
+ }
+ provider, err := RefreshableToken(src)
+ require.NoError(t, err)
+
+ md, err := provider.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+ assert.Equal(t, "Bearer fresh-token", md["authorization"])
+ assert.Equal(t, 1, src.calls())
+}
+
+func TestGetRequestMetadata_CachedTokenNoExtraCall(t *testing.T) {
+ src := &mockTokenSource{
+ tokenFunc: func() (*oauth2.Token, error) {
+ return &oauth2.Token{AccessToken: "cached-token", Expiry: time.Now().Add(time.Hour)}, nil
+ },
+ }
+ provider, err := RefreshableToken(src)
+ require.NoError(t, err)
+
+ _, err = provider.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+
+ md, err := provider.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+ assert.Equal(t, "Bearer cached-token", md["authorization"])
+ assert.Equal(t, 1, src.calls(), "second call should use cache, not invoke TokenSource")
+}
+
+func TestGetRequestMetadata_RefreshesExpiredToken(t *testing.T) {
+ var callNum atomic.Int32
+ src := &mockTokenSource{
+ tokenFunc: func() (*oauth2.Token, error) {
+ n := callNum.Add(1)
+ if n == 1 {
+ return &oauth2.Token{AccessToken: "old", Expiry: time.Now().Add(-time.Minute)}, nil
+ }
+ return &oauth2.Token{AccessToken: "new", Expiry: time.Now().Add(time.Hour)}, nil
+ },
+ }
+ provider, err := RefreshableToken(src, WithLeeway(0))
+ require.NoError(t, err)
+
+ // First call gets the expired token, which is immediately stale.
+ md, err := provider.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+ assert.Equal(t, "Bearer old", md["authorization"])
+
+ // Second call should trigger a refresh since the cached token is expired.
+ md, err = provider.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+ assert.Equal(t, "Bearer new", md["authorization"])
+ assert.Equal(t, 2, src.calls())
+}
+
+func TestGetRequestMetadata_ConcurrentSingleFlight(t *testing.T) {
+ var fetchCount atomic.Int32
+ src := &mockTokenSource{
+ tokenFunc: func() (*oauth2.Token, error) {
+ fetchCount.Add(1)
+ time.Sleep(10 * time.Millisecond) // simulate slow token fetch
+ return &oauth2.Token{AccessToken: "shared-token", Expiry: time.Now().Add(time.Hour)}, nil
+ },
+ }
+ provider, err := RefreshableToken(src)
+ require.NoError(t, err)
+
+ const goroutines = 1000
+ var wg sync.WaitGroup
+ wg.Add(goroutines)
+ results := make([]string, goroutines)
+ errs := make([]error, goroutines)
+
+ for i := range goroutines {
+ go func(idx int) {
+ defer wg.Done()
+ md, e := provider.GetRequestMetadata(context.Background())
+ errs[idx] = e
+ if md != nil {
+ results[idx] = md["authorization"]
+ }
+ }(i)
+ }
+ wg.Wait()
+
+ for i := range goroutines {
+ require.NoError(t, errs[i], "goroutine %d failed", i)
+ assert.Equal(t, "Bearer shared-token", results[i], "goroutine %d got wrong token", i)
+ }
+ assert.Equal(t, int32(1), fetchCount.Load(), "expected exactly 1 TokenSource.Token() call, got %d", fetchCount.Load())
+}
+
+func TestRefreshableAuth_RequireTransportSecurity(t *testing.T) {
+ src := &mockTokenSource{
+ tokenFunc: func() (*oauth2.Token, error) {
+ return &oauth2.Token{AccessToken: "t"}, nil
+ },
+ }
+ provider, err := RefreshableToken(src)
+ require.NoError(t, err)
+ assert.True(t, provider.RequireTransportSecurity())
+}
+
+// --- Phase 4 / US2 tests: graceful degradation ---
+
+func TestGetRequestMetadata_RefreshFailureReturnsStaleCachedToken(t *testing.T) {
+ var callNum atomic.Int32
+ src := &mockTokenSource{
+ tokenFunc: func() (*oauth2.Token, error) {
+ n := callNum.Add(1)
+ if n == 1 {
+ return &oauth2.Token{AccessToken: "stale", Expiry: time.Now().Add(-time.Minute)}, nil
+ }
+ return nil, fmt.Errorf("idp unavailable")
+ },
+ }
+ provider, err := RefreshableToken(src, WithLeeway(0))
+ require.NoError(t, err)
+
+ // First call succeeds but returns already-expired token.
+ _, err = provider.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+
+ // Second call: refresh fails, should return stale token.
+ md, err := provider.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+ assert.Equal(t, "Bearer stale", md["authorization"])
+}
+
+func TestGetRequestMetadata_RefreshFailureLogsWarning(t *testing.T) {
+ var callNum atomic.Int32
+ src := &mockTokenSource{
+ tokenFunc: func() (*oauth2.Token, error) {
+ n := callNum.Add(1)
+ if n == 1 {
+ return &oauth2.Token{AccessToken: "stale", Expiry: time.Now().Add(-time.Minute)}, nil
+ }
+ return nil, fmt.Errorf("idp unavailable")
+ },
+ }
+
+ logger := &captureLogger{}
+ provider, err := RefreshableToken(src, WithLeeway(0), WithLogger(logger))
+ require.NoError(t, err)
+
+ _, _ = provider.GetRequestMetadata(context.Background())
+ _, _ = provider.GetRequestMetadata(context.Background())
+
+ require.Len(t, logger.errors, 1)
+ assert.Contains(t, logger.errors[0].msg, "token refresh failed")
+}
+
+func TestGetRequestMetadata_RefreshFailureNoCachedTokenReturnsError(t *testing.T) {
+ src := &mockTokenSource{
+ tokenFunc: func() (*oauth2.Token, error) {
+ return nil, fmt.Errorf("idp unavailable")
+ },
+ }
+ provider, err := RefreshableToken(src)
+ require.NoError(t, err)
+
+ _, err = provider.GetRequestMetadata(context.Background())
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "idp unavailable")
+}
+
+func TestGetRequestMetadata_RefreshFailureNoLoggerNoPanic(t *testing.T) {
+ var callNum atomic.Int32
+ src := &mockTokenSource{
+ tokenFunc: func() (*oauth2.Token, error) {
+ n := callNum.Add(1)
+ if n == 1 {
+ return &oauth2.Token{AccessToken: "stale", Expiry: time.Now().Add(-time.Minute)}, nil
+ }
+ return nil, fmt.Errorf("idp unavailable")
+ },
+ }
+ provider, err := RefreshableToken(src, WithLeeway(0))
+ require.NoError(t, err)
+
+ _, _ = provider.GetRequestMetadata(context.Background())
+
+ assert.NotPanics(t, func() {
+ _, _ = provider.GetRequestMetadata(context.Background())
+ })
+}
+
+// --- Phase 5 / US3 tests: configurable leeway ---
+
+func TestGetRequestMetadata_DefaultLeewayTriggersRefresh(t *testing.T) {
+ var callNum atomic.Int32
+ src := &mockTokenSource{
+ tokenFunc: func() (*oauth2.Token, error) {
+ n := callNum.Add(1)
+ return &oauth2.Token{
+ AccessToken: fmt.Sprintf("token-%d", n),
+ Expiry: time.Now().Add(5 * time.Second), // within default 10s leeway
+ }, nil
+ },
+ }
+ provider, err := RefreshableToken(src) // default 10s leeway
+ require.NoError(t, err)
+
+ _, err = provider.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+
+ // Token expires in 5s, which is within 10s leeway, so next call should refresh.
+ md, err := provider.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+ assert.Equal(t, "Bearer token-2", md["authorization"])
+ assert.Equal(t, 2, src.calls())
+}
+
+func TestGetRequestMetadata_CustomLeewayTriggersRefresh(t *testing.T) {
+ var callNum atomic.Int32
+ src := &mockTokenSource{
+ tokenFunc: func() (*oauth2.Token, error) {
+ n := callNum.Add(1)
+ return &oauth2.Token{
+ AccessToken: fmt.Sprintf("token-%d", n),
+ Expiry: time.Now().Add(25 * time.Second), // within custom 30s leeway
+ }, nil
+ },
+ }
+ provider, err := RefreshableToken(src, WithLeeway(30*time.Second))
+ require.NoError(t, err)
+
+ _, err = provider.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+
+ // Token expires in 25s, which is within 30s leeway, so next call should refresh.
+ md, err := provider.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+ assert.Equal(t, "Bearer token-2", md["authorization"])
+ assert.Equal(t, 2, src.calls())
+}
+
+func TestGetRequestMetadata_ZeroExpiryNeverRefreshes(t *testing.T) {
+ src := &mockTokenSource{
+ tokenFunc: func() (*oauth2.Token, error) {
+ return &oauth2.Token{AccessToken: "forever-token"}, nil // zero Expiry
+ },
+ }
+ provider, err := RefreshableToken(src)
+ require.NoError(t, err)
+
+ _, err = provider.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+
+ // Call multiple times; should never refresh since expiry is zero.
+ for range 10 {
+ _, err = provider.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+ }
+ assert.Equal(t, 1, src.calls(), "zero-expiry token should never be refreshed")
+}
+
+// --- benchmarks ---
+
+func BenchmarkGetRequestMetadata_CachedToken(b *testing.B) {
+ src := &mockTokenSource{
+ tokenFunc: func() (*oauth2.Token, error) {
+ return &oauth2.Token{AccessToken: "bench-token", Expiry: time.Now().Add(time.Hour)}, nil
+ },
+ }
+ provider, err := RefreshableToken(src)
+ require.NoError(b, err)
+
+ // Prime the cache.
+ _, err = provider.GetRequestMetadata(context.Background())
+ require.NoError(b, err)
+
+ b.ResetTimer()
+ b.ReportAllocs()
+ for range b.N {
+ _, _ = provider.GetRequestMetadata(context.Background())
+ }
+}
+
+// --- helpers ---
+
+type logEntry struct {
+ err error
+ msg string
+}
+
+type captureLogger struct {
+ mu sync.Mutex
+ debugs []string
+ infos []string
+ errors []logEntry
+}
+
+func (l *captureLogger) Debug(msg string, _ ...any) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ l.debugs = append(l.debugs, msg)
+}
+
+func (l *captureLogger) Info(msg string, _ ...any) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ l.infos = append(l.infos, msg)
+}
+
+func (l *captureLogger) Error(err error, msg string, _ ...any) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ l.errors = append(l.errors, logEntry{err: err, msg: msg})
+}
diff --git a/sdk/go/openshell/v1/auth_test.go b/sdk/go/openshell/v1/auth_test.go
new file mode 100644
index 000000000..2981fd792
--- /dev/null
+++ b/sdk/go/openshell/v1/auth_test.go
@@ -0,0 +1,36 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestNoAuth_GetRequestMetadata(t *testing.T) {
+ auth := NoAuth()
+ md, err := auth.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+ assert.Empty(t, md)
+}
+
+func TestNoAuth_RequireTransportSecurity(t *testing.T) {
+ auth := NoAuth()
+ assert.False(t, auth.RequireTransportSecurity())
+}
+
+func TestStaticToken_GetRequestMetadata(t *testing.T) {
+ auth := StaticToken("my-secret-token")
+ md, err := auth.GetRequestMetadata(context.Background())
+ require.NoError(t, err)
+ assert.Equal(t, "Bearer my-secret-token", md["authorization"])
+}
+
+func TestStaticToken_RequireTransportSecurity(t *testing.T) {
+ auth := StaticToken("token")
+ assert.True(t, auth.RequireTransportSecurity())
+}
diff --git a/sdk/go/openshell/v1/client.go b/sdk/go/openshell/v1/client.go
new file mode 100644
index 000000000..85defcaaa
--- /dev/null
+++ b/sdk/go/openshell/v1/client.go
@@ -0,0 +1,142 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "sync"
+
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+
+ internalgrpc "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/internal/grpc"
+ "google.golang.org/grpc"
+)
+
+// Config holds all settings needed to create a Client.
+type Config = types.Config
+
+// ClientInterface defines the top-level SDK surface.
+type ClientInterface interface {
+ Sandboxes() SandboxInterface
+ Providers() ProviderInterface
+ Services() ServiceInterface
+ Exec() ExecInterface
+ Files() FileInterface
+ Health() HealthInterface
+ SSH() SSHInterface
+ TCP() TCPInterface
+ Config() ConfigInterface
+ Policy() PolicyInterface
+ Close() error
+}
+
+// SandboxInterface is defined in sandbox.go
+
+// ProviderInterface is defined in provider.go
+
+// ExecInterface is defined in exec.go
+
+// FileInterface is defined in file.go
+
+// Client implements ClientInterface. It holds a gRPC connection and provides
+// sub-client accessors following the Kubernetes client-go pattern.
+type Client struct {
+ conn *grpc.ClientConn
+ config Config
+
+ closeOnce sync.Once
+ closeErr error
+
+ sandboxes SandboxInterface
+ providers ProviderInterface
+ services ServiceInterface
+ exec ExecInterface
+ files FileInterface
+ health HealthInterface
+ ssh SSHInterface
+ tcp TCPInterface
+ cfg ConfigInterface
+ policy PolicyInterface
+}
+
+// NewClient creates a new SDK client connected to the given gateway.
+func NewClient(cfg Config) (*Client, error) {
+ if cfg.Address == "" {
+ return nil, &StatusError{Code: ErrorInvalidArgument, Message: "address must not be empty"}
+ }
+
+ if cfg.Auth == nil {
+ cfg.Auth = NoAuth()
+ }
+
+ var tlsParams *internalgrpc.TLSParams
+ if cfg.TLS != nil {
+ tlsParams = &internalgrpc.TLSParams{
+ CertFile: cfg.TLS.CertFile,
+ KeyFile: cfg.TLS.KeyFile,
+ CAFile: cfg.TLS.CAFile,
+ Insecure: cfg.TLS.Insecure,
+ }
+ }
+
+ conn, err := internalgrpc.NewConnection(cfg.Address, tlsParams, cfg.Auth)
+ if err != nil {
+ return nil, err
+ }
+
+ c := &Client{
+ conn: conn,
+ config: cfg,
+ }
+
+ c.sandboxes = newSandboxClient(conn)
+ c.providers = &stubProviders{}
+ c.services = &stubServices{}
+ c.exec = &stubExec{}
+ c.files = &stubFiles{}
+ c.health = &stubHealth{}
+ c.ssh = &stubSSH{}
+ c.tcp = &stubTCP{}
+ c.cfg = &stubConfig{}
+ c.policy = &stubPolicy{}
+
+ return c, nil
+}
+
+// Sandboxes returns the sandbox sub-client.
+func (c *Client) Sandboxes() SandboxInterface { return c.sandboxes }
+
+// Providers returns the provider sub-client.
+func (c *Client) Providers() ProviderInterface { return c.providers }
+
+// Services returns the service sub-client.
+func (c *Client) Services() ServiceInterface { return c.services }
+
+// Exec returns the exec sub-client.
+func (c *Client) Exec() ExecInterface { return c.exec }
+
+// Files returns the file sub-client.
+func (c *Client) Files() FileInterface { return c.files }
+
+// Health returns the health sub-client.
+func (c *Client) Health() HealthInterface { return c.health }
+
+// SSH returns the SSH session sub-client.
+func (c *Client) SSH() SSHInterface { return c.ssh }
+
+// TCP returns the TCP port forwarding sub-client.
+func (c *Client) TCP() TCPInterface { return c.tcp }
+
+// Config returns the configuration sub-client.
+func (c *Client) Config() ConfigInterface { return c.cfg }
+
+// Policy returns the policy management sub-client.
+func (c *Client) Policy() PolicyInterface { return c.policy }
+
+// Close closes the underlying gRPC connection. Safe to call multiple times.
+func (c *Client) Close() error {
+ c.closeOnce.Do(func() {
+ c.closeErr = c.conn.Close()
+ })
+ return c.closeErr
+}
diff --git a/sdk/go/openshell/v1/client_test.go b/sdk/go/openshell/v1/client_test.go
new file mode 100644
index 000000000..7d6029b05
--- /dev/null
+++ b/sdk/go/openshell/v1/client_test.go
@@ -0,0 +1,61 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestNewClient_EmptyAddress(t *testing.T) {
+ _, err := NewClient(Config{Address: ""})
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "address")
+}
+
+func TestNewClient_ValidConfig(t *testing.T) {
+ client, err := NewClient(Config{
+ Address: "localhost:50051",
+ Auth: NoAuth(),
+ TLS: &TLSConfig{Insecure: true},
+ })
+ require.NoError(t, err)
+ require.NotNil(t, client)
+
+ assert.NotNil(t, client.Sandboxes())
+ assert.NotNil(t, client.Providers())
+ assert.NotNil(t, client.Exec())
+ assert.NotNil(t, client.Files())
+ assert.NotNil(t, client.Health())
+
+ err = client.Close()
+ assert.NoError(t, err)
+}
+
+func TestClient_CloseIdempotent(t *testing.T) {
+ client, err := NewClient(Config{
+ Address: "localhost:50051",
+ Auth: NoAuth(),
+ TLS: &TLSConfig{Insecure: true},
+ })
+ require.NoError(t, err)
+
+ err = client.Close()
+ assert.NoError(t, err)
+
+ err = client.Close()
+ assert.NoError(t, err)
+}
+
+func TestNewClient_DefaultAuth(t *testing.T) {
+ client, err := NewClient(Config{
+ Address: "localhost:50051",
+ TLS: &TLSConfig{Insecure: true},
+ })
+ require.NoError(t, err)
+ require.NotNil(t, client)
+ _ = client.Close()
+}
diff --git a/sdk/go/openshell/v1/config.go b/sdk/go/openshell/v1/config.go
new file mode 100644
index 000000000..58efb9bf2
--- /dev/null
+++ b/sdk/go/openshell/v1/config.go
@@ -0,0 +1,76 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+)
+
+// SandboxConfig represents the full configuration state of a sandbox.
+type SandboxConfig = types.SandboxConfig
+
+// GatewayConfig represents gateway-global settings.
+type GatewayConfig = types.GatewayConfig
+
+// ConfigUpdate represents a configuration mutation request.
+type ConfigUpdate = types.ConfigUpdate
+
+// ConfigUpdateResult holds the result of a configuration update operation.
+type ConfigUpdateResult = types.ConfigUpdateResult
+
+// SettingValue is a typed setting value (string, bool, int64, or bytes).
+type SettingValue = types.SettingValue
+
+// SettingValueType identifies which typed field of a SettingValue is active.
+type SettingValueType = types.SettingValueType
+
+// EffectiveSetting is a setting value paired with its resolved scope.
+type EffectiveSetting = types.EffectiveSetting
+
+// SettingScope indicates whether a setting is sandbox or global.
+type SettingScope = types.SettingScope
+
+// PolicySource indicates the source of a policy payload.
+type PolicySource = types.PolicySource
+
+// SettingValueType constants re-exported from types package.
+const (
+ SettingValueString = types.SettingValueString
+ SettingValueBool = types.SettingValueBool
+ SettingValueInt = types.SettingValueInt
+ SettingValueBytes = types.SettingValueBytes
+)
+
+// SettingScope constants re-exported from types package.
+const (
+ SettingScopeUnspecified = types.SettingScopeUnspecified
+ SettingScopeSandbox = types.SettingScopeSandbox
+ SettingScopeGlobal = types.SettingScopeGlobal
+)
+
+// PolicySource constants re-exported from types package.
+const (
+ PolicySourceUnspecified = types.PolicySourceUnspecified
+ PolicySourceSandbox = types.PolicySourceSandbox
+ PolicySourceGlobal = types.PolicySourceGlobal
+)
+
+// ConfigInterface defines operations for reading and updating gateway and
+// sandbox configuration.
+type ConfigInterface interface {
+ // GetSandbox retrieves the full configuration state for a sandbox,
+ // including policy, effective settings, and revision metadata.
+ // The sandbox is identified by name; the SDK resolves it to an ID internally.
+ GetSandbox(ctx context.Context, workspace, sandboxName string) (*SandboxConfig, error)
+
+ // GetGateway retrieves gateway-global settings.
+ GetGateway(ctx context.Context) (*GatewayConfig, error)
+
+ // Update applies a configuration mutation. For sandbox-scoped updates,
+ // set ConfigUpdate.Name to the sandbox name. For global-scoped updates,
+ // set ConfigUpdate.Global to true.
+ Update(ctx context.Context, workspace string, update *ConfigUpdate) (*ConfigUpdateResult, error)
+}
diff --git a/sdk/go/openshell/v1/doc.go b/sdk/go/openshell/v1/doc.go
new file mode 100644
index 000000000..dd78d8189
--- /dev/null
+++ b/sdk/go/openshell/v1/doc.go
@@ -0,0 +1,358 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+// Package v1 provides a Go SDK for interacting with OpenShell servers.
+//
+// The SDK follows the Kubernetes client-go sub-client pattern: a single Client
+// provides typed accessors for each resource domain (Sandboxes, Providers, Exec,
+// Files, Health, Services, SSH, TCP, Config). All operations accept a context.Context and return idiomatic
+// Go types. Proto-generated types never appear in the public API.
+//
+// # Quick Start
+//
+// client, err := v1.NewClient(v1.Config{
+// Address: "gateway.example.com:443",
+// Auth: v1.StaticToken("my-token"),
+// })
+// if err != nil {
+// log.Fatal(err)
+// }
+// defer client.Close()
+//
+// # Sandbox Lifecycle
+//
+// sandbox, err := client.Sandboxes().Create(ctx, "default", "my-sandbox", &v1.SandboxSpec{
+// Template: &v1.SandboxTemplate{Image: "python:3.12"},
+// Environment: map[string]string{"LANG": "en_US.UTF-8"},
+// }, nil)
+// if err != nil {
+// log.Fatal(err)
+// }
+//
+// sandbox, err = client.Sandboxes().WaitReady(ctx, "default", sandbox.Name)
+// if err != nil {
+// log.Fatal(err)
+// }
+//
+// # Command Execution (available in a future release)
+//
+// result, err := client.Exec().Run(ctx, "default", sandbox.Name, []string{"echo", "hello"}, v1.ExecOptions{})
+// if err != nil {
+// log.Fatal(err)
+// }
+// fmt.Println(string(result.Stdout)) // "hello\n"
+//
+// # Error Handling
+//
+// _, err = client.Sandboxes().Get(ctx, "default", "missing")
+// if v1.IsNotFound(err) {
+// // handle not found
+// }
+//
+// # Watching
+//
+// watcher, err := client.Sandboxes().Watch(ctx, "default", sandbox.Name)
+// if err != nil {
+// log.Fatal(err)
+// }
+// defer watcher.Stop()
+// for event := range watcher.ResultChan() {
+// fmt.Printf("%s: %s\n", event.Type, event.Object.Name)
+// }
+//
+// # Watching with StopOnTerminal
+//
+// Use StopOnTerminal to auto-close the watcher when the sandbox reaches a
+// terminal phase (Ready or Error):
+//
+// watcher, err := client.Sandboxes().Watch(ctx, "default", sandbox.Name,
+// v1.WatchOptions{StopOnTerminal: true},
+// )
+// if err != nil {
+// log.Fatal(err)
+// }
+// for event := range watcher.ResultChan() {
+// fmt.Printf("phase: %s\n", event.Object.Status.Phase)
+// }
+// // channel closes automatically after Ready or Error
+//
+// # Service Exposure (available in a future release)
+//
+// Expose an HTTP service running inside a sandbox and retrieve its public URL:
+//
+// endpoint, err := client.Services().Expose(ctx, "default", "my-sandbox", "api", 8080, true)
+// if err != nil {
+// log.Fatal(err)
+// }
+// fmt.Printf("Service URL: %s\n", endpoint.URL)
+//
+// endpoints, err := client.Services().List(ctx, "default", "my-sandbox")
+// if err != nil {
+// log.Fatal(err)
+// }
+// for _, ep := range endpoints {
+// fmt.Printf(" %s → port %d (URL: %s)\n", ep.ServiceName, ep.TargetPort, ep.URL)
+// }
+//
+// # Provider Profiles (available in a future release)
+//
+// List available provider profiles and import new ones:
+//
+// profiles, err := client.Providers().Profiles().List(ctx, "default")
+// if err != nil {
+// log.Fatal(err)
+// }
+// for _, p := range profiles {
+// fmt.Printf("%s (%s): %s\n", p.DisplayName, p.Category, p.Description)
+// }
+//
+// result, err := client.Providers().Profiles().Import(ctx, "default", []v1.ProfileImportItem{
+// {Source: "openai-profile.yaml", Profile: v1.ProviderProfile{
+// DisplayName: "OpenAI",
+// Category: v1.ProfileCategoryInference,
+// }},
+// })
+// if err != nil {
+// log.Fatal(err)
+// }
+// for _, d := range result.Diagnostics {
+// fmt.Printf("[%s] %s: %s\n", d.Severity, d.Field, d.Message)
+// }
+//
+// # Credential Refresh (available in a future release)
+//
+// Configure gateway-owned credential refresh for a provider:
+//
+// status, err := client.Providers().Refresh().Configure(ctx, "default", &v1.RefreshConfig{
+// Provider: "openai",
+// CredentialKey: "api-key",
+// Strategy: v1.RefreshStrategyOAuth2ClientCredentials,
+// Material: map[string]string{"client_id": "xxx", "client_secret": "yyy"},
+// })
+// if err != nil {
+// log.Fatal(err)
+// }
+// fmt.Printf("Refresh status: %s (next: %s)\n", status.Status, status.NextRefreshAt)
+//
+// # Token Refresh
+//
+// Use RefreshableToken for automatic OAuth2 token caching and refresh.
+// Concurrent callers share a single refresh call:
+//
+// tokenSource := oauth2Config.TokenSource(ctx, initialToken)
+// auth, err := v1.RefreshableToken(tokenSource,
+// v1.WithLeeway(30*time.Second),
+// )
+// if err != nil {
+// log.Fatal(err)
+// }
+// client, err := v1.NewClient(v1.Config{
+// Address: "gateway.example.com:443",
+// Auth: auth,
+// })
+// if err != nil {
+// log.Fatal(err)
+// }
+// defer client.Close()
+//
+// # Extra Headers
+//
+// Use WithExtraHeaders to attach additional per-RPC headers to any auth
+// provider. This is useful for edge proxies, API gateways, or any middleware
+// that requires custom headers alongside standard authentication:
+//
+// base := v1.StaticToken("my-token")
+// auth, err := v1.WithExtraHeaders(base, map[string]string{
+// "x-proxy-key": "proxy-secret",
+// "x-tenant-id": "acme-corp",
+// })
+// if err != nil {
+// log.Fatal(err)
+// }
+// client, err := v1.NewClient(v1.Config{
+// Address: "gateway.example.com:443",
+// Auth: auth,
+// })
+// if err != nil {
+// log.Fatal(err)
+// }
+// defer client.Close()
+//
+// Keys are normalized to lowercase (per HTTP/2 RFC 9113). On key collision,
+// extra headers take precedence over base auth headers. Empty-string values
+// are silently dropped. WithExtraHeaders composes with any AuthProvider,
+// including RefreshableToken:
+//
+// tokenSource := oauth2Config.TokenSource(ctx, initialToken)
+// refreshAuth, err := v1.RefreshableToken(tokenSource)
+// if err != nil {
+// log.Fatal(err)
+// }
+// auth, err := v1.WithExtraHeaders(refreshAuth, map[string]string{
+// "x-proxy-key": "proxy-secret",
+// })
+//
+// # SSH Session Management (available in a future release)
+//
+// Create an SSH session for a sandbox and use the returned connection details.
+// Note: CreateSession accepts a sandbox ID, not a name. For name-based access
+// with automatic session cleanup, prefer SSH().Tunnel() instead.
+//
+// session, err := client.SSH().CreateSession(ctx, "default", sandbox.ID)
+// if err != nil {
+// log.Fatal(err)
+// }
+// fmt.Printf("SSH to %s:%d (scheme: %s)\n",
+// session.GatewayHost, session.GatewayPort, session.GatewayScheme)
+// fmt.Printf("Host key: %s\n", session.HostKeyFingerprint)
+// // Use session.Token to authenticate the SSH connection.
+//
+// revoked, err := client.SSH().RevokeSession(ctx, "default", session.Token)
+// if err != nil {
+// log.Fatal(err)
+// }
+// fmt.Printf("Session revoked: %v\n", revoked)
+//
+// # TCP Port Forwarding (available in a future release)
+//
+// Forward a local connection to a port inside a sandbox:
+//
+// conn, err := client.TCP().Forward(ctx, "default", "my-sandbox", 5432)
+// if err != nil {
+// log.Fatal(err)
+// }
+// defer conn.Close()
+//
+// // conn implements io.ReadWriteCloser, use it like a net.Conn.
+// _, err = conn.Write([]byte("PING\n"))
+// if err != nil {
+// log.Fatal(err)
+// }
+// buf := make([]byte, 1024)
+// n, err := conn.Read(buf)
+// if err != nil {
+// log.Fatal(err)
+// }
+// fmt.Printf("Response: %s\n", buf[:n])
+//
+// Use WithForwardServiceID to tag the forwarding session with a service
+// identifier for audit logging:
+//
+// conn, err := client.TCP().Forward(ctx, "default", "my-sandbox", 5432,
+// v1.WithForwardServiceID("billing-db"),
+// )
+//
+// # SSH Tunneling (available in a future release)
+//
+// Create an SSH tunnel to a sandbox port in a single call. Tunnel combines
+// session creation, TCP forwarding with an SSH relay target, and automatic
+// session cleanup into one operation:
+//
+// tunnel, err := client.SSH().Tunnel(ctx, "default", "my-sandbox", 22)
+// if err != nil {
+// log.Fatal(err)
+// }
+// defer tunnel.Close()
+//
+// // tunnel implements io.ReadWriteCloser. The underlying SSH session
+// // is automatically revoked when Close is called.
+// _, err = tunnel.Write([]byte("SSH-2.0-client\r\n"))
+// if err != nil {
+// log.Fatal(err)
+// }
+// buf := make([]byte, 256)
+// n, err := tunnel.Read(buf)
+// if err != nil {
+// log.Fatal(err)
+// }
+// fmt.Printf("Server banner: %s\n", buf[:n])
+//
+// Use WithTunnelServiceID to associate a service identifier with the tunnel:
+//
+// tunnel, err := client.SSH().Tunnel(ctx, "default", "my-sandbox", 22,
+// v1.WithTunnelServiceID("dev-ssh"),
+// )
+//
+// # Sandbox Policy
+//
+// Set an initial security policy when creating a sandbox:
+//
+// sandbox, err := client.Sandboxes().Create(ctx, "default", "secure-sandbox", &v1.SandboxSpec{
+// Template: &v1.SandboxTemplate{Image: "python:3.12"},
+// Policy: &v1.SandboxPolicy{
+// Version: 1,
+// Filesystem: &v1.FilesystemPolicy{
+// IncludeWorkdir: true,
+// ReadOnly: []string{"/usr", "/lib"},
+// },
+// Process: &v1.ProcessPolicy{
+// RunAsUser: "sandbox",
+// RunAsGroup: "sandbox",
+// },
+// NetworkPolicies: map[string]v1.NetworkPolicyRule{
+// "allow-api": {
+// Name: "allow-api",
+// Endpoints: []v1.PolicyNetworkEndpoint{
+// {Host: "api.example.com", Port: 443, Protocol: "tcp"},
+// },
+// },
+// },
+// },
+// }, nil)
+//
+// Replace the full policy at runtime via configuration update (available in a future release):
+//
+// result, err := client.Config().Update(ctx, "default", &v1.ConfigUpdate{
+// Name: "secure-sandbox",
+// Policy: &v1.SandboxPolicy{
+// Version: 2,
+// NetworkPolicies: map[string]v1.NetworkPolicyRule{
+// "allow-all": {Name: "allow-all"},
+// },
+// },
+// })
+//
+// Read a policy back from revision history (available in a future release):
+//
+// revisions, err := client.Policy().List(ctx, "default")
+// if err != nil {
+// log.Fatal(err)
+// }
+// for _, rev := range revisions {
+// if rev.Policy != nil {
+// fmt.Printf("v%d: %d network rules\n", rev.Version, len(rev.Policy.NetworkPolicies))
+// }
+// }
+//
+// # Configuration Management (available in a future release)
+//
+// Read sandbox and gateway configuration, and update settings:
+//
+// sbCfg, err := client.Config().GetSandbox(ctx, "default", "my-sandbox")
+// if err != nil {
+// log.Fatal(err)
+// }
+// fmt.Printf("Config revision: %d\n", sbCfg.ConfigRevision)
+// for name, setting := range sbCfg.Settings {
+// fmt.Printf(" %s = %v (scope: %s)\n", name, setting.Value, setting.Scope)
+// }
+//
+// gwCfg, err := client.Config().GetGateway(ctx)
+// if err != nil {
+// log.Fatal(err)
+// }
+// fmt.Printf("Gateway settings revision: %d\n", gwCfg.SettingsRevision)
+//
+// result, err := client.Config().Update(ctx, "default", &v1.ConfigUpdate{
+// Name: "my-sandbox",
+// SettingKey: "max_tokens",
+// SettingValue: &v1.SettingValue{
+// Type: v1.SettingValueInt,
+// IntVal: 8192,
+// },
+// })
+// if err != nil {
+// log.Fatal(err)
+// }
+// fmt.Printf("New settings revision: %d\n", result.SettingsRevision)
+package v1
diff --git a/sdk/go/openshell/v1/errors.go b/sdk/go/openshell/v1/errors.go
new file mode 100644
index 000000000..0033ae977
--- /dev/null
+++ b/sdk/go/openshell/v1/errors.go
@@ -0,0 +1,60 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+)
+
+// ErrorCode classifies SDK errors by their gRPC origin.
+type ErrorCode = types.ErrorCode
+
+// ErrorCode values for classifying gRPC errors.
+const (
+ ErrorNotFound = types.ErrorNotFound
+ ErrorAlreadyExists = types.ErrorAlreadyExists
+ ErrorUnavailable = types.ErrorUnavailable
+ ErrorPermissionDenied = types.ErrorPermissionDenied
+ ErrorInvalidArgument = types.ErrorInvalidArgument
+ ErrorDeadlineExceeded = types.ErrorDeadlineExceeded
+ ErrorCancelled = types.ErrorCancelled
+ ErrorInternal = types.ErrorInternal
+ ErrorUnimplemented = types.ErrorUnimplemented
+ ErrorConflict = types.ErrorConflict
+ ErrorUnauthenticated = types.ErrorUnauthenticated
+)
+
+// StatusError is the typed error returned by all SDK operations.
+type StatusError = types.StatusError
+
+// IsNotFound returns true if the error indicates a resource was not found.
+func IsNotFound(err error) bool { return types.IsNotFound(err) }
+
+// IsAlreadyExists returns true if the error indicates a resource already exists.
+func IsAlreadyExists(err error) bool { return types.IsAlreadyExists(err) }
+
+// IsUnavailable returns true if the error indicates the service is unavailable.
+func IsUnavailable(err error) bool { return types.IsUnavailable(err) }
+
+// IsPermissionDenied returns true if the error indicates insufficient permissions.
+func IsPermissionDenied(err error) bool { return types.IsPermissionDenied(err) }
+
+// IsInvalidArgument returns true if the error indicates an invalid argument.
+func IsInvalidArgument(err error) bool { return types.IsInvalidArgument(err) }
+
+// IsDeadlineExceeded returns true if the error indicates a deadline was exceeded.
+func IsDeadlineExceeded(err error) bool { return types.IsDeadlineExceeded(err) }
+
+// IsCancelled returns true if the error indicates the operation was cancelled.
+func IsCancelled(err error) bool { return types.IsCancelled(err) }
+
+// IsUnimplemented returns true if the error indicates the operation is not implemented.
+func IsUnimplemented(err error) bool { return types.IsUnimplemented(err) }
+
+// IsConflict returns true if the error indicates a conflict, such as
+// optimistic concurrency or an invalid state transition.
+func IsConflict(err error) bool { return types.IsConflict(err) }
+
+// IsUnauthenticated returns true if the error indicates missing or invalid credentials.
+func IsUnauthenticated(err error) bool { return types.IsUnauthenticated(err) }
diff --git a/sdk/go/openshell/v1/errors_test.go b/sdk/go/openshell/v1/errors_test.go
new file mode 100644
index 000000000..acc15c84b
--- /dev/null
+++ b/sdk/go/openshell/v1/errors_test.go
@@ -0,0 +1,127 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "errors"
+ "fmt"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestStatusError_Error(t *testing.T) {
+ err := &StatusError{
+ Code: ErrorNotFound,
+ Message: "sandbox not found",
+ }
+ s := err.Error()
+ assert.Contains(t, s, "NotFound")
+ assert.Contains(t, s, "sandbox not found")
+}
+
+func TestStatusError_ErrorWithCause(t *testing.T) {
+ cause := fmt.Errorf("underlying issue")
+ err := &StatusError{
+ Code: ErrorInvalidArgument,
+ Message: "bad name",
+ Cause: cause,
+ }
+ s := err.Error()
+ assert.Contains(t, s, "InvalidArgument")
+ assert.Contains(t, s, "bad name")
+ assert.ErrorIs(t, err, cause)
+}
+
+func TestIsNotFound(t *testing.T) {
+ err := &StatusError{Code: ErrorNotFound, Message: "not found"}
+ assert.True(t, IsNotFound(err))
+ assert.False(t, IsAlreadyExists(err))
+}
+
+func TestIsAlreadyExists(t *testing.T) {
+ err := &StatusError{Code: ErrorAlreadyExists, Message: "exists"}
+ assert.True(t, IsAlreadyExists(err))
+ assert.False(t, IsNotFound(err))
+}
+
+func TestIsUnavailable(t *testing.T) {
+ err := &StatusError{Code: ErrorUnavailable, Message: "down"}
+ assert.True(t, IsUnavailable(err))
+}
+
+func TestIsPermissionDenied(t *testing.T) {
+ err := &StatusError{Code: ErrorPermissionDenied, Message: "denied"}
+ assert.True(t, IsPermissionDenied(err))
+}
+
+func TestIsInvalidArgument(t *testing.T) {
+ err := &StatusError{Code: ErrorInvalidArgument, Message: "invalid"}
+ assert.True(t, IsInvalidArgument(err))
+}
+
+func TestIsDeadlineExceeded(t *testing.T) {
+ err := &StatusError{Code: ErrorDeadlineExceeded, Message: "timeout"}
+ assert.True(t, IsDeadlineExceeded(err))
+}
+
+func TestIsCancelled(t *testing.T) {
+ err := &StatusError{Code: ErrorCancelled, Message: "cancelled"}
+ assert.True(t, IsCancelled(err))
+}
+
+func TestIsConflict(t *testing.T) {
+ err := &StatusError{Code: ErrorConflict, Message: "version conflict"}
+ assert.True(t, IsConflict(err))
+ assert.False(t, IsNotFound(err))
+}
+
+func TestIsHelpers_NonStatusError(t *testing.T) {
+ err := errors.New("plain error")
+ assert.False(t, IsNotFound(err))
+ assert.False(t, IsAlreadyExists(err))
+ assert.False(t, IsUnavailable(err))
+ assert.False(t, IsPermissionDenied(err))
+ assert.False(t, IsInvalidArgument(err))
+ assert.False(t, IsDeadlineExceeded(err))
+ assert.False(t, IsCancelled(err))
+ assert.False(t, IsConflict(err))
+}
+
+func TestIsHelpers_NilError(t *testing.T) {
+ assert.False(t, IsNotFound(nil))
+ assert.False(t, IsConflict(nil))
+}
+
+func TestStatusError_WrappedError(t *testing.T) {
+ inner := &StatusError{Code: ErrorNotFound, Message: "not found"}
+ wrapped := fmt.Errorf("operation failed: %w", inner)
+ assert.True(t, IsNotFound(wrapped))
+
+ var se *StatusError
+ require.True(t, errors.As(wrapped, &se))
+ assert.Equal(t, ErrorNotFound, se.Code)
+}
+
+func TestErrorCode_String(t *testing.T) {
+ tests := []struct {
+ code ErrorCode
+ want string
+ }{
+ {ErrorNotFound, "NotFound"},
+ {ErrorAlreadyExists, "AlreadyExists"},
+ {ErrorUnavailable, "Unavailable"},
+ {ErrorPermissionDenied, "PermissionDenied"},
+ {ErrorInvalidArgument, "InvalidArgument"},
+ {ErrorDeadlineExceeded, "DeadlineExceeded"},
+ {ErrorCancelled, "Cancelled"},
+ {ErrorInternal, "Internal"},
+ {ErrorUnimplemented, "Unimplemented"},
+ {ErrorConflict, "Conflict"},
+ }
+ for _, tt := range tests {
+ assert.Equal(t, tt.want, tt.code.String())
+ }
+}
diff --git a/sdk/go/openshell/v1/exec.go b/sdk/go/openshell/v1/exec.go
new file mode 100644
index 000000000..217a1dc9b
--- /dev/null
+++ b/sdk/go/openshell/v1/exec.go
@@ -0,0 +1,40 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+)
+
+// ExecResult holds the collected output of a completed command execution.
+type ExecResult = types.ExecResult
+
+// ExecChunk represents a single chunk of output from a streaming command execution.
+type ExecChunk = types.ExecChunk
+
+// ExecStream provides an iterator interface over streaming command output.
+type ExecStream interface {
+ Next() (*ExecChunk, error)
+ ExitCode() (int, error)
+ Close() error
+}
+
+// InteractiveSession provides bidirectional I/O for interactive command execution.
+type InteractiveSession interface {
+ Read(p []byte) (int, error)
+ Write(p []byte) (int, error)
+ Resize(cols, rows uint32) error
+ ExitCode() (int, error)
+ Close() error
+}
+
+// ExecInterface defines command execution operations on sandboxes.
+// Methods accept a sandbox name and resolve it to an ID internally.
+type ExecInterface interface {
+ Run(ctx context.Context, workspace, sandboxName string, command []string, opts ...ExecOptions) (*ExecResult, error)
+ Stream(ctx context.Context, workspace, sandboxName string, command []string, opts ...ExecOptions) (ExecStream, error)
+ Interactive(ctx context.Context, workspace, sandboxName string, command []string, cols, rows uint32, opts ...ExecOptions) (InteractiveSession, error)
+}
diff --git a/sdk/go/openshell/v1/file.go b/sdk/go/openshell/v1/file.go
new file mode 100644
index 000000000..0893c9c6c
--- /dev/null
+++ b/sdk/go/openshell/v1/file.go
@@ -0,0 +1,13 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import "context"
+
+// FileInterface defines file transfer operations on sandboxes.
+// Methods accept a sandbox name and resolve it to an ID internally.
+type FileInterface interface {
+ Upload(ctx context.Context, workspace, sandboxName string, localPath string, remotePath string) error
+ Download(ctx context.Context, workspace, sandboxName string, remotePath string, localPath string) error
+}
diff --git a/sdk/go/openshell/v1/grpc_errors.go b/sdk/go/openshell/v1/grpc_errors.go
new file mode 100644
index 000000000..4c3135116
--- /dev/null
+++ b/sdk/go/openshell/v1/grpc_errors.go
@@ -0,0 +1,22 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+// Package v1 provides the OpenShell SDK client.
+// gRPC error conversion is handled by the internal/converter package.
+package v1
+
+import "context"
+
+func contextError(err error) error {
+ if err == nil {
+ return nil
+ }
+ switch err {
+ case context.DeadlineExceeded:
+ return &StatusError{Code: ErrorDeadlineExceeded, Message: err.Error(), Cause: err}
+ case context.Canceled:
+ return &StatusError{Code: ErrorCancelled, Message: err.Error(), Cause: err}
+ default:
+ return &StatusError{Code: ErrorInternal, Message: err.Error(), Cause: err}
+ }
+}
diff --git a/sdk/go/openshell/v1/health.go b/sdk/go/openshell/v1/health.go
new file mode 100644
index 000000000..c5e62eaa3
--- /dev/null
+++ b/sdk/go/openshell/v1/health.go
@@ -0,0 +1,18 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+)
+
+// HealthResult holds the result of a health check.
+type HealthResult = types.HealthResult
+
+// HealthInterface defines health check operations.
+type HealthInterface interface {
+ Check(ctx context.Context) (*HealthResult, error)
+}
diff --git a/sdk/go/openshell/v1/integration_test.go b/sdk/go/openshell/v1/integration_test.go
new file mode 100644
index 000000000..9c8123052
--- /dev/null
+++ b/sdk/go/openshell/v1/integration_test.go
@@ -0,0 +1,76 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+//go:build integration
+
+package v1
+
+import (
+ "context"
+ "os"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func gatewayAddress(t *testing.T) string {
+ t.Helper()
+ addr := os.Getenv("OPENSHELL_GATEWAY_ADDRESS")
+ if addr == "" {
+ t.Skip("OPENSHELL_GATEWAY_ADDRESS not set")
+ }
+ return addr
+}
+
+func TestIntegration_HealthCheck(t *testing.T) {
+ addr := gatewayAddress(t)
+
+ client, err := NewClient(Config{Address: addr})
+ require.NoError(t, err)
+ defer client.Close()
+
+ t.Skip("TODO: Health().Check() is a stub until PR B lands")
+
+ _, err = client.Health().Check(context.Background())
+ require.NoError(t, err)
+}
+
+func TestIntegration_ProviderLifecycle(t *testing.T) {
+ addr := gatewayAddress(t)
+
+ client, err := NewClient(Config{Address: addr})
+ require.NoError(t, err)
+ defer client.Close()
+
+ t.Skip("TODO: implement provider create/get/list/delete integration test")
+}
+
+func TestIntegration_SandboxLifecycle(t *testing.T) {
+ addr := gatewayAddress(t)
+
+ client, err := NewClient(Config{Address: addr})
+ require.NoError(t, err)
+ defer client.Close()
+
+ t.Skip("TODO: implement sandbox create/wait-ready/delete integration test")
+}
+
+func TestIntegration_ExecRun(t *testing.T) {
+ addr := gatewayAddress(t)
+
+ client, err := NewClient(Config{Address: addr})
+ require.NoError(t, err)
+ defer client.Close()
+
+ t.Skip("TODO: implement exec run integration test")
+}
+
+func TestIntegration_FileTransfer(t *testing.T) {
+ addr := gatewayAddress(t)
+
+ client, err := NewClient(Config{Address: addr})
+ require.NoError(t, err)
+ defer client.Close()
+
+ t.Skip("TODO: implement file upload/download integration test")
+}
diff --git a/sdk/go/openshell/v1/internal/converter/copy.go b/sdk/go/openshell/v1/internal/converter/copy.go
new file mode 100644
index 000000000..9ab7f0f0e
--- /dev/null
+++ b/sdk/go/openshell/v1/internal/converter/copy.go
@@ -0,0 +1,65 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package converter
+
+import "google.golang.org/protobuf/types/known/structpb"
+
+// CopyStringMap returns a shallow copy of a string-to-string map.
+// Returns nil for nil input.
+func CopyStringMap(m map[string]string) map[string]string {
+ if m == nil {
+ return nil
+ }
+ c := make(map[string]string, len(m))
+ for k, v := range m {
+ c[k] = v
+ }
+ return c
+}
+
+// CopyBoolPtr returns a copy of a *bool pointer.
+// Returns nil for nil input.
+func CopyBoolPtr(p *bool) *bool {
+ if p == nil {
+ return nil
+ }
+ v := *p
+ return &v
+}
+
+// CopyStringSlice returns a copy of a string slice.
+// Returns nil for nil input.
+func CopyStringSlice(s []string) []string {
+ if s == nil {
+ return nil
+ }
+ c := make([]string, len(s))
+ copy(c, s)
+ return c
+}
+
+// CopyByteSlice returns a copy of a byte slice.
+// Returns nil for nil input.
+func CopyByteSlice(b []byte) []byte {
+ if b == nil {
+ return nil
+ }
+ c := make([]byte, len(b))
+ copy(c, b)
+ return c
+}
+
+func structToMap(s *structpb.Struct) map[string]any {
+ if s == nil {
+ return nil
+ }
+ return s.AsMap()
+}
+
+func mapToStruct(m map[string]any) (*structpb.Struct, error) {
+ if m == nil {
+ return nil, nil
+ }
+ return structpb.NewStruct(m)
+}
diff --git a/sdk/go/openshell/v1/internal/converter/coverage_test.go b/sdk/go/openshell/v1/internal/converter/coverage_test.go
new file mode 100644
index 000000000..38ed5f5ed
--- /dev/null
+++ b/sdk/go/openshell/v1/internal/converter/coverage_test.go
@@ -0,0 +1,234 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package converter
+
+import (
+ "testing"
+
+ dm "github.com/NVIDIA/OpenShell/sdk/go/proto/datamodelv1"
+ pb "github.com/NVIDIA/OpenShell/sdk/go/proto/openshellv1"
+ sandboxpb "github.com/NVIDIA/OpenShell/sdk/go/proto/sandboxv1"
+ "google.golang.org/protobuf/reflect/protoreflect"
+)
+
+// These tests use protobuf reflection to detect proto fields that the
+// converter layer does not handle. When buf generates new fields from an
+// updated .proto, the field name appears in the proto descriptor but not in
+// the "handled" set below.
+//
+// Unhandled fields FAIL the test so that proto drift is caught immediately.
+// If a field is intentionally deferred, add it to the "skipped" set with a
+// justification comment.
+
+func TestConverterCoversAllProtoFields_SandboxSpec(t *testing.T) {
+ handled := fieldSet{
+ "log_level": true,
+ "environment": true,
+ "template": true,
+ "policy": true,
+ "providers": true,
+ "resource_requirements": true,
+ }
+
+ assertAllFieldsCovered(t, (&pb.SandboxSpec{}).ProtoReflect().Descriptor(), handled, nil)
+}
+
+func TestConverterCoversAllProtoFields_SandboxTemplate(t *testing.T) {
+ handled := fieldSet{
+ "image": true,
+ "runtime_class_name": true,
+ "agent_socket": true,
+ "labels": true,
+ "annotations": true,
+ "environment": true,
+ "resources": true,
+ "user_namespaces": true,
+ "driver_config": true,
+ }
+
+ assertAllFieldsCovered(t, (&pb.SandboxTemplate{}).ProtoReflect().Descriptor(), handled, nil)
+}
+
+func TestConverterCoversAllProtoFields_SandboxStatus(t *testing.T) {
+ handled := fieldSet{
+ "sandbox_name": true,
+ "agent_pod": true,
+ "agent_fd": true,
+ "sandbox_fd": true,
+ "phase": true,
+ "conditions": true,
+ "current_policy_version": true,
+ }
+
+ assertAllFieldsCovered(t, (&pb.SandboxStatus{}).ProtoReflect().Descriptor(), handled, nil)
+}
+
+func TestConverterCoversAllProtoFields_SandboxCondition(t *testing.T) {
+ handled := fieldSet{
+ "type": true,
+ "status": true,
+ "reason": true,
+ "message": true,
+ "last_transition_time": true,
+ }
+
+ assertAllFieldsCovered(t, (&pb.SandboxCondition{}).ProtoReflect().Descriptor(), handled, nil)
+}
+
+func TestConverterCoversAllProtoFields_SandboxPolicy(t *testing.T) {
+ handled := fieldSet{
+ "version": true,
+ "filesystem": true,
+ "network_policies": true,
+ "process": true,
+ "landlock": true,
+ }
+
+ skipped := fieldSet{
+ // Middleware support is not yet exposed in the SDK domain model.
+ // Tracked in GitHub issue #36 for Drop D.
+ "network_middlewares": true,
+ }
+
+ assertAllFieldsCovered(t, (&sandboxpb.SandboxPolicy{}).ProtoReflect().Descriptor(), handled, skipped)
+}
+
+func TestConverterCoversAllProtoFields_NetworkEndpoint(t *testing.T) {
+ handled := fieldSet{
+ "host": true,
+ "port": true,
+ "ports": true,
+ "protocol": true,
+ "tls": true,
+ "enforcement": true,
+ "access": true,
+ "rules": true,
+ "allowed_ips": true,
+ "deny_rules": true,
+ "allow_encoded_slash": true,
+ "persisted_queries": true,
+ "graphql_persisted_queries": true,
+ "graphql_max_body_bytes": true,
+ "path": true,
+ "websocket_credential_rewrite": true,
+ "request_body_credential_rewrite": true,
+ "advisor_proposed": true,
+ "credential_signing": true,
+ "signing_service": true,
+ "signing_region": true,
+ "json_rpc_max_body_bytes": true,
+ "mcp": true,
+ }
+
+ assertAllFieldsCovered(t, (&sandboxpb.NetworkEndpoint{}).ProtoReflect().Descriptor(), handled, nil)
+}
+
+func TestConverterCoversAllProtoFields_L7Allow(t *testing.T) {
+ handled := fieldSet{
+ "method": true,
+ "path": true,
+ "command": true,
+ "query": true,
+ "operation_type": true,
+ "operation_name": true,
+ "fields": true,
+ "params": true,
+ }
+
+ assertAllFieldsCovered(t, (&sandboxpb.L7Allow{}).ProtoReflect().Descriptor(), handled, nil)
+}
+
+func TestConverterCoversAllProtoFields_L7DenyRule(t *testing.T) {
+ handled := fieldSet{
+ "method": true,
+ "path": true,
+ "command": true,
+ "query": true,
+ "operation_type": true,
+ "operation_name": true,
+ "fields": true,
+ "params": true,
+ }
+
+ assertAllFieldsCovered(t, (&sandboxpb.L7DenyRule{}).ProtoReflect().Descriptor(), handled, nil)
+}
+
+func TestConverterCoversAllProtoFields_Provider(t *testing.T) {
+ handled := fieldSet{
+ "metadata": true,
+ "type": true,
+ "credentials": true,
+ "config": true,
+ "credential_expires_at_ms": true,
+ "profile_workspace": true,
+ "credential_handles": true,
+ }
+
+ assertAllFieldsCovered(t, (&dm.Provider{}).ProtoReflect().Descriptor(), handled, nil)
+}
+
+func TestConverterCoversAllProtoFields_CredentialHandle(t *testing.T) {
+ handled := fieldSet{
+ "driver": true,
+ "handle": true,
+ "metadata": true,
+ }
+
+ assertAllFieldsCovered(t, (&dm.CredentialHandle{}).ProtoReflect().Descriptor(), handled, nil)
+}
+
+func TestConverterCoversAllProtoFields_McpOptions(t *testing.T) {
+ handled := fieldSet{
+ "strict_tool_names": true,
+ "allow_all_known_mcp_methods": true,
+ }
+
+ assertAllFieldsCovered(t, (&sandboxpb.McpOptions{}).ProtoReflect().Descriptor(), handled, nil)
+}
+
+// fieldSet tracks proto field names that the converter handles.
+type fieldSet map[string]bool
+
+// assertAllFieldsCovered fails the test for proto fields not present in
+// either handled or skipped. Stale entries in the handled set (fields
+// removed from the proto) also fail.
+func assertAllFieldsCovered(
+ t *testing.T,
+ desc protoreflect.MessageDescriptor,
+ handled fieldSet,
+ skipped fieldSet,
+) {
+ t.Helper()
+
+ fields := desc.Fields()
+ for i := 0; i < fields.Len(); i++ {
+ name := string(fields.Get(i).Name())
+ if handled[name] || skipped[name] {
+ continue
+ }
+ t.Errorf(
+ "proto %s field %q is not handled by the converter and not explicitly skipped. "+
+ "Add converter support in the appropriate FromProto/ToProto function, "+
+ "or add it to the skipped set with a justification.",
+ desc.FullName(), name,
+ )
+ }
+
+ for name := range handled {
+ found := false
+ for i := 0; i < fields.Len(); i++ {
+ if string(fields.Get(i).Name()) == name {
+ found = true
+ break
+ }
+ }
+ if !found {
+ t.Errorf(
+ "handled field %q is listed for proto %s but does not exist in the descriptor. "+
+ "The proto field may have been removed or renamed.",
+ name, desc.FullName(),
+ )
+ }
+ }
+}
diff --git a/sdk/go/openshell/v1/internal/converter/errors.go b/sdk/go/openshell/v1/internal/converter/errors.go
new file mode 100644
index 000000000..d589088e8
--- /dev/null
+++ b/sdk/go/openshell/v1/internal/converter/errors.go
@@ -0,0 +1,54 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+// Package converter maps between gRPC/proto types and SDK domain types.
+package converter
+
+import (
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+var grpcToSDK = map[codes.Code]types.ErrorCode{
+ codes.NotFound: types.ErrorNotFound,
+ codes.AlreadyExists: types.ErrorAlreadyExists,
+ codes.Unavailable: types.ErrorUnavailable,
+ codes.PermissionDenied: types.ErrorPermissionDenied,
+ codes.Unauthenticated: types.ErrorUnauthenticated,
+ codes.InvalidArgument: types.ErrorInvalidArgument,
+ codes.DeadlineExceeded: types.ErrorDeadlineExceeded,
+ codes.Canceled: types.ErrorCancelled,
+ codes.Internal: types.ErrorInternal,
+ codes.Unimplemented: types.ErrorUnimplemented,
+ codes.Aborted: types.ErrorConflict,
+ codes.FailedPrecondition: types.ErrorConflict,
+}
+
+// FromGRPCError converts a gRPC error to a typed StatusError.
+// Returns nil for nil errors and OK status. Non-gRPC errors pass through unchanged.
+func FromGRPCError(err error) error {
+ if err == nil {
+ return nil
+ }
+
+ st, ok := status.FromError(err)
+ if !ok {
+ return err
+ }
+
+ if st.Code() == codes.OK {
+ return nil
+ }
+
+ code, mapped := grpcToSDK[st.Code()]
+ if !mapped {
+ code = types.ErrorInternal
+ }
+
+ return &types.StatusError{
+ Code: code,
+ Message: st.Message(),
+ Cause: err,
+ }
+}
diff --git a/sdk/go/openshell/v1/internal/converter/errors_test.go b/sdk/go/openshell/v1/internal/converter/errors_test.go
new file mode 100644
index 000000000..c7238eaae
--- /dev/null
+++ b/sdk/go/openshell/v1/internal/converter/errors_test.go
@@ -0,0 +1,122 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package converter
+
+import (
+ "testing"
+
+ v1 "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+func TestFromGRPCError_NotFound(t *testing.T) {
+ grpcErr := status.Error(codes.NotFound, "sandbox not found")
+ err := FromGRPCError(grpcErr)
+ require.Error(t, err)
+ assert.True(t, v1.IsNotFound(err))
+}
+
+func TestFromGRPCError_AlreadyExists(t *testing.T) {
+ grpcErr := status.Error(codes.AlreadyExists, "already exists")
+ err := FromGRPCError(grpcErr)
+ require.Error(t, err)
+ assert.True(t, v1.IsAlreadyExists(err))
+}
+
+func TestFromGRPCError_Unavailable(t *testing.T) {
+ grpcErr := status.Error(codes.Unavailable, "service down")
+ err := FromGRPCError(grpcErr)
+ require.Error(t, err)
+ assert.True(t, v1.IsUnavailable(err))
+}
+
+func TestFromGRPCError_PermissionDenied(t *testing.T) {
+ grpcErr := status.Error(codes.PermissionDenied, "denied")
+ err := FromGRPCError(grpcErr)
+ require.Error(t, err)
+ assert.True(t, v1.IsPermissionDenied(err))
+}
+
+func TestFromGRPCError_InvalidArgument(t *testing.T) {
+ grpcErr := status.Error(codes.InvalidArgument, "bad arg")
+ err := FromGRPCError(grpcErr)
+ require.Error(t, err)
+ assert.True(t, v1.IsInvalidArgument(err))
+}
+
+func TestFromGRPCError_DeadlineExceeded(t *testing.T) {
+ grpcErr := status.Error(codes.DeadlineExceeded, "timeout")
+ err := FromGRPCError(grpcErr)
+ require.Error(t, err)
+ assert.True(t, v1.IsDeadlineExceeded(err))
+}
+
+func TestFromGRPCError_Cancelled(t *testing.T) {
+ grpcErr := status.Error(codes.Canceled, "cancelled")
+ err := FromGRPCError(grpcErr)
+ require.Error(t, err)
+ assert.True(t, v1.IsCancelled(err))
+}
+
+func TestFromGRPCError_Internal(t *testing.T) {
+ grpcErr := status.Error(codes.Internal, "internal error")
+ err := FromGRPCError(grpcErr)
+ require.Error(t, err)
+
+ var se *v1.StatusError
+ require.ErrorAs(t, err, &se)
+ assert.Equal(t, v1.ErrorInternal, se.Code)
+}
+
+func TestFromGRPCError_Unimplemented(t *testing.T) {
+ grpcErr := status.Error(codes.Unimplemented, "not implemented")
+ err := FromGRPCError(grpcErr)
+ require.Error(t, err)
+
+ var se *v1.StatusError
+ require.ErrorAs(t, err, &se)
+ assert.Equal(t, v1.ErrorUnimplemented, se.Code)
+}
+
+func TestFromGRPCError_Aborted(t *testing.T) {
+ grpcErr := status.Error(codes.Aborted, "version conflict")
+ err := FromGRPCError(grpcErr)
+ require.Error(t, err)
+ assert.True(t, v1.IsConflict(err))
+
+ var se *v1.StatusError
+ require.ErrorAs(t, err, &se)
+ assert.Equal(t, v1.ErrorConflict, se.Code)
+ assert.Equal(t, "version conflict", se.Message)
+}
+
+func TestFromGRPCError_UnmappedCode(t *testing.T) {
+ grpcErr := status.Error(codes.DataLoss, "data loss")
+ err := FromGRPCError(grpcErr)
+ require.Error(t, err)
+
+ var se *v1.StatusError
+ require.ErrorAs(t, err, &se)
+ assert.Equal(t, v1.ErrorInternal, se.Code)
+}
+
+func TestFromGRPCError_NilError(t *testing.T) {
+ err := FromGRPCError(nil)
+ assert.NoError(t, err)
+}
+
+func TestFromGRPCError_NonGRPCError(t *testing.T) {
+ err := FromGRPCError(assert.AnError)
+ require.Error(t, err)
+ assert.Equal(t, assert.AnError, err)
+}
+
+func TestFromGRPCError_OKStatus(t *testing.T) {
+ grpcErr := status.Error(codes.OK, "")
+ err := FromGRPCError(grpcErr)
+ assert.NoError(t, err)
+}
diff --git a/sdk/go/openshell/v1/internal/converter/log.go b/sdk/go/openshell/v1/internal/converter/log.go
new file mode 100644
index 000000000..42f530fb1
--- /dev/null
+++ b/sdk/go/openshell/v1/internal/converter/log.go
@@ -0,0 +1,47 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package converter
+
+import (
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+ pb "github.com/NVIDIA/OpenShell/sdk/go/proto/openshellv1"
+)
+
+// --- LogLine ---
+
+// LogLineFromProto converts a proto SandboxLogLine to an SDK LogLine.
+func LogLineFromProto(l *pb.SandboxLogLine) *types.LogLine {
+ if l == nil {
+ return nil
+ }
+ return &types.LogLine{
+ Timestamp: TimeFromMillis(l.GetTimestampMs()),
+ Level: l.GetLevel(),
+ Target: l.GetTarget(),
+ Message: l.GetMessage(),
+ Source: l.GetSource(),
+ Fields: CopyStringMap(l.GetFields()),
+ }
+}
+
+// --- LogResult ---
+
+// LogResultFromProto converts a proto GetSandboxLogsResponse to an SDK LogResult.
+func LogResultFromProto(r *pb.GetSandboxLogsResponse) *types.LogResult {
+ if r == nil {
+ return nil
+ }
+ result := &types.LogResult{
+ BufferTotal: r.GetBufferTotal(),
+ }
+ if logs := r.GetLogs(); len(logs) > 0 {
+ result.Lines = make([]types.LogLine, 0, len(logs))
+ for _, l := range logs {
+ if converted := LogLineFromProto(l); converted != nil {
+ result.Lines = append(result.Lines, *converted)
+ }
+ }
+ }
+ return result
+}
diff --git a/sdk/go/openshell/v1/internal/converter/log_test.go b/sdk/go/openshell/v1/internal/converter/log_test.go
new file mode 100644
index 000000000..746239626
--- /dev/null
+++ b/sdk/go/openshell/v1/internal/converter/log_test.go
@@ -0,0 +1,97 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package converter
+
+import (
+ "testing"
+
+ pb "github.com/NVIDIA/OpenShell/sdk/go/proto/openshellv1"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+// --- LogLine ---
+
+func TestLogLineFromProto(t *testing.T) {
+ proto := &pb.SandboxLogLine{
+ SandboxId: "sbx-1",
+ TimestampMs: 1700000000000,
+ Level: "INFO",
+ Target: "network",
+ Message: "Connection established",
+ Source: "sandbox-agent",
+ Fields: map[string]string{
+ "host": "api.example.com",
+ "port": "443",
+ },
+ }
+
+ line := LogLineFromProto(proto)
+
+ require.NotNil(t, line)
+ assert.False(t, line.Timestamp.IsZero())
+ assert.Equal(t, "INFO", line.Level)
+ assert.Equal(t, "network", line.Target)
+ assert.Equal(t, "Connection established", line.Message)
+ assert.Equal(t, "sandbox-agent", line.Source)
+ assert.Equal(t, "api.example.com", line.Fields["host"])
+ assert.Equal(t, "443", line.Fields["port"])
+}
+
+func TestLogLineFromProto_Nil(t *testing.T) {
+ assert.Nil(t, LogLineFromProto(nil))
+}
+
+func TestLogLineDeepCopy(t *testing.T) {
+ proto := &pb.SandboxLogLine{
+ TimestampMs: 1700000000000,
+ Level: "WARN",
+ Message: "test",
+ Fields: map[string]string{
+ "key": "value",
+ },
+ }
+
+ line := LogLineFromProto(proto)
+ proto.Fields["key"] = "changed"
+
+ assert.Equal(t, "value", line.Fields["key"])
+}
+
+// --- LogResult ---
+
+func TestLogResultFromProto(t *testing.T) {
+ proto := &pb.GetSandboxLogsResponse{
+ Logs: []*pb.SandboxLogLine{
+ {TimestampMs: 1700000000000, Level: "INFO", Message: "first"},
+ {TimestampMs: 1700000001000, Level: "DEBUG", Message: "second"},
+ },
+ BufferTotal: 100,
+ }
+
+ result := LogResultFromProto(proto)
+
+ require.NotNil(t, result)
+ assert.Len(t, result.Lines, 2)
+ assert.Equal(t, "INFO", result.Lines[0].Level)
+ assert.Equal(t, "first", result.Lines[0].Message)
+ assert.Equal(t, "DEBUG", result.Lines[1].Level)
+ assert.Equal(t, "second", result.Lines[1].Message)
+ assert.Equal(t, uint32(100), result.BufferTotal)
+}
+
+func TestLogResultFromProto_Nil(t *testing.T) {
+ assert.Nil(t, LogResultFromProto(nil))
+}
+
+func TestLogResultFromProto_EmptyLogs(t *testing.T) {
+ proto := &pb.GetSandboxLogsResponse{
+ BufferTotal: 0,
+ }
+
+ result := LogResultFromProto(proto)
+ require.NotNil(t, result)
+ assert.Empty(t, result.Lines)
+ assert.Equal(t, uint32(0), result.BufferTotal)
+}
diff --git a/sdk/go/openshell/v1/internal/converter/network_policy.go b/sdk/go/openshell/v1/internal/converter/network_policy.go
new file mode 100644
index 000000000..3e3e4887d
--- /dev/null
+++ b/sdk/go/openshell/v1/internal/converter/network_policy.go
@@ -0,0 +1,332 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package converter
+
+import (
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+ sbv1 "github.com/NVIDIA/OpenShell/sdk/go/proto/sandboxv1"
+)
+
+// --- NetworkPolicyRule ---
+
+// NetworkPolicyRuleFromProto converts a proto NetworkPolicyRule to an SDK NetworkPolicyRule.
+func NetworkPolicyRuleFromProto(r *sbv1.NetworkPolicyRule) *types.NetworkPolicyRule {
+ if r == nil {
+ return nil
+ }
+ result := &types.NetworkPolicyRule{
+ Name: r.GetName(),
+ }
+ if eps := r.GetEndpoints(); len(eps) > 0 {
+ result.Endpoints = make([]types.PolicyNetworkEndpoint, len(eps))
+ for i, ep := range eps {
+ if ep != nil {
+ result.Endpoints[i] = policyNetworkEndpointFromProto(ep)
+ }
+ }
+ }
+ if bins := r.GetBinaries(); len(bins) > 0 {
+ result.Binaries = make([]types.PolicyNetworkBinary, len(bins))
+ for i, b := range bins {
+ if b != nil {
+ result.Binaries[i] = types.PolicyNetworkBinary{Path: b.GetPath()}
+ }
+ }
+ }
+ return result
+}
+
+// NetworkPolicyRuleToProto converts an SDK NetworkPolicyRule to a proto NetworkPolicyRule.
+func NetworkPolicyRuleToProto(r *types.NetworkPolicyRule) *sbv1.NetworkPolicyRule {
+ if r == nil {
+ return nil
+ }
+ result := &sbv1.NetworkPolicyRule{
+ Name: r.Name,
+ }
+ if len(r.Endpoints) > 0 {
+ result.Endpoints = make([]*sbv1.NetworkEndpoint, len(r.Endpoints))
+ for i := range r.Endpoints {
+ result.Endpoints[i] = policyNetworkEndpointToProto(&r.Endpoints[i])
+ }
+ }
+ if len(r.Binaries) > 0 {
+ result.Binaries = make([]*sbv1.NetworkBinary, len(r.Binaries))
+ for i := range r.Binaries {
+ result.Binaries[i] = &sbv1.NetworkBinary{Path: r.Binaries[i].Path}
+ }
+ }
+ return result
+}
+
+// --- PolicyNetworkEndpoint ---
+
+func policyNetworkEndpointFromProto(ep *sbv1.NetworkEndpoint) types.PolicyNetworkEndpoint {
+ result := types.PolicyNetworkEndpoint{
+ Host: ep.GetHost(),
+ Port: ep.GetPort(),
+ Protocol: ep.GetProtocol(),
+ TLS: ep.GetTls(),
+ Enforcement: ep.GetEnforcement(),
+ Access: ep.GetAccess(),
+ AllowEncodedSlash: ep.GetAllowEncodedSlash(),
+ PersistedQueries: ep.GetPersistedQueries(),
+ GraphqlMaxBodyBytes: ep.GetGraphqlMaxBodyBytes(),
+ Path: ep.GetPath(),
+ WebsocketCredentialRewrite: ep.GetWebsocketCredentialRewrite(),
+ RequestBodyCredentialRewrite: ep.GetRequestBodyCredentialRewrite(),
+ AdvisorProposed: ep.GetAdvisorProposed(),
+ CredentialSigning: ep.GetCredentialSigning(),
+ SigningService: ep.GetSigningService(),
+ SigningRegion: ep.GetSigningRegion(),
+ JsonRpcMaxBodyBytes: ep.GetJsonRpcMaxBodyBytes(),
+ }
+ if mcp := ep.GetMcp(); mcp != nil {
+ result.Mcp = mcpOptionsFromProto(mcp)
+ }
+ if ports := ep.GetPorts(); len(ports) > 0 {
+ result.Ports = make([]uint32, len(ports))
+ copy(result.Ports, ports)
+ }
+ if ips := ep.GetAllowedIps(); len(ips) > 0 {
+ result.AllowedIPs = CopyStringSlice(ips)
+ }
+ if rules := ep.GetRules(); len(rules) > 0 {
+ result.Rules = make([]types.L7Rule, len(rules))
+ for i, r := range rules {
+ if r != nil {
+ result.Rules[i] = l7RuleFromProto(r)
+ }
+ }
+ }
+ if deny := ep.GetDenyRules(); len(deny) > 0 {
+ result.DenyRules = make([]types.L7DenyRule, len(deny))
+ for i, r := range deny {
+ if r != nil {
+ result.DenyRules[i] = l7DenyRuleFromProto(r)
+ }
+ }
+ }
+ if gql := ep.GetGraphqlPersistedQueries(); len(gql) > 0 {
+ result.GraphqlPersistedQueries = make(map[string]types.GraphqlOperation, len(gql))
+ for k, v := range gql {
+ if v != nil {
+ result.GraphqlPersistedQueries[k] = graphqlOperationFromProto(v)
+ }
+ }
+ }
+ return result
+}
+
+func policyNetworkEndpointToProto(ep *types.PolicyNetworkEndpoint) *sbv1.NetworkEndpoint {
+ result := &sbv1.NetworkEndpoint{
+ Host: ep.Host,
+ Port: ep.Port,
+ Protocol: ep.Protocol,
+ Tls: ep.TLS,
+ Enforcement: ep.Enforcement,
+ Access: ep.Access,
+ AllowEncodedSlash: ep.AllowEncodedSlash,
+ PersistedQueries: ep.PersistedQueries,
+ GraphqlMaxBodyBytes: ep.GraphqlMaxBodyBytes,
+ Path: ep.Path,
+ WebsocketCredentialRewrite: ep.WebsocketCredentialRewrite,
+ RequestBodyCredentialRewrite: ep.RequestBodyCredentialRewrite,
+ AdvisorProposed: ep.AdvisorProposed,
+ CredentialSigning: ep.CredentialSigning,
+ SigningService: ep.SigningService,
+ SigningRegion: ep.SigningRegion,
+ JsonRpcMaxBodyBytes: ep.JsonRpcMaxBodyBytes,
+ }
+ if ep.Mcp != nil {
+ result.Mcp = mcpOptionsToProto(ep.Mcp)
+ }
+ if len(ep.Ports) > 0 {
+ result.Ports = make([]uint32, len(ep.Ports))
+ copy(result.Ports, ep.Ports)
+ }
+ if len(ep.AllowedIPs) > 0 {
+ result.AllowedIps = CopyStringSlice(ep.AllowedIPs)
+ }
+ if len(ep.Rules) > 0 {
+ result.Rules = make([]*sbv1.L7Rule, len(ep.Rules))
+ for i := range ep.Rules {
+ result.Rules[i] = l7RuleToProto(&ep.Rules[i])
+ }
+ }
+ if len(ep.DenyRules) > 0 {
+ result.DenyRules = make([]*sbv1.L7DenyRule, len(ep.DenyRules))
+ for i := range ep.DenyRules {
+ result.DenyRules[i] = l7DenyRuleToProto(&ep.DenyRules[i])
+ }
+ }
+ if len(ep.GraphqlPersistedQueries) > 0 {
+ result.GraphqlPersistedQueries = make(map[string]*sbv1.GraphqlOperation, len(ep.GraphqlPersistedQueries))
+ for k, v := range ep.GraphqlPersistedQueries {
+ result.GraphqlPersistedQueries[k] = graphqlOperationToProto(&v)
+ }
+ }
+ return result
+}
+
+// --- L7Rule ---
+
+func l7RuleFromProto(r *sbv1.L7Rule) types.L7Rule {
+ result := types.L7Rule{}
+ if a := r.GetAllow(); a != nil {
+ result.Allow = &types.L7Allow{
+ Method: a.GetMethod(),
+ Path: a.GetPath(),
+ Command: a.GetCommand(),
+ OperationType: a.GetOperationType(),
+ OperationName: a.GetOperationName(),
+ Fields: CopyStringSlice(a.GetFields()),
+ }
+ if q := a.GetQuery(); len(q) > 0 {
+ result.Allow.Query = l7QueryMapFromProto(q)
+ }
+ if p := a.GetParams(); len(p) > 0 {
+ result.Allow.Params = l7QueryMapFromProto(p)
+ }
+ }
+ return result
+}
+
+func l7RuleToProto(r *types.L7Rule) *sbv1.L7Rule {
+ result := &sbv1.L7Rule{}
+ if r.Allow != nil {
+ result.Allow = &sbv1.L7Allow{
+ Method: r.Allow.Method,
+ Path: r.Allow.Path,
+ Command: r.Allow.Command,
+ OperationType: r.Allow.OperationType,
+ OperationName: r.Allow.OperationName,
+ Fields: CopyStringSlice(r.Allow.Fields),
+ }
+ if len(r.Allow.Query) > 0 {
+ result.Allow.Query = l7QueryMapToProto(r.Allow.Query)
+ }
+ if len(r.Allow.Params) > 0 {
+ result.Allow.Params = l7QueryMapToProto(r.Allow.Params)
+ }
+ }
+ return result
+}
+
+// --- L7DenyRule ---
+
+func l7DenyRuleFromProto(r *sbv1.L7DenyRule) types.L7DenyRule {
+ result := types.L7DenyRule{
+ Method: r.GetMethod(),
+ Path: r.GetPath(),
+ Command: r.GetCommand(),
+ OperationType: r.GetOperationType(),
+ OperationName: r.GetOperationName(),
+ Fields: CopyStringSlice(r.GetFields()),
+ Query: l7QueryMapFromProtoDeny(r.GetQuery()),
+ }
+ if p := r.GetParams(); len(p) > 0 {
+ result.Params = l7QueryMapFromProto(p)
+ }
+ return result
+}
+
+func l7DenyRuleToProto(r *types.L7DenyRule) *sbv1.L7DenyRule {
+ result := &sbv1.L7DenyRule{
+ Method: r.Method,
+ Path: r.Path,
+ Command: r.Command,
+ OperationType: r.OperationType,
+ OperationName: r.OperationName,
+ Fields: CopyStringSlice(r.Fields),
+ }
+ if len(r.Query) > 0 {
+ result.Query = l7QueryMapToProtoDeny(r.Query)
+ }
+ if len(r.Params) > 0 {
+ result.Params = l7QueryMapToProto(r.Params)
+ }
+ return result
+}
+
+// --- L7QueryMatcher helpers ---
+
+func l7QueryMapFromProto(m map[string]*sbv1.L7QueryMatcher) map[string]types.L7QueryMatcher {
+ if len(m) == 0 {
+ return nil
+ }
+ result := make(map[string]types.L7QueryMatcher, len(m))
+ for k, v := range m {
+ if v != nil {
+ result[k] = types.L7QueryMatcher{
+ Glob: v.GetGlob(),
+ Any: CopyStringSlice(v.GetAny()),
+ }
+ }
+ }
+ return result
+}
+
+func l7QueryMapToProto(m map[string]types.L7QueryMatcher) map[string]*sbv1.L7QueryMatcher {
+ if len(m) == 0 {
+ return nil
+ }
+ result := make(map[string]*sbv1.L7QueryMatcher, len(m))
+ for k, v := range m {
+ result[k] = &sbv1.L7QueryMatcher{
+ Glob: v.Glob,
+ Any: CopyStringSlice(v.Any),
+ }
+ }
+ return result
+}
+
+// L7DenyRule uses the same L7QueryMatcher proto type but on a different message.
+func l7QueryMapFromProtoDeny(m map[string]*sbv1.L7QueryMatcher) map[string]types.L7QueryMatcher {
+ return l7QueryMapFromProto(m)
+}
+
+func l7QueryMapToProtoDeny(m map[string]types.L7QueryMatcher) map[string]*sbv1.L7QueryMatcher {
+ return l7QueryMapToProto(m)
+}
+
+// --- GraphqlOperation ---
+
+func graphqlOperationFromProto(op *sbv1.GraphqlOperation) types.GraphqlOperation {
+ return types.GraphqlOperation{
+ OperationType: op.GetOperationType(),
+ OperationName: op.GetOperationName(),
+ Fields: CopyStringSlice(op.GetFields()),
+ }
+}
+
+func graphqlOperationToProto(op *types.GraphqlOperation) *sbv1.GraphqlOperation {
+ return &sbv1.GraphqlOperation{
+ OperationType: op.OperationType,
+ OperationName: op.OperationName,
+ Fields: CopyStringSlice(op.Fields),
+ }
+}
+
+// --- McpOptions ---
+
+func mcpOptionsFromProto(m *sbv1.McpOptions) *types.McpOptions {
+ if m == nil {
+ return nil
+ }
+ return &types.McpOptions{
+ StrictToolNames: m.StrictToolNames,
+ AllowAllKnownMcpMethods: m.AllowAllKnownMcpMethods,
+ }
+}
+
+func mcpOptionsToProto(m *types.McpOptions) *sbv1.McpOptions {
+ if m == nil {
+ return nil
+ }
+ return &sbv1.McpOptions{
+ StrictToolNames: m.StrictToolNames,
+ AllowAllKnownMcpMethods: m.AllowAllKnownMcpMethods,
+ }
+}
diff --git a/sdk/go/openshell/v1/internal/converter/policy.go b/sdk/go/openshell/v1/internal/converter/policy.go
new file mode 100644
index 000000000..780fadb56
--- /dev/null
+++ b/sdk/go/openshell/v1/internal/converter/policy.go
@@ -0,0 +1,304 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package converter
+
+import (
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+ pb "github.com/NVIDIA/OpenShell/sdk/go/proto/openshellv1"
+ sbv1 "github.com/NVIDIA/OpenShell/sdk/go/proto/sandboxv1"
+)
+
+// --- PolicyLoadStatus enum mapping ---
+
+// PolicyLoadStatusFromProto converts a proto PolicyStatus to an SDK PolicyLoadStatus.
+func PolicyLoadStatusFromProto(s pb.PolicyStatus) types.PolicyLoadStatus {
+ switch s {
+ case pb.PolicyStatus_POLICY_STATUS_PENDING:
+ return types.PolicyLoadStatusPending
+ case pb.PolicyStatus_POLICY_STATUS_LOADED:
+ return types.PolicyLoadStatusLoaded
+ case pb.PolicyStatus_POLICY_STATUS_FAILED:
+ return types.PolicyLoadStatusFailed
+ case pb.PolicyStatus_POLICY_STATUS_SUPERSEDED:
+ return types.PolicyLoadStatusSuperseded
+ default:
+ return types.PolicyLoadStatusUnspecified
+ }
+}
+
+// PolicyLoadStatusToProto converts an SDK PolicyLoadStatus to a proto PolicyStatus.
+func PolicyLoadStatusToProto(s types.PolicyLoadStatus) pb.PolicyStatus {
+ switch s {
+ case types.PolicyLoadStatusPending:
+ return pb.PolicyStatus_POLICY_STATUS_PENDING
+ case types.PolicyLoadStatusLoaded:
+ return pb.PolicyStatus_POLICY_STATUS_LOADED
+ case types.PolicyLoadStatusFailed:
+ return pb.PolicyStatus_POLICY_STATUS_FAILED
+ case types.PolicyLoadStatusSuperseded:
+ return pb.PolicyStatus_POLICY_STATUS_SUPERSEDED
+ default:
+ return pb.PolicyStatus_POLICY_STATUS_UNSPECIFIED
+ }
+}
+
+// --- PolicyChunk ---
+
+// PolicyChunkFromProto converts a proto PolicyChunk to an SDK PolicyChunk.
+func PolicyChunkFromProto(c *pb.PolicyChunk) *types.PolicyChunk {
+ if c == nil {
+ return nil
+ }
+ return &types.PolicyChunk{
+ ID: c.GetId(),
+ Status: c.GetStatus(),
+ RuleName: c.GetRuleName(),
+ ProposedRule: NetworkPolicyRuleFromProto(c.GetProposedRule()),
+ Rationale: c.GetRationale(),
+ SecurityNotes: c.GetSecurityNotes(),
+ Confidence: c.GetConfidence(),
+ DenialSummaryIDs: CopyStringSlice(c.GetDenialSummaryIds()),
+ CreatedAt: TimeFromMillis(c.GetCreatedAtMs()),
+ DecidedAt: TimeFromMillis(c.GetDecidedAtMs()),
+ Stage: c.GetStage(),
+ SupersedesChunkID: c.GetSupersedesChunkId(),
+ HitCount: c.GetHitCount(),
+ FirstSeen: TimeFromMillis(c.GetFirstSeenMs()),
+ LastSeen: TimeFromMillis(c.GetLastSeenMs()),
+ Binary: c.GetBinary(),
+ ValidationResult: c.GetValidationResult(),
+ RejectionReason: c.GetRejectionReason(),
+ }
+}
+
+// --- DraftPolicy ---
+
+// DraftPolicyFromProto converts a proto GetDraftPolicyResponse to an SDK DraftPolicy.
+func DraftPolicyFromProto(r *pb.GetDraftPolicyResponse) *types.DraftPolicy {
+ if r == nil {
+ return nil
+ }
+ result := &types.DraftPolicy{
+ RollingSummary: r.GetRollingSummary(),
+ DraftVersion: r.GetDraftVersion(),
+ LastAnalyzedAt: TimeFromMillis(r.GetLastAnalyzedAtMs()),
+ }
+ if chunks := r.GetChunks(); len(chunks) > 0 {
+ result.Chunks = make([]types.PolicyChunk, 0, len(chunks))
+ for _, c := range chunks {
+ if converted := PolicyChunkFromProto(c); converted != nil {
+ result.Chunks = append(result.Chunks, *converted)
+ }
+ }
+ }
+ return result
+}
+
+// --- SandboxPolicy ---
+
+// SandboxPolicyFromProto converts a proto SandboxPolicy to an SDK SandboxPolicy.
+// Returns nil for nil input. All slice and map fields are deep-copied.
+func SandboxPolicyFromProto(p *sbv1.SandboxPolicy) *types.SandboxPolicy {
+ if p == nil {
+ return nil
+ }
+ result := &types.SandboxPolicy{
+ Version: p.GetVersion(),
+ Filesystem: filesystemPolicyFromProto(p.GetFilesystem()),
+ Landlock: landlockPolicyFromProto(p.GetLandlock()),
+ Process: processPolicyFromProto(p.GetProcess()),
+ }
+ if np := p.GetNetworkPolicies(); np != nil {
+ result.NetworkPolicies = make(map[string]types.NetworkPolicyRule, len(np))
+ for k, v := range np {
+ if converted := NetworkPolicyRuleFromProto(v); converted != nil {
+ result.NetworkPolicies[k] = *converted
+ }
+ }
+ }
+ return result
+}
+
+// SandboxPolicyToProto converts an SDK SandboxPolicy to a proto SandboxPolicy.
+// Returns nil for nil input. All slice and map fields are deep-copied.
+func SandboxPolicyToProto(p *types.SandboxPolicy) *sbv1.SandboxPolicy {
+ if p == nil {
+ return nil
+ }
+ result := &sbv1.SandboxPolicy{
+ Version: p.Version,
+ Filesystem: filesystemPolicyToProto(p.Filesystem),
+ Landlock: landlockPolicyToProto(p.Landlock),
+ Process: processPolicyToProto(p.Process),
+ }
+ if p.NetworkPolicies != nil {
+ result.NetworkPolicies = make(map[string]*sbv1.NetworkPolicyRule, len(p.NetworkPolicies))
+ for k, v := range p.NetworkPolicies {
+ result.NetworkPolicies[k] = NetworkPolicyRuleToProto(&v)
+ }
+ }
+ return result
+}
+
+func filesystemPolicyFromProto(f *sbv1.FilesystemPolicy) *types.FilesystemPolicy {
+ if f == nil {
+ return nil
+ }
+ return &types.FilesystemPolicy{
+ IncludeWorkdir: f.GetIncludeWorkdir(),
+ ReadOnly: CopyStringSlice(f.GetReadOnly()),
+ ReadWrite: CopyStringSlice(f.GetReadWrite()),
+ }
+}
+
+func filesystemPolicyToProto(f *types.FilesystemPolicy) *sbv1.FilesystemPolicy {
+ if f == nil {
+ return nil
+ }
+ return &sbv1.FilesystemPolicy{
+ IncludeWorkdir: f.IncludeWorkdir,
+ ReadOnly: CopyStringSlice(f.ReadOnly),
+ ReadWrite: CopyStringSlice(f.ReadWrite),
+ }
+}
+
+func landlockPolicyFromProto(l *sbv1.LandlockPolicy) *types.LandlockPolicy {
+ if l == nil {
+ return nil
+ }
+ return &types.LandlockPolicy{
+ Compatibility: l.GetCompatibility(),
+ }
+}
+
+func landlockPolicyToProto(l *types.LandlockPolicy) *sbv1.LandlockPolicy {
+ if l == nil {
+ return nil
+ }
+ return &sbv1.LandlockPolicy{
+ Compatibility: l.Compatibility,
+ }
+}
+
+func processPolicyFromProto(p *sbv1.ProcessPolicy) *types.ProcessPolicy {
+ if p == nil {
+ return nil
+ }
+ return &types.ProcessPolicy{
+ RunAsUser: p.GetRunAsUser(),
+ RunAsGroup: p.GetRunAsGroup(),
+ }
+}
+
+func processPolicyToProto(p *types.ProcessPolicy) *sbv1.ProcessPolicy {
+ if p == nil {
+ return nil
+ }
+ return &sbv1.ProcessPolicy{
+ RunAsUser: p.RunAsUser,
+ RunAsGroup: p.RunAsGroup,
+ }
+}
+
+// --- SandboxPolicyRevision ---
+
+// SandboxPolicyRevisionFromProto converts a proto SandboxPolicyRevision to an SDK SandboxPolicyRevision.
+func SandboxPolicyRevisionFromProto(r *pb.SandboxPolicyRevision) *types.SandboxPolicyRevision {
+ if r == nil {
+ return nil
+ }
+ return &types.SandboxPolicyRevision{
+ Version: r.GetVersion(),
+ PolicyHash: r.GetPolicyHash(),
+ Status: PolicyLoadStatusFromProto(r.GetStatus()),
+ LoadError: r.GetLoadError(),
+ CreatedAt: TimeFromMillis(r.GetCreatedAtMs()),
+ LoadedAt: TimeFromMillis(r.GetLoadedAtMs()),
+ Policy: SandboxPolicyFromProto(r.GetPolicy()),
+ }
+}
+
+// --- PolicyStatusResult ---
+
+// PolicyStatusResultFromProto converts a proto GetSandboxPolicyStatusResponse to an SDK PolicyStatusResult.
+func PolicyStatusResultFromProto(r *pb.GetSandboxPolicyStatusResponse) *types.PolicyStatusResult {
+ if r == nil {
+ return nil
+ }
+ result := &types.PolicyStatusResult{
+ ActiveVersion: r.GetActiveVersion(),
+ }
+ if rev := SandboxPolicyRevisionFromProto(r.GetRevision()); rev != nil {
+ result.Revision = *rev
+ }
+ return result
+}
+
+// --- ApproveResult ---
+
+// ApproveResultFromProto converts a proto ApproveDraftChunkResponse to an SDK ApproveResult.
+func ApproveResultFromProto(r *pb.ApproveDraftChunkResponse) *types.ApproveResult {
+ if r == nil {
+ return nil
+ }
+ return &types.ApproveResult{
+ PolicyVersion: r.GetPolicyVersion(),
+ PolicyHash: r.GetPolicyHash(),
+ }
+}
+
+// --- ApproveAllResult ---
+
+// ApproveAllResultFromProto converts a proto ApproveAllDraftChunksResponse to an SDK ApproveAllResult.
+func ApproveAllResultFromProto(r *pb.ApproveAllDraftChunksResponse) *types.ApproveAllResult {
+ if r == nil {
+ return nil
+ }
+ return &types.ApproveAllResult{
+ PolicyVersion: r.GetPolicyVersion(),
+ PolicyHash: r.GetPolicyHash(),
+ ChunksApproved: r.GetChunksApproved(),
+ ChunksSkipped: r.GetChunksSkipped(),
+ }
+}
+
+// --- UndoResult ---
+
+// UndoResultFromProto converts a proto UndoDraftChunkResponse to an SDK UndoResult.
+func UndoResultFromProto(r *pb.UndoDraftChunkResponse) *types.UndoResult {
+ if r == nil {
+ return nil
+ }
+ return &types.UndoResult{
+ PolicyVersion: r.GetPolicyVersion(),
+ PolicyHash: r.GetPolicyHash(),
+ }
+}
+
+// --- ClearResult ---
+
+// ClearResultFromProto converts a proto ClearDraftChunksResponse to an SDK ClearResult.
+func ClearResultFromProto(r *pb.ClearDraftChunksResponse) *types.ClearResult {
+ if r == nil {
+ return nil
+ }
+ return &types.ClearResult{
+ ChunksCleared: r.GetChunksCleared(),
+ }
+}
+
+// --- DraftHistoryEntry ---
+
+// DraftHistoryEntryFromProto converts a proto DraftHistoryEntry to an SDK DraftHistoryEntry.
+func DraftHistoryEntryFromProto(e *pb.DraftHistoryEntry) *types.DraftHistoryEntry {
+ if e == nil {
+ return nil
+ }
+ return &types.DraftHistoryEntry{
+ Timestamp: TimeFromMillis(e.GetTimestampMs()),
+ EventType: e.GetEventType(),
+ Description: e.GetDescription(),
+ ChunkID: e.GetChunkId(),
+ }
+}
diff --git a/sdk/go/openshell/v1/internal/converter/provider.go b/sdk/go/openshell/v1/internal/converter/provider.go
new file mode 100644
index 000000000..42799feab
--- /dev/null
+++ b/sdk/go/openshell/v1/internal/converter/provider.go
@@ -0,0 +1,101 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package converter
+
+import (
+ "time"
+
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+ dm "github.com/NVIDIA/OpenShell/sdk/go/proto/datamodelv1"
+)
+
+// ProviderFromProto converts a proto Provider to an SDK Provider.
+func ProviderFromProto(p *dm.Provider) *types.Provider {
+ if p == nil {
+ return nil
+ }
+
+ result := &types.Provider{
+ Type: p.GetType(),
+ Spec: types.ProviderSpec{
+ Config: CopyStringMap(p.GetConfig()),
+ ProfileWorkspace: p.GetProfileWorkspace(),
+ },
+ }
+
+ if m := p.GetMetadata(); m != nil {
+ result.ID = m.GetId()
+ result.Name = m.GetName()
+ result.CreatedAt = TimeFromMillis(m.GetCreatedAtMs())
+ result.Labels = CopyStringMap(m.GetLabels())
+ result.Annotations = CopyStringMap(m.GetAnnotations())
+ result.ResourceVersion = m.GetResourceVersion()
+ result.Workspace = m.GetWorkspace()
+ result.DeletionTimestamp = TimeFromMillisPtr(m.GetDeletionTimestampMs())
+ }
+
+ if expires := p.GetCredentialExpiresAtMs(); len(expires) > 0 {
+ result.Spec.CredentialExpiresAt = make(map[string]time.Time, len(expires))
+ for k, ms := range expires {
+ result.Spec.CredentialExpiresAt[k] = TimeFromMillis(ms)
+ }
+ }
+
+ if handles := p.GetCredentialHandles(); len(handles) > 0 {
+ result.Spec.CredentialHandles = make(map[string]types.CredentialHandle, len(handles))
+ for k, h := range handles {
+ result.Spec.CredentialHandles[k] = types.CredentialHandle{
+ Driver: h.GetDriver(),
+ Handle: h.GetHandle(),
+ Metadata: CopyStringMap(h.GetMetadata()),
+ }
+ }
+ }
+
+ return result
+}
+
+// ProviderToProto converts an SDK Provider to a proto Provider.
+func ProviderToProto(p *types.Provider) *dm.Provider {
+ if p == nil {
+ return nil
+ }
+
+ result := &dm.Provider{
+ Metadata: &dm.ObjectMeta{
+ Id: p.ID,
+ Name: p.Name,
+ CreatedAtMs: MillisFromTime(p.CreatedAt),
+ Labels: CopyStringMap(p.Labels),
+ Annotations: CopyStringMap(p.Annotations),
+ ResourceVersion: p.ResourceVersion,
+ Workspace: p.Workspace,
+ DeletionTimestampMs: MillisFromTimePtr(p.DeletionTimestamp),
+ },
+ Type: p.Type,
+ Credentials: CopyStringMap(p.Spec.Credentials),
+ Config: CopyStringMap(p.Spec.Config),
+ ProfileWorkspace: p.Spec.ProfileWorkspace,
+ }
+
+ if len(p.Spec.CredentialExpiresAt) > 0 {
+ result.CredentialExpiresAtMs = make(map[string]int64, len(p.Spec.CredentialExpiresAt))
+ for k, t := range p.Spec.CredentialExpiresAt {
+ result.CredentialExpiresAtMs[k] = MillisFromTime(t)
+ }
+ }
+
+ if len(p.Spec.CredentialHandles) > 0 {
+ result.CredentialHandles = make(map[string]*dm.CredentialHandle, len(p.Spec.CredentialHandles))
+ for k, h := range p.Spec.CredentialHandles {
+ result.CredentialHandles[k] = &dm.CredentialHandle{
+ Driver: h.Driver,
+ Handle: h.Handle,
+ Metadata: CopyStringMap(h.Metadata),
+ }
+ }
+ }
+
+ return result
+}
diff --git a/sdk/go/openshell/v1/internal/converter/provider_test.go b/sdk/go/openshell/v1/internal/converter/provider_test.go
new file mode 100644
index 000000000..dcead666a
--- /dev/null
+++ b/sdk/go/openshell/v1/internal/converter/provider_test.go
@@ -0,0 +1,174 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package converter
+
+import (
+ "testing"
+ "time"
+
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+ dm "github.com/NVIDIA/OpenShell/sdk/go/proto/datamodelv1"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestProviderFromProto_Nil(t *testing.T) {
+ assert.Nil(t, ProviderFromProto(nil))
+}
+
+func TestProviderFromProto_Full(t *testing.T) {
+ proto := &dm.Provider{
+ Metadata: &dm.ObjectMeta{
+ Id: "prov-1",
+ Name: "claude-provider",
+ CreatedAtMs: 1700000000000,
+ Labels: map[string]string{"env": "prod"},
+ Annotations: map[string]string{"note": "test"},
+ ResourceVersion: 42,
+ Workspace: "default",
+ },
+ Type: "claude",
+ Credentials: map[string]string{"api_key": "secret"},
+ Config: map[string]string{"base_url": "https://api.example.com"},
+ ProfileWorkspace: "shared",
+ CredentialExpiresAtMs: map[string]int64{
+ "api_key": 1700003600000,
+ },
+ CredentialHandles: map[string]*dm.CredentialHandle{
+ "api_key": {
+ Driver: "vault",
+ Handle: "secret/data/claude",
+ Metadata: map[string]string{"version": "3"},
+ },
+ },
+ }
+
+ result := ProviderFromProto(proto)
+
+ require.NotNil(t, result)
+ assert.Equal(t, "prov-1", result.ID)
+ assert.Equal(t, "claude-provider", result.Name)
+ assert.Equal(t, "claude", result.Type)
+ assert.Equal(t, uint64(42), result.ResourceVersion)
+ assert.Equal(t, "default", result.Workspace)
+ assert.Equal(t, map[string]string{"env": "prod"}, result.Labels)
+ assert.Equal(t, map[string]string{"note": "test"}, result.Annotations)
+ assert.Equal(t, map[string]string{"base_url": "https://api.example.com"}, result.Spec.Config)
+ assert.Equal(t, "shared", result.Spec.ProfileWorkspace)
+
+ require.Len(t, result.Spec.CredentialExpiresAt, 1)
+ assert.False(t, result.Spec.CredentialExpiresAt["api_key"].IsZero())
+
+ require.Len(t, result.Spec.CredentialHandles, 1)
+ h := result.Spec.CredentialHandles["api_key"]
+ assert.Equal(t, "vault", h.Driver)
+ assert.Equal(t, "secret/data/claude", h.Handle)
+ assert.Equal(t, map[string]string{"version": "3"}, h.Metadata)
+}
+
+func TestProviderFromProto_NilMetadata(t *testing.T) {
+ proto := &dm.Provider{
+ Type: "openai",
+ Config: map[string]string{"key": "val"},
+ }
+
+ result := ProviderFromProto(proto)
+
+ require.NotNil(t, result)
+ assert.Equal(t, "", result.ID)
+ assert.Equal(t, "", result.Name)
+ assert.Equal(t, "openai", result.Type)
+ assert.Equal(t, map[string]string{"key": "val"}, result.Spec.Config)
+}
+
+func TestProviderFromProto_EmptyHandles(t *testing.T) {
+ proto := &dm.Provider{
+ Type: "test",
+ CredentialHandles: map[string]*dm.CredentialHandle{},
+ }
+
+ result := ProviderFromProto(proto)
+
+ require.NotNil(t, result)
+ assert.Nil(t, result.Spec.CredentialHandles)
+}
+
+func TestProviderToProto_Nil(t *testing.T) {
+ assert.Nil(t, ProviderToProto(nil))
+}
+
+func TestProviderToProto_Full(t *testing.T) {
+ expires := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
+ provider := &types.Provider{
+ ID: "prov-1",
+ Name: "test-provider",
+ Type: "claude",
+ Labels: map[string]string{"env": "dev"},
+ Annotations: map[string]string{"note": "x"},
+ ResourceVersion: 7,
+ Workspace: "ws-1",
+ Spec: types.ProviderSpec{
+ Credentials: map[string]string{"token": "abc"},
+ Config: map[string]string{"url": "https://example.com"},
+ ProfileWorkspace: "global",
+ CredentialExpiresAt: map[string]time.Time{"token": expires},
+ CredentialHandles: map[string]types.CredentialHandle{
+ "token": {
+ Driver: "k8s-secrets",
+ Handle: "ns/secret-name",
+ Metadata: map[string]string{"k": "v"},
+ },
+ },
+ },
+ }
+
+ result := ProviderToProto(provider)
+
+ require.NotNil(t, result)
+ assert.Equal(t, "prov-1", result.Metadata.Id)
+ assert.Equal(t, "test-provider", result.Metadata.Name)
+ assert.Equal(t, "claude", result.Type)
+ assert.Equal(t, "global", result.ProfileWorkspace)
+ assert.Equal(t, map[string]string{"token": "abc"}, result.Credentials)
+ assert.Equal(t, map[string]string{"url": "https://example.com"}, result.Config)
+
+ require.Len(t, result.CredentialExpiresAtMs, 1)
+ assert.Greater(t, result.CredentialExpiresAtMs["token"], int64(0))
+
+ require.Len(t, result.CredentialHandles, 1)
+ h := result.CredentialHandles["token"]
+ assert.Equal(t, "k8s-secrets", h.Driver)
+ assert.Equal(t, "ns/secret-name", h.Handle)
+ assert.Equal(t, map[string]string{"k": "v"}, h.Metadata)
+}
+
+func TestProviderRoundTrip(t *testing.T) {
+ original := &types.Provider{
+ ID: "rt-1",
+ Name: "roundtrip",
+ Type: "gitlab",
+ ResourceVersion: 3,
+ Workspace: "default",
+ Labels: map[string]string{"team": "infra"},
+ Spec: types.ProviderSpec{
+ Config: map[string]string{"url": "https://gitlab.com"},
+ ProfileWorkspace: "shared",
+ CredentialHandles: map[string]types.CredentialHandle{
+ "pat": {Driver: "vault", Handle: "secret/gitlab", Metadata: map[string]string{"ver": "1"}},
+ },
+ },
+ }
+
+ proto := ProviderToProto(original)
+ back := ProviderFromProto(proto)
+
+ assert.Equal(t, original.ID, back.ID)
+ assert.Equal(t, original.Name, back.Name)
+ assert.Equal(t, original.Type, back.Type)
+ assert.Equal(t, original.Workspace, back.Workspace)
+ assert.Equal(t, original.Labels, back.Labels)
+ assert.Equal(t, original.Spec.Config, back.Spec.Config)
+ assert.Equal(t, original.Spec.ProfileWorkspace, back.Spec.ProfileWorkspace)
+ assert.Equal(t, original.Spec.CredentialHandles, back.Spec.CredentialHandles)
+}
diff --git a/sdk/go/openshell/v1/internal/converter/sandbox.go b/sdk/go/openshell/v1/internal/converter/sandbox.go
new file mode 100644
index 000000000..b522454b8
--- /dev/null
+++ b/sdk/go/openshell/v1/internal/converter/sandbox.go
@@ -0,0 +1,206 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package converter
+
+import (
+ "fmt"
+
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+ dm "github.com/NVIDIA/OpenShell/sdk/go/proto/datamodelv1"
+ pb "github.com/NVIDIA/OpenShell/sdk/go/proto/openshellv1"
+)
+
+// SandboxFromProto converts a proto Sandbox to an SDK Sandbox.
+func SandboxFromProto(s *pb.Sandbox) *types.Sandbox {
+ if s == nil {
+ return nil
+ }
+
+ result := &types.Sandbox{}
+
+ if m := s.GetMetadata(); m != nil {
+ result.ID = m.GetId()
+ result.Name = m.GetName()
+ result.CreatedAt = TimeFromMillis(m.GetCreatedAtMs())
+ result.Labels = CopyStringMap(m.GetLabels())
+ result.Annotations = CopyStringMap(m.GetAnnotations())
+ result.ResourceVersion = m.GetResourceVersion()
+ result.Workspace = m.GetWorkspace()
+ result.DeletionTimestamp = TimeFromMillisPtr(m.GetDeletionTimestampMs())
+ }
+
+ if spec := s.GetSpec(); spec != nil {
+ result.Spec = sandboxSpecFromProto(spec)
+ }
+
+ if status := s.GetStatus(); status != nil {
+ result.Status = sandboxStatusFromProto(status)
+ } else {
+ result.Status.Phase = types.SandboxUnknown
+ }
+
+ return result
+}
+
+func sandboxSpecFromProto(spec *pb.SandboxSpec) types.SandboxSpec {
+ result := types.SandboxSpec{
+ LogLevel: spec.GetLogLevel(),
+ Environment: CopyStringMap(spec.GetEnvironment()),
+ Providers: CopyStringSlice(spec.GetProviders()),
+ Policy: SandboxPolicyFromProto(spec.GetPolicy()),
+ }
+
+ if tmpl := spec.GetTemplate(); tmpl != nil {
+ result.Template = &types.SandboxTemplate{
+ Image: tmpl.GetImage(),
+ RuntimeClassName: tmpl.GetRuntimeClassName(),
+ AgentSocket: tmpl.GetAgentSocket(),
+ Labels: CopyStringMap(tmpl.GetLabels()),
+ Annotations: CopyStringMap(tmpl.GetAnnotations()),
+ Environment: CopyStringMap(tmpl.GetEnvironment()),
+ Resources: structToMap(tmpl.GetResources()),
+ UserNamespaces: CopyBoolPtr(tmpl.UserNamespaces),
+ DriverConfig: structToMap(tmpl.GetDriverConfig()),
+ }
+ }
+
+ if rr := spec.GetResourceRequirements(); rr != nil {
+ if gpu := rr.GetGpu(); gpu != nil && gpu.Count != nil {
+ result.GPUCount = gpu.Count
+ }
+ }
+
+ return result
+}
+
+func sandboxStatusFromProto(status *pb.SandboxStatus) types.SandboxStatus {
+ result := types.SandboxStatus{
+ SandboxName: status.GetSandboxName(),
+ AgentPod: status.GetAgentPod(),
+ AgentFd: status.GetAgentFd(),
+ SandboxFd: status.GetSandboxFd(),
+ Phase: SandboxPhaseFromProto(status.GetPhase()),
+ CurrentPolicyVersion: status.GetCurrentPolicyVersion(),
+ }
+
+ for _, c := range status.GetConditions() {
+ result.Conditions = append(result.Conditions, types.SandboxCondition{
+ Type: c.GetType(),
+ Status: c.GetStatus(),
+ Reason: c.GetReason(),
+ Message: c.GetMessage(),
+ LastTransitionTime: c.GetLastTransitionTime(),
+ })
+ }
+
+ return result
+}
+
+// SandboxPhaseFromProto converts a proto SandboxPhase to an SDK SandboxPhase.
+func SandboxPhaseFromProto(phase pb.SandboxPhase) types.SandboxPhase {
+ switch phase {
+ case pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING:
+ return types.SandboxProvisioning
+ case pb.SandboxPhase_SANDBOX_PHASE_READY:
+ return types.SandboxReady
+ case pb.SandboxPhase_SANDBOX_PHASE_ERROR:
+ return types.SandboxError
+ case pb.SandboxPhase_SANDBOX_PHASE_DELETING:
+ return types.SandboxDeleting
+ case pb.SandboxPhase_SANDBOX_PHASE_UNKNOWN:
+ return types.SandboxUnknown
+ default:
+ return types.SandboxUnknown
+ }
+}
+
+// SandboxPhaseToProto converts an SDK SandboxPhase to a proto SandboxPhase.
+func SandboxPhaseToProto(phase types.SandboxPhase) pb.SandboxPhase {
+ switch phase {
+ case types.SandboxProvisioning:
+ return pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING
+ case types.SandboxReady:
+ return pb.SandboxPhase_SANDBOX_PHASE_READY
+ case types.SandboxError:
+ return pb.SandboxPhase_SANDBOX_PHASE_ERROR
+ case types.SandboxDeleting:
+ return pb.SandboxPhase_SANDBOX_PHASE_DELETING
+ case types.SandboxUnknown:
+ return pb.SandboxPhase_SANDBOX_PHASE_UNKNOWN
+ default:
+ return pb.SandboxPhase_SANDBOX_PHASE_UNKNOWN
+ }
+}
+
+// SandboxToProto converts an SDK Sandbox to a proto Sandbox.
+func SandboxToProto(s *types.Sandbox) (*pb.Sandbox, error) {
+ if s == nil {
+ return nil, nil
+ }
+
+ spec, err := SandboxSpecToProto(&s.Spec)
+ if err != nil {
+ return nil, fmt.Errorf("convert sandbox spec: %w", err)
+ }
+
+ return &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{
+ Id: s.ID,
+ Name: s.Name,
+ CreatedAtMs: MillisFromTime(s.CreatedAt),
+ Labels: CopyStringMap(s.Labels),
+ Annotations: CopyStringMap(s.Annotations),
+ ResourceVersion: s.ResourceVersion,
+ Workspace: s.Workspace,
+ DeletionTimestampMs: MillisFromTimePtr(s.DeletionTimestamp),
+ },
+ Spec: spec,
+ }, nil
+}
+
+// SandboxSpecToProto converts an SDK SandboxSpec to a proto SandboxSpec.
+func SandboxSpecToProto(spec *types.SandboxSpec) (*pb.SandboxSpec, error) {
+ if spec == nil {
+ return nil, nil
+ }
+
+ result := &pb.SandboxSpec{
+ LogLevel: spec.LogLevel,
+ Environment: CopyStringMap(spec.Environment),
+ Providers: CopyStringSlice(spec.Providers),
+ Policy: SandboxPolicyToProto(spec.Policy),
+ }
+
+ if spec.Template != nil {
+ resources, err := mapToStruct(spec.Template.Resources)
+ if err != nil {
+ return nil, fmt.Errorf("convert template resources: %w", err)
+ }
+ driverConfig, err := mapToStruct(spec.Template.DriverConfig)
+ if err != nil {
+ return nil, fmt.Errorf("convert template driver config: %w", err)
+ }
+ result.Template = &pb.SandboxTemplate{
+ Image: spec.Template.Image,
+ RuntimeClassName: spec.Template.RuntimeClassName,
+ AgentSocket: spec.Template.AgentSocket,
+ Labels: CopyStringMap(spec.Template.Labels),
+ Annotations: CopyStringMap(spec.Template.Annotations),
+ Environment: CopyStringMap(spec.Template.Environment),
+ Resources: resources,
+ UserNamespaces: CopyBoolPtr(spec.Template.UserNamespaces),
+ DriverConfig: driverConfig,
+ }
+ }
+
+ if spec.GPUCount != nil {
+ result.ResourceRequirements = &pb.ResourceRequirements{
+ Gpu: &pb.GpuResourceRequirements{
+ Count: spec.GPUCount,
+ },
+ }
+ }
+
+ return result, nil
+}
diff --git a/sdk/go/openshell/v1/internal/converter/sandbox_test.go b/sdk/go/openshell/v1/internal/converter/sandbox_test.go
new file mode 100644
index 000000000..f3c41650e
--- /dev/null
+++ b/sdk/go/openshell/v1/internal/converter/sandbox_test.go
@@ -0,0 +1,404 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package converter
+
+import (
+ "testing"
+ "time"
+
+ v1 "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+ dm "github.com/NVIDIA/OpenShell/sdk/go/proto/datamodelv1"
+ pb "github.com/NVIDIA/OpenShell/sdk/go/proto/openshellv1"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "google.golang.org/protobuf/proto"
+)
+
+func TestSandboxFromProto(t *testing.T) {
+ userNS := true
+ gpuCount := uint32(2)
+ proto := &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{
+ Id: "sb-1",
+ Name: "my-sandbox",
+ CreatedAtMs: 1700000000000,
+ Labels: map[string]string{"env": "dev"},
+ Annotations: map[string]string{"owner": "team-a"},
+ ResourceVersion: 3,
+ Workspace: "prod",
+ DeletionTimestampMs: 1700000060000,
+ },
+ Spec: &pb.SandboxSpec{
+ LogLevel: "debug",
+ Environment: map[string]string{"FOO": "bar"},
+ Template: &pb.SandboxTemplate{
+ Image: "nvidia/sandbox:latest",
+ RuntimeClassName: "kata",
+ AgentSocket: "/var/run/agent.sock",
+ Labels: map[string]string{"app": "test"},
+ Annotations: map[string]string{"note": "hello"},
+ Environment: map[string]string{"TMPL_VAR": "val"},
+ UserNamespaces: &userNS,
+ },
+ Providers: []string{"claude", "github"},
+ ResourceRequirements: &pb.ResourceRequirements{
+ Gpu: &pb.GpuResourceRequirements{
+ Count: &gpuCount,
+ },
+ },
+ },
+ Status: &pb.SandboxStatus{
+ SandboxName: "sb-compute-1",
+ AgentPod: "agent-pod-xyz",
+ AgentFd: "fd-agent",
+ SandboxFd: "fd-sandbox",
+ Phase: pb.SandboxPhase_SANDBOX_PHASE_READY,
+ CurrentPolicyVersion: 7,
+ Conditions: []*pb.SandboxCondition{
+ {
+ Type: "Ready",
+ Status: "True",
+ Reason: "AllGood",
+ Message: "Sandbox is ready",
+ LastTransitionTime: "2024-01-01T00:00:00Z",
+ },
+ },
+ },
+ }
+
+ s := SandboxFromProto(proto)
+
+ require.NotNil(t, s)
+ assert.Equal(t, "sb-1", s.ID)
+ assert.Equal(t, "my-sandbox", s.Name)
+ assert.Equal(t, time.UnixMilli(1700000000000).UTC(), s.CreatedAt)
+ assert.Equal(t, map[string]string{"env": "dev"}, s.Labels)
+ assert.Equal(t, map[string]string{"owner": "team-a"}, s.Annotations)
+ assert.Equal(t, uint64(3), s.ResourceVersion)
+ assert.Equal(t, "prod", s.Workspace)
+ require.NotNil(t, s.DeletionTimestamp)
+ assert.Equal(t, time.UnixMilli(1700000060000).UTC(), *s.DeletionTimestamp)
+
+ // Spec
+ assert.Equal(t, "debug", s.Spec.LogLevel)
+ assert.Equal(t, map[string]string{"FOO": "bar"}, s.Spec.Environment)
+ assert.Equal(t, []string{"claude", "github"}, s.Spec.Providers)
+ require.NotNil(t, s.Spec.GPUCount)
+ assert.Equal(t, uint32(2), *s.Spec.GPUCount)
+
+ // Template
+ require.NotNil(t, s.Spec.Template)
+ assert.Equal(t, "nvidia/sandbox:latest", s.Spec.Template.Image)
+ assert.Equal(t, "kata", s.Spec.Template.RuntimeClassName)
+ assert.Equal(t, "/var/run/agent.sock", s.Spec.Template.AgentSocket)
+ assert.Equal(t, map[string]string{"app": "test"}, s.Spec.Template.Labels)
+ assert.Equal(t, map[string]string{"note": "hello"}, s.Spec.Template.Annotations)
+ assert.Equal(t, map[string]string{"TMPL_VAR": "val"}, s.Spec.Template.Environment)
+ require.NotNil(t, s.Spec.Template.UserNamespaces)
+ assert.True(t, *s.Spec.Template.UserNamespaces)
+
+ // Status
+ assert.Equal(t, "sb-compute-1", s.Status.SandboxName)
+ assert.Equal(t, "agent-pod-xyz", s.Status.AgentPod)
+ assert.Equal(t, "fd-agent", s.Status.AgentFd)
+ assert.Equal(t, "fd-sandbox", s.Status.SandboxFd)
+ assert.Equal(t, v1.SandboxReady, s.Status.Phase)
+ assert.Equal(t, uint32(7), s.Status.CurrentPolicyVersion)
+ require.Len(t, s.Status.Conditions, 1)
+ assert.Equal(t, "Ready", s.Status.Conditions[0].Type)
+ assert.Equal(t, "True", s.Status.Conditions[0].Status)
+ assert.Equal(t, "AllGood", s.Status.Conditions[0].Reason)
+ assert.Equal(t, "Sandbox is ready", s.Status.Conditions[0].Message)
+ assert.Equal(t, "2024-01-01T00:00:00Z", s.Status.Conditions[0].LastTransitionTime)
+}
+
+func TestSandboxFromProto_NilFields(t *testing.T) {
+ proto := &pb.Sandbox{}
+
+ s := SandboxFromProto(proto)
+
+ require.NotNil(t, s)
+ assert.Empty(t, s.ID)
+ assert.Empty(t, s.Name)
+ assert.True(t, s.CreatedAt.IsZero())
+ assert.Nil(t, s.Spec.Template)
+ assert.Nil(t, s.Spec.GPUCount)
+ assert.Equal(t, v1.SandboxUnknown, s.Status.Phase)
+}
+
+func TestSandboxFromProto_Nil(t *testing.T) {
+ s := SandboxFromProto(nil)
+ assert.Nil(t, s)
+}
+
+func TestSandboxPhaseFromProto(t *testing.T) {
+ tests := []struct {
+ proto pb.SandboxPhase
+ expected v1.SandboxPhase
+ }{
+ {pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING, v1.SandboxProvisioning},
+ {pb.SandboxPhase_SANDBOX_PHASE_READY, v1.SandboxReady},
+ {pb.SandboxPhase_SANDBOX_PHASE_ERROR, v1.SandboxError},
+ {pb.SandboxPhase_SANDBOX_PHASE_DELETING, v1.SandboxDeleting},
+ {pb.SandboxPhase_SANDBOX_PHASE_UNKNOWN, v1.SandboxUnknown},
+ {pb.SandboxPhase_SANDBOX_PHASE_UNSPECIFIED, v1.SandboxUnknown},
+ {pb.SandboxPhase(999), v1.SandboxUnknown},
+ }
+
+ for _, tt := range tests {
+ assert.Equal(t, tt.expected, SandboxPhaseFromProto(tt.proto), "phase %v", tt.proto)
+ }
+}
+
+func TestSandboxPhaseToProto(t *testing.T) {
+ tests := []struct {
+ sdk v1.SandboxPhase
+ expected pb.SandboxPhase
+ }{
+ {v1.SandboxProvisioning, pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING},
+ {v1.SandboxReady, pb.SandboxPhase_SANDBOX_PHASE_READY},
+ {v1.SandboxError, pb.SandboxPhase_SANDBOX_PHASE_ERROR},
+ {v1.SandboxDeleting, pb.SandboxPhase_SANDBOX_PHASE_DELETING},
+ {v1.SandboxUnknown, pb.SandboxPhase_SANDBOX_PHASE_UNKNOWN},
+ {v1.SandboxPhase("bogus"), pb.SandboxPhase_SANDBOX_PHASE_UNKNOWN},
+ }
+
+ for _, tt := range tests {
+ assert.Equal(t, tt.expected, SandboxPhaseToProto(tt.sdk), "phase %v", tt.sdk)
+ }
+}
+
+func TestSandboxToProto(t *testing.T) {
+ userNS := true
+ gpuCount := uint32(4)
+ delTime := time.UnixMilli(1700000060000).UTC()
+ s := &v1.Sandbox{
+ ID: "sb-1",
+ Name: "my-sandbox",
+ CreatedAt: time.UnixMilli(1700000000000).UTC(),
+ Labels: map[string]string{"env": "dev"},
+ Annotations: map[string]string{"owner": "team-a"},
+ ResourceVersion: 3,
+ Workspace: "prod",
+ DeletionTimestamp: &delTime,
+ Spec: v1.SandboxSpec{
+ LogLevel: "info",
+ Environment: map[string]string{"KEY": "val"},
+ Template: &v1.SandboxTemplate{
+ Image: "img:v1",
+ RuntimeClassName: "runc",
+ AgentSocket: "/sock",
+ Labels: map[string]string{"l": "v"},
+ Annotations: map[string]string{"a": "v"},
+ Environment: map[string]string{"E": "V"},
+ UserNamespaces: &userNS,
+ },
+ Providers: []string{"prov-a"},
+ GPUCount: &gpuCount,
+ },
+ }
+
+ p, err := SandboxToProto(s)
+ require.NoError(t, err)
+ require.NotNil(t, p)
+ require.NotNil(t, p.Metadata)
+ assert.Equal(t, "sb-1", p.Metadata.Id)
+ assert.Equal(t, "my-sandbox", p.Metadata.Name)
+ assert.Equal(t, int64(1700000000000), p.Metadata.CreatedAtMs)
+ assert.Equal(t, map[string]string{"env": "dev"}, p.Metadata.Labels)
+ assert.Equal(t, map[string]string{"owner": "team-a"}, p.Metadata.Annotations)
+ assert.Equal(t, uint64(3), p.Metadata.ResourceVersion)
+ assert.Equal(t, "prod", p.Metadata.Workspace)
+ assert.Equal(t, int64(1700000060000), p.Metadata.DeletionTimestampMs)
+
+ require.NotNil(t, p.Spec)
+ assert.Equal(t, "info", p.Spec.LogLevel)
+ assert.Equal(t, map[string]string{"KEY": "val"}, p.Spec.Environment)
+ assert.Equal(t, []string{"prov-a"}, p.Spec.Providers)
+
+ require.NotNil(t, p.Spec.ResourceRequirements)
+ require.NotNil(t, p.Spec.ResourceRequirements.Gpu)
+ assert.Equal(t, uint32(4), p.Spec.ResourceRequirements.Gpu.GetCount())
+
+ require.NotNil(t, p.Spec.Template)
+ assert.Equal(t, "img:v1", p.Spec.Template.Image)
+ assert.Equal(t, "runc", p.Spec.Template.RuntimeClassName)
+ assert.Equal(t, "/sock", p.Spec.Template.AgentSocket)
+ assert.Equal(t, map[string]string{"l": "v"}, p.Spec.Template.Labels)
+ assert.Equal(t, map[string]string{"a": "v"}, p.Spec.Template.Annotations)
+ assert.Equal(t, map[string]string{"E": "V"}, p.Spec.Template.Environment)
+ require.NotNil(t, p.Spec.Template.UserNamespaces)
+ assert.True(t, *p.Spec.Template.UserNamespaces)
+}
+
+func TestSandboxToProto_Nil(t *testing.T) {
+ p, err := SandboxToProto(nil)
+ require.NoError(t, err)
+ assert.Nil(t, p)
+}
+
+func TestSandboxToProto_NilTemplate(t *testing.T) {
+ s := &v1.Sandbox{
+ Spec: v1.SandboxSpec{
+ LogLevel: "warn",
+ },
+ }
+
+ p, err := SandboxToProto(s)
+ require.NoError(t, err)
+ require.NotNil(t, p)
+ require.NotNil(t, p.Spec)
+ assert.Nil(t, p.Spec.Template)
+ assert.Nil(t, p.Spec.ResourceRequirements)
+}
+
+func TestSandboxRoundTrip(t *testing.T) {
+ userNS := false
+ gpuCount := uint32(1)
+ rtDelTime := time.UnixMilli(1700000090000).UTC()
+ original := &v1.Sandbox{
+ ID: "sb-rt",
+ Name: "round-trip",
+ CreatedAt: time.UnixMilli(1700000000000).UTC(),
+ Labels: map[string]string{"team": "platform"},
+ Annotations: map[string]string{"note": "rt-test"},
+ ResourceVersion: 10,
+ Workspace: "staging",
+ DeletionTimestamp: &rtDelTime,
+ Spec: v1.SandboxSpec{
+ LogLevel: "trace",
+ Environment: map[string]string{"A": "B"},
+ Template: &v1.SandboxTemplate{
+ Image: "img:rt",
+ UserNamespaces: &userNS,
+ },
+ Providers: []string{"p1", "p2"},
+ GPUCount: &gpuCount,
+ Policy: &v1.SandboxPolicy{
+ Version: 3,
+ Filesystem: &v1.FilesystemPolicy{
+ IncludeWorkdir: true,
+ ReadOnly: []string{"/etc", "/usr/share"},
+ ReadWrite: []string{"/tmp"},
+ },
+ Landlock: &v1.LandlockPolicy{
+ Compatibility: "best_effort",
+ },
+ Process: &v1.ProcessPolicy{
+ RunAsUser: "sandbox",
+ RunAsGroup: "sandbox-group",
+ },
+ NetworkPolicies: map[string]v1.NetworkPolicyRule{
+ "web": {
+ Name: "web",
+ Endpoints: []v1.PolicyNetworkEndpoint{
+ {Host: "api.example.com", Port: 443, Protocol: "rest"},
+ },
+ },
+ },
+ },
+ },
+ }
+
+ p, err := SandboxToProto(original)
+ require.NoError(t, err)
+ back := SandboxFromProto(p)
+
+ assert.Equal(t, original.ID, back.ID)
+ assert.Equal(t, original.Name, back.Name)
+ assert.Equal(t, original.CreatedAt, back.CreatedAt)
+ assert.Equal(t, original.Labels, back.Labels)
+ assert.Equal(t, original.Annotations, back.Annotations)
+ assert.Equal(t, original.ResourceVersion, back.ResourceVersion)
+ assert.Equal(t, original.Workspace, back.Workspace)
+ require.NotNil(t, back.DeletionTimestamp)
+ assert.Equal(t, *original.DeletionTimestamp, *back.DeletionTimestamp)
+ assert.Equal(t, original.Spec.LogLevel, back.Spec.LogLevel)
+ assert.Equal(t, original.Spec.Environment, back.Spec.Environment)
+ assert.Equal(t, original.Spec.Providers, back.Spec.Providers)
+ require.NotNil(t, back.Spec.GPUCount)
+ assert.Equal(t, *original.Spec.GPUCount, *back.Spec.GPUCount)
+ require.NotNil(t, back.Spec.Template)
+ assert.Equal(t, original.Spec.Template.Image, back.Spec.Template.Image)
+ require.NotNil(t, back.Spec.Template.UserNamespaces)
+ assert.Equal(t, *original.Spec.Template.UserNamespaces, *back.Spec.Template.UserNamespaces)
+
+ // Policy round-trip
+ require.NotNil(t, back.Spec.Policy)
+ assert.Equal(t, uint32(3), back.Spec.Policy.Version)
+ require.NotNil(t, back.Spec.Policy.Filesystem)
+ assert.True(t, back.Spec.Policy.Filesystem.IncludeWorkdir)
+ assert.Equal(t, []string{"/etc", "/usr/share"}, back.Spec.Policy.Filesystem.ReadOnly)
+ assert.Equal(t, []string{"/tmp"}, back.Spec.Policy.Filesystem.ReadWrite)
+ require.NotNil(t, back.Spec.Policy.Landlock)
+ assert.Equal(t, "best_effort", back.Spec.Policy.Landlock.Compatibility)
+ require.NotNil(t, back.Spec.Policy.Process)
+ assert.Equal(t, "sandbox", back.Spec.Policy.Process.RunAsUser)
+ assert.Equal(t, "sandbox-group", back.Spec.Policy.Process.RunAsGroup)
+ require.Len(t, back.Spec.Policy.NetworkPolicies, 1)
+ webRule, ok := back.Spec.Policy.NetworkPolicies["web"]
+ require.True(t, ok)
+ assert.Equal(t, "web", webRule.Name)
+ require.Len(t, webRule.Endpoints, 1)
+ assert.Equal(t, "api.example.com", webRule.Endpoints[0].Host)
+}
+
+func TestSandboxSpecToProto(t *testing.T) {
+ gpuCount := uint32(3)
+ spec := &v1.SandboxSpec{
+ LogLevel: "debug",
+ Environment: map[string]string{"X": "Y"},
+ Template: &v1.SandboxTemplate{
+ Image: "img:spec",
+ },
+ Providers: []string{"prov"},
+ GPUCount: &gpuCount,
+ Policy: &v1.SandboxPolicy{
+ Version: 2,
+ Filesystem: &v1.FilesystemPolicy{
+ ReadOnly: []string{"/etc"},
+ },
+ },
+ }
+
+ p, err := SandboxSpecToProto(spec)
+ require.NoError(t, err)
+ require.NotNil(t, p)
+ assert.Equal(t, "debug", p.LogLevel)
+ assert.Equal(t, map[string]string{"X": "Y"}, p.Environment)
+ assert.Equal(t, []string{"prov"}, p.Providers)
+ require.NotNil(t, p.ResourceRequirements)
+ assert.Equal(t, uint32(3), p.ResourceRequirements.Gpu.GetCount())
+ require.NotNil(t, p.Template)
+ assert.Equal(t, "img:spec", p.Template.Image)
+
+ // Policy conversion
+ require.NotNil(t, p.Policy)
+ assert.Equal(t, uint32(2), p.Policy.Version)
+ require.NotNil(t, p.Policy.Filesystem)
+ assert.Equal(t, []string{"/etc"}, p.Policy.Filesystem.ReadOnly)
+}
+
+func TestSandboxSpecToProto_Nil(t *testing.T) {
+ p, err := SandboxSpecToProto(nil)
+ require.NoError(t, err)
+ assert.Nil(t, p)
+}
+
+func TestSandboxSpecToProto_InvalidMapReturnsError(t *testing.T) {
+ spec := &v1.SandboxSpec{
+ Template: &v1.SandboxTemplate{
+ Image: "img:v1",
+ Resources: map[string]any{"bad": make(chan int)},
+ },
+ }
+
+ p, err := SandboxSpecToProto(spec)
+ require.Error(t, err, "SandboxSpecToProto must return an error for unconvertible map values")
+ assert.Nil(t, p)
+ assert.Contains(t, err.Error(), "convert template resources")
+}
+
+// Verify proto import is used (suppress unused import warning).
+var _ = proto.Marshal
diff --git a/sdk/go/openshell/v1/internal/converter/time.go b/sdk/go/openshell/v1/internal/converter/time.go
new file mode 100644
index 000000000..28a633cdf
--- /dev/null
+++ b/sdk/go/openshell/v1/internal/converter/time.go
@@ -0,0 +1,43 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package converter
+
+import "time"
+
+// TimeFromMillis converts a millisecond epoch timestamp to time.Time.
+// A zero value returns the zero time.
+func TimeFromMillis(ms int64) time.Time {
+ if ms == 0 {
+ return time.Time{}
+ }
+ return time.UnixMilli(ms).UTC()
+}
+
+// MillisFromTime converts a time.Time to a millisecond epoch timestamp.
+// A zero time returns 0.
+func MillisFromTime(t time.Time) int64 {
+ if t.IsZero() {
+ return 0
+ }
+ return t.UnixMilli()
+}
+
+// TimeFromMillisPtr converts a millisecond epoch timestamp to a *time.Time.
+// A zero value returns nil (the resource is not being deleted).
+func TimeFromMillisPtr(ms int64) *time.Time {
+ if ms == 0 {
+ return nil
+ }
+ t := time.UnixMilli(ms).UTC()
+ return &t
+}
+
+// MillisFromTimePtr converts a *time.Time to a millisecond epoch timestamp.
+// A nil pointer returns 0.
+func MillisFromTimePtr(t *time.Time) int64 {
+ if t == nil {
+ return 0
+ }
+ return t.UnixMilli()
+}
diff --git a/sdk/go/openshell/v1/internal/converter/time_test.go b/sdk/go/openshell/v1/internal/converter/time_test.go
new file mode 100644
index 000000000..0b4d44fd2
--- /dev/null
+++ b/sdk/go/openshell/v1/internal/converter/time_test.go
@@ -0,0 +1,73 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package converter
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestTimeFromMillis(t *testing.T) {
+ ms := int64(1719475200000) // 2024-06-27T08:00:00Z
+ tm := TimeFromMillis(ms)
+ assert.Equal(t, 2024, tm.Year())
+ assert.Equal(t, time.June, tm.Month())
+ assert.Equal(t, 27, tm.Day())
+}
+
+func TestTimeFromMillis_Zero(t *testing.T) {
+ tm := TimeFromMillis(0)
+ assert.True(t, tm.IsZero())
+}
+
+func TestMillisFromTime(t *testing.T) {
+ tm := time.Date(2024, time.June, 27, 12, 0, 0, 0, time.UTC)
+ ms := MillisFromTime(tm)
+ assert.Equal(t, int64(1719489600000), ms)
+}
+
+func TestMillisFromTime_Zero(t *testing.T) {
+ ms := MillisFromTime(time.Time{})
+ assert.Equal(t, int64(0), ms)
+}
+
+func TestRoundTrip(t *testing.T) {
+ original := time.Date(2025, time.March, 15, 10, 30, 0, 0, time.UTC)
+ ms := MillisFromTime(original)
+ restored := TimeFromMillis(ms)
+ assert.Equal(t, original.Unix(), restored.Unix())
+}
+
+func TestTimeFromMillisPtr_NonZero(t *testing.T) {
+ ms := int64(1719475200000)
+ tp := TimeFromMillisPtr(ms)
+ assert.NotNil(t, tp)
+ assert.Equal(t, 2024, tp.Year())
+}
+
+func TestTimeFromMillisPtr_Zero(t *testing.T) {
+ tp := TimeFromMillisPtr(0)
+ assert.Nil(t, tp)
+}
+
+func TestMillisFromTimePtr_NonNil(t *testing.T) {
+ tm := time.Date(2024, time.June, 27, 12, 0, 0, 0, time.UTC)
+ ms := MillisFromTimePtr(&tm)
+ assert.Equal(t, int64(1719489600000), ms)
+}
+
+func TestMillisFromTimePtr_Nil(t *testing.T) {
+ ms := MillisFromTimePtr(nil)
+ assert.Equal(t, int64(0), ms)
+}
+
+func TestPtrRoundTrip(t *testing.T) {
+ original := time.Date(2025, time.March, 15, 10, 30, 0, 0, time.UTC)
+ ms := MillisFromTimePtr(&original)
+ restored := TimeFromMillisPtr(ms)
+ assert.NotNil(t, restored)
+ assert.Equal(t, original.Unix(), restored.Unix())
+}
diff --git a/sdk/go/openshell/v1/internal/grpc/conn.go b/sdk/go/openshell/v1/internal/grpc/conn.go
new file mode 100644
index 000000000..e2198546a
--- /dev/null
+++ b/sdk/go/openshell/v1/internal/grpc/conn.go
@@ -0,0 +1,96 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+// Package grpc provides gRPC connection setup utilities.
+package grpc
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "fmt"
+ "os"
+ "strings"
+
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/credentials"
+ "google.golang.org/grpc/credentials/insecure"
+)
+
+// TLSParams holds TLS settings without importing the v1 package.
+type TLSParams struct {
+ CertFile string
+ KeyFile string
+ CAFile string
+ Insecure bool
+}
+
+// NewConnection creates a gRPC client connection.
+// The address may include an http:// or https:// scheme (as written by the
+// upstream gateway). The scheme drives transport selection: http:// uses
+// plaintext, https:// or no scheme uses TLS.
+func NewConnection(address string, tlsCfg *TLSParams, auth credentials.PerRPCCredentials) (*grpc.ClientConn, error) {
+ usePlaintext := false
+ if strings.HasPrefix(address, "http://") {
+ usePlaintext = true
+ address = strings.TrimPrefix(address, "http://")
+ } else {
+ address = strings.TrimPrefix(address, "https://")
+ }
+ opts := []grpc.DialOption{}
+
+ if usePlaintext {
+ opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
+ } else if tlsCfg != nil {
+ creds, err := buildTLSCredentials(tlsCfg)
+ if err != nil {
+ return nil, fmt.Errorf("tls config: %w", err)
+ }
+ opts = append(opts, grpc.WithTransportCredentials(creds))
+ } else {
+ opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12})))
+ }
+
+ if auth != nil {
+ if usePlaintext && auth.RequireTransportSecurity() {
+ return nil, fmt.Errorf("grpc connect: auth provider requires transport security but address uses plaintext (http://)")
+ }
+ opts = append(opts, grpc.WithPerRPCCredentials(auth))
+ }
+
+ conn, err := grpc.NewClient(address, opts...)
+ if err != nil {
+ return nil, fmt.Errorf("grpc connect: %w", err)
+ }
+ return conn, nil
+}
+
+func buildTLSCredentials(cfg *TLSParams) (credentials.TransportCredentials, error) {
+ tlsConfig := &tls.Config{
+ MinVersion: tls.VersionTLS12,
+ InsecureSkipVerify: cfg.Insecure, //nolint:gosec // user-requested skip for dev gateways
+ }
+
+ if cfg.CAFile != "" {
+ caCert, err := os.ReadFile(cfg.CAFile)
+ if err != nil {
+ return nil, fmt.Errorf("read CA file: %w", err)
+ }
+ pool := x509.NewCertPool()
+ if !pool.AppendCertsFromPEM(caCert) {
+ return nil, fmt.Errorf("invalid CA certificate")
+ }
+ tlsConfig.RootCAs = pool
+ }
+
+ if cfg.CertFile != "" && cfg.KeyFile != "" {
+ cert, err := tls.LoadX509KeyPair(cfg.CertFile, cfg.KeyFile)
+ if err != nil {
+ return nil, fmt.Errorf("load client cert: %w", err)
+ }
+ tlsConfig.Certificates = []tls.Certificate{cert}
+ } else if cfg.CertFile != "" || cfg.KeyFile != "" {
+ return nil, fmt.Errorf("both CertFile and KeyFile must be provided for client certificate authentication")
+ }
+
+ return credentials.NewTLS(tlsConfig), nil
+}
diff --git a/sdk/go/openshell/v1/internal/grpc/conn_test.go b/sdk/go/openshell/v1/internal/grpc/conn_test.go
new file mode 100644
index 000000000..a1da2883e
--- /dev/null
+++ b/sdk/go/openshell/v1/internal/grpc/conn_test.go
@@ -0,0 +1,101 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package grpc
+
+import (
+ "context"
+ "net"
+ "testing"
+
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/credentials/insecure"
+)
+
+func TestNewConnectionHTTPSchemeUsesPlaintext(t *testing.T) {
+ lis, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatalf("listen: %v", err)
+ }
+ defer func() { _ = lis.Close() }()
+
+ srv := grpc.NewServer()
+ go func() { _ = srv.Serve(lis) }()
+ defer srv.Stop()
+
+ conn, err := NewConnection("http://"+lis.Addr().String(), nil, nil)
+ if err != nil {
+ t.Fatalf("NewConnection with http:// scheme failed: %v", err)
+ }
+ defer func() { _ = conn.Close() }()
+}
+
+func TestNewConnectionHTTPSSchemeUsesTLS(t *testing.T) {
+ // https:// with nil TLS config should default to system TLS.
+ // We cannot dial a real TLS server here, but we can verify the
+ // connection is created (it will fail on handshake, not on dial).
+ conn, err := NewConnection("https://127.0.0.1:1", nil, nil)
+ if err != nil {
+ t.Fatalf("NewConnection with https:// scheme should not fail on create: %v", err)
+ }
+ defer func() { _ = conn.Close() }()
+}
+
+func TestNewConnectionNoSchemeUsesTLS(t *testing.T) {
+ conn, err := NewConnection("127.0.0.1:1", nil, nil)
+ if err != nil {
+ t.Fatalf("NewConnection without scheme should not fail on create: %v", err)
+ }
+ defer func() { _ = conn.Close() }()
+}
+
+func TestNewConnectionInsecureTLSConfig(t *testing.T) {
+ // Insecure: true means TLS with InsecureSkipVerify, not plaintext.
+ // We can verify the connection is created (handshake will fail since
+ // the server is not TLS, but NewClient itself should succeed).
+ conn, err := NewConnection("127.0.0.1:1", &TLSParams{Insecure: true}, nil)
+ if err != nil {
+ t.Fatalf("NewConnection with Insecure TLS config failed: %v", err)
+ }
+ defer func() { _ = conn.Close() }()
+}
+
+func TestNewConnectionHTTPWithSecureAuthRejects(t *testing.T) {
+ auth := &testTokenAuth{token: "dev-token", requireSecurity: true}
+ _, err := NewConnection("http://127.0.0.1:1", nil, auth)
+ if err == nil {
+ t.Fatal("expected error when using http:// with auth that requires transport security")
+ }
+}
+
+func TestNewConnectionHTTPWithInsecureAuth(t *testing.T) {
+ lis, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatalf("listen: %v", err)
+ }
+ defer func() { _ = lis.Close() }()
+
+ srv := grpc.NewServer(grpc.Creds(insecure.NewCredentials()))
+ go func() { _ = srv.Serve(lis) }()
+ defer srv.Stop()
+
+ auth := &testTokenAuth{token: "dev-token", requireSecurity: false}
+ conn, err := NewConnection("http://"+lis.Addr().String(), nil, auth)
+ if err != nil {
+ t.Fatalf("NewConnection with http:// + insecure auth failed: %v", err)
+ }
+ defer func() { _ = conn.Close() }()
+}
+
+type testTokenAuth struct {
+ token string
+ requireSecurity bool
+}
+
+func (a *testTokenAuth) GetRequestMetadata(_ context.Context, _ ...string) (map[string]string, error) {
+ return map[string]string{"authorization": "Bearer " + a.token}, nil
+}
+
+func (a *testTokenAuth) RequireTransportSecurity() bool {
+ return a.requireSecurity
+}
diff --git a/sdk/go/openshell/v1/logger.go b/sdk/go/openshell/v1/logger.go
new file mode 100644
index 000000000..e8274012a
--- /dev/null
+++ b/sdk/go/openshell/v1/logger.go
@@ -0,0 +1,12 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+)
+
+// Logger defines structured logging for the SDK. Compatible with logr.Logger
+// and slog.Logger adapters.
+type Logger = types.Logger
diff --git a/sdk/go/openshell/v1/options.go b/sdk/go/openshell/v1/options.go
new file mode 100644
index 000000000..cb165b23a
--- /dev/null
+++ b/sdk/go/openshell/v1/options.go
@@ -0,0 +1,32 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+)
+
+// CreateOptions configures resource creation.
+type CreateOptions = types.CreateOptions
+
+// GetOptions configures resource retrieval.
+type GetOptions = types.GetOptions
+
+// ListOptions configures resource listing with pagination and filtering.
+type ListOptions = types.ListOptions
+
+// DeleteOptions configures resource deletion.
+type DeleteOptions = types.DeleteOptions
+
+// UpdateOptions configures resource updates.
+type UpdateOptions = types.UpdateOptions
+
+// WatchOptions configures watch behavior.
+type WatchOptions = types.WatchOptions
+
+// WaitOptions configures wait behavior. Use context for timeout control.
+type WaitOptions = types.WaitOptions
+
+// ExecOptions configures command execution.
+type ExecOptions = types.ExecOptions
diff --git a/sdk/go/openshell/v1/policy.go b/sdk/go/openshell/v1/policy.go
new file mode 100644
index 000000000..b6e5070d9
--- /dev/null
+++ b/sdk/go/openshell/v1/policy.go
@@ -0,0 +1,173 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+)
+
+// SandboxPolicy is the top-level security policy configuration for a sandbox.
+type SandboxPolicy = types.SandboxPolicy
+
+// FilesystemPolicy controls which directories the sandbox can access.
+type FilesystemPolicy = types.FilesystemPolicy
+
+// LandlockPolicy configures the Linux Landlock LSM.
+type LandlockPolicy = types.LandlockPolicy
+
+// ProcessPolicy controls the user and group identity for sandboxed processes.
+type ProcessPolicy = types.ProcessPolicy
+
+// PolicyChunk represents a single proposed policy change in the draft inbox.
+type PolicyChunk = types.PolicyChunk
+
+// DraftPolicy contains the full draft policy state returned by GetDraft.
+type DraftPolicy = types.DraftPolicy
+
+// PolicyStatusResult contains the status of a sandbox's policy.
+type PolicyStatusResult = types.PolicyStatusResult
+
+// SandboxPolicyRevision represents a versioned policy revision for a sandbox.
+type SandboxPolicyRevision = types.SandboxPolicyRevision
+
+// PolicyLoadStatus represents the load state of a policy revision.
+type PolicyLoadStatus = types.PolicyLoadStatus
+
+// PolicyLoadStatus constants re-exported from types package.
+const (
+ PolicyLoadStatusUnspecified = types.PolicyLoadStatusUnspecified
+ PolicyLoadStatusPending = types.PolicyLoadStatusPending
+ PolicyLoadStatusLoaded = types.PolicyLoadStatusLoaded
+ PolicyLoadStatusFailed = types.PolicyLoadStatusFailed
+ PolicyLoadStatusSuperseded = types.PolicyLoadStatusSuperseded
+)
+
+// ApproveResult contains the result of approving a single draft chunk.
+type ApproveResult = types.ApproveResult
+
+// ApproveAllResult contains the result of approving all draft chunks.
+type ApproveAllResult = types.ApproveAllResult
+
+// UndoResult contains the result of undoing a draft chunk approval.
+type UndoResult = types.UndoResult
+
+// ClearResult contains the result of clearing all draft chunks.
+type ClearResult = types.ClearResult
+
+// DraftHistoryEntry represents a single event in the draft policy history.
+type DraftHistoryEntry = types.DraftHistoryEntry
+
+// GetDraftOption configures a GetDraft call.
+type GetDraftOption = types.GetDraftOption
+
+// WithStatusFilter filters draft chunks by approval status.
+var WithStatusFilter = types.WithStatusFilter
+
+// ApproveAllOption configures an ApproveAllDraftChunks call.
+type ApproveAllOption = types.ApproveAllOption
+
+// WithIncludeSecurityFlagged includes security-flagged chunks in bulk approval.
+var WithIncludeSecurityFlagged = types.WithIncludeSecurityFlagged
+
+// GetStatusOption configures a GetStatus call.
+type GetStatusOption = types.GetStatusOption
+
+// WithVersion queries a specific policy version instead of the latest.
+var WithVersion = types.WithVersion
+
+// ListPolicyOption configures a List call.
+type ListPolicyOption = types.ListPolicyOption
+
+// WithLimit sets the maximum number of revisions to return.
+var WithLimit = types.WithLimit
+
+// WithOffset sets the pagination offset.
+var WithOffset = types.WithOffset
+
+// PolicyInterface defines operations for managing sandbox policy drafts,
+// approvals, and revision history.
+type PolicyInterface interface {
+ // GetDraft retrieves the current draft policy for a sandbox, including
+ // all pending, approved, and rejected chunks. Use WithStatusFilter to
+ // return only chunks matching a specific status.
+ //
+ // Errors: NotFound if the sandbox does not exist; InvalidArgument if the
+ // sandbox name is empty; Unimplemented by the fake client.
+ GetDraft(ctx context.Context, workspace, sandboxName string, opts ...GetDraftOption) (*DraftPolicy, error)
+
+ // ApproveDraftChunk approves a single pending draft chunk, merging
+ // its proposed rule into the active policy.
+ //
+ // Errors: NotFound if the sandbox or chunk does not exist;
+ // InvalidArgument if the sandbox name or chunk ID is empty;
+ // Conflict if the chunk has already been approved or rejected;
+ // Unimplemented by the fake client.
+ ApproveDraftChunk(ctx context.Context, workspace, sandboxName, chunkID string) (*ApproveResult, error)
+
+ // RejectDraftChunk rejects a single pending draft chunk with an
+ // optional reason that is fed to future LLM analysis context.
+ //
+ // Errors: NotFound if the sandbox or chunk does not exist;
+ // InvalidArgument if the sandbox name or chunk ID is empty;
+ // Conflict if the chunk has already been approved or rejected;
+ // Unimplemented by the fake client.
+ RejectDraftChunk(ctx context.Context, workspace, sandboxName, chunkID, reason string) error
+
+ // ApproveAllDraftChunks approves all pending draft chunks at once.
+ // By default, security-flagged chunks are skipped. Use
+ // WithIncludeSecurityFlagged to include them.
+ //
+ // Errors: NotFound if the sandbox does not exist; InvalidArgument if
+ // the sandbox name is empty; Unimplemented by the fake client.
+ ApproveAllDraftChunks(ctx context.Context, workspace, sandboxName string, opts ...ApproveAllOption) (*ApproveAllResult, error)
+
+ // ClearDraftChunks removes all pending draft chunks for a sandbox.
+ //
+ // Errors: NotFound if the sandbox does not exist; InvalidArgument if
+ // the sandbox name is empty; Unimplemented by the fake client.
+ ClearDraftChunks(ctx context.Context, workspace, sandboxName string) (*ClearResult, error)
+
+ // GetDraftHistory returns the chronological decision history for a
+ // sandbox's draft policy (approvals, rejections, edits, undos, clears).
+ //
+ // Errors: NotFound if the sandbox does not exist; InvalidArgument if
+ // the sandbox name is empty; Unimplemented by the fake client.
+ GetDraftHistory(ctx context.Context, workspace, sandboxName string) ([]DraftHistoryEntry, error)
+
+ // GetStatus retrieves the policy status for a sandbox, including the
+ // queried revision and the active version. Use WithVersion to query a
+ // specific version instead of the latest.
+ //
+ // Errors: NotFound if the sandbox or requested version does not exist;
+ // InvalidArgument if the sandbox name is empty;
+ // Unimplemented by the fake client.
+ GetStatus(ctx context.Context, workspace, sandboxName string, opts ...GetStatusOption) (*PolicyStatusResult, error)
+
+ // List returns policy revisions for a sandbox, ordered by version.
+ // Use WithLimit and WithOffset for pagination.
+ //
+ // Errors: NotFound if the sandbox does not exist; InvalidArgument if
+ // the sandbox name is empty; Unimplemented by the fake client.
+ List(ctx context.Context, workspace string, opts ...ListPolicyOption) ([]SandboxPolicyRevision, error)
+
+ // EditDraftChunk replaces the proposed rule of a pending draft chunk
+ // with the given network policy rule.
+ //
+ // Errors: NotFound if the sandbox or chunk does not exist;
+ // InvalidArgument if the sandbox name, chunk ID, or proposed rule is
+ // empty/nil; Conflict if the chunk is not in a pending state;
+ // Unimplemented by the fake client.
+ EditDraftChunk(ctx context.Context, workspace, sandboxName, chunkID string, proposedRule *NetworkPolicyRule) error
+
+ // UndoDraftChunk reverses a previously approved chunk, removing its
+ // merged rule from the active policy.
+ //
+ // Errors: NotFound if the sandbox or chunk does not exist;
+ // InvalidArgument if the sandbox name or chunk ID is empty;
+ // Conflict if the chunk has not been approved;
+ // Unimplemented by the fake client.
+ UndoDraftChunk(ctx context.Context, workspace, sandboxName, chunkID string) (*UndoResult, error)
+}
diff --git a/sdk/go/openshell/v1/profile.go b/sdk/go/openshell/v1/profile.go
new file mode 100644
index 000000000..7a91632d5
--- /dev/null
+++ b/sdk/go/openshell/v1/profile.go
@@ -0,0 +1,70 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+)
+
+// ProviderProfile represents a provider type template.
+type ProviderProfile = types.ProviderProfile
+
+// ProfileCredential defines a single credential required by a provider profile.
+type ProfileCredential = types.ProfileCredential
+
+// ProfileCategory classifies a provider profile.
+type ProfileCategory = types.ProfileCategory
+
+// NetworkEndpoint describes a network endpoint provided by a profile.
+type NetworkEndpoint = types.NetworkEndpoint
+
+// NetworkBinary describes a binary artifact provided by a profile.
+type NetworkBinary = types.NetworkBinary
+
+// ProfileDiscovery holds local discovery configuration for a profile.
+type ProfileDiscovery = types.ProfileDiscovery
+
+// ProfileImportItem is an item submitted for profile import or lint validation.
+type ProfileImportItem = types.ProfileImportItem
+
+// ProfileDiagnostic is a validation finding from Import, Update, or Lint.
+type ProfileDiagnostic = types.ProfileDiagnostic
+
+// ImportResult holds the result of a profile import operation.
+type ImportResult = types.ImportResult
+
+// UpdateResult holds the result of a profile update operation.
+type UpdateResult = types.UpdateResult
+
+// LintResult holds the result of a profile lint operation.
+type LintResult = types.LintResult
+
+// ProfileCategory values.
+const (
+ ProfileCategoryOther = types.ProfileCategoryOther
+ ProfileCategoryInference = types.ProfileCategoryInference
+ ProfileCategoryAgent = types.ProfileCategoryAgent
+ ProfileCategorySourceControl = types.ProfileCategorySourceControl
+ ProfileCategoryMessaging = types.ProfileCategoryMessaging
+ ProfileCategoryData = types.ProfileCategoryData
+ ProfileCategoryKnowledge = types.ProfileCategoryKnowledge
+)
+
+// ProfileInterface defines operations for managing provider profiles.
+type ProfileInterface interface {
+ // List returns all provider profiles.
+ List(ctx context.Context, workspace string, opts ...ListOptions) ([]*ProviderProfile, error)
+ // Get retrieves a provider profile by ID.
+ Get(ctx context.Context, workspace, id string) (*ProviderProfile, error)
+ // Import submits profiles for import and returns the result with diagnostics.
+ Import(ctx context.Context, workspace string, items []ProfileImportItem) (*ImportResult, error)
+ // Update replaces an existing profile identified by ID and expected resource version.
+ Update(ctx context.Context, workspace, id string, expectedResourceVersion uint64, item ProfileImportItem) (*UpdateResult, error)
+ // Lint validates profiles without persisting them and returns diagnostics.
+ Lint(ctx context.Context, workspace string, items []ProfileImportItem) (*LintResult, error)
+ // Delete removes a provider profile by ID. Returns true if deleted.
+ Delete(ctx context.Context, workspace, id string) (bool, error)
+}
diff --git a/sdk/go/openshell/v1/provider.go b/sdk/go/openshell/v1/provider.go
new file mode 100644
index 000000000..f1ab67c48
--- /dev/null
+++ b/sdk/go/openshell/v1/provider.go
@@ -0,0 +1,29 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+)
+
+// Provider represents an AI provider registration.
+type Provider = types.Provider
+
+// ProviderSpec holds provider-specific configuration and credentials.
+type ProviderSpec = types.ProviderSpec
+
+// ProviderInterface defines CRUD and Ensure operations on providers,
+// plus sub-client accessors for profiles and credential refresh.
+type ProviderInterface interface {
+ Create(ctx context.Context, workspace string, provider *Provider) (*Provider, error)
+ Get(ctx context.Context, workspace, name string) (*Provider, error)
+ List(ctx context.Context, workspace string, opts ...ListOptions) ([]*Provider, error)
+ Update(ctx context.Context, workspace string, provider *Provider) (*Provider, error)
+ Delete(ctx context.Context, workspace, name string) error
+ Ensure(ctx context.Context, workspace string, provider *Provider) (*Provider, error)
+ Profiles() ProfileInterface
+ Refresh() RefreshInterface
+}
diff --git a/sdk/go/openshell/v1/refresh.go b/sdk/go/openshell/v1/refresh.go
new file mode 100644
index 000000000..6aec9bbc5
--- /dev/null
+++ b/sdk/go/openshell/v1/refresh.go
@@ -0,0 +1,42 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+)
+
+// RefreshStrategy describes how credentials are refreshed.
+type RefreshStrategy = types.RefreshStrategy
+
+// RefreshStatus reports the current state of credential refresh for a provider credential.
+type RefreshStatus = types.RefreshStatus
+
+// RefreshConfig holds configuration parameters for credential refresh.
+type RefreshConfig = types.RefreshConfig
+
+// RefreshStrategy values.
+const (
+ RefreshStrategyStatic = types.RefreshStrategyStatic
+ RefreshStrategyExternal = types.RefreshStrategyExternal
+ RefreshStrategyOAuth2RefreshToken = types.RefreshStrategyOAuth2RefreshToken
+ RefreshStrategyOAuth2ClientCredentials = types.RefreshStrategyOAuth2ClientCredentials
+ RefreshStrategyGoogleServiceAccountJWT = types.RefreshStrategyGoogleServiceAccountJWT
+ RefreshStrategyAWSStsAssumeRole = types.RefreshStrategyAWSStsAssumeRole
+)
+
+// RefreshInterface defines operations for managing provider credential refresh.
+type RefreshInterface interface {
+ // GetStatus returns the refresh status for a provider's credential.
+ // If credentialKey is empty, statuses for all credentials are returned.
+ GetStatus(ctx context.Context, workspace, provider, credentialKey string) ([]*RefreshStatus, error)
+ // Configure sets up credential refresh for a provider credential.
+ Configure(ctx context.Context, workspace string, config *RefreshConfig) (*RefreshStatus, error)
+ // Rotate triggers an immediate credential rotation.
+ Rotate(ctx context.Context, workspace, provider, credentialKey string) (*RefreshStatus, error)
+ // Delete removes credential refresh configuration. Returns true if deleted.
+ Delete(ctx context.Context, workspace, provider, credentialKey string) (bool, error)
+}
diff --git a/sdk/go/openshell/v1/sandbox.go b/sdk/go/openshell/v1/sandbox.go
new file mode 100644
index 000000000..2dfc6ba8a
--- /dev/null
+++ b/sdk/go/openshell/v1/sandbox.go
@@ -0,0 +1,73 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+)
+
+// Sandbox represents a sandbox instance.
+type Sandbox = types.Sandbox
+
+// SandboxSpec holds the desired state of a sandbox.
+type SandboxSpec = types.SandboxSpec
+
+// SandboxTemplate defines the container template for a sandbox.
+type SandboxTemplate = types.SandboxTemplate
+
+// SandboxStatus holds the observed state of a sandbox.
+type SandboxStatus = types.SandboxStatus
+
+// SandboxCondition describes an observed condition of a sandbox.
+type SandboxCondition = types.SandboxCondition
+
+// AttachProviderResult holds the result of attaching a provider to a sandbox.
+type AttachProviderResult = types.AttachProviderResult
+
+// DetachProviderResult holds the result of detaching a provider from a sandbox.
+type DetachProviderResult = types.DetachProviderResult
+
+// LogLine represents a single log entry from a sandbox.
+type LogLine = types.LogLine
+
+// LogResult contains the result of a GetLogs call.
+type LogResult = types.LogResult
+
+// LogOption configures a GetLogs call.
+type LogOption = types.LogOption
+
+// WithLogLines sets the maximum number of log lines to return.
+var WithLogLines = types.WithLogLines
+
+// WithLogSince filters logs to entries at or after the given time.
+var WithLogSince = types.WithLogSince
+
+// WithLogSources filters logs by source (e.g., "gateway", "sandbox").
+var WithLogSources = types.WithLogSources
+
+// WithLogMinLevel sets the minimum log level to include.
+var WithLogMinLevel = types.WithLogMinLevel
+
+// SandboxInterface defines lifecycle operations on sandboxes.
+type SandboxInterface interface {
+ Create(ctx context.Context, workspace, name string, spec *SandboxSpec, labels map[string]string) (*Sandbox, error)
+ Get(ctx context.Context, workspace, name string) (*Sandbox, error)
+ List(ctx context.Context, workspace string, opts ...ListOptions) ([]*Sandbox, error)
+ Delete(ctx context.Context, workspace, name string) error
+ AttachProvider(ctx context.Context, workspace, sandboxName, providerName string, expectedResourceVersion uint64) (*AttachProviderResult, error)
+ DetachProvider(ctx context.Context, workspace, sandboxName, providerName string, expectedResourceVersion uint64) (*DetachProviderResult, error)
+ ListProviders(ctx context.Context, workspace, sandboxName string) ([]*Provider, error)
+ WaitReady(ctx context.Context, workspace, name string, opts ...WaitOptions) (*Sandbox, error)
+ Watch(ctx context.Context, workspace, name string, opts ...WatchOptions) (WatchInterface[*Sandbox], error)
+ // GetLogs retrieves log entries for a sandbox. The sandbox is resolved
+ // by name (an internal Get call translates name to ID). Use
+ // WithLogLines, WithLogSince, WithLogSources, and WithLogMinLevel to
+ // filter the results.
+ //
+ // Errors: NotFound if the sandbox does not exist; InvalidArgument if
+ // the sandbox name is empty; Unimplemented by the fake client.
+ GetLogs(ctx context.Context, workspace, sandboxName string, opts ...LogOption) (*LogResult, error)
+}
diff --git a/sdk/go/openshell/v1/sandbox_client.go b/sdk/go/openshell/v1/sandbox_client.go
new file mode 100644
index 000000000..6c38db781
--- /dev/null
+++ b/sdk/go/openshell/v1/sandbox_client.go
@@ -0,0 +1,291 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "time"
+
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/internal/converter"
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+ pb "github.com/NVIDIA/OpenShell/sdk/go/proto/openshellv1"
+ "google.golang.org/grpc"
+)
+
+const defaultPollInterval = 500 * time.Millisecond
+
+type sandboxClient struct {
+ client pb.OpenShellClient
+}
+
+func newSandboxClient(conn grpc.ClientConnInterface) *sandboxClient {
+ return &sandboxClient{client: pb.NewOpenShellClient(conn)}
+}
+
+func (s *sandboxClient) Create(ctx context.Context, workspace, name string, spec *SandboxSpec, labels map[string]string) (*Sandbox, error) {
+ pbSpec, err := converter.SandboxSpecToProto(spec)
+ if err != nil {
+ return nil, &StatusError{Code: ErrorInvalidArgument, Message: err.Error()}
+ }
+ resp, err := s.client.CreateSandbox(ctx, &pb.CreateSandboxRequest{
+ Name: name,
+ Spec: pbSpec,
+ Labels: labels,
+ Workspace: workspace,
+ })
+ if err != nil {
+ return nil, converter.FromGRPCError(err)
+ }
+ return converter.SandboxFromProto(resp.GetSandbox()), nil
+}
+
+func (s *sandboxClient) Get(ctx context.Context, workspace, name string) (*Sandbox, error) {
+ resp, err := s.client.GetSandbox(ctx, &pb.GetSandboxRequest{
+ Name: name,
+ Workspace: workspace,
+ })
+ if err != nil {
+ return nil, converter.FromGRPCError(err)
+ }
+ return converter.SandboxFromProto(resp.GetSandbox()), nil
+}
+
+func (s *sandboxClient) List(ctx context.Context, workspace string, opts ...ListOptions) ([]*Sandbox, error) {
+ req := &pb.ListSandboxesRequest{
+ Workspace: workspace,
+ }
+ if len(opts) > 0 {
+ if opts[0].Limit > 0 {
+ req.Limit = uint32(opts[0].Limit)
+ }
+ if opts[0].Offset > 0 {
+ req.Offset = uint32(opts[0].Offset)
+ }
+ req.LabelSelector = opts[0].LabelSelector
+ req.AllWorkspaces = opts[0].AllWorkspaces
+ }
+
+ resp, err := s.client.ListSandboxes(ctx, req)
+ if err != nil {
+ return nil, converter.FromGRPCError(err)
+ }
+
+ sandboxes := make([]*Sandbox, 0, len(resp.GetSandboxes()))
+ for _, proto := range resp.GetSandboxes() {
+ sandboxes = append(sandboxes, converter.SandboxFromProto(proto))
+ }
+ return sandboxes, nil
+}
+
+func (s *sandboxClient) Delete(ctx context.Context, workspace, name string) error {
+ _, err := s.client.DeleteSandbox(ctx, &pb.DeleteSandboxRequest{
+ Name: name,
+ Workspace: workspace,
+ })
+ if err != nil {
+ return converter.FromGRPCError(err)
+ }
+ return nil
+}
+
+func (s *sandboxClient) AttachProvider(ctx context.Context, workspace, sandboxName, providerName string, expectedResourceVersion uint64) (*AttachProviderResult, error) {
+ resp, err := s.client.AttachSandboxProvider(ctx, &pb.AttachSandboxProviderRequest{
+ SandboxName: sandboxName,
+ ProviderName: providerName,
+ ExpectedResourceVersion: expectedResourceVersion,
+ Workspace: workspace,
+ })
+ if err != nil {
+ return nil, converter.FromGRPCError(err)
+ }
+ return &AttachProviderResult{
+ Sandbox: converter.SandboxFromProto(resp.GetSandbox()),
+ Attached: resp.GetAttached(),
+ }, nil
+}
+
+func (s *sandboxClient) DetachProvider(ctx context.Context, workspace, sandboxName, providerName string, expectedResourceVersion uint64) (*DetachProviderResult, error) {
+ resp, err := s.client.DetachSandboxProvider(ctx, &pb.DetachSandboxProviderRequest{
+ SandboxName: sandboxName,
+ ProviderName: providerName,
+ ExpectedResourceVersion: expectedResourceVersion,
+ Workspace: workspace,
+ })
+ if err != nil {
+ return nil, converter.FromGRPCError(err)
+ }
+ return &DetachProviderResult{
+ Sandbox: converter.SandboxFromProto(resp.GetSandbox()),
+ Detached: resp.GetDetached(),
+ }, nil
+}
+
+func (s *sandboxClient) ListProviders(ctx context.Context, workspace, sandboxName string) ([]*Provider, error) {
+ resp, err := s.client.ListSandboxProviders(ctx, &pb.ListSandboxProvidersRequest{
+ SandboxName: sandboxName,
+ Workspace: workspace,
+ })
+ if err != nil {
+ return nil, converter.FromGRPCError(err)
+ }
+
+ providers := make([]*Provider, 0, len(resp.GetProviders()))
+ for _, proto := range resp.GetProviders() {
+ providers = append(providers, converter.ProviderFromProto(proto))
+ }
+ return providers, nil
+}
+
+func (s *sandboxClient) WaitReady(ctx context.Context, workspace, name string, opts ...WaitOptions) (*Sandbox, error) {
+ interval := defaultPollInterval
+ if len(opts) > 0 && opts[0].PollInterval > 0 {
+ interval = opts[0].PollInterval
+ }
+
+ sb, err := s.Get(ctx, workspace, name)
+ if err != nil {
+ return nil, err
+ }
+
+ if sb.Status.Phase == SandboxReady {
+ return sb, nil
+ }
+ if sb.Status.Phase == SandboxError {
+ return nil, &StatusError{Code: ErrorInternal, Message: fmt.Sprintf("sandbox %q is in error state", name)}
+ }
+ if sb.Status.Phase == SandboxDeleting {
+ return nil, &StatusError{Code: ErrorInternal, Message: fmt.Sprintf("sandbox %q is being deleted", name)}
+ }
+
+ ticker := time.NewTicker(interval)
+ defer ticker.Stop()
+
+ for {
+ select {
+ case <-ctx.Done():
+ return nil, contextError(ctx.Err())
+ case <-ticker.C:
+ sb, err = s.Get(ctx, workspace, name)
+ if err != nil {
+ return nil, err
+ }
+ if sb.Status.Phase == SandboxReady {
+ return sb, nil
+ }
+ if sb.Status.Phase == SandboxError {
+ return nil, &StatusError{Code: ErrorInternal, Message: fmt.Sprintf("sandbox %q is in error state", name)}
+ }
+ if sb.Status.Phase == SandboxDeleting {
+ return nil, &StatusError{Code: ErrorInternal, Message: fmt.Sprintf("sandbox %q is being deleted", name)}
+ }
+ }
+ }
+}
+
+func (s *sandboxClient) Watch(ctx context.Context, workspace, name string, opts ...WatchOptions) (WatchInterface[*Sandbox], error) {
+ if name == "" {
+ return nil, &StatusError{Code: ErrorInvalidArgument, Message: "sandbox name must not be empty"}
+ }
+
+ var watchOpts WatchOptions
+ if len(opts) > 0 {
+ watchOpts = opts[0]
+ }
+
+ // Resolve sandbox name to ID — the proto RPC takes Id, not name.
+ sb, err := s.Get(ctx, workspace, name)
+ if err != nil {
+ return nil, err
+ }
+
+ streamCtx, streamCancel := context.WithCancel(ctx)
+ stream, err := s.client.WatchSandbox(streamCtx, &pb.WatchSandboxRequest{
+ Id: sb.ID,
+ FollowStatus: true,
+ StopOnTerminal: watchOpts.StopOnTerminal,
+ })
+ if err != nil {
+ streamCancel()
+ return nil, converter.FromGRPCError(err)
+ }
+
+ first, err := stream.Recv()
+ if err != nil {
+ streamCancel()
+ return nil, converter.FromGRPCError(err)
+ }
+
+ ch := make(chan Event[*Sandbox], 64)
+ w := newWatcher(ch, streamCancel)
+
+ go func() {
+ defer close(ch)
+ defer streamCancel()
+ ev := first
+ isFirst := true
+ for {
+ if sbPayload, ok := ev.Payload.(*pb.SandboxStreamEvent_Sandbox); ok && sbPayload.Sandbox != nil {
+ sandbox := converter.SandboxFromProto(sbPayload.Sandbox)
+ eventType := EventModified
+ if isFirst {
+ eventType = EventAdded
+ isFirst = false
+ } else if sandbox.Status.Phase == SandboxDeleting {
+ eventType = EventDeleted
+ }
+ select {
+ case ch <- Event[*Sandbox]{Type: eventType, Object: sandbox}:
+ case <-w.done:
+ return
+ }
+ // StopOnTerminal: close watcher after delivering a terminal phase event
+ if watchOpts.StopOnTerminal && (sandbox.Status.Phase == SandboxReady || sandbox.Status.Phase == SandboxError) {
+ w.Stop()
+ return
+ }
+ }
+ var recvErr error
+ ev, recvErr = stream.Recv()
+ if recvErr != nil {
+ if recvErr != io.EOF {
+ select {
+ case ch <- Event[*Sandbox]{Type: EventError, Err: converter.FromGRPCError(recvErr)}:
+ case <-w.done:
+ }
+ }
+ return
+ }
+ }
+ }()
+
+ return w, nil
+}
+
+func (s *sandboxClient) GetLogs(ctx context.Context, workspace, sandboxName string, opts ...LogOption) (*LogResult, error) {
+ // Resolve sandbox name to ID — the proto RPC takes SandboxId, not name.
+ sb, err := s.Get(ctx, workspace, sandboxName)
+ if err != nil {
+ return nil, err
+ }
+
+ cfg := types.ApplyLogOptions(opts)
+ req := &pb.GetSandboxLogsRequest{
+ SandboxId: sb.ID,
+ Lines: cfg.Lines(),
+ Sources: cfg.Sources(),
+ MinLevel: cfg.MinLevel(),
+ Workspace: workspace,
+ }
+ if !cfg.Since().IsZero() {
+ req.SinceMs = converter.MillisFromTime(cfg.Since())
+ }
+
+ resp, err := s.client.GetSandboxLogs(ctx, req)
+ if err != nil {
+ return nil, converter.FromGRPCError(err)
+ }
+ return converter.LogResultFromProto(resp), nil
+}
diff --git a/sdk/go/openshell/v1/sandbox_client_test.go b/sdk/go/openshell/v1/sandbox_client_test.go
new file mode 100644
index 000000000..2574348ec
--- /dev/null
+++ b/sdk/go/openshell/v1/sandbox_client_test.go
@@ -0,0 +1,1068 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+ "net"
+ "sync"
+ "testing"
+ "time"
+
+ dm "github.com/NVIDIA/OpenShell/sdk/go/proto/datamodelv1"
+ pb "github.com/NVIDIA/OpenShell/sdk/go/proto/openshellv1"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/credentials/insecure"
+ "google.golang.org/grpc/status"
+ "google.golang.org/grpc/test/bufconn"
+ "google.golang.org/protobuf/proto"
+)
+
+const bufSize = 1024 * 1024
+
+type mockSandboxServer struct {
+ pb.UnimplementedOpenShellServer
+ mu sync.Mutex
+ sandboxes map[string]*pb.Sandbox
+ providers map[string][]*dm.Provider
+ createErr error
+ getErr error
+ listErr error
+ deleteErr error
+ attachErr error
+ detachErr error
+ listProvErr error
+ watchEvents []*pb.SandboxStreamEvent
+ watchErr error
+ watchPostEventsErr error
+ watchKeepOpen chan struct{} // if non-nil, WatchSandbox blocks after sending events until closed
+ watchRequest *pb.WatchSandboxRequest // recorded request
+
+ // GetLogs fields
+ getLogsResp *pb.GetSandboxLogsResponse
+ getLogsErr error
+ getLogsRequest *pb.GetSandboxLogsRequest // recorded request
+}
+
+func newMockSandboxServer() *mockSandboxServer {
+ return &mockSandboxServer{
+ sandboxes: make(map[string]*pb.Sandbox),
+ providers: make(map[string][]*dm.Provider),
+ }
+}
+
+func (s *mockSandboxServer) CreateSandbox(_ context.Context, req *pb.CreateSandboxRequest) (*pb.SandboxResponse, error) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if s.createErr != nil {
+ return nil, s.createErr
+ }
+ sb := &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{
+ Id: "sb-" + req.GetName(),
+ Name: req.GetName(),
+ CreatedAtMs: 1700000000000,
+ Labels: req.GetLabels(),
+ ResourceVersion: 1,
+ },
+ Spec: req.GetSpec(),
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING},
+ }
+ s.sandboxes[req.GetName()] = sb
+ return &pb.SandboxResponse{Sandbox: sb}, nil
+}
+
+func (s *mockSandboxServer) GetSandbox(_ context.Context, req *pb.GetSandboxRequest) (*pb.SandboxResponse, error) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if s.getErr != nil {
+ return nil, s.getErr
+ }
+ sb, ok := s.sandboxes[req.GetName()]
+ if !ok {
+ return nil, status.Errorf(codes.NotFound, "sandbox %q not found", req.GetName())
+ }
+ cloned := proto.Clone(sb).(*pb.Sandbox)
+ return &pb.SandboxResponse{Sandbox: cloned}, nil
+}
+
+func (s *mockSandboxServer) setPhase(name string, phase pb.SandboxPhase) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if sb, ok := s.sandboxes[name]; ok {
+ sb.Status.Phase = phase
+ }
+}
+
+func (s *mockSandboxServer) ListSandboxes(_ context.Context, _ *pb.ListSandboxesRequest) (*pb.ListSandboxesResponse, error) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if s.listErr != nil {
+ return nil, s.listErr
+ }
+ var list []*pb.Sandbox
+ for _, sb := range s.sandboxes {
+ list = append(list, sb)
+ }
+ return &pb.ListSandboxesResponse{Sandboxes: list}, nil
+}
+
+func (s *mockSandboxServer) DeleteSandbox(_ context.Context, req *pb.DeleteSandboxRequest) (*pb.DeleteSandboxResponse, error) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if s.deleteErr != nil {
+ return nil, s.deleteErr
+ }
+ _, ok := s.sandboxes[req.GetName()]
+ if !ok {
+ return nil, status.Errorf(codes.NotFound, "sandbox %q not found", req.GetName())
+ }
+ delete(s.sandboxes, req.GetName())
+ return &pb.DeleteSandboxResponse{Deleted: true}, nil
+}
+
+func (s *mockSandboxServer) AttachSandboxProvider(_ context.Context, req *pb.AttachSandboxProviderRequest) (*pb.AttachSandboxProviderResponse, error) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if s.attachErr != nil {
+ return nil, s.attachErr
+ }
+ sb, ok := s.sandboxes[req.GetSandboxName()]
+ if !ok {
+ return nil, status.Errorf(codes.NotFound, "sandbox %q not found", req.GetSandboxName())
+ }
+ sb.Spec.Providers = append(sb.Spec.Providers, req.GetProviderName())
+ return &pb.AttachSandboxProviderResponse{Sandbox: sb, Attached: true}, nil
+}
+
+func (s *mockSandboxServer) DetachSandboxProvider(_ context.Context, req *pb.DetachSandboxProviderRequest) (*pb.DetachSandboxProviderResponse, error) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if s.detachErr != nil {
+ return nil, s.detachErr
+ }
+ sb, ok := s.sandboxes[req.GetSandboxName()]
+ if !ok {
+ return nil, status.Errorf(codes.NotFound, "sandbox %q not found", req.GetSandboxName())
+ }
+ return &pb.DetachSandboxProviderResponse{Sandbox: sb, Detached: true}, nil
+}
+
+func (s *mockSandboxServer) ListSandboxProviders(_ context.Context, req *pb.ListSandboxProvidersRequest) (*pb.ListSandboxProvidersResponse, error) {
+ if s.listProvErr != nil {
+ return nil, s.listProvErr
+ }
+ provs := s.providers[req.GetSandboxName()]
+ return &pb.ListSandboxProvidersResponse{Providers: provs}, nil
+}
+
+func (s *mockSandboxServer) WatchSandbox(req *pb.WatchSandboxRequest, stream grpc.ServerStreamingServer[pb.SandboxStreamEvent]) error {
+ s.mu.Lock()
+ s.watchRequest = req
+ s.mu.Unlock()
+ if s.watchErr != nil {
+ return s.watchErr
+ }
+ s.mu.Lock()
+ events := make([]*pb.SandboxStreamEvent, len(s.watchEvents))
+ copy(events, s.watchEvents)
+ keepOpen := s.watchKeepOpen
+ s.mu.Unlock()
+ for _, ev := range events {
+ if err := stream.Send(ev); err != nil {
+ return err
+ }
+ }
+ if s.watchPostEventsErr != nil {
+ return s.watchPostEventsErr
+ }
+ // If watchKeepOpen is set, block until it is closed (simulates long-running stream)
+ if keepOpen != nil {
+ <-keepOpen
+ }
+ return nil
+}
+
+func (s *mockSandboxServer) GetSandboxLogs(_ context.Context, req *pb.GetSandboxLogsRequest) (*pb.GetSandboxLogsResponse, error) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ s.getLogsRequest = req
+ if s.getLogsErr != nil {
+ return nil, s.getLogsErr
+ }
+ if s.getLogsResp != nil {
+ return s.getLogsResp, nil
+ }
+ return &pb.GetSandboxLogsResponse{}, nil
+}
+
+func setupSandboxTest(t *testing.T, mock *mockSandboxServer) (*sandboxClient, func()) {
+ t.Helper()
+ lis := bufconn.Listen(bufSize)
+ srv := grpc.NewServer()
+ pb.RegisterOpenShellServer(srv, mock)
+ go func() { _ = srv.Serve(lis) }()
+
+ conn, err := grpc.NewClient("passthrough:///bufconn",
+ grpc.WithContextDialer(func(_ context.Context, _ string) (net.Conn, error) {
+ return lis.Dial()
+ }),
+ grpc.WithTransportCredentials(insecure.NewCredentials()),
+ )
+ require.NoError(t, err)
+
+ return newSandboxClient(conn), func() {
+ _ = conn.Close()
+ srv.Stop()
+ }
+}
+
+// --- T029: Sandbox CRUD tests ---
+
+func TestSandboxCreate(t *testing.T) {
+ mock := newMockSandboxServer()
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ spec := &SandboxSpec{
+ LogLevel: "debug",
+ Environment: map[string]string{"FOO": "bar"},
+ Providers: []string{"claude"},
+ }
+ labels := map[string]string{"env": "dev"}
+
+ result, err := client.Create(context.Background(), "default", "my-sandbox", spec, labels)
+
+ require.NoError(t, err)
+ require.NotNil(t, result)
+ assert.Equal(t, "my-sandbox", result.Name)
+ assert.Equal(t, "sb-my-sandbox", result.ID)
+ assert.Equal(t, map[string]string{"env": "dev"}, result.Labels)
+ assert.Equal(t, SandboxProvisioning, result.Status.Phase)
+}
+
+func TestSandboxCreate_AlreadyExists(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.createErr = status.Error(codes.AlreadyExists, "sandbox already exists")
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ _, err := client.Create(context.Background(), "default", "dup", &SandboxSpec{}, nil)
+
+ require.Error(t, err)
+ assert.True(t, IsAlreadyExists(err))
+}
+
+func TestSandboxGet(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["existing"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Id: "sb-1", Name: "existing", ResourceVersion: 5},
+ Spec: &pb.SandboxSpec{LogLevel: "info"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ result, err := client.Get(context.Background(), "default", "existing")
+
+ require.NoError(t, err)
+ require.NotNil(t, result)
+ assert.Equal(t, "existing", result.Name)
+ assert.Equal(t, "sb-1", result.ID)
+ assert.Equal(t, uint64(5), result.ResourceVersion)
+ assert.Equal(t, SandboxReady, result.Status.Phase)
+}
+
+func TestSandboxGet_NotFound(t *testing.T) {
+ mock := newMockSandboxServer()
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ _, err := client.Get(context.Background(), "default", "nonexistent")
+
+ require.Error(t, err)
+ assert.True(t, IsNotFound(err))
+}
+
+func TestSandboxList(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["sb1"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "sb1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY},
+ }
+ mock.sandboxes["sb2"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "sb2"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ result, err := client.List(context.Background(), "default")
+
+ require.NoError(t, err)
+ assert.Len(t, result, 2)
+}
+
+func TestSandboxList_Empty(t *testing.T) {
+ mock := newMockSandboxServer()
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ result, err := client.List(context.Background(), "default")
+
+ require.NoError(t, err)
+ assert.Empty(t, result)
+}
+
+func TestSandboxList_WithOptions(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["sb1"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "sb1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ result, err := client.List(context.Background(), "default", ListOptions{Limit: 10, Offset: 0})
+
+ require.NoError(t, err)
+ assert.Len(t, result, 1)
+}
+
+func TestSandboxDelete(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["deleteme"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "deleteme"},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ err := client.Delete(context.Background(), "default", "deleteme")
+
+ require.NoError(t, err)
+ assert.Empty(t, mock.sandboxes["deleteme"])
+}
+
+func TestSandboxDelete_NotFound(t *testing.T) {
+ mock := newMockSandboxServer()
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ err := client.Delete(context.Background(), "default", "nonexistent")
+
+ require.Error(t, err)
+ assert.True(t, IsNotFound(err))
+}
+
+// --- T030: AttachProvider, DetachProvider, ListProviders tests ---
+
+func TestSandboxAttachProvider(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["my-sb"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "my-sb", ResourceVersion: 2},
+ Spec: &pb.SandboxSpec{Providers: []string{"existing-prov"}},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ result, err := client.AttachProvider(context.Background(), "default", "my-sb", "new-prov", 2)
+
+ require.NoError(t, err)
+ require.NotNil(t, result)
+ assert.True(t, result.Attached)
+ require.NotNil(t, result.Sandbox)
+ assert.Equal(t, "my-sb", result.Sandbox.Name)
+}
+
+func TestSandboxAttachProvider_NotFound(t *testing.T) {
+ mock := newMockSandboxServer()
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ _, err := client.AttachProvider(context.Background(), "default", "missing", "prov", 1)
+
+ require.Error(t, err)
+ assert.True(t, IsNotFound(err))
+}
+
+func TestSandboxAttachProvider_Error(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.attachErr = status.Error(codes.InvalidArgument, "bad version")
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ _, err := client.AttachProvider(context.Background(), "default", "sb", "prov", 99)
+
+ require.Error(t, err)
+ assert.True(t, IsInvalidArgument(err))
+}
+
+func TestSandboxDetachProvider(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["my-sb"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "my-sb", ResourceVersion: 3},
+ Spec: &pb.SandboxSpec{Providers: []string{"prov-a", "prov-b"}},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ result, err := client.DetachProvider(context.Background(), "default", "my-sb", "prov-a", 3)
+
+ require.NoError(t, err)
+ require.NotNil(t, result)
+ assert.True(t, result.Detached)
+ require.NotNil(t, result.Sandbox)
+ assert.Equal(t, "my-sb", result.Sandbox.Name)
+}
+
+func TestSandboxDetachProvider_NotFound(t *testing.T) {
+ mock := newMockSandboxServer()
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ _, err := client.DetachProvider(context.Background(), "default", "missing", "prov", 1)
+
+ require.Error(t, err)
+ assert.True(t, IsNotFound(err))
+}
+
+func TestSandboxListProviders(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.providers["my-sb"] = []*dm.Provider{
+ {Metadata: &dm.ObjectMeta{Name: "claude-prov"}, Type: "claude"},
+ {Metadata: &dm.ObjectMeta{Name: "github-prov"}, Type: "github"},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ result, err := client.ListProviders(context.Background(), "default", "my-sb")
+
+ require.NoError(t, err)
+ assert.Len(t, result, 2)
+}
+
+func TestSandboxListProviders_Empty(t *testing.T) {
+ mock := newMockSandboxServer()
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ result, err := client.ListProviders(context.Background(), "default", "empty-sb")
+
+ require.NoError(t, err)
+ assert.Empty(t, result)
+}
+
+func TestSandboxListProviders_Error(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.listProvErr = status.Error(codes.Unavailable, "service down")
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ _, err := client.ListProviders(context.Background(), "default", "sb")
+
+ require.Error(t, err)
+ assert.True(t, IsUnavailable(err))
+}
+
+// --- T031: WaitReady tests ---
+
+func TestSandboxWaitReady_AlreadyReady(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["ready-sb"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "ready-sb"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ result, err := client.WaitReady(context.Background(), "default", "ready-sb")
+
+ require.NoError(t, err)
+ require.NotNil(t, result)
+ assert.Equal(t, "ready-sb", result.Name)
+ assert.Equal(t, SandboxReady, result.Status.Phase)
+}
+
+func TestSandboxWaitReady_BecomesReady(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["pending-sb"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "pending-sb"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ go func() {
+ time.Sleep(50 * time.Millisecond)
+ mock.setPhase("pending-sb", pb.SandboxPhase_SANDBOX_PHASE_READY)
+ }()
+
+ ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
+ defer cancel()
+
+ result, err := client.WaitReady(ctx, "default", "pending-sb", WaitOptions{PollInterval: 20 * time.Millisecond})
+
+ require.NoError(t, err)
+ require.NotNil(t, result)
+ assert.Equal(t, SandboxReady, result.Status.Phase)
+}
+
+func TestSandboxWaitReady_ContextTimeout(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["stuck-sb"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "stuck-sb"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
+ defer cancel()
+
+ _, err := client.WaitReady(ctx, "default", "stuck-sb", WaitOptions{PollInterval: 20 * time.Millisecond})
+
+ require.Error(t, err)
+ assert.True(t, IsDeadlineExceeded(err), "WaitReady must wrap context.DeadlineExceeded in StatusError")
+}
+
+func TestSandboxWaitReady_ContextCancelled(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["cancel-sb"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "cancel-sb"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ ctx, cancel := context.WithCancel(context.Background())
+ go func() {
+ time.Sleep(50 * time.Millisecond)
+ cancel()
+ }()
+
+ _, err := client.WaitReady(ctx, "default", "cancel-sb", WaitOptions{PollInterval: 20 * time.Millisecond})
+
+ require.Error(t, err)
+ assert.True(t, IsCancelled(err), "WaitReady must wrap context.Canceled in StatusError")
+}
+
+func TestSandboxWaitReady_SandboxFailed(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["fail-sb"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "fail-sb"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_ERROR},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ _, err := client.WaitReady(context.Background(), "default", "fail-sb")
+
+ require.Error(t, err)
+}
+
+func TestSandboxWaitReady_NotFound(t *testing.T) {
+ mock := newMockSandboxServer()
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ _, err := client.WaitReady(context.Background(), "default", "nonexistent")
+
+ require.Error(t, err)
+ assert.True(t, IsNotFound(err))
+}
+
+// --- T039: Watch integration tests ---
+
+func TestSandboxWatch_ReceivesEvents(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["sb-1"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Id: "id-1", Name: "sb-1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING},
+ }
+ mock.watchEvents = []*pb.SandboxStreamEvent{
+ {Payload: &pb.SandboxStreamEvent_Sandbox{Sandbox: &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "sb-1", Id: "id-1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING},
+ }}},
+ {Payload: &pb.SandboxStreamEvent_Sandbox{Sandbox: &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "sb-1", Id: "id-1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY},
+ }}},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ w, err := client.Watch(context.Background(), "default", "sb-1")
+ require.NoError(t, err)
+ defer w.Stop()
+
+ ev1 := <-w.ResultChan()
+ assert.Equal(t, EventAdded, ev1.Type)
+ require.NotNil(t, ev1.Object)
+ assert.Equal(t, "sb-1", ev1.Object.Name)
+ assert.Equal(t, SandboxProvisioning, ev1.Object.Status.Phase)
+
+ ev2 := <-w.ResultChan()
+ assert.Equal(t, EventModified, ev2.Type)
+ assert.Equal(t, SandboxReady, ev2.Object.Status.Phase)
+}
+
+func TestSandboxWatch_FiltersSandboxEventsOnly(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["sb-1"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Id: "id-1", Name: "sb-1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY},
+ }
+ mock.watchEvents = []*pb.SandboxStreamEvent{
+ {Payload: &pb.SandboxStreamEvent_Log{Log: &pb.SandboxLogLine{Message: "some log"}}},
+ {Payload: &pb.SandboxStreamEvent_Sandbox{Sandbox: &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "sb-1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY},
+ }}},
+ {Payload: &pb.SandboxStreamEvent_Warning{Warning: &pb.SandboxStreamWarning{Message: "warn"}}},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ w, err := client.Watch(context.Background(), "default", "sb-1")
+ require.NoError(t, err)
+ defer w.Stop()
+
+ ev := <-w.ResultChan()
+ assert.Equal(t, EventAdded, ev.Type)
+ assert.Equal(t, "sb-1", ev.Object.Name)
+
+ // Stream ends after server sends all events; channel should close
+ select {
+ case _, ok := <-w.ResultChan():
+ assert.False(t, ok, "channel should close after stream ends")
+ case <-time.After(time.Second):
+ t.Fatal("timed out waiting for channel close")
+ }
+}
+
+func TestSandboxWatch_StopCancelsStream(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["sb-1"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Id: "id-1", Name: "sb-1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY},
+ }
+ mock.watchEvents = []*pb.SandboxStreamEvent{
+ {Payload: &pb.SandboxStreamEvent_Sandbox{Sandbox: &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "sb-1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY},
+ }}},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ w, err := client.Watch(context.Background(), "default", "sb-1")
+ require.NoError(t, err)
+
+ <-w.ResultChan()
+ w.Stop()
+
+ select {
+ case _, ok := <-w.ResultChan():
+ assert.False(t, ok, "channel should be closed after Stop")
+ case <-time.After(time.Second):
+ t.Fatal("timed out waiting for channel close after Stop")
+ }
+}
+
+func TestSandboxWatch_RPCError(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["watch-err"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Id: "id-watch-err", Name: "watch-err"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY},
+ }
+ mock.watchErr = status.Error(codes.Unavailable, "stream unavailable")
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ _, err := client.Watch(context.Background(), "default", "watch-err")
+
+ require.Error(t, err)
+ assert.True(t, IsUnavailable(err))
+}
+
+func TestSandboxWatch_MidStreamErrorDeliveredAsStatusError(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["sb-1"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Id: "id-1", Name: "sb-1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING},
+ }
+ mock.watchEvents = []*pb.SandboxStreamEvent{
+ {Payload: &pb.SandboxStreamEvent_Sandbox{Sandbox: &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "sb-1", Id: "id-1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING},
+ }}},
+ }
+ mock.watchPostEventsErr = status.Error(codes.Unavailable, "connection lost")
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ w, err := client.Watch(context.Background(), "default", "sb-1")
+ require.NoError(t, err)
+ defer w.Stop()
+
+ ev1 := <-w.ResultChan()
+ assert.Equal(t, EventAdded, ev1.Type)
+
+ ev2 := <-w.ResultChan()
+ assert.Equal(t, EventError, ev2.Type)
+ require.Error(t, ev2.Err)
+ assert.True(t, IsUnavailable(ev2.Err), "mid-stream error should be converted to StatusError")
+}
+
+// --- T016: Watch name-to-ID resolution verification tests ---
+
+func TestSandboxWatch_ResolvesNameToID(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["my-sandbox"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Id: "resolved-id-123", Name: "my-sandbox"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING},
+ }
+ mock.watchKeepOpen = make(chan struct{})
+ defer close(mock.watchKeepOpen)
+ mock.watchEvents = []*pb.SandboxStreamEvent{
+ {Payload: &pb.SandboxStreamEvent_Sandbox{Sandbox: &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "my-sandbox", Id: "resolved-id-123"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING},
+ }}},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ w, err := client.Watch(context.Background(), "default", "my-sandbox")
+ require.NoError(t, err)
+ defer w.Stop()
+
+ // Verify the WatchSandboxRequest.Id contains the resolved ID, not the name
+ mock.mu.Lock()
+ req := mock.watchRequest
+ mock.mu.Unlock()
+ require.NotNil(t, req)
+ assert.Equal(t, "resolved-id-123", req.GetId(), "Watch should send resolved sandbox ID, not the name")
+}
+
+func TestSandboxWatch_ResolutionError(t *testing.T) {
+ mock := newMockSandboxServer()
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ _, err := client.Watch(context.Background(), "default", "nonexistent")
+
+ require.Error(t, err)
+ assert.True(t, IsNotFound(err), "Watch should return NotFound when sandbox name cannot be resolved")
+}
+
+func TestSandboxWatch_EmptySandboxName(t *testing.T) {
+ mock := newMockSandboxServer()
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ _, err := client.Watch(context.Background(), "default", "")
+
+ require.Error(t, err)
+ assert.True(t, IsInvalidArgument(err), "Watch should reject empty sandbox name")
+}
+
+// --- T023/T024: StopOnTerminal watch tests ---
+
+func TestSandboxWatch_StopOnTerminal_Ready(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["sb-1"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Id: "id-1", Name: "sb-1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING},
+ }
+ mock.watchKeepOpen = make(chan struct{})
+ defer close(mock.watchKeepOpen)
+ mock.watchEvents = []*pb.SandboxStreamEvent{
+ {Payload: &pb.SandboxStreamEvent_Sandbox{Sandbox: &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "sb-1", Id: "id-1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING},
+ }}},
+ {Payload: &pb.SandboxStreamEvent_Sandbox{Sandbox: &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "sb-1", Id: "id-1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY},
+ }}},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ w, err := client.Watch(context.Background(), "default", "sb-1", WatchOptions{StopOnTerminal: true})
+ require.NoError(t, err)
+ defer w.Stop()
+
+ // Should receive the Provisioning event
+ ev1 := <-w.ResultChan()
+ assert.Equal(t, EventAdded, ev1.Type)
+ assert.Equal(t, SandboxProvisioning, ev1.Object.Status.Phase)
+
+ // Should receive the Ready event (terminal)
+ ev2 := <-w.ResultChan()
+ assert.Equal(t, EventModified, ev2.Type)
+ assert.Equal(t, SandboxReady, ev2.Object.Status.Phase)
+
+ // Channel should close automatically after terminal event (stream is still open)
+ select {
+ case _, ok := <-w.ResultChan():
+ assert.False(t, ok, "channel should close after terminal Ready event")
+ case <-time.After(time.Second):
+ t.Fatal("timed out waiting for channel close after terminal Ready event")
+ }
+}
+
+func TestSandboxWatch_StopOnTerminal_Error(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["sb-1"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Id: "id-1", Name: "sb-1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING},
+ }
+ mock.watchKeepOpen = make(chan struct{})
+ defer close(mock.watchKeepOpen)
+ mock.watchEvents = []*pb.SandboxStreamEvent{
+ {Payload: &pb.SandboxStreamEvent_Sandbox{Sandbox: &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "sb-1", Id: "id-1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING},
+ }}},
+ {Payload: &pb.SandboxStreamEvent_Sandbox{Sandbox: &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "sb-1", Id: "id-1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_ERROR},
+ }}},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ w, err := client.Watch(context.Background(), "default", "sb-1", WatchOptions{StopOnTerminal: true})
+ require.NoError(t, err)
+ defer w.Stop()
+
+ // Should receive the Provisioning event
+ ev1 := <-w.ResultChan()
+ assert.Equal(t, EventAdded, ev1.Type)
+ assert.Equal(t, SandboxProvisioning, ev1.Object.Status.Phase)
+
+ // Should receive the Error event (terminal)
+ ev2 := <-w.ResultChan()
+ assert.Equal(t, EventModified, ev2.Type)
+ assert.Equal(t, SandboxError, ev2.Object.Status.Phase)
+
+ // Channel should close automatically after terminal event (stream is still open)
+ select {
+ case _, ok := <-w.ResultChan():
+ assert.False(t, ok, "channel should close after terminal Error event")
+ case <-time.After(time.Second):
+ t.Fatal("timed out waiting for channel close after terminal Error event")
+ }
+}
+
+func TestSandboxWatch_StopOnTerminal_False_DoesNotClose(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["sb-1"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Id: "id-1", Name: "sb-1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY},
+ }
+ mock.watchKeepOpen = make(chan struct{})
+ defer close(mock.watchKeepOpen)
+ mock.watchEvents = []*pb.SandboxStreamEvent{
+ {Payload: &pb.SandboxStreamEvent_Sandbox{Sandbox: &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "sb-1", Id: "id-1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY},
+ }}},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ w, err := client.Watch(context.Background(), "default", "sb-1")
+ require.NoError(t, err)
+ defer w.Stop()
+
+ ev := <-w.ResultChan()
+ assert.Equal(t, EventAdded, ev.Type)
+ assert.Equal(t, SandboxReady, ev.Object.Status.Phase)
+
+ // Channel must NOT close: stream is still open and StopOnTerminal=false
+ select {
+ case <-w.ResultChan():
+ t.Fatal("channel should stay open when StopOnTerminal is false")
+ case <-time.After(100 * time.Millisecond):
+ }
+}
+
+func TestSandboxWatch_DeletedEvent(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["sb-1"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Id: "id-1", Name: "sb-1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING},
+ }
+ mock.watchEvents = []*pb.SandboxStreamEvent{
+ {Payload: &pb.SandboxStreamEvent_Sandbox{Sandbox: &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "sb-1", Id: "id-1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_PROVISIONING},
+ }}},
+ {Payload: &pb.SandboxStreamEvent_Sandbox{Sandbox: &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Name: "sb-1", Id: "id-1"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_DELETING},
+ }}},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ w, err := client.Watch(context.Background(), "default", "sb-1")
+ require.NoError(t, err)
+ defer w.Stop()
+
+ ev1 := <-w.ResultChan()
+ assert.Equal(t, EventAdded, ev1.Type)
+
+ ev2 := <-w.ResultChan()
+ assert.Equal(t, EventDeleted, ev2.Type)
+ assert.Equal(t, SandboxDeleting, ev2.Object.Status.Phase)
+}
+
+// --- T027: GetLogs tests ---
+
+func TestSandboxGetLogs(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["log-sb"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Id: "sb-id-123", Name: "log-sb"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY},
+ }
+ mock.getLogsResp = &pb.GetSandboxLogsResponse{
+ Logs: []*pb.SandboxLogLine{
+ {TimestampMs: 1700000000000, Level: "INFO", Target: "gateway", Message: "connected", Source: "gateway"},
+ {TimestampMs: 1700000001000, Level: "DEBUG", Target: "sandbox", Message: "init done", Source: "sandbox"},
+ },
+ BufferTotal: 42,
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ result, err := client.GetLogs(context.Background(), "default", "log-sb")
+
+ require.NoError(t, err)
+ require.NotNil(t, result)
+ assert.Len(t, result.Lines, 2)
+ assert.Equal(t, uint32(42), result.BufferTotal)
+ assert.Equal(t, "INFO", result.Lines[0].Level)
+ assert.Equal(t, "connected", result.Lines[0].Message)
+ assert.Equal(t, "gateway", result.Lines[0].Source)
+ assert.Equal(t, "DEBUG", result.Lines[1].Level)
+ assert.Equal(t, "init done", result.Lines[1].Message)
+
+ // Verify name→id resolution: the proto request should contain the sandbox ID
+ mock.mu.Lock()
+ assert.Equal(t, "sb-id-123", mock.getLogsRequest.GetSandboxId())
+ mock.mu.Unlock()
+}
+
+func TestSandboxGetLogs_WithOptions(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["opts-sb"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Id: "sb-id-opts", Name: "opts-sb"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY},
+ }
+ mock.getLogsResp = &pb.GetSandboxLogsResponse{
+ Logs: []*pb.SandboxLogLine{{TimestampMs: 1700000000000, Level: "WARN", Message: "high cpu"}},
+ BufferTotal: 100,
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ since := time.Date(2023, 11, 14, 0, 0, 0, 0, time.UTC)
+ result, err := client.GetLogs(context.Background(), "default", "opts-sb",
+ WithLogLines(50),
+ WithLogSince(since),
+ WithLogSources("gateway", "sandbox"),
+ WithLogMinLevel("WARN"),
+ )
+
+ require.NoError(t, err)
+ require.NotNil(t, result)
+ assert.Len(t, result.Lines, 1)
+ assert.Equal(t, "WARN", result.Lines[0].Level)
+
+ // Verify all options were passed to the proto request
+ mock.mu.Lock()
+ req := mock.getLogsRequest
+ mock.mu.Unlock()
+ assert.Equal(t, "sb-id-opts", req.GetSandboxId())
+ assert.Equal(t, uint32(50), req.GetLines())
+ assert.Equal(t, since.UnixMilli(), req.GetSinceMs())
+ assert.Equal(t, []string{"gateway", "sandbox"}, req.GetSources())
+ assert.Equal(t, "WARN", req.GetMinLevel())
+}
+
+func TestSandboxGetLogs_SandboxNotFound(t *testing.T) {
+ mock := newMockSandboxServer()
+ // No sandbox registered — Get will return NotFound
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ _, err := client.GetLogs(context.Background(), "default", "nonexistent")
+
+ require.Error(t, err)
+ assert.True(t, IsNotFound(err))
+}
+
+func TestSandboxGetLogs_RPCError(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["rpc-err-sb"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Id: "sb-id-rpc", Name: "rpc-err-sb"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY},
+ }
+ mock.getLogsErr = status.Error(codes.Unavailable, "log service down")
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ _, err := client.GetLogs(context.Background(), "default", "rpc-err-sb")
+
+ require.Error(t, err)
+ assert.True(t, IsUnavailable(err))
+}
+
+func TestSandboxGetLogs_EmptyResult(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["empty-sb"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Id: "sb-id-empty", Name: "empty-sb"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY},
+ }
+ mock.getLogsResp = &pb.GetSandboxLogsResponse{
+ BufferTotal: 0,
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ result, err := client.GetLogs(context.Background(), "default", "empty-sb")
+
+ require.NoError(t, err)
+ require.NotNil(t, result)
+ assert.Empty(t, result.Lines)
+ assert.Equal(t, uint32(0), result.BufferTotal)
+}
+
+func TestSandboxGetLogs_SinceZeroNotSent(t *testing.T) {
+ mock := newMockSandboxServer()
+ mock.sandboxes["zero-sb"] = &pb.Sandbox{
+ Metadata: &dm.ObjectMeta{Id: "sb-id-zero", Name: "zero-sb"},
+ Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY},
+ }
+ client, cleanup := setupSandboxTest(t, mock)
+ defer cleanup()
+
+ // Call without WithLogSince — SinceMs should be 0 (not set)
+ _, err := client.GetLogs(context.Background(), "default", "zero-sb")
+
+ require.NoError(t, err)
+ mock.mu.Lock()
+ assert.Equal(t, int64(0), mock.getLogsRequest.GetSinceMs())
+ mock.mu.Unlock()
+}
diff --git a/sdk/go/openshell/v1/service.go b/sdk/go/openshell/v1/service.go
new file mode 100644
index 000000000..8d3f3c0f5
--- /dev/null
+++ b/sdk/go/openshell/v1/service.go
@@ -0,0 +1,25 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+)
+
+// ServiceEndpoint represents an exposed HTTP service endpoint within a sandbox.
+type ServiceEndpoint = types.ServiceEndpoint
+
+// ServiceInterface defines operations for managing sandbox service endpoints.
+type ServiceInterface interface {
+ // Expose creates a new service endpoint in the given sandbox.
+ Expose(ctx context.Context, workspace, sandboxName, serviceName string, targetPort uint32, domain bool) (*ServiceEndpoint, error)
+ // Get retrieves a service endpoint by sandbox and service name.
+ Get(ctx context.Context, workspace, sandboxName, serviceName string) (*ServiceEndpoint, error)
+ // List returns all service endpoints for a sandbox. An empty sandboxName returns endpoints across all sandboxes.
+ List(ctx context.Context, workspace, sandboxName string, opts ...ListOptions) ([]*ServiceEndpoint, error)
+ // Delete removes a service endpoint by sandbox and service name.
+ Delete(ctx context.Context, workspace, sandboxName, serviceName string) error
+}
diff --git a/sdk/go/openshell/v1/ssh.go b/sdk/go/openshell/v1/ssh.go
new file mode 100644
index 000000000..de8d29b66
--- /dev/null
+++ b/sdk/go/openshell/v1/ssh.go
@@ -0,0 +1,58 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+ "io"
+
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+)
+
+// SSHSession represents an SSH session created for a sandbox.
+type SSHSession = types.SSHSession
+
+// tunnelConfig accumulates options for the Tunnel method.
+type tunnelConfig struct {
+ serviceID string
+}
+
+// TunnelOption configures an SSH tunnel opened via [SSHInterface.Tunnel].
+type TunnelOption func(*tunnelConfig)
+
+// WithTunnelServiceID sets an optional service identifier on the tunnel's
+// init frame for audit and correlation purposes.
+func WithTunnelServiceID(id string) TunnelOption {
+ return func(c *tunnelConfig) {
+ c.serviceID = id
+ }
+}
+
+// SSHInterface defines operations for managing SSH sessions.
+type SSHInterface interface {
+ // CreateSession creates a new SSH session for the given sandbox.
+ // The returned SSHSession contains connection details including the
+ // sensitive Token field that must not be logged.
+ //
+ // Note: CreateSession accepts a raw sandbox ID, not a name.
+ // For name-based access with automatic session lifecycle management,
+ // prefer [SSHInterface.Tunnel] which resolves sandbox names internally
+ // and revokes the session on Close.
+ CreateSession(ctx context.Context, workspace, sandboxID string) (*SSHSession, error)
+ // RevokeSession revokes an existing SSH session by its token.
+ // Returns true if the session was actively revoked, false if it was
+ // already expired or not found.
+ RevokeSession(ctx context.Context, workspace, token string) (bool, error)
+ // Tunnel opens a bidirectional SSH tunnel to the given port inside a
+ // sandbox. It combines CreateSession and ForwardTcp(SshRelayTarget)
+ // into a single call with automatic session cleanup on Close.
+ //
+ // The sandboxName is resolved to a sandbox ID internally. Port must
+ // be in the range 1-65535.
+ //
+ // Errors: InvalidArgument if port is out of range or sandboxName is
+ // empty; NotFound if the sandbox does not exist; Unimplemented by
+ // the fake client; Unavailable if the client is closed.
+ Tunnel(ctx context.Context, workspace, sandboxName string, port uint32, opts ...TunnelOption) (io.ReadWriteCloser, error)
+}
diff --git a/sdk/go/openshell/v1/stub_clients.go b/sdk/go/openshell/v1/stub_clients.go
new file mode 100644
index 000000000..1fb25a86a
--- /dev/null
+++ b/sdk/go/openshell/v1/stub_clients.go
@@ -0,0 +1,195 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+ "io"
+ "net"
+)
+
+func stubError(method string) error {
+ return &StatusError{
+ Code: ErrorUnimplemented,
+ Message: method + " not yet available - see https://github.com/NVIDIA/OpenShell/issues/2270",
+ }
+}
+
+// stubExec implements ExecInterface as a placeholder.
+type stubExec struct{}
+
+func (s *stubExec) Run(_ context.Context, _, _ string, _ []string, _ ...ExecOptions) (*ExecResult, error) {
+ return nil, stubError("Exec.Run")
+}
+func (s *stubExec) Stream(_ context.Context, _, _ string, _ []string, _ ...ExecOptions) (ExecStream, error) {
+ return nil, stubError("Exec.Stream")
+}
+func (s *stubExec) Interactive(_ context.Context, _, _ string, _ []string, _, _ uint32, _ ...ExecOptions) (InteractiveSession, error) {
+ return nil, stubError("Exec.Interactive")
+}
+
+// stubFiles implements FileInterface as a placeholder.
+type stubFiles struct{}
+
+func (s *stubFiles) Upload(_ context.Context, _, _, _, _ string) error {
+ return stubError("Files.Upload")
+}
+func (s *stubFiles) Download(_ context.Context, _, _, _, _ string) error {
+ return stubError("Files.Download")
+}
+
+// stubHealth implements HealthInterface as a placeholder.
+type stubHealth struct{}
+
+func (s *stubHealth) Check(_ context.Context) (*HealthResult, error) {
+ return nil, stubError("Health.Check")
+}
+
+// stubProviders implements ProviderInterface as a placeholder.
+type stubProviders struct{}
+
+func (s *stubProviders) Create(_ context.Context, _ string, _ *Provider) (*Provider, error) {
+ return nil, stubError("Providers.Create")
+}
+func (s *stubProviders) Get(_ context.Context, _, _ string) (*Provider, error) {
+ return nil, stubError("Providers.Get")
+}
+func (s *stubProviders) List(_ context.Context, _ string, _ ...ListOptions) ([]*Provider, error) {
+ return nil, stubError("Providers.List")
+}
+func (s *stubProviders) Update(_ context.Context, _ string, _ *Provider) (*Provider, error) {
+ return nil, stubError("Providers.Update")
+}
+func (s *stubProviders) Delete(_ context.Context, _, _ string) error {
+ return stubError("Providers.Delete")
+}
+func (s *stubProviders) Ensure(_ context.Context, _ string, _ *Provider) (*Provider, error) {
+ return nil, stubError("Providers.Ensure")
+}
+func (s *stubProviders) Profiles() ProfileInterface { return &stubProfiles{} }
+func (s *stubProviders) Refresh() RefreshInterface { return &stubRefresh{} }
+
+// stubProfiles implements ProfileInterface as a placeholder.
+type stubProfiles struct{}
+
+func (s *stubProfiles) List(_ context.Context, _ string, _ ...ListOptions) ([]*ProviderProfile, error) {
+ return nil, stubError("Profiles.List")
+}
+func (s *stubProfiles) Get(_ context.Context, _, _ string) (*ProviderProfile, error) {
+ return nil, stubError("Profiles.Get")
+}
+func (s *stubProfiles) Import(_ context.Context, _ string, _ []ProfileImportItem) (*ImportResult, error) {
+ return nil, stubError("Profiles.Import")
+}
+func (s *stubProfiles) Update(_ context.Context, _, _ string, _ uint64, _ ProfileImportItem) (*UpdateResult, error) {
+ return nil, stubError("Profiles.Update")
+}
+func (s *stubProfiles) Lint(_ context.Context, _ string, _ []ProfileImportItem) (*LintResult, error) {
+ return nil, stubError("Profiles.Lint")
+}
+func (s *stubProfiles) Delete(_ context.Context, _, _ string) (bool, error) {
+ return false, stubError("Profiles.Delete")
+}
+
+// stubRefresh implements RefreshInterface as a placeholder.
+type stubRefresh struct{}
+
+func (s *stubRefresh) GetStatus(_ context.Context, _, _, _ string) ([]*RefreshStatus, error) {
+ return nil, stubError("Refresh.GetStatus")
+}
+func (s *stubRefresh) Configure(_ context.Context, _ string, _ *RefreshConfig) (*RefreshStatus, error) {
+ return nil, stubError("Refresh.Configure")
+}
+func (s *stubRefresh) Rotate(_ context.Context, _, _, _ string) (*RefreshStatus, error) {
+ return nil, stubError("Refresh.Rotate")
+}
+func (s *stubRefresh) Delete(_ context.Context, _, _, _ string) (bool, error) {
+ return false, stubError("Refresh.Delete")
+}
+
+// stubServices implements ServiceInterface as a placeholder.
+type stubServices struct{}
+
+func (s *stubServices) Expose(_ context.Context, _, _, _ string, _ uint32, _ bool) (*ServiceEndpoint, error) {
+ return nil, stubError("Services.Expose")
+}
+func (s *stubServices) Get(_ context.Context, _, _, _ string) (*ServiceEndpoint, error) {
+ return nil, stubError("Services.Get")
+}
+func (s *stubServices) List(_ context.Context, _, _ string, _ ...ListOptions) ([]*ServiceEndpoint, error) {
+ return nil, stubError("Services.List")
+}
+func (s *stubServices) Delete(_ context.Context, _, _, _ string) error {
+ return stubError("Services.Delete")
+}
+
+// stubSSH implements SSHInterface as a placeholder.
+type stubSSH struct{}
+
+func (s *stubSSH) CreateSession(_ context.Context, _, _ string) (*SSHSession, error) {
+ return nil, stubError("SSH.CreateSession")
+}
+func (s *stubSSH) RevokeSession(_ context.Context, _, _ string) (bool, error) {
+ return false, stubError("SSH.RevokeSession")
+}
+func (s *stubSSH) Tunnel(_ context.Context, _, _ string, _ uint32, _ ...TunnelOption) (io.ReadWriteCloser, error) {
+ return nil, stubError("SSH.Tunnel")
+}
+
+// stubTCP implements TCPInterface as a placeholder.
+type stubTCP struct{}
+
+func (s *stubTCP) Forward(_ context.Context, _, _ string, _ uint32, _ ...ForwardOption) (io.ReadWriteCloser, error) {
+ return nil, stubError("TCP.Forward")
+}
+func (s *stubTCP) Listen(_ context.Context, _, _ string, _, _ uint32, _ ...ListenOption) (net.Listener, error) {
+ return nil, stubError("TCP.Listen")
+}
+
+// stubConfig implements ConfigInterface as a placeholder.
+type stubConfig struct{}
+
+func (s *stubConfig) GetSandbox(_ context.Context, _, _ string) (*SandboxConfig, error) {
+ return nil, stubError("Config.GetSandbox")
+}
+func (s *stubConfig) GetGateway(_ context.Context) (*GatewayConfig, error) {
+ return nil, stubError("Config.GetGateway")
+}
+func (s *stubConfig) Update(_ context.Context, _ string, _ *ConfigUpdate) (*ConfigUpdateResult, error) {
+ return nil, stubError("Config.Update")
+}
+
+// stubPolicy implements PolicyInterface as a placeholder.
+type stubPolicy struct{}
+
+func (s *stubPolicy) GetDraft(_ context.Context, _, _ string, _ ...GetDraftOption) (*DraftPolicy, error) {
+ return nil, stubError("Policy.GetDraft")
+}
+func (s *stubPolicy) ApproveDraftChunk(_ context.Context, _, _, _ string) (*ApproveResult, error) {
+ return nil, stubError("Policy.ApproveDraftChunk")
+}
+func (s *stubPolicy) RejectDraftChunk(_ context.Context, _, _, _, _ string) error {
+ return stubError("Policy.RejectDraftChunk")
+}
+func (s *stubPolicy) ApproveAllDraftChunks(_ context.Context, _, _ string, _ ...ApproveAllOption) (*ApproveAllResult, error) {
+ return nil, stubError("Policy.ApproveAllDraftChunks")
+}
+func (s *stubPolicy) ClearDraftChunks(_ context.Context, _, _ string) (*ClearResult, error) {
+ return nil, stubError("Policy.ClearDraftChunks")
+}
+func (s *stubPolicy) GetDraftHistory(_ context.Context, _, _ string) ([]DraftHistoryEntry, error) {
+ return nil, stubError("Policy.GetDraftHistory")
+}
+func (s *stubPolicy) GetStatus(_ context.Context, _, _ string, _ ...GetStatusOption) (*PolicyStatusResult, error) {
+ return nil, stubError("Policy.GetStatus")
+}
+func (s *stubPolicy) List(_ context.Context, _ string, _ ...ListPolicyOption) ([]SandboxPolicyRevision, error) {
+ return nil, stubError("Policy.List")
+}
+func (s *stubPolicy) EditDraftChunk(_ context.Context, _, _, _ string, _ *NetworkPolicyRule) error {
+ return stubError("Policy.EditDraftChunk")
+}
+func (s *stubPolicy) UndoDraftChunk(_ context.Context, _, _, _ string) (*UndoResult, error) {
+ return nil, stubError("Policy.UndoDraftChunk")
+}
diff --git a/sdk/go/openshell/v1/tcp.go b/sdk/go/openshell/v1/tcp.go
new file mode 100644
index 000000000..950d2e206
--- /dev/null
+++ b/sdk/go/openshell/v1/tcp.go
@@ -0,0 +1,97 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+ "io"
+ "net"
+)
+
+// forwardConfig accumulates options for the Forward method.
+type forwardConfig struct {
+ serviceID string
+}
+
+// ForwardOption configures a TCP forward opened via [TCPInterface.Forward].
+type ForwardOption func(*forwardConfig)
+
+// WithForwardServiceID sets an optional service identifier on the forward's
+// init frame for audit and correlation purposes.
+func WithForwardServiceID(id string) ForwardOption {
+ return func(c *forwardConfig) {
+ c.serviceID = id
+ }
+}
+
+// listenConfig accumulates options for the Listen method.
+type listenConfig struct {
+ bindAddress string
+ useSSHTunnel bool
+ serviceID string
+}
+
+// ListenOption configures a local listener opened via [TCPInterface.Listen].
+type ListenOption func(*listenConfig)
+
+// WithBindAddress overrides the default local bind address ("127.0.0.1").
+// Pass "0.0.0.0" to accept connections from any interface.
+func WithBindAddress(addr string) ListenOption {
+ return func(c *listenConfig) {
+ c.bindAddress = addr
+ }
+}
+
+// WithSSHTunnel routes each accepted connection through an SSH tunnel
+// ([SSHInterface.Tunnel]) instead of the default TCP forward
+// ([TCPInterface.Forward]).
+func WithSSHTunnel() ListenOption {
+ return func(c *listenConfig) {
+ c.useSSHTunnel = true
+ }
+}
+
+// WithListenServiceID sets an optional service identifier on each tunneled
+// connection's init frame for audit and correlation purposes.
+func WithListenServiceID(id string) ListenOption {
+ return func(c *listenConfig) {
+ c.serviceID = id
+ }
+}
+
+// TCPInterface defines operations for TCP port forwarding to sandboxes.
+// Methods accept a sandbox name and resolve it to an ID internally.
+type TCPInterface interface {
+ // Forward opens a bidirectional TCP connection to the given port inside a
+ // sandbox. The sandbox is identified by name; the SDK resolves it to an
+ // ID internally. The returned io.ReadWriteCloser wraps the underlying
+ // gRPC stream; closing it terminates the stream. Port must be in the
+ // range 1-65535; out-of-range values are rejected client-side with an
+ // InvalidArgument error before opening the gRPC stream.
+ //
+ // The connection respects context cancellation: if ctx is cancelled,
+ // the stream is closed and pending Read/Write calls return a context error.
+ Forward(ctx context.Context, workspace, sandboxName string, port uint32, opts ...ForwardOption) (io.ReadWriteCloser, error)
+
+ // Listen binds a local TCP port and tunnels every accepted connection to
+ // the given port inside a sandbox, returning a standard [net.Listener].
+ // Each call to Accept on the returned listener establishes a new tunnel
+ // to the sandbox port, bridging data bidirectionally.
+ //
+ // The sandbox is identified by name; the SDK resolves it to an ID
+ // internally. remotePort must be in the range 1-65535; localPort must be
+ // in the range 0-65535, where 0 lets the OS assign an ephemeral port
+ // (discoverable via Addr).
+ //
+ // Closing the listener stops accepting new connections, tears down all
+ // active tunnels, and blocks until all bridge goroutines finish.
+ // Cancelling ctx triggers the same shutdown behavior.
+ //
+ // Errors:
+ // - InvalidArgument: sandboxName is empty, remotePort is 0 or > 65535,
+ // or localPort is > 65535
+ // - Unimplemented: returned by the fake client
+ // - Unavailable: client is closed
+ Listen(ctx context.Context, workspace, sandboxName string, remotePort uint32, localPort uint32, opts ...ListenOption) (net.Listener, error)
+}
diff --git a/sdk/go/openshell/v1/types.go b/sdk/go/openshell/v1/types.go
new file mode 100644
index 000000000..012811cab
--- /dev/null
+++ b/sdk/go/openshell/v1/types.go
@@ -0,0 +1,46 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+)
+
+// SandboxPhase represents the lifecycle phase of a sandbox.
+type SandboxPhase = types.SandboxPhase
+
+// SandboxPhase values for sandbox lifecycle.
+const (
+ SandboxProvisioning = types.SandboxProvisioning
+ SandboxReady = types.SandboxReady
+ SandboxError = types.SandboxError
+ SandboxDeleting = types.SandboxDeleting
+ SandboxUnknown = types.SandboxUnknown
+)
+
+// EventType classifies watch events.
+type EventType = types.EventType
+
+// EventType values for watch events.
+const (
+ EventAdded = types.EventAdded
+ EventModified = types.EventModified
+ EventDeleted = types.EventDeleted
+ EventError = types.EventError
+)
+
+// StreamType identifies which output stream a chunk belongs to.
+type StreamType = types.StreamType
+
+// StreamType values for exec output.
+const (
+ StreamStdout = types.StreamStdout
+ StreamStderr = types.StreamStderr
+)
+
+// TLSConfig holds TLS connection settings.
+type TLSConfig = types.TLSConfig
+
+// RetryPolicy configures automatic retry behavior for failed RPCs.
+type RetryPolicy = types.RetryPolicy
diff --git a/sdk/go/openshell/v1/types/auth.go b/sdk/go/openshell/v1/types/auth.go
new file mode 100644
index 000000000..90da22473
--- /dev/null
+++ b/sdk/go/openshell/v1/types/auth.go
@@ -0,0 +1,13 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package types
+
+import "context"
+
+// AuthProvider supplies per-RPC credentials. It implements the
+// grpc credentials.PerRPCCredentials interface.
+type AuthProvider interface {
+ GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error)
+ RequireTransportSecurity() bool
+}
diff --git a/sdk/go/openshell/v1/types/config.go b/sdk/go/openshell/v1/types/config.go
new file mode 100644
index 000000000..9657061ff
--- /dev/null
+++ b/sdk/go/openshell/v1/types/config.go
@@ -0,0 +1,19 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package types
+
+import "time"
+
+// Config holds all settings needed to create a Client.
+type Config struct {
+ Address string
+ TLS *TLSConfig
+ Auth AuthProvider
+ // Timeout is reserved for future use. It is not yet applied.
+ Timeout time.Duration
+ // RetryPolicy is reserved for future use. It is not yet applied.
+ RetryPolicy *RetryPolicy
+ // Logger is reserved for future use. It is not yet applied.
+ Logger Logger
+}
diff --git a/sdk/go/openshell/v1/types/doc.go b/sdk/go/openshell/v1/types/doc.go
new file mode 100644
index 000000000..c6577baf4
--- /dev/null
+++ b/sdk/go/openshell/v1/types/doc.go
@@ -0,0 +1,10 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+// Package types defines all domain data types for the OpenShell SDK v1 API.
+//
+// These types are the canonical definitions used by both the client layer
+// (openshell/v1) and the converter layer (openshell/v1/internal/converter).
+// The v1 package re-exports all types via type aliases for backward
+// compatibility.
+package types
diff --git a/sdk/go/openshell/v1/types/errors.go b/sdk/go/openshell/v1/types/errors.go
new file mode 100644
index 000000000..14d43cd75
--- /dev/null
+++ b/sdk/go/openshell/v1/types/errors.go
@@ -0,0 +1,134 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package types
+
+import (
+ "errors"
+ "fmt"
+)
+
+// ErrorCode classifies SDK errors by their gRPC origin.
+type ErrorCode int
+
+// ErrorCode values for classifying gRPC errors.
+const (
+ ErrorNotFound ErrorCode = iota + 1
+ ErrorAlreadyExists
+ ErrorUnavailable
+ ErrorPermissionDenied
+ ErrorInvalidArgument
+ ErrorDeadlineExceeded
+ ErrorCancelled
+ ErrorInternal
+ ErrorUnimplemented
+ ErrorConflict
+ ErrorUnauthenticated
+)
+
+// String returns the human-readable name of the error code.
+func (c ErrorCode) String() string {
+ switch c {
+ case ErrorNotFound:
+ return "NotFound"
+ case ErrorAlreadyExists:
+ return "AlreadyExists"
+ case ErrorUnavailable:
+ return "Unavailable"
+ case ErrorPermissionDenied:
+ return "PermissionDenied"
+ case ErrorInvalidArgument:
+ return "InvalidArgument"
+ case ErrorDeadlineExceeded:
+ return "DeadlineExceeded"
+ case ErrorCancelled:
+ return "Cancelled"
+ case ErrorInternal:
+ return "Internal"
+ case ErrorUnimplemented:
+ return "Unimplemented"
+ case ErrorConflict:
+ return "Conflict"
+ case ErrorUnauthenticated:
+ return "Unauthenticated"
+ default:
+ return fmt.Sprintf("Unknown(%d)", int(c))
+ }
+}
+
+// StatusError is the typed error returned by all SDK operations.
+type StatusError struct {
+ Code ErrorCode
+ Message string
+ Cause error
+}
+
+func (e *StatusError) Error() string {
+ return fmt.Sprintf("%s: %s", e.Code, e.Message)
+}
+
+func (e *StatusError) Unwrap() error {
+ return e.Cause
+}
+
+// IsNotFound returns true if the error indicates a resource was not found.
+func IsNotFound(err error) bool {
+ return hasCode(err, ErrorNotFound)
+}
+
+// IsAlreadyExists returns true if the error indicates a resource already exists.
+func IsAlreadyExists(err error) bool {
+ return hasCode(err, ErrorAlreadyExists)
+}
+
+// IsUnavailable returns true if the error indicates the service is unavailable.
+func IsUnavailable(err error) bool {
+ return hasCode(err, ErrorUnavailable)
+}
+
+// IsPermissionDenied returns true if the error indicates insufficient permissions.
+func IsPermissionDenied(err error) bool {
+ return hasCode(err, ErrorPermissionDenied)
+}
+
+// IsInvalidArgument returns true if the error indicates an invalid argument.
+func IsInvalidArgument(err error) bool {
+ return hasCode(err, ErrorInvalidArgument)
+}
+
+// IsDeadlineExceeded returns true if the error indicates a deadline was exceeded.
+func IsDeadlineExceeded(err error) bool {
+ return hasCode(err, ErrorDeadlineExceeded)
+}
+
+// IsCancelled returns true if the error indicates the operation was cancelled.
+func IsCancelled(err error) bool {
+ return hasCode(err, ErrorCancelled)
+}
+
+// IsUnimplemented returns true if the error indicates the operation is not implemented.
+func IsUnimplemented(err error) bool {
+ return hasCode(err, ErrorUnimplemented)
+}
+
+// IsConflict returns true if the error indicates a conflict, such as
+// optimistic concurrency or an invalid state transition.
+func IsConflict(err error) bool {
+ return hasCode(err, ErrorConflict)
+}
+
+// IsUnauthenticated returns true if the error indicates missing or invalid credentials.
+func IsUnauthenticated(err error) bool {
+ return hasCode(err, ErrorUnauthenticated)
+}
+
+func hasCode(err error, code ErrorCode) bool {
+ if err == nil {
+ return false
+ }
+ var se *StatusError
+ if errors.As(err, &se) {
+ return se.Code == code
+ }
+ return false
+}
diff --git a/sdk/go/openshell/v1/types/exec.go b/sdk/go/openshell/v1/types/exec.go
new file mode 100644
index 000000000..ecc322a2d
--- /dev/null
+++ b/sdk/go/openshell/v1/types/exec.go
@@ -0,0 +1,17 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package types
+
+// ExecResult holds the collected output of a completed command execution.
+type ExecResult struct {
+ ExitCode int
+ Stdout []byte
+ Stderr []byte
+}
+
+// ExecChunk represents a single chunk of output from a streaming command execution.
+type ExecChunk struct {
+ Stream StreamType
+ Data []byte
+}
diff --git a/sdk/go/openshell/v1/types/health.go b/sdk/go/openshell/v1/types/health.go
new file mode 100644
index 000000000..003618318
--- /dev/null
+++ b/sdk/go/openshell/v1/types/health.go
@@ -0,0 +1,10 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package types
+
+// HealthResult holds the result of a health check.
+type HealthResult struct {
+ Healthy bool
+ Version string
+}
diff --git a/sdk/go/openshell/v1/types/log.go b/sdk/go/openshell/v1/types/log.go
new file mode 100644
index 000000000..85a62c29d
--- /dev/null
+++ b/sdk/go/openshell/v1/types/log.go
@@ -0,0 +1,98 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package types
+
+import "time"
+
+// LogLine represents a single log entry from a sandbox.
+type LogLine struct {
+ // Timestamp is when the log entry was recorded.
+ Timestamp time.Time
+ // Level is the log severity level (e.g., "INFO", "WARN", "ERROR").
+ Level string
+ // Target is the log target/module.
+ Target string
+ // Message is the log message text.
+ Message string
+ // Source is the log source: "gateway" or "sandbox".
+ Source string
+ // Fields contains structured key-value fields from the tracing event.
+ Fields map[string]string
+}
+
+// LogResult contains the result of a GetLogs call.
+type LogResult struct {
+ // Lines contains the log entries in chronological order.
+ Lines []LogLine
+ // BufferTotal is the total number of lines in the server's buffer.
+ BufferTotal uint32
+}
+
+// logConfig holds configuration for GetLogs calls.
+type logConfig struct {
+ lines uint32
+ since time.Time
+ sources []string
+ minLevel string
+}
+
+// LogOption configures a GetLogs call.
+type LogOption func(*logConfig)
+
+// WithLogLines sets the maximum number of log lines to return.
+func WithLogLines(n uint32) LogOption {
+ return func(c *logConfig) {
+ c.lines = n
+ }
+}
+
+// WithLogSince filters logs to entries at or after the given time.
+func WithLogSince(t time.Time) LogOption {
+ return func(c *logConfig) {
+ c.since = t
+ }
+}
+
+// WithLogSources filters logs by source (e.g., "gateway", "sandbox").
+func WithLogSources(sources ...string) LogOption {
+ return func(c *logConfig) {
+ c.sources = sources
+ }
+}
+
+// WithLogMinLevel sets the minimum log level to include.
+func WithLogMinLevel(level string) LogOption {
+ return func(c *logConfig) {
+ c.minLevel = level
+ }
+}
+
+// ApplyLogOptions applies options and returns the config.
+func ApplyLogOptions(opts []LogOption) logConfig { //nolint:revive // unexported return is intentional; consumed only by v1 package
+ var cfg logConfig
+ for _, opt := range opts {
+ opt(&cfg)
+ }
+ return cfg
+}
+
+// Lines returns the configured max lines (0 means server default).
+func (c *logConfig) Lines() uint32 {
+ return c.lines
+}
+
+// Since returns the configured since timestamp (zero means no filter).
+func (c *logConfig) Since() time.Time {
+ return c.since
+}
+
+// Sources returns the configured source filters.
+func (c *logConfig) Sources() []string {
+ return c.sources
+}
+
+// MinLevel returns the configured minimum log level.
+func (c *logConfig) MinLevel() string {
+ return c.minLevel
+}
diff --git a/sdk/go/openshell/v1/types/logger.go b/sdk/go/openshell/v1/types/logger.go
new file mode 100644
index 000000000..351630cb0
--- /dev/null
+++ b/sdk/go/openshell/v1/types/logger.go
@@ -0,0 +1,12 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package types
+
+// Logger defines structured logging for the SDK. Compatible with logr.Logger
+// and slog.Logger adapters.
+type Logger interface {
+ Debug(msg string, keysAndValues ...any)
+ Info(msg string, keysAndValues ...any)
+ Error(err error, msg string, keysAndValues ...any)
+}
diff --git a/sdk/go/openshell/v1/types/network_policy.go b/sdk/go/openshell/v1/types/network_policy.go
new file mode 100644
index 000000000..334a47574
--- /dev/null
+++ b/sdk/go/openshell/v1/types/network_policy.go
@@ -0,0 +1,170 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package types
+
+// NetworkPolicyRule defines a named network policy rule containing endpoints and binaries.
+type NetworkPolicyRule struct {
+ // Name is the map key for this rule in the sandbox policy.
+ Name string
+ // Endpoints lists the network endpoints governed by this rule.
+ Endpoints []PolicyNetworkEndpoint
+ // Binaries lists the binaries governed by this rule.
+ Binaries []PolicyNetworkBinary
+}
+
+// PolicyNetworkEndpoint describes a full network endpoint with its access controls
+// as used in sandbox network policy rules. This is distinct from [NetworkEndpoint]
+// which is the simplified profile-level endpoint (Host, Port, Protocol only).
+type PolicyNetworkEndpoint struct {
+ Host string
+ Port uint32
+ Ports []uint32
+ Protocol string
+ TLS string
+ Enforcement string
+ Access string
+ Rules []L7Rule
+ AllowedIPs []string
+ DenyRules []L7DenyRule
+ AllowEncodedSlash bool
+ PersistedQueries string
+ GraphqlPersistedQueries map[string]GraphqlOperation
+ GraphqlMaxBodyBytes uint32
+ Path string
+ WebsocketCredentialRewrite bool
+ RequestBodyCredentialRewrite bool
+ AdvisorProposed bool
+ CredentialSigning string
+ SigningService string
+ SigningRegion string
+ JsonRpcMaxBodyBytes uint32
+ Mcp *McpOptions
+}
+
+// PolicyNetworkBinary identifies a binary subject to network policy enforcement.
+// This is distinct from [NetworkBinary] which is the simplified profile-level binary.
+type PolicyNetworkBinary struct {
+ // Path is the filesystem path to the binary.
+ Path string
+}
+
+// L7Rule wraps an L7 allow rule.
+type L7Rule struct {
+ // Allow holds the layer-7 allow criteria.
+ Allow *L7Allow
+}
+
+// L7Allow specifies layer-7 allow criteria for HTTP/GraphQL/MCP traffic.
+type L7Allow struct {
+ Method string
+ Path string
+ Command string
+ Query map[string]L7QueryMatcher
+ OperationType string
+ OperationName string
+ Fields []string
+ Params map[string]L7QueryMatcher
+}
+
+// L7DenyRule specifies layer-7 deny criteria for HTTP/GraphQL/MCP traffic.
+type L7DenyRule struct {
+ Method string
+ Path string
+ Command string
+ Query map[string]L7QueryMatcher
+ OperationType string
+ OperationName string
+ Fields []string
+ Params map[string]L7QueryMatcher
+}
+
+// McpOptions holds MCP-specific policy and inspection options.
+type McpOptions struct {
+ StrictToolNames *bool
+ AllowAllKnownMcpMethods *bool
+}
+
+// L7QueryMatcher matches query parameters by glob pattern or exact values.
+type L7QueryMatcher struct {
+ Glob string
+ Any []string
+}
+
+// GraphqlOperation describes a GraphQL operation for persisted-query validation.
+type GraphqlOperation struct {
+ OperationType string
+ OperationName string
+ Fields []string
+}
+
+// --- MergeOperation types ---
+
+// PolicyMergeOperation represents a single atomic policy mutation.
+// Exactly one of the pointer fields must be non-nil, modelling the proto oneof.
+type PolicyMergeOperation struct {
+ // AddRule adds a new named network policy rule.
+ AddRule *AddNetworkRule
+ // RemoveEndpoint removes a single endpoint from a rule.
+ RemoveEndpoint *RemoveNetworkEndpoint
+ // RemoveRule removes an entire named rule.
+ RemoveRule *RemoveNetworkRule
+ // AddDenyRules appends deny rules to an endpoint.
+ AddDenyRules *AddDenyRules
+ // AddAllowRules appends allow rules to an endpoint.
+ AddAllowRules *AddAllowRules
+ // RemoveBinary removes a binary from a rule.
+ RemoveBinary *RemoveNetworkBinary
+}
+
+// AddNetworkRule adds a named network policy rule with a full rule definition.
+type AddNetworkRule struct {
+ // RuleName is the name key for the rule.
+ RuleName string
+ // Rule is the full network policy rule to add.
+ Rule NetworkPolicyRule
+}
+
+// RemoveNetworkEndpoint removes a specific endpoint from a named rule.
+type RemoveNetworkEndpoint struct {
+ // RuleName is the name of the rule containing the endpoint.
+ RuleName string
+ // Host is the endpoint host to remove.
+ Host string
+ // Port is the endpoint port to remove.
+ Port uint32
+}
+
+// RemoveNetworkRule removes an entire named rule from the policy.
+type RemoveNetworkRule struct {
+ // RuleName is the name of the rule to remove.
+ RuleName string
+}
+
+// AddDenyRules appends layer-7 deny rules to a specific endpoint.
+type AddDenyRules struct {
+ // Host identifies the target endpoint host.
+ Host string
+ // Port identifies the target endpoint port.
+ Port uint32
+ // DenyRules are the deny rules to append.
+ DenyRules []L7DenyRule
+}
+
+// AddAllowRules appends layer-7 allow rules to a specific endpoint.
+type AddAllowRules struct {
+ // Host identifies the target endpoint host.
+ Host string
+ // Port identifies the target endpoint port.
+ Port uint32
+ // Rules are the allow rules to append.
+ Rules []L7Rule
+}
+
+// RemoveNetworkBinary removes a binary from a named rule.
+type RemoveNetworkBinary struct {
+ // RuleName is the name of the rule containing the binary.
+ RuleName string
+ // BinaryPath is the filesystem path of the binary to remove.
+ BinaryPath string
+}
diff --git a/sdk/go/openshell/v1/types/options.go b/sdk/go/openshell/v1/types/options.go
new file mode 100644
index 000000000..4454b383b
--- /dev/null
+++ b/sdk/go/openshell/v1/types/options.go
@@ -0,0 +1,48 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package types
+
+import "time"
+
+// CreateOptions configures resource creation.
+type CreateOptions struct{}
+
+// GetOptions configures resource retrieval.
+type GetOptions struct{}
+
+// ListOptions configures resource listing with pagination and filtering.
+type ListOptions struct {
+ Limit int
+ Offset int
+ LabelSelector string
+ AllWorkspaces bool
+}
+
+// DeleteOptions configures resource deletion.
+type DeleteOptions struct{}
+
+// UpdateOptions configures resource updates.
+type UpdateOptions struct{}
+
+// WatchOptions configures watch behavior.
+type WatchOptions struct {
+ // TimeoutSeconds is reserved for future use. Use context for timeout control.
+ TimeoutSeconds int64
+ // LabelSelector is reserved for future use.
+ LabelSelector string
+ // StopOnTerminal causes the watch to close automatically when the sandbox
+ // reaches a terminal phase (Ready or Error).
+ StopOnTerminal bool
+}
+
+// WaitOptions configures wait behavior. Use context for timeout control.
+type WaitOptions struct {
+ PollInterval time.Duration
+}
+
+// ExecOptions configures command execution.
+type ExecOptions struct {
+ Env map[string]string
+ WorkDir string
+}
diff --git a/sdk/go/openshell/v1/types/policy.go b/sdk/go/openshell/v1/types/policy.go
new file mode 100644
index 000000000..f71aeca1d
--- /dev/null
+++ b/sdk/go/openshell/v1/types/policy.go
@@ -0,0 +1,341 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package types
+
+import "time"
+
+// PolicyLoadStatus represents the load state of a policy revision.
+type PolicyLoadStatus int
+
+const (
+ // PolicyLoadStatusUnspecified is the default zero value.
+ PolicyLoadStatusUnspecified PolicyLoadStatus = iota
+ // PolicyLoadStatusPending means the policy is queued for loading.
+ PolicyLoadStatusPending
+ // PolicyLoadStatusLoaded means the policy was successfully loaded.
+ PolicyLoadStatusLoaded
+ // PolicyLoadStatusFailed means the policy failed to load.
+ PolicyLoadStatusFailed
+ // PolicyLoadStatusSuperseded means a newer revision replaced this one.
+ PolicyLoadStatusSuperseded
+)
+
+// String returns the human-readable name of the load status.
+func (s PolicyLoadStatus) String() string {
+ switch s {
+ case PolicyLoadStatusUnspecified:
+ return "Unspecified"
+ case PolicyLoadStatusPending:
+ return "Pending"
+ case PolicyLoadStatusLoaded:
+ return "Loaded"
+ case PolicyLoadStatusFailed:
+ return "Failed"
+ case PolicyLoadStatusSuperseded:
+ return "Superseded"
+ default:
+ return "Unknown"
+ }
+}
+
+// PolicyChunk represents a single proposed policy change in the draft inbox.
+type PolicyChunk struct {
+ // ID is the unique chunk identifier.
+ ID string
+ // Status is the approval status: "pending", "approved", "rejected".
+ Status string
+ // RuleName is the proposed network_policies map key.
+ RuleName string
+ // ProposedRule is the proposed network policy rule.
+ ProposedRule *NetworkPolicyRule
+
+ // Rationale is a human-readable explanation of why this rule is proposed.
+ Rationale string
+ // SecurityNotes contains security concerns flagged by analysis (empty if none).
+ SecurityNotes string
+ // Confidence is the analysis confidence score (0.0-1.0).
+ Confidence float32
+ // DenialSummaryIDs lists the IDs of denial summaries that led to this chunk.
+ DenialSummaryIDs []string
+ // CreatedAt is when the chunk was created.
+ CreatedAt time.Time
+ // DecidedAt is when the user approved/rejected (zero if undecided).
+ DecidedAt time.Time
+ // Stage is the recommendation stage: "initial" or "refined".
+ Stage string
+ // SupersedesChunkID is the initial chunk ID this refined chunk replaces.
+ SupersedesChunkID string
+ // HitCount is how many times this endpoint was seen across denial flush cycles.
+ HitCount int32
+ // FirstSeen is the first time this endpoint was proposed.
+ FirstSeen time.Time
+ // LastSeen is the most recent time this endpoint was re-proposed.
+ LastSeen time.Time
+ // Binary is the binary path that triggered the denial.
+ Binary string
+ // ValidationResult is the prover output from gateway-side static checks.
+ ValidationResult string
+ // RejectionReason is the operator-supplied text accompanying a rejection.
+ RejectionReason string
+}
+
+// DraftPolicy contains the full draft policy state returned by GetDraft.
+type DraftPolicy struct {
+ // Chunks contains the draft policy chunks.
+ Chunks []PolicyChunk
+ // RollingSummary is an LLM-generated summary of all analysis.
+ RollingSummary string
+ // DraftVersion is the current draft version number.
+ DraftVersion uint64
+ // LastAnalyzedAt is when the last analysis completed.
+ LastAnalyzedAt time.Time
+}
+
+// SandboxPolicy is the top-level security policy configuration for a sandbox.
+// It contains filesystem access rules, Landlock LSM configuration, process
+// identity rules, and named network access policies.
+type SandboxPolicy struct {
+ // Version is the policy version number. The server may override this on write.
+ Version uint32
+ // Filesystem controls which directories the sandbox can access.
+ // Nil means no filesystem policy is specified.
+ Filesystem *FilesystemPolicy
+ // Landlock configures the Linux Landlock LSM.
+ // Nil means no landlock policy is specified.
+ Landlock *LandlockPolicy
+ // Process controls the user and group identity for sandboxed processes.
+ // Nil means no process policy is specified.
+ Process *ProcessPolicy
+ // NetworkPolicies contains named network access rules.
+ // Nil means no network policies are specified; an empty map is distinct from nil.
+ NetworkPolicies map[string]NetworkPolicyRule
+}
+
+// FilesystemPolicy controls which directories the sandbox can access
+// in read-only or read-write mode.
+type FilesystemPolicy struct {
+ // IncludeWorkdir auto-includes the working directory as read-write.
+ IncludeWorkdir bool
+ // ReadOnly is the list of read-only directory paths.
+ // Nil means no read-only directories; an empty slice is distinct from nil.
+ ReadOnly []string
+ // ReadWrite is the list of read-write directory paths.
+ // Nil means no read-write directories; an empty slice is distinct from nil.
+ ReadWrite []string
+}
+
+// LandlockPolicy configures the Linux Landlock LSM for filesystem restriction enforcement.
+type LandlockPolicy struct {
+ // Compatibility is the compatibility mode (e.g., "best_effort", "hard_requirement").
+ Compatibility string
+}
+
+// ProcessPolicy controls the user and group identity under which sandboxed processes execute.
+type ProcessPolicy struct {
+ // RunAsUser is the user name for sandboxed processes.
+ RunAsUser string
+ // RunAsGroup is the group name for sandboxed processes.
+ RunAsGroup string
+}
+
+// SandboxPolicyRevision represents a versioned policy revision for a sandbox.
+type SandboxPolicyRevision struct {
+ // Version is the policy version (monotonically increasing per sandbox).
+ Version uint32
+ // PolicyHash is the SHA-256 hash of the serialized policy payload.
+ PolicyHash string
+ // Status is the load status of this revision.
+ Status PolicyLoadStatus
+ // LoadError is the error message if status is Failed.
+ LoadError string
+ // CreatedAt is when this revision was created.
+ CreatedAt time.Time
+ // LoadedAt is when this revision was loaded by the sandbox.
+ LoadedAt time.Time
+ // Policy is the typed security policy for this revision. Nil when not requested or absent.
+ Policy *SandboxPolicy
+}
+
+// PolicyStatusResult contains the status of a sandbox's policy.
+type PolicyStatusResult struct {
+ // Revision is the queried policy revision.
+ Revision SandboxPolicyRevision
+ // ActiveVersion is the currently active (loaded) policy version.
+ ActiveVersion uint32
+}
+
+// ApproveResult contains the result of approving a single draft chunk.
+type ApproveResult struct {
+ // PolicyVersion is the new policy version after merge.
+ PolicyVersion uint32
+ // PolicyHash is the SHA-256 hash of the new policy.
+ PolicyHash string
+}
+
+// ApproveAllResult contains the result of approving all draft chunks.
+type ApproveAllResult struct {
+ // PolicyVersion is the new policy version after merge.
+ PolicyVersion uint32
+ // PolicyHash is the SHA-256 hash of the new policy.
+ PolicyHash string
+ // ChunksApproved is the number of chunks approved.
+ ChunksApproved uint32
+ // ChunksSkipped is the number of chunks skipped (security-flagged).
+ ChunksSkipped uint32
+}
+
+// UndoResult contains the result of undoing a draft chunk approval.
+type UndoResult struct {
+ // PolicyVersion is the new policy version after removal.
+ PolicyVersion uint32
+ // PolicyHash is the SHA-256 hash of the updated policy.
+ PolicyHash string
+}
+
+// ClearResult contains the result of clearing all draft chunks.
+type ClearResult struct {
+ // ChunksCleared is the number of chunks cleared.
+ ChunksCleared uint32
+}
+
+// DraftHistoryEntry represents a single event in the draft policy history.
+type DraftHistoryEntry struct {
+ // Timestamp is when the event occurred.
+ Timestamp time.Time
+ // EventType is the event type (e.g., "approved", "rejected", "cleared").
+ EventType string
+ // Description is a human-readable description.
+ Description string
+ // ChunkID is the associated chunk ID (if applicable).
+ ChunkID string
+}
+
+// getDraftConfig holds configuration for GetDraft calls.
+type getDraftConfig struct {
+ statusFilter string
+}
+
+// GetDraftOption configures a GetDraft call.
+type GetDraftOption func(*getDraftConfig)
+
+// WithStatusFilter filters draft chunks by approval status.
+func WithStatusFilter(status string) GetDraftOption {
+ return func(c *getDraftConfig) {
+ c.statusFilter = status
+ }
+}
+
+// ApplyGetDraftOptions applies options and returns the config.
+func ApplyGetDraftOptions(opts []GetDraftOption) getDraftConfig { //nolint:revive // unexported return is intentional; consumed only by v1 package
+ var cfg getDraftConfig
+ for _, opt := range opts {
+ opt(&cfg)
+ }
+ return cfg
+}
+
+// StatusFilter returns the configured status filter.
+func (c *getDraftConfig) StatusFilter() string {
+ return c.statusFilter
+}
+
+// approveAllConfig holds configuration for ApproveAllDraftChunks calls.
+type approveAllConfig struct {
+ includeSecurityFlagged bool
+}
+
+// ApproveAllOption configures an ApproveAllDraftChunks call.
+type ApproveAllOption func(*approveAllConfig)
+
+// WithIncludeSecurityFlagged includes security-flagged chunks in bulk approval.
+func WithIncludeSecurityFlagged() ApproveAllOption {
+ return func(c *approveAllConfig) {
+ c.includeSecurityFlagged = true
+ }
+}
+
+// ApplyApproveAllOptions applies options and returns the config.
+func ApplyApproveAllOptions(opts []ApproveAllOption) approveAllConfig { //nolint:revive // unexported return is intentional; consumed only by v1 package
+ var cfg approveAllConfig
+ for _, opt := range opts {
+ opt(&cfg)
+ }
+ return cfg
+}
+
+// IncludeSecurityFlagged returns whether security-flagged chunks are included.
+func (c *approveAllConfig) IncludeSecurityFlagged() bool {
+ return c.includeSecurityFlagged
+}
+
+// getStatusConfig holds configuration for GetStatus calls.
+type getStatusConfig struct {
+ version uint32
+}
+
+// GetStatusOption configures a GetStatus call.
+type GetStatusOption func(*getStatusConfig)
+
+// WithVersion queries a specific policy version instead of the latest.
+func WithVersion(version uint32) GetStatusOption {
+ return func(c *getStatusConfig) {
+ c.version = version
+ }
+}
+
+// ApplyGetStatusOptions applies options and returns the config.
+func ApplyGetStatusOptions(opts []GetStatusOption) getStatusConfig { //nolint:revive // unexported return is intentional; consumed only by v1 package
+ var cfg getStatusConfig
+ for _, opt := range opts {
+ opt(&cfg)
+ }
+ return cfg
+}
+
+// Version returns the configured version (0 means latest).
+func (c *getStatusConfig) Version() uint32 {
+ return c.version
+}
+
+// listPolicyConfig holds configuration for List calls.
+type listPolicyConfig struct {
+ limit uint32
+ offset uint32
+}
+
+// ListPolicyOption configures a List call.
+type ListPolicyOption func(*listPolicyConfig)
+
+// WithLimit sets the maximum number of revisions to return.
+func WithLimit(limit uint32) ListPolicyOption {
+ return func(c *listPolicyConfig) {
+ c.limit = limit
+ }
+}
+
+// WithOffset sets the pagination offset.
+func WithOffset(offset uint32) ListPolicyOption {
+ return func(c *listPolicyConfig) {
+ c.offset = offset
+ }
+}
+
+// ApplyListPolicyOptions applies options and returns the config.
+func ApplyListPolicyOptions(opts []ListPolicyOption) listPolicyConfig { //nolint:revive // unexported return is intentional; consumed only by v1 package
+ var cfg listPolicyConfig
+ for _, opt := range opts {
+ opt(&cfg)
+ }
+ return cfg
+}
+
+// Limit returns the configured limit (0 means server default).
+func (c *listPolicyConfig) Limit() uint32 {
+ return c.limit
+}
+
+// Offset returns the configured offset.
+func (c *listPolicyConfig) Offset() uint32 {
+ return c.offset
+}
diff --git a/sdk/go/openshell/v1/types/profile.go b/sdk/go/openshell/v1/types/profile.go
new file mode 100644
index 000000000..0f987335a
--- /dev/null
+++ b/sdk/go/openshell/v1/types/profile.go
@@ -0,0 +1,93 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package types
+
+// ProfileCategory classifies a provider profile.
+type ProfileCategory string
+
+// ProfileCategory values.
+const (
+ ProfileCategoryOther ProfileCategory = "Other"
+ ProfileCategoryInference ProfileCategory = "Inference"
+ ProfileCategoryAgent ProfileCategory = "Agent"
+ ProfileCategorySourceControl ProfileCategory = "SourceControl"
+ ProfileCategoryMessaging ProfileCategory = "Messaging"
+ ProfileCategoryData ProfileCategory = "Data"
+ ProfileCategoryKnowledge ProfileCategory = "Knowledge"
+)
+
+// ProviderProfile defines a provider type template with credentials schema,
+// endpoints, binaries, and discovery configuration.
+type ProviderProfile struct {
+ ID string
+ DisplayName string
+ Description string
+ Category ProfileCategory
+ Credentials []ProfileCredential
+ Endpoints []NetworkEndpoint
+ Binaries []NetworkBinary
+ InferenceCapable bool
+ Discovery ProfileDiscovery
+ ResourceVersion uint64
+}
+
+// ProfileCredential defines a single credential required by a provider profile.
+type ProfileCredential struct {
+ Name string
+ Description string
+ Required bool
+ Secret bool
+}
+
+// NetworkEndpoint describes a network endpoint provided by a profile.
+type NetworkEndpoint struct {
+ Host string
+ Port uint32
+ Protocol string
+}
+
+// NetworkBinary describes a binary artifact provided by a profile.
+type NetworkBinary struct {
+ Path string
+}
+
+// ProfileDiscovery holds local discovery configuration for a profile.
+type ProfileDiscovery struct {
+ Credentials []string
+}
+
+// ProfileImportItem is an item submitted for profile import or lint validation.
+type ProfileImportItem struct {
+ Profile ProviderProfile
+ Source string
+}
+
+// ProfileDiagnostic is a validation finding from Import, Update, or Lint.
+type ProfileDiagnostic struct {
+ Source string
+ ProfileID string
+ Field string
+ Message string
+ Severity string
+}
+
+// ImportResult holds the result of a profile import operation.
+type ImportResult struct {
+ Diagnostics []ProfileDiagnostic
+ Profiles []ProviderProfile
+ Imported bool
+}
+
+// UpdateResult holds the result of a profile update operation.
+type UpdateResult struct {
+ Diagnostics []ProfileDiagnostic
+ Profile *ProviderProfile
+ Updated bool
+}
+
+// LintResult holds the result of a profile lint operation.
+type LintResult struct {
+ Diagnostics []ProfileDiagnostic
+ Valid bool
+}
diff --git a/sdk/go/openshell/v1/types/provider.go b/sdk/go/openshell/v1/types/provider.go
new file mode 100644
index 000000000..7b8e4c2ef
--- /dev/null
+++ b/sdk/go/openshell/v1/types/provider.go
@@ -0,0 +1,38 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package types
+
+import "time"
+
+// Provider represents an AI provider registration.
+type Provider struct {
+ ID string
+ Name string
+ Type string
+ CreatedAt time.Time
+ Labels map[string]string
+ Annotations map[string]string
+ ResourceVersion uint64
+ Workspace string
+ DeletionTimestamp *time.Time
+ Spec ProviderSpec
+}
+
+// ProviderSpec holds provider-specific configuration and credentials.
+type ProviderSpec struct {
+ Credentials map[string]string
+ Config map[string]string
+ CredentialExpiresAt map[string]time.Time
+ ProfileWorkspace string
+ CredentialHandles map[string]CredentialHandle
+}
+
+// CredentialHandle is an opaque handle for a provider credential stored by
+// gateway credential storage. Handles are created by OpenShell and are not
+// accepted as user-authored input.
+type CredentialHandle struct {
+ Driver string
+ Handle string
+ Metadata map[string]string
+}
diff --git a/sdk/go/openshell/v1/types/refresh.go b/sdk/go/openshell/v1/types/refresh.go
new file mode 100644
index 000000000..b67ba3584
--- /dev/null
+++ b/sdk/go/openshell/v1/types/refresh.go
@@ -0,0 +1,44 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package types
+
+import "time"
+
+// RefreshStrategy describes how credentials are refreshed.
+type RefreshStrategy string
+
+// RefreshStrategy values.
+const (
+ RefreshStrategyStatic RefreshStrategy = "Static"
+ RefreshStrategyExternal RefreshStrategy = "External"
+ RefreshStrategyOAuth2RefreshToken RefreshStrategy = "OAuth2RefreshToken"
+ RefreshStrategyOAuth2ClientCredentials RefreshStrategy = "OAuth2ClientCredentials"
+ RefreshStrategyGoogleServiceAccountJWT RefreshStrategy = "GoogleServiceAccountJWT"
+ RefreshStrategyAWSStsAssumeRole RefreshStrategy = "AWSStsAssumeRole"
+)
+
+// RefreshStatus reports the current state of credential refresh for a specific
+// provider credential.
+type RefreshStatus struct {
+ ProviderName string
+ ProviderID string
+ CredentialKey string
+ Strategy RefreshStrategy
+ Status string
+ ExpiresAt time.Time
+ NextRefreshAt time.Time
+ LastRefreshAt time.Time
+ LastError string
+}
+
+// RefreshConfig holds configuration parameters for gateway-owned credential
+// refresh on a provider credential.
+type RefreshConfig struct {
+ Provider string
+ CredentialKey string
+ Strategy RefreshStrategy
+ Material map[string]string
+ SecretMaterialKeys []string
+ ExpiresAt *time.Time
+}
diff --git a/sdk/go/openshell/v1/types/sandbox.go b/sdk/go/openshell/v1/types/sandbox.go
new file mode 100644
index 000000000..97bf723eb
--- /dev/null
+++ b/sdk/go/openshell/v1/types/sandbox.go
@@ -0,0 +1,76 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package types
+
+import "time"
+
+// Sandbox represents a sandbox instance.
+type Sandbox struct {
+ ID string
+ Name string
+ CreatedAt time.Time
+ Labels map[string]string
+ Annotations map[string]string
+ ResourceVersion uint64
+ Workspace string
+ DeletionTimestamp *time.Time
+ Spec SandboxSpec
+ Status SandboxStatus
+}
+
+// SandboxSpec holds the desired state of a sandbox.
+type SandboxSpec struct {
+ LogLevel string
+ Environment map[string]string
+ Template *SandboxTemplate
+ Providers []string
+ GPUCount *uint32
+ // Policy is the security policy for the sandbox. Nil means no policy specified.
+ Policy *SandboxPolicy
+}
+
+// SandboxTemplate defines the container template for a sandbox.
+type SandboxTemplate struct {
+ Image string
+ RuntimeClassName string
+ AgentSocket string
+ Labels map[string]string
+ Annotations map[string]string
+ Environment map[string]string
+ Resources map[string]any
+ UserNamespaces *bool
+ DriverConfig map[string]any
+}
+
+// SandboxStatus holds the observed state of a sandbox.
+type SandboxStatus struct {
+ SandboxName string
+ AgentPod string
+ AgentFd string
+ SandboxFd string
+ Phase SandboxPhase
+ Conditions []SandboxCondition
+ CurrentPolicyVersion uint32
+}
+
+// SandboxCondition describes an observed condition of a sandbox.
+type SandboxCondition struct {
+ Type string
+ Status string
+ Reason string
+ Message string
+ LastTransitionTime string
+}
+
+// AttachProviderResult holds the result of attaching a provider to a sandbox.
+type AttachProviderResult struct {
+ Sandbox *Sandbox
+ Attached bool
+}
+
+// DetachProviderResult holds the result of detaching a provider from a sandbox.
+type DetachProviderResult struct {
+ Sandbox *Sandbox
+ Detached bool
+}
diff --git a/sdk/go/openshell/v1/types/service.go b/sdk/go/openshell/v1/types/service.go
new file mode 100644
index 000000000..c25cb9b63
--- /dev/null
+++ b/sdk/go/openshell/v1/types/service.go
@@ -0,0 +1,15 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package types
+
+// ServiceEndpoint represents an exposed HTTP service on a sandbox.
+type ServiceEndpoint struct {
+ ID string
+ SandboxID string
+ SandboxName string
+ ServiceName string
+ TargetPort uint32
+ Domain bool
+ URL string
+}
diff --git a/sdk/go/openshell/v1/types/setting.go b/sdk/go/openshell/v1/types/setting.go
new file mode 100644
index 000000000..005ff36c0
--- /dev/null
+++ b/sdk/go/openshell/v1/types/setting.go
@@ -0,0 +1,115 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package types
+
+// SettingValueType identifies which typed field of a SettingValue is active.
+type SettingValueType string
+
+// SettingValueType constants.
+const (
+ SettingValueString SettingValueType = "string"
+ SettingValueBool SettingValueType = "bool"
+ SettingValueInt SettingValueType = "int"
+ SettingValueBytes SettingValueType = "bytes"
+)
+
+// SettingValue is a typed setting value supporting string, bool, int64, and bytes variants.
+// The Type field indicates which value field is populated.
+type SettingValue struct {
+ Type SettingValueType
+ StringVal string
+ BoolVal bool
+ IntVal int64
+ BytesVal []byte
+}
+
+// SettingScope indicates whether a setting is controlled at sandbox or global level.
+type SettingScope string
+
+// SettingScope constants.
+const (
+ SettingScopeUnspecified SettingScope = ""
+ SettingScopeSandbox SettingScope = "sandbox"
+ SettingScopeGlobal SettingScope = "global"
+)
+
+// PolicySource indicates the source of the policy payload in a SandboxConfig response.
+type PolicySource string
+
+// PolicySource constants.
+const (
+ PolicySourceUnspecified PolicySource = ""
+ PolicySourceSandbox PolicySource = "sandbox"
+ PolicySourceGlobal PolicySource = "global"
+)
+
+// EffectiveSetting is a setting value paired with the scope it was resolved from.
+type EffectiveSetting struct {
+ Value SettingValue
+ Scope SettingScope
+}
+
+// SandboxConfig represents the full configuration state of a sandbox,
+// including policy, effective settings, and revision metadata.
+type SandboxConfig struct {
+ // Policy is the typed security policy for this sandbox. Nil means no policy in the response.
+ Policy *SandboxPolicy
+ // PolicyVersion is monotonically increasing per sandbox.
+ PolicyVersion uint32
+ // PolicyHash is the SHA-256 of the serialized policy payload.
+ PolicyHash string
+ // Settings is the effective settings resolved for this sandbox.
+ Settings map[string]EffectiveSetting
+ // ConfigRevision is the fingerprint for effective config (policy + settings).
+ ConfigRevision uint64
+ // PolicySource indicates where the policy came from (sandbox or global).
+ PolicySource PolicySource
+ // GlobalPolicyVersion is the global policy version (0 if not applicable).
+ GlobalPolicyVersion uint32
+ // ProviderEnvRevision is the fingerprint for provider credential inputs.
+ ProviderEnvRevision uint64
+}
+
+// GatewayConfig represents gateway-global settings.
+type GatewayConfig struct {
+ // Settings is the global settings map.
+ Settings map[string]SettingValue
+ // SettingsRevision is a monotonically increasing revision for gateway-global settings.
+ SettingsRevision uint64
+}
+
+// ConfigUpdate represents a configuration mutation request.
+// For sandbox-scoped updates, set Name to the sandbox name.
+// For global-scoped updates, set Global to true.
+type ConfigUpdate struct {
+ // Name is the sandbox name (required for sandbox-scoped updates).
+ Name string
+ // Policy is the typed security policy for a full policy replacement. Nil means no policy change.
+ Policy *SandboxPolicy
+ // SettingKey is a single setting key to mutate.
+ SettingKey string
+ // SettingValue is the setting value for upsert. Nil means no value change.
+ SettingValue *SettingValue
+ // DeleteSetting deletes the setting key when true.
+ DeleteSetting bool
+ // Global applies the update at gateway-global scope when true.
+ Global bool
+ // MergeOperations is a list of typed policy merge operations.
+ MergeOperations []PolicyMergeOperation
+ // ExpectedResourceVersion is for optimistic concurrency (0 = skip check).
+ ExpectedResourceVersion uint64
+}
+
+// ConfigUpdateResult holds the result of a configuration update operation.
+// Named ConfigUpdateResult to avoid collision with profile.UpdateResult.
+type ConfigUpdateResult struct {
+ // Version is the assigned policy version.
+ Version uint32
+ // PolicyHash is the SHA-256 of the serialized policy.
+ PolicyHash string
+ // SettingsRevision is the settings revision for the modified scope.
+ SettingsRevision uint64
+ // Deleted is true when a setting delete removed an existing key.
+ Deleted bool
+}
diff --git a/sdk/go/openshell/v1/types/ssh.go b/sdk/go/openshell/v1/types/ssh.go
new file mode 100644
index 000000000..ec5e58e51
--- /dev/null
+++ b/sdk/go/openshell/v1/types/ssh.go
@@ -0,0 +1,34 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package types
+
+import "fmt"
+
+// SSHSession represents an SSH session created for a sandbox.
+// The Token field is sensitive and MUST NOT be logged or included in error messages.
+// The String() method redacts the token to prevent accidental exposure via fmt or logging.
+type SSHSession struct {
+ // SandboxID is the sandbox this session connects to.
+ SandboxID string
+ // Token is the session token for gateway tunnel authentication.
+ // This is a sensitive credential — treat it like an API key.
+ Token string
+ // GatewayHost is the host for SSH proxy connection.
+ GatewayHost string
+ // GatewayPort is the gateway port (1-65535).
+ GatewayPort uint32
+ // GatewayScheme is the gateway protocol scheme ("http" or "https").
+ GatewayScheme string
+ // HostKeyFingerprint is the optional host key fingerprint.
+ HostKeyFingerprint string
+ // ExpiresAtMs is the session expiry in milliseconds since epoch.
+ // Zero means no expiry.
+ ExpiresAtMs int64
+}
+
+// String returns a human-readable representation with the Token redacted.
+func (s SSHSession) String() string {
+ return fmt.Sprintf("SSHSession{SandboxID:%s, GatewayHost:%s, GatewayPort:%d, GatewayScheme:%s, Token:[REDACTED]}",
+ s.SandboxID, s.GatewayHost, s.GatewayPort, s.GatewayScheme)
+}
diff --git a/sdk/go/openshell/v1/types/types.go b/sdk/go/openshell/v1/types/types.go
new file mode 100644
index 000000000..01da4ba9c
--- /dev/null
+++ b/sdk/go/openshell/v1/types/types.go
@@ -0,0 +1,54 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package types
+
+import "time"
+
+// SandboxPhase represents the lifecycle phase of a sandbox.
+type SandboxPhase string
+
+// SandboxPhase values for sandbox lifecycle.
+const (
+ SandboxProvisioning SandboxPhase = "Provisioning"
+ SandboxReady SandboxPhase = "Ready"
+ SandboxError SandboxPhase = "Error"
+ SandboxDeleting SandboxPhase = "Deleting"
+ SandboxUnknown SandboxPhase = "Unknown"
+)
+
+// EventType classifies watch events.
+type EventType string
+
+// EventType values for watch events.
+const (
+ EventAdded EventType = "ADDED"
+ EventModified EventType = "MODIFIED"
+ EventDeleted EventType = "DELETED"
+ EventError EventType = "ERROR"
+)
+
+// StreamType identifies which output stream a chunk belongs to.
+type StreamType string
+
+// StreamType values for exec output.
+const (
+ StreamStdout StreamType = "stdout"
+ StreamStderr StreamType = "stderr"
+)
+
+// TLSConfig holds TLS connection settings.
+type TLSConfig struct {
+ CertFile string
+ KeyFile string
+ CAFile string
+ // Insecure skips TLS certificate verification. Use http:// for plaintext.
+ Insecure bool
+}
+
+// RetryPolicy configures automatic retry behavior for failed RPCs.
+type RetryPolicy struct {
+ MaxRetries int
+ InitialWait time.Duration
+ MaxWait time.Duration
+}
diff --git a/sdk/go/openshell/v1/types/watch.go b/sdk/go/openshell/v1/types/watch.go
new file mode 100644
index 000000000..0a8c9d498
--- /dev/null
+++ b/sdk/go/openshell/v1/types/watch.go
@@ -0,0 +1,18 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package types
+
+// Event represents a watch event carrying a resource that changed.
+type Event[T any] struct {
+ Type EventType
+ Object T
+ Err error
+}
+
+// WatchInterface delivers a stream of typed events. Modeled after
+// k8s.io/apimachinery/pkg/watch.Interface.
+type WatchInterface[T any] interface {
+ ResultChan() <-chan Event[T]
+ Stop()
+}
diff --git a/sdk/go/openshell/v1/types_reexport.go b/sdk/go/openshell/v1/types_reexport.go
new file mode 100644
index 000000000..b92aa80bc
--- /dev/null
+++ b/sdk/go/openshell/v1/types_reexport.go
@@ -0,0 +1,57 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+)
+
+// --- Network Policy types ---
+
+// NetworkPolicyRule defines a named network policy rule containing endpoints and binaries.
+type NetworkPolicyRule = types.NetworkPolicyRule
+
+// PolicyNetworkEndpoint describes a full network endpoint in a sandbox network policy rule.
+type PolicyNetworkEndpoint = types.PolicyNetworkEndpoint
+
+// PolicyNetworkBinary identifies a binary subject to network policy enforcement.
+type PolicyNetworkBinary = types.PolicyNetworkBinary
+
+// L7Rule wraps an L7 allow rule.
+type L7Rule = types.L7Rule
+
+// L7Allow specifies layer-7 allow criteria for HTTP/GraphQL traffic.
+type L7Allow = types.L7Allow
+
+// L7DenyRule specifies layer-7 deny criteria for HTTP/GraphQL traffic.
+type L7DenyRule = types.L7DenyRule
+
+// L7QueryMatcher matches query parameters by glob pattern or exact values.
+type L7QueryMatcher = types.L7QueryMatcher
+
+// GraphqlOperation describes a GraphQL operation for persisted-query validation.
+type GraphqlOperation = types.GraphqlOperation
+
+// --- MergeOperation types ---
+
+// PolicyMergeOperation represents a single atomic policy mutation.
+type PolicyMergeOperation = types.PolicyMergeOperation
+
+// AddNetworkRule adds a named network policy rule with a full rule definition.
+type AddNetworkRule = types.AddNetworkRule
+
+// RemoveNetworkEndpoint removes a specific endpoint from a named rule.
+type RemoveNetworkEndpoint = types.RemoveNetworkEndpoint
+
+// RemoveNetworkRule removes an entire named rule from the policy.
+type RemoveNetworkRule = types.RemoveNetworkRule
+
+// AddDenyRules appends layer-7 deny rules to a specific endpoint.
+type AddDenyRules = types.AddDenyRules
+
+// AddAllowRules appends layer-7 allow rules to a specific endpoint.
+type AddAllowRules = types.AddAllowRules
+
+// RemoveNetworkBinary removes a binary from a named rule.
+type RemoveNetworkBinary = types.RemoveNetworkBinary
diff --git a/sdk/go/openshell/v1/watch.go b/sdk/go/openshell/v1/watch.go
new file mode 100644
index 000000000..696d8a9bd
--- /dev/null
+++ b/sdk/go/openshell/v1/watch.go
@@ -0,0 +1,46 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "context"
+ "sync"
+
+ "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
+)
+
+// Event represents a watch event carrying a resource that changed.
+type Event[T any] = types.Event[T]
+
+// WatchInterface delivers a stream of typed events. Modeled after
+// k8s.io/apimachinery/pkg/watch.Interface.
+type WatchInterface[T any] = types.WatchInterface[T]
+
+type watcher[T any] struct {
+ result chan Event[T]
+ done chan struct{}
+ cancel context.CancelFunc
+ stopOnce sync.Once
+}
+
+func newWatcher[T any](ch chan Event[T], cancel context.CancelFunc) *watcher[T] {
+ return &watcher[T]{
+ result: ch,
+ done: make(chan struct{}),
+ cancel: cancel,
+ }
+}
+
+func (w *watcher[T]) ResultChan() <-chan Event[T] {
+ return w.result
+}
+
+func (w *watcher[T]) Stop() {
+ w.stopOnce.Do(func() {
+ close(w.done)
+ if w.cancel != nil {
+ w.cancel()
+ }
+ })
+}
diff --git a/sdk/go/openshell/v1/watch_test.go b/sdk/go/openshell/v1/watch_test.go
new file mode 100644
index 000000000..1d6d5dc07
--- /dev/null
+++ b/sdk/go/openshell/v1/watch_test.go
@@ -0,0 +1,134 @@
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package v1
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+// newTestWatcher creates a watcher with a simulated producer goroutine that
+// forwards events from src to the watcher's channel and closes it when the
+// producer finishes or Stop is called.
+func newTestWatcher(src <-chan Event[string]) *watcher[string] {
+ ch := make(chan Event[string], 10)
+ w := newWatcher(ch, nil)
+ go func() {
+ defer close(ch)
+ for {
+ select {
+ case ev, ok := <-src:
+ if !ok {
+ return
+ }
+ select {
+ case ch <- ev:
+ case <-w.done:
+ return
+ }
+ case <-w.done:
+ return
+ }
+ }
+ }()
+ return w
+}
+
+// --- T038: WatchInterface event delivery, Stop, and error handling ---
+
+func TestWatcher_DeliversEvents(t *testing.T) {
+ src := make(chan Event[string], 10)
+ w := newTestWatcher(src)
+
+ src <- Event[string]{Type: EventAdded, Object: "sandbox-1"}
+ src <- Event[string]{Type: EventModified, Object: "sandbox-1"}
+
+ resultCh := w.ResultChan()
+
+ ev1 := <-resultCh
+ assert.Equal(t, EventAdded, ev1.Type)
+ assert.Equal(t, "sandbox-1", ev1.Object)
+
+ ev2 := <-resultCh
+ assert.Equal(t, EventModified, ev2.Type)
+ assert.Equal(t, "sandbox-1", ev2.Object)
+}
+
+func TestWatcher_StopClosesChannel(t *testing.T) {
+ src := make(chan Event[string], 10)
+ w := newTestWatcher(src)
+
+ w.Stop()
+
+ select {
+ case _, ok := <-w.ResultChan():
+ assert.False(t, ok, "channel should be closed after Stop")
+ case <-time.After(time.Second):
+ t.Fatal("timed out waiting for channel close")
+ }
+}
+
+func TestWatcher_StopIsIdempotent(_ *testing.T) {
+ src := make(chan Event[string], 10)
+ w := newTestWatcher(src)
+
+ w.Stop()
+ w.Stop() // must not panic
+}
+
+func TestWatcher_ErrorEvent(t *testing.T) {
+ src := make(chan Event[string], 10)
+ w := newTestWatcher(src)
+
+ src <- Event[string]{Type: EventError, Object: "error details"}
+
+ ev := <-w.ResultChan()
+ assert.Equal(t, EventError, ev.Type)
+ assert.Equal(t, "error details", ev.Object)
+}
+
+func TestWatcher_ChannelClosesWhenSourceEnds(t *testing.T) {
+ src := make(chan Event[string], 10)
+ w := newTestWatcher(src)
+
+ src <- Event[string]{Type: EventAdded, Object: "sb-1"}
+ close(src)
+
+ ev := <-w.ResultChan()
+ require.Equal(t, "sb-1", ev.Object)
+
+ select {
+ case _, ok := <-w.ResultChan():
+ assert.False(t, ok, "channel should close when source ends")
+ case <-time.After(time.Second):
+ t.Fatal("timed out waiting for channel to close")
+ }
+}
+
+func TestWatcher_DrainAfterStop(t *testing.T) {
+ src := make(chan Event[string], 10)
+ w := newTestWatcher(src)
+
+ src <- Event[string]{Type: EventAdded, Object: "sb-1"}
+
+ ev := <-w.ResultChan()
+ require.Equal(t, "sb-1", ev.Object)
+
+ w.Stop()
+
+ timeout := time.After(time.Second)
+ for {
+ select {
+ case _, ok := <-w.ResultChan():
+ if !ok {
+ return // success: channel closed
+ }
+ case <-timeout:
+ t.Fatal("timed out waiting for channel to close after Stop")
+ }
+ }
+}
diff --git a/sdk/go/proto/datamodelv1/datamodel.pb.go b/sdk/go/proto/datamodelv1/datamodel.pb.go
new file mode 100644
index 000000000..a672bf3d8
--- /dev/null
+++ b/sdk/go/proto/datamodelv1/datamodel.pb.go
@@ -0,0 +1,599 @@
+// 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 (unknown)
+// source: datamodel.proto
+
+package datamodelv1
+
+import (
+ _ "github.com/NVIDIA/OpenShell/sdk/go/proto/optionsv1"
+ 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)
+)
+
+// Phase of a workspace's lifecycle.
+type WorkspacePhase int32
+
+const (
+ WorkspacePhase_WORKSPACE_PHASE_UNSPECIFIED WorkspacePhase = 0
+ WorkspacePhase_WORKSPACE_PHASE_ACTIVE WorkspacePhase = 1
+ WorkspacePhase_WORKSPACE_PHASE_TERMINATING WorkspacePhase = 2
+)
+
+// Enum value maps for WorkspacePhase.
+var (
+ WorkspacePhase_name = map[int32]string{
+ 0: "WORKSPACE_PHASE_UNSPECIFIED",
+ 1: "WORKSPACE_PHASE_ACTIVE",
+ 2: "WORKSPACE_PHASE_TERMINATING",
+ }
+ WorkspacePhase_value = map[string]int32{
+ "WORKSPACE_PHASE_UNSPECIFIED": 0,
+ "WORKSPACE_PHASE_ACTIVE": 1,
+ "WORKSPACE_PHASE_TERMINATING": 2,
+ }
+)
+
+func (x WorkspacePhase) Enum() *WorkspacePhase {
+ p := new(WorkspacePhase)
+ *p = x
+ return p
+}
+
+func (x WorkspacePhase) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (WorkspacePhase) Descriptor() protoreflect.EnumDescriptor {
+ return file_datamodel_proto_enumTypes[0].Descriptor()
+}
+
+func (WorkspacePhase) Type() protoreflect.EnumType {
+ return &file_datamodel_proto_enumTypes[0]
+}
+
+func (x WorkspacePhase) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use WorkspacePhase.Descriptor instead.
+func (WorkspacePhase) EnumDescriptor() ([]byte, []int) {
+ return file_datamodel_proto_rawDescGZIP(), []int{0}
+}
+
+// Kubernetes-style metadata shared by all top-level OpenShell domain objects.
+//
+// This structure provides consistent metadata (identity, labels, annotations,
+// timestamps, resource versioning) across Sandbox, Provider, SshSession, and
+// other resources.
+type ObjectMeta struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Stable object ID generated by the gateway.
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+ // Human-readable object name (unique per object type).
+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+ // Milliseconds since Unix epoch when the object was created.
+ CreatedAtMs int64 `protobuf:"varint,3,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"`
+ // Key-value labels for filtering and organization.
+ // Labels must follow Kubernetes conventions: alphanumeric + `-._/`, max 63 chars per segment.
+ 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"`
+ // Optimistic concurrency control version.
+ // Incremented by the gateway on each update. Clients can use this for compare-and-swap operations.
+ ResourceVersion uint64 `protobuf:"varint,5,opt,name=resource_version,json=resourceVersion,proto3" json:"resource_version,omitempty"`
+ // Opaque key-value metadata that is not used for selectors.
+ // Annotation keys use the same qualified-key shape as labels, but values may be longer.
+ Annotations map[string]string `protobuf:"bytes,6,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ // Workspace that owns this resource. Empty is normalized to "default" by the
+ // gateway. Immutable after creation.
+ Workspace string `protobuf:"bytes,7,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ // Milliseconds since Unix epoch when graceful deletion was initiated.
+ // Zero means the object is not being deleted. Once set, this field is
+ // immutable — the only path forward is completing deletion.
+ DeletionTimestampMs int64 `protobuf:"varint,8,opt,name=deletion_timestamp_ms,json=deletionTimestampMs,proto3" json:"deletion_timestamp_ms,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ObjectMeta) Reset() {
+ *x = ObjectMeta{}
+ mi := &file_datamodel_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ObjectMeta) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ObjectMeta) ProtoMessage() {}
+
+func (x *ObjectMeta) 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 ObjectMeta.ProtoReflect.Descriptor instead.
+func (*ObjectMeta) Descriptor() ([]byte, []int) {
+ return file_datamodel_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *ObjectMeta) GetId() string {
+ if x != nil {
+ return x.Id
+ }
+ return ""
+}
+
+func (x *ObjectMeta) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *ObjectMeta) GetCreatedAtMs() int64 {
+ if x != nil {
+ return x.CreatedAtMs
+ }
+ return 0
+}
+
+func (x *ObjectMeta) GetLabels() map[string]string {
+ if x != nil {
+ return x.Labels
+ }
+ return nil
+}
+
+func (x *ObjectMeta) GetResourceVersion() uint64 {
+ if x != nil {
+ return x.ResourceVersion
+ }
+ return 0
+}
+
+func (x *ObjectMeta) GetAnnotations() map[string]string {
+ if x != nil {
+ return x.Annotations
+ }
+ return nil
+}
+
+func (x *ObjectMeta) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+func (x *ObjectMeta) GetDeletionTimestampMs() int64 {
+ if x != nil {
+ return x.DeletionTimestampMs
+ }
+ return 0
+}
+
+// Status of a workspace.
+type WorkspaceStatus struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Phase WorkspacePhase `protobuf:"varint,1,opt,name=phase,proto3,enum=openshell.datamodel.v1.WorkspacePhase" json:"phase,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *WorkspaceStatus) Reset() {
+ *x = WorkspaceStatus{}
+ mi := &file_datamodel_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *WorkspaceStatus) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*WorkspaceStatus) ProtoMessage() {}
+
+func (x *WorkspaceStatus) 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 WorkspaceStatus.ProtoReflect.Descriptor instead.
+func (*WorkspaceStatus) Descriptor() ([]byte, []int) {
+ return file_datamodel_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *WorkspaceStatus) GetPhase() WorkspacePhase {
+ if x != nil {
+ return x.Phase
+ }
+ return WorkspacePhase_WORKSPACE_PHASE_UNSPECIFIED
+}
+
+// Workspace resource. A hard isolation boundary for sandboxes, providers, and
+// other workspace-scoped resources.
+type Workspace struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Kubernetes-style metadata (id, name, labels, timestamps, resource version).
+ // The workspace field in this ObjectMeta is unused (a workspace does not
+ // belong to another workspace).
+ Metadata *ObjectMeta `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"`
+ // Current lifecycle status.
+ Status *WorkspaceStatus `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *Workspace) Reset() {
+ *x = Workspace{}
+ mi := &file_datamodel_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *Workspace) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Workspace) ProtoMessage() {}
+
+func (x *Workspace) 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 Workspace.ProtoReflect.Descriptor instead.
+func (*Workspace) Descriptor() ([]byte, []int) {
+ return file_datamodel_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *Workspace) GetMetadata() *ObjectMeta {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+func (x *Workspace) GetStatus() *WorkspaceStatus {
+ if x != nil {
+ return x.Status
+ }
+ return nil
+}
+
+// Opaque handle for a provider credential stored by gateway credential storage.
+// Handles are created by OpenShell and must not be authored by users.
+type CredentialHandle struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Internal storage owner or credential driver that owns this handle.
+ Driver string `protobuf:"bytes,1,opt,name=driver,proto3" json:"driver,omitempty"`
+ // Owner-owned opaque handle string.
+ Handle string `protobuf:"bytes,2,opt,name=handle,proto3" json:"handle,omitempty"`
+ // Owner-owned non-secret metadata.
+ Metadata map[string]string `protobuf:"bytes,3,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 *CredentialHandle) Reset() {
+ *x = CredentialHandle{}
+ mi := &file_datamodel_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *CredentialHandle) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CredentialHandle) ProtoMessage() {}
+
+func (x *CredentialHandle) 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 CredentialHandle.ProtoReflect.Descriptor instead.
+func (*CredentialHandle) Descriptor() ([]byte, []int) {
+ return file_datamodel_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *CredentialHandle) GetDriver() string {
+ if x != nil {
+ return x.Driver
+ }
+ return ""
+}
+
+func (x *CredentialHandle) GetHandle() string {
+ if x != nil {
+ return x.Handle
+ }
+ return ""
+}
+
+func (x *CredentialHandle) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+// Provider model stored by OpenShell.
+type Provider struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Kubernetes-style metadata (id, name, labels, timestamps, resource version).
+ Metadata *ObjectMeta `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"`
+ // Canonical provider type slug (for example: "claude", "gitlab").
+ Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
+ // Secret values used for authentication.
+ Credentials map[string]string `protobuf:"bytes,3,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,4,rep,name=config,proto3" json:"config,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ // Expiration timestamps for credential values, keyed by credential/env var
+ // name. A zero or missing value means the credential does not expire.
+ CredentialExpiresAtMs map[string]int64 `protobuf:"bytes,5,rep,name=credential_expires_at_ms,json=credentialExpiresAtMs,proto3" json:"credential_expires_at_ms,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"`
+ // Workspace where this provider's type profile is stored.
+ // Empty string = platform/global scope. Must be empty or match
+ // metadata.workspace; cross-workspace references are rejected.
+ ProfileWorkspace string `protobuf:"bytes,6,opt,name=profile_workspace,json=profileWorkspace,proto3" json:"profile_workspace,omitempty"`
+ // Opaque handles for secret values stored through gateway credential storage.
+ // This map is internal gateway state and is not accepted as user-authored input.
+ CredentialHandles map[string]*CredentialHandle `protobuf:"bytes,7,rep,name=credential_handles,json=credentialHandles,proto3" json:"credential_handles,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[4]
+ 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[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 Provider.ProtoReflect.Descriptor instead.
+func (*Provider) Descriptor() ([]byte, []int) {
+ return file_datamodel_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *Provider) GetMetadata() *ObjectMeta {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+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
+}
+
+func (x *Provider) GetCredentialExpiresAtMs() map[string]int64 {
+ if x != nil {
+ return x.CredentialExpiresAtMs
+ }
+ return nil
+}
+
+func (x *Provider) GetProfileWorkspace() string {
+ if x != nil {
+ return x.ProfileWorkspace
+ }
+ return ""
+}
+
+func (x *Provider) GetCredentialHandles() map[string]*CredentialHandle {
+ if x != nil {
+ return x.CredentialHandles
+ }
+ return nil
+}
+
+var File_datamodel_proto protoreflect.FileDescriptor
+
+const file_datamodel_proto_rawDesc = "" +
+ "\n" +
+ "\x0fdatamodel.proto\x12\x16openshell.datamodel.v1\x1a\roptions.proto\"\xeb\x03\n" +
+ "\n" +
+ "ObjectMeta\x12\x0e\n" +
+ "\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" +
+ "\x04name\x18\x02 \x01(\tR\x04name\x12\"\n" +
+ "\rcreated_at_ms\x18\x03 \x01(\x03R\vcreatedAtMs\x12F\n" +
+ "\x06labels\x18\x04 \x03(\v2..openshell.datamodel.v1.ObjectMeta.LabelsEntryR\x06labels\x12)\n" +
+ "\x10resource_version\x18\x05 \x01(\x04R\x0fresourceVersion\x12U\n" +
+ "\vannotations\x18\x06 \x03(\v23.openshell.datamodel.v1.ObjectMeta.AnnotationsEntryR\vannotations\x12\x1c\n" +
+ "\tworkspace\x18\a \x01(\tR\tworkspace\x122\n" +
+ "\x15deletion_timestamp_ms\x18\b \x01(\x03R\x13deletionTimestampMs\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\"O\n" +
+ "\x0fWorkspaceStatus\x12<\n" +
+ "\x05phase\x18\x01 \x01(\x0e2&.openshell.datamodel.v1.WorkspacePhaseR\x05phase\"\x8c\x01\n" +
+ "\tWorkspace\x12>\n" +
+ "\bmetadata\x18\x01 \x01(\v2\".openshell.datamodel.v1.ObjectMetaR\bmetadata\x12?\n" +
+ "\x06status\x18\x02 \x01(\v2'.openshell.datamodel.v1.WorkspaceStatusR\x06status\"\xd3\x01\n" +
+ "\x10CredentialHandle\x12\x16\n" +
+ "\x06driver\x18\x01 \x01(\tR\x06driver\x12\x16\n" +
+ "\x06handle\x18\x02 \x01(\tR\x06handle\x12R\n" +
+ "\bmetadata\x18\x03 \x03(\v26.openshell.datamodel.v1.CredentialHandle.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\"\xbf\x06\n" +
+ "\bProvider\x12>\n" +
+ "\bmetadata\x18\x01 \x01(\v2\".openshell.datamodel.v1.ObjectMetaR\bmetadata\x12\x12\n" +
+ "\x04type\x18\x02 \x01(\tR\x04type\x12Y\n" +
+ "\vcredentials\x18\x03 \x03(\v21.openshell.datamodel.v1.Provider.CredentialsEntryB\x04\x88\xb5\x18\x01R\vcredentials\x12D\n" +
+ "\x06config\x18\x04 \x03(\v2,.openshell.datamodel.v1.Provider.ConfigEntryR\x06config\x12t\n" +
+ "\x18credential_expires_at_ms\x18\x05 \x03(\v2;.openshell.datamodel.v1.Provider.CredentialExpiresAtMsEntryR\x15credentialExpiresAtMs\x12+\n" +
+ "\x11profile_workspace\x18\x06 \x01(\tR\x10profileWorkspace\x12f\n" +
+ "\x12credential_handles\x18\a \x03(\v27.openshell.datamodel.v1.Provider.CredentialHandlesEntryR\x11credentialHandles\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\x1aH\n" +
+ "\x1aCredentialExpiresAtMsEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\x03R\x05value:\x028\x01\x1an\n" +
+ "\x16CredentialHandlesEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12>\n" +
+ "\x05value\x18\x02 \x01(\v2(.openshell.datamodel.v1.CredentialHandleR\x05value:\x028\x01*n\n" +
+ "\x0eWorkspacePhase\x12\x1f\n" +
+ "\x1bWORKSPACE_PHASE_UNSPECIFIED\x10\x00\x12\x1a\n" +
+ "\x16WORKSPACE_PHASE_ACTIVE\x10\x01\x12\x1f\n" +
+ "\x1bWORKSPACE_PHASE_TERMINATING\x10\x02b\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{
+ (WorkspacePhase)(0), // 0: openshell.datamodel.v1.WorkspacePhase
+ (*ObjectMeta)(nil), // 1: openshell.datamodel.v1.ObjectMeta
+ (*WorkspaceStatus)(nil), // 2: openshell.datamodel.v1.WorkspaceStatus
+ (*Workspace)(nil), // 3: openshell.datamodel.v1.Workspace
+ (*CredentialHandle)(nil), // 4: openshell.datamodel.v1.CredentialHandle
+ (*Provider)(nil), // 5: openshell.datamodel.v1.Provider
+ nil, // 6: openshell.datamodel.v1.ObjectMeta.LabelsEntry
+ nil, // 7: openshell.datamodel.v1.ObjectMeta.AnnotationsEntry
+ nil, // 8: openshell.datamodel.v1.CredentialHandle.MetadataEntry
+ nil, // 9: openshell.datamodel.v1.Provider.CredentialsEntry
+ nil, // 10: openshell.datamodel.v1.Provider.ConfigEntry
+ nil, // 11: openshell.datamodel.v1.Provider.CredentialExpiresAtMsEntry
+ nil, // 12: openshell.datamodel.v1.Provider.CredentialHandlesEntry
+}
+var file_datamodel_proto_depIdxs = []int32{
+ 6, // 0: openshell.datamodel.v1.ObjectMeta.labels:type_name -> openshell.datamodel.v1.ObjectMeta.LabelsEntry
+ 7, // 1: openshell.datamodel.v1.ObjectMeta.annotations:type_name -> openshell.datamodel.v1.ObjectMeta.AnnotationsEntry
+ 0, // 2: openshell.datamodel.v1.WorkspaceStatus.phase:type_name -> openshell.datamodel.v1.WorkspacePhase
+ 1, // 3: openshell.datamodel.v1.Workspace.metadata:type_name -> openshell.datamodel.v1.ObjectMeta
+ 2, // 4: openshell.datamodel.v1.Workspace.status:type_name -> openshell.datamodel.v1.WorkspaceStatus
+ 8, // 5: openshell.datamodel.v1.CredentialHandle.metadata:type_name -> openshell.datamodel.v1.CredentialHandle.MetadataEntry
+ 1, // 6: openshell.datamodel.v1.Provider.metadata:type_name -> openshell.datamodel.v1.ObjectMeta
+ 9, // 7: openshell.datamodel.v1.Provider.credentials:type_name -> openshell.datamodel.v1.Provider.CredentialsEntry
+ 10, // 8: openshell.datamodel.v1.Provider.config:type_name -> openshell.datamodel.v1.Provider.ConfigEntry
+ 11, // 9: openshell.datamodel.v1.Provider.credential_expires_at_ms:type_name -> openshell.datamodel.v1.Provider.CredentialExpiresAtMsEntry
+ 12, // 10: openshell.datamodel.v1.Provider.credential_handles:type_name -> openshell.datamodel.v1.Provider.CredentialHandlesEntry
+ 4, // 11: openshell.datamodel.v1.Provider.CredentialHandlesEntry.value:type_name -> openshell.datamodel.v1.CredentialHandle
+ 12, // [12:12] is the sub-list for method output_type
+ 12, // [12:12] is the sub-list for method input_type
+ 12, // [12:12] is the sub-list for extension type_name
+ 12, // [12:12] is the sub-list for extension extendee
+ 0, // [0:12] 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
+ }
+ 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/sdk/go/proto/openshellv1/openshell.pb.go b/sdk/go/proto/openshellv1/openshell.pb.go
new file mode 100644
index 000000000..2696be0e0
--- /dev/null
+++ b/sdk/go/proto/openshellv1/openshell.pb.go
@@ -0,0 +1,14464 @@
+// 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 (unknown)
+// source: openshell.proto
+
+package openshellv1
+
+import (
+ datamodelv1 "github.com/NVIDIA/OpenShell/sdk/go/proto/datamodelv1"
+ _ "github.com/NVIDIA/OpenShell/sdk/go/proto/optionsv1"
+ sandboxv1 "github.com/NVIDIA/OpenShell/sdk/go/proto/sandboxv1"
+ 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 derived by the gateway.
+//
+// Clients should rely on this normalized lifecycle summary for readiness and
+// deletion decisions instead of interpreting raw conditions.
+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_openshell_proto_enumTypes[0].Descriptor()
+}
+
+func (SandboxPhase) Type() protoreflect.EnumType {
+ return &file_openshell_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_openshell_proto_rawDescGZIP(), []int{0}
+}
+
+type ProviderCredentialRefreshStrategy int32
+
+const (
+ ProviderCredentialRefreshStrategy_PROVIDER_CREDENTIAL_REFRESH_STRATEGY_UNSPECIFIED ProviderCredentialRefreshStrategy = 0
+ ProviderCredentialRefreshStrategy_PROVIDER_CREDENTIAL_REFRESH_STRATEGY_STATIC ProviderCredentialRefreshStrategy = 1
+ ProviderCredentialRefreshStrategy_PROVIDER_CREDENTIAL_REFRESH_STRATEGY_EXTERNAL ProviderCredentialRefreshStrategy = 2
+ ProviderCredentialRefreshStrategy_PROVIDER_CREDENTIAL_REFRESH_STRATEGY_OAUTH2_REFRESH_TOKEN ProviderCredentialRefreshStrategy = 3
+ ProviderCredentialRefreshStrategy_PROVIDER_CREDENTIAL_REFRESH_STRATEGY_OAUTH2_CLIENT_CREDENTIALS ProviderCredentialRefreshStrategy = 4
+ ProviderCredentialRefreshStrategy_PROVIDER_CREDENTIAL_REFRESH_STRATEGY_GOOGLE_SERVICE_ACCOUNT_JWT ProviderCredentialRefreshStrategy = 5
+ ProviderCredentialRefreshStrategy_PROVIDER_CREDENTIAL_REFRESH_STRATEGY_AWS_STS_ASSUME_ROLE ProviderCredentialRefreshStrategy = 6
+)
+
+// Enum value maps for ProviderCredentialRefreshStrategy.
+var (
+ ProviderCredentialRefreshStrategy_name = map[int32]string{
+ 0: "PROVIDER_CREDENTIAL_REFRESH_STRATEGY_UNSPECIFIED",
+ 1: "PROVIDER_CREDENTIAL_REFRESH_STRATEGY_STATIC",
+ 2: "PROVIDER_CREDENTIAL_REFRESH_STRATEGY_EXTERNAL",
+ 3: "PROVIDER_CREDENTIAL_REFRESH_STRATEGY_OAUTH2_REFRESH_TOKEN",
+ 4: "PROVIDER_CREDENTIAL_REFRESH_STRATEGY_OAUTH2_CLIENT_CREDENTIALS",
+ 5: "PROVIDER_CREDENTIAL_REFRESH_STRATEGY_GOOGLE_SERVICE_ACCOUNT_JWT",
+ 6: "PROVIDER_CREDENTIAL_REFRESH_STRATEGY_AWS_STS_ASSUME_ROLE",
+ }
+ ProviderCredentialRefreshStrategy_value = map[string]int32{
+ "PROVIDER_CREDENTIAL_REFRESH_STRATEGY_UNSPECIFIED": 0,
+ "PROVIDER_CREDENTIAL_REFRESH_STRATEGY_STATIC": 1,
+ "PROVIDER_CREDENTIAL_REFRESH_STRATEGY_EXTERNAL": 2,
+ "PROVIDER_CREDENTIAL_REFRESH_STRATEGY_OAUTH2_REFRESH_TOKEN": 3,
+ "PROVIDER_CREDENTIAL_REFRESH_STRATEGY_OAUTH2_CLIENT_CREDENTIALS": 4,
+ "PROVIDER_CREDENTIAL_REFRESH_STRATEGY_GOOGLE_SERVICE_ACCOUNT_JWT": 5,
+ "PROVIDER_CREDENTIAL_REFRESH_STRATEGY_AWS_STS_ASSUME_ROLE": 6,
+ }
+)
+
+func (x ProviderCredentialRefreshStrategy) Enum() *ProviderCredentialRefreshStrategy {
+ p := new(ProviderCredentialRefreshStrategy)
+ *p = x
+ return p
+}
+
+func (x ProviderCredentialRefreshStrategy) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (ProviderCredentialRefreshStrategy) Descriptor() protoreflect.EnumDescriptor {
+ return file_openshell_proto_enumTypes[1].Descriptor()
+}
+
+func (ProviderCredentialRefreshStrategy) Type() protoreflect.EnumType {
+ return &file_openshell_proto_enumTypes[1]
+}
+
+func (x ProviderCredentialRefreshStrategy) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use ProviderCredentialRefreshStrategy.Descriptor instead.
+func (ProviderCredentialRefreshStrategy) EnumDescriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{1}
+}
+
+// Stable provider profile categories used by clients for grouping and filtering.
+type ProviderProfileCategory int32
+
+const (
+ ProviderProfileCategory_PROVIDER_PROFILE_CATEGORY_UNSPECIFIED ProviderProfileCategory = 0
+ ProviderProfileCategory_PROVIDER_PROFILE_CATEGORY_OTHER ProviderProfileCategory = 1
+ ProviderProfileCategory_PROVIDER_PROFILE_CATEGORY_INFERENCE ProviderProfileCategory = 2
+ ProviderProfileCategory_PROVIDER_PROFILE_CATEGORY_AGENT ProviderProfileCategory = 3
+ ProviderProfileCategory_PROVIDER_PROFILE_CATEGORY_SOURCE_CONTROL ProviderProfileCategory = 4
+ ProviderProfileCategory_PROVIDER_PROFILE_CATEGORY_MESSAGING ProviderProfileCategory = 5
+ ProviderProfileCategory_PROVIDER_PROFILE_CATEGORY_DATA ProviderProfileCategory = 6
+ ProviderProfileCategory_PROVIDER_PROFILE_CATEGORY_KNOWLEDGE ProviderProfileCategory = 7
+)
+
+// Enum value maps for ProviderProfileCategory.
+var (
+ ProviderProfileCategory_name = map[int32]string{
+ 0: "PROVIDER_PROFILE_CATEGORY_UNSPECIFIED",
+ 1: "PROVIDER_PROFILE_CATEGORY_OTHER",
+ 2: "PROVIDER_PROFILE_CATEGORY_INFERENCE",
+ 3: "PROVIDER_PROFILE_CATEGORY_AGENT",
+ 4: "PROVIDER_PROFILE_CATEGORY_SOURCE_CONTROL",
+ 5: "PROVIDER_PROFILE_CATEGORY_MESSAGING",
+ 6: "PROVIDER_PROFILE_CATEGORY_DATA",
+ 7: "PROVIDER_PROFILE_CATEGORY_KNOWLEDGE",
+ }
+ ProviderProfileCategory_value = map[string]int32{
+ "PROVIDER_PROFILE_CATEGORY_UNSPECIFIED": 0,
+ "PROVIDER_PROFILE_CATEGORY_OTHER": 1,
+ "PROVIDER_PROFILE_CATEGORY_INFERENCE": 2,
+ "PROVIDER_PROFILE_CATEGORY_AGENT": 3,
+ "PROVIDER_PROFILE_CATEGORY_SOURCE_CONTROL": 4,
+ "PROVIDER_PROFILE_CATEGORY_MESSAGING": 5,
+ "PROVIDER_PROFILE_CATEGORY_DATA": 6,
+ "PROVIDER_PROFILE_CATEGORY_KNOWLEDGE": 7,
+ }
+)
+
+func (x ProviderProfileCategory) Enum() *ProviderProfileCategory {
+ p := new(ProviderProfileCategory)
+ *p = x
+ return p
+}
+
+func (x ProviderProfileCategory) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (ProviderProfileCategory) Descriptor() protoreflect.EnumDescriptor {
+ return file_openshell_proto_enumTypes[2].Descriptor()
+}
+
+func (ProviderProfileCategory) Type() protoreflect.EnumType {
+ return &file_openshell_proto_enumTypes[2]
+}
+
+func (x ProviderProfileCategory) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use ProviderProfileCategory.Descriptor instead.
+func (ProviderProfileCategory) EnumDescriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{2}
+}
+
+// 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[3].Descriptor()
+}
+
+func (PolicyStatus) Type() protoreflect.EnumType {
+ return &file_openshell_proto_enumTypes[3]
+}
+
+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{3}
+}
+
+// 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[4].Descriptor()
+}
+
+func (ServiceStatus) Type() protoreflect.EnumType {
+ return &file_openshell_proto_enumTypes[4]
+}
+
+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{4}
+}
+
+// Workspace-scoped role for members.
+type WorkspaceRole int32
+
+const (
+ WorkspaceRole_WORKSPACE_ROLE_UNSPECIFIED WorkspaceRole = 0
+ WorkspaceRole_WORKSPACE_ROLE_USER WorkspaceRole = 1
+ WorkspaceRole_WORKSPACE_ROLE_ADMIN WorkspaceRole = 2
+)
+
+// Enum value maps for WorkspaceRole.
+var (
+ WorkspaceRole_name = map[int32]string{
+ 0: "WORKSPACE_ROLE_UNSPECIFIED",
+ 1: "WORKSPACE_ROLE_USER",
+ 2: "WORKSPACE_ROLE_ADMIN",
+ }
+ WorkspaceRole_value = map[string]int32{
+ "WORKSPACE_ROLE_UNSPECIFIED": 0,
+ "WORKSPACE_ROLE_USER": 1,
+ "WORKSPACE_ROLE_ADMIN": 2,
+ }
+)
+
+func (x WorkspaceRole) Enum() *WorkspaceRole {
+ p := new(WorkspaceRole)
+ *p = x
+ return p
+}
+
+func (x WorkspaceRole) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (WorkspaceRole) Descriptor() protoreflect.EnumDescriptor {
+ return file_openshell_proto_enumTypes[5].Descriptor()
+}
+
+func (WorkspaceRole) Type() protoreflect.EnumType {
+ return &file_openshell_proto_enumTypes[5]
+}
+
+func (x WorkspaceRole) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use WorkspaceRole.Descriptor instead.
+func (WorkspaceRole) EnumDescriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{5}
+}
+
+// IssueSandboxToken request. Empty body; identity is established by the
+// authentication credentials carried in the request headers (a projected
+// Kubernetes ServiceAccount JWT in the K8s driver path).
+type IssueSandboxTokenRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *IssueSandboxTokenRequest) Reset() {
+ *x = IssueSandboxTokenRequest{}
+ mi := &file_openshell_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *IssueSandboxTokenRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*IssueSandboxTokenRequest) ProtoMessage() {}
+
+func (x *IssueSandboxTokenRequest) 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 IssueSandboxTokenRequest.ProtoReflect.Descriptor instead.
+func (*IssueSandboxTokenRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{0}
+}
+
+// IssueSandboxToken response. The supervisor caches the returned token in
+// memory and presents it as `Authorization: Bearer` on every subsequent
+// gateway RPC.
+type IssueSandboxTokenResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Gateway-minted JWT bound to the calling sandbox's UUID.
+ Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
+ // Absolute expiry of the issued token, milliseconds since the epoch. 0 means
+ // the token is non-expiring.
+ ExpiresAtMs int64 `protobuf:"varint,2,opt,name=expires_at_ms,json=expiresAtMs,proto3" json:"expires_at_ms,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *IssueSandboxTokenResponse) Reset() {
+ *x = IssueSandboxTokenResponse{}
+ mi := &file_openshell_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *IssueSandboxTokenResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*IssueSandboxTokenResponse) ProtoMessage() {}
+
+func (x *IssueSandboxTokenResponse) 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 IssueSandboxTokenResponse.ProtoReflect.Descriptor instead.
+func (*IssueSandboxTokenResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *IssueSandboxTokenResponse) GetToken() string {
+ if x != nil {
+ return x.Token
+ }
+ return ""
+}
+
+func (x *IssueSandboxTokenResponse) GetExpiresAtMs() int64 {
+ if x != nil {
+ return x.ExpiresAtMs
+ }
+ return 0
+}
+
+// RefreshSandboxToken request. Empty body; the calling principal must
+// already be a sandbox principal (i.e. the request carries a still-valid
+// gateway-minted JWT in its Authorization header).
+type RefreshSandboxTokenRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RefreshSandboxTokenRequest) Reset() {
+ *x = RefreshSandboxTokenRequest{}
+ mi := &file_openshell_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RefreshSandboxTokenRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RefreshSandboxTokenRequest) ProtoMessage() {}
+
+func (x *RefreshSandboxTokenRequest) 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 RefreshSandboxTokenRequest.ProtoReflect.Descriptor instead.
+func (*RefreshSandboxTokenRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{2}
+}
+
+// RefreshSandboxToken response. The new token replaces the supervisor's
+// in-memory bearer credential.
+type RefreshSandboxTokenResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Fresh gateway-minted JWT bound to the same sandbox UUID.
+ Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
+ // Absolute expiry of the new token, milliseconds since the epoch. 0 means
+ // the token is non-expiring.
+ ExpiresAtMs int64 `protobuf:"varint,2,opt,name=expires_at_ms,json=expiresAtMs,proto3" json:"expires_at_ms,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RefreshSandboxTokenResponse) Reset() {
+ *x = RefreshSandboxTokenResponse{}
+ mi := &file_openshell_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RefreshSandboxTokenResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RefreshSandboxTokenResponse) ProtoMessage() {}
+
+func (x *RefreshSandboxTokenResponse) 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 RefreshSandboxTokenResponse.ProtoReflect.Descriptor instead.
+func (*RefreshSandboxTokenResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *RefreshSandboxTokenResponse) GetToken() string {
+ if x != nil {
+ return x.Token
+ }
+ return ""
+}
+
+func (x *RefreshSandboxTokenResponse) GetExpiresAtMs() int64 {
+ if x != nil {
+ return x.ExpiresAtMs
+ }
+ return 0
+}
+
+// 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[4]
+ 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[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 HealthRequest.ProtoReflect.Descriptor instead.
+func (*HealthRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{4}
+}
+
+// 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[5]
+ 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[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 HealthResponse.ProtoReflect.Descriptor instead.
+func (*HealthResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{5}
+}
+
+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 ""
+}
+
+// Current-user request. The identity comes from the authenticated request.
+type GetCurrentUserRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetCurrentUserRequest) Reset() {
+ *x = GetCurrentUserRequest{}
+ mi := &file_openshell_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetCurrentUserRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetCurrentUserRequest) ProtoMessage() {}
+
+func (x *GetCurrentUserRequest) 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 GetCurrentUserRequest.ProtoReflect.Descriptor instead.
+func (*GetCurrentUserRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{6}
+}
+
+// Authenticated user identity as validated by the gateway.
+type GetCurrentUserResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Stable identity subject (for example, the OIDC `sub` claim).
+ Subject string `protobuf:"bytes,1,opt,name=subject,proto3" json:"subject,omitempty"`
+ // Human-readable identity name when supplied by the authentication provider.
+ DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"`
+ // Roles granted to the authenticated identity.
+ Roles []string `protobuf:"bytes,3,rep,name=roles,proto3" json:"roles,omitempty"`
+ // OAuth2 scopes granted to the authenticated identity.
+ Scopes []string `protobuf:"bytes,4,rep,name=scopes,proto3" json:"scopes,omitempty"`
+ // Authentication provider that established the identity.
+ IdentityProvider string `protobuf:"bytes,5,opt,name=identity_provider,json=identityProvider,proto3" json:"identity_provider,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetCurrentUserResponse) Reset() {
+ *x = GetCurrentUserResponse{}
+ mi := &file_openshell_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetCurrentUserResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetCurrentUserResponse) ProtoMessage() {}
+
+func (x *GetCurrentUserResponse) 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 GetCurrentUserResponse.ProtoReflect.Descriptor instead.
+func (*GetCurrentUserResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *GetCurrentUserResponse) GetSubject() string {
+ if x != nil {
+ return x.Subject
+ }
+ return ""
+}
+
+func (x *GetCurrentUserResponse) GetDisplayName() string {
+ if x != nil {
+ return x.DisplayName
+ }
+ return ""
+}
+
+func (x *GetCurrentUserResponse) GetRoles() []string {
+ if x != nil {
+ return x.Roles
+ }
+ return nil
+}
+
+func (x *GetCurrentUserResponse) GetScopes() []string {
+ if x != nil {
+ return x.Scopes
+ }
+ return nil
+}
+
+func (x *GetCurrentUserResponse) GetIdentityProvider() string {
+ if x != nil {
+ return x.IdentityProvider
+ }
+ return ""
+}
+
+// Gateway info request.
+type GetGatewayInfoRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetGatewayInfoRequest) Reset() {
+ *x = GetGatewayInfoRequest{}
+ mi := &file_openshell_proto_msgTypes[8]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetGatewayInfoRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetGatewayInfoRequest) ProtoMessage() {}
+
+func (x *GetGatewayInfoRequest) 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 GetGatewayInfoRequest.ProtoReflect.Descriptor instead.
+func (*GetGatewayInfoRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{8}
+}
+
+// Gateway info response.
+type GetGatewayInfoResponse 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"`
+ // OpenShell gateway binary version.
+ GatewayVersion string `protobuf:"bytes,2,opt,name=gateway_version,json=gatewayVersion,proto3" json:"gateway_version,omitempty"`
+ // Compute driver runtimes initialized by this gateway. Current gateways
+ // return exactly one entry.
+ ComputeDrivers []*ComputeDriverInfo `protobuf:"bytes,3,rep,name=compute_drivers,json=computeDrivers,proto3" json:"compute_drivers,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetGatewayInfoResponse) Reset() {
+ *x = GetGatewayInfoResponse{}
+ mi := &file_openshell_proto_msgTypes[9]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetGatewayInfoResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetGatewayInfoResponse) ProtoMessage() {}
+
+func (x *GetGatewayInfoResponse) 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 GetGatewayInfoResponse.ProtoReflect.Descriptor instead.
+func (*GetGatewayInfoResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *GetGatewayInfoResponse) GetStatus() ServiceStatus {
+ if x != nil {
+ return x.Status
+ }
+ return ServiceStatus_SERVICE_STATUS_UNSPECIFIED
+}
+
+func (x *GetGatewayInfoResponse) GetGatewayVersion() string {
+ if x != nil {
+ return x.GatewayVersion
+ }
+ return ""
+}
+
+func (x *GetGatewayInfoResponse) GetComputeDrivers() []*ComputeDriverInfo {
+ if x != nil {
+ return x.ComputeDrivers
+ }
+ return nil
+}
+
+// Info for one initialized compute driver runtime.
+type ComputeDriverInfo struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Gateway-selected driver name used for routing and driver_config keys.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // Capabilities reported by the driver during gateway runtime initialization.
+ Capabilities *ComputeDriverCapabilities `protobuf:"bytes,2,opt,name=capabilities,proto3" json:"capabilities,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ComputeDriverInfo) Reset() {
+ *x = ComputeDriverInfo{}
+ mi := &file_openshell_proto_msgTypes[10]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ComputeDriverInfo) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ComputeDriverInfo) ProtoMessage() {}
+
+func (x *ComputeDriverInfo) 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 ComputeDriverInfo.ProtoReflect.Descriptor instead.
+func (*ComputeDriverInfo) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *ComputeDriverInfo) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *ComputeDriverInfo) GetCapabilities() *ComputeDriverCapabilities {
+ if x != nil {
+ return x.Capabilities
+ }
+ return nil
+}
+
+// Public compute driver capability snapshot.
+type ComputeDriverCapabilities struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Driver-reported human-readable name from the startup capability snapshot.
+ DriverName string `protobuf:"bytes,1,opt,name=driver_name,json=driverName,proto3" json:"driver_name,omitempty"`
+ // Driver-reported implementation version from the startup capability snapshot.
+ DriverVersion string `protobuf:"bytes,2,opt,name=driver_version,json=driverVersion,proto3" json:"driver_version,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ComputeDriverCapabilities) Reset() {
+ *x = ComputeDriverCapabilities{}
+ mi := &file_openshell_proto_msgTypes[11]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ComputeDriverCapabilities) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ComputeDriverCapabilities) ProtoMessage() {}
+
+func (x *ComputeDriverCapabilities) 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 ComputeDriverCapabilities.ProtoReflect.Descriptor instead.
+func (*ComputeDriverCapabilities) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{11}
+}
+
+func (x *ComputeDriverCapabilities) GetDriverName() string {
+ if x != nil {
+ return x.DriverName
+ }
+ return ""
+}
+
+func (x *ComputeDriverCapabilities) GetDriverVersion() string {
+ if x != nil {
+ return x.DriverVersion
+ }
+ return ""
+}
+
+// Public sandbox resource exposed by the OpenShell API.
+//
+// This is the canonical gateway-owned view of a sandbox. It merges user intent
+// (`spec`) with gateway-managed metadata and status derived from internal
+// compute-driver observations.
+//
+// Note: The `namespace` field has been removed from the public API. It remains
+// in the internal `DriverSandbox` message as a compute-driver implementation detail.
+type Sandbox struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Kubernetes-style metadata (id, name, labels, timestamps, resource version).
+ Metadata *datamodelv1.ObjectMeta `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"`
+ // Desired sandbox configuration submitted through the API.
+ Spec *SandboxSpec `protobuf:"bytes,2,opt,name=spec,proto3" json:"spec,omitempty"`
+ // Latest user-facing observed status derived by the gateway.
+ Status *SandboxStatus `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *Sandbox) Reset() {
+ *x = Sandbox{}
+ mi := &file_openshell_proto_msgTypes[12]
+ 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_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 Sandbox.ProtoReflect.Descriptor instead.
+func (*Sandbox) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{12}
+}
+
+func (x *Sandbox) GetMetadata() *datamodelv1.ObjectMeta {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+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
+}
+
+// Desired sandbox configuration provided through the public API.
+type SandboxSpec struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Log level exposed to processes running inside the sandbox.
+ LogLevel string `protobuf:"bytes,1,opt,name=log_level,json=logLevel,proto3" json:"log_level,omitempty"`
+ // Environment variables injected into the sandbox runtime.
+ 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"`
+ // Container or VM template used to provision the sandbox.
+ Template *SandboxTemplate `protobuf:"bytes,6,opt,name=template,proto3" json:"template,omitempty"`
+ // Required sandbox policy configuration.
+ Policy *sandboxv1.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"`
+ // Portable resource requirements used by the gateway for driver selection
+ // and by drivers for provisioning.
+ ResourceRequirements *ResourceRequirements `protobuf:"bytes,9,opt,name=resource_requirements,json=resourceRequirements,proto3" json:"resource_requirements,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SandboxSpec) Reset() {
+ *x = SandboxSpec{}
+ mi := &file_openshell_proto_msgTypes[13]
+ 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_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 SandboxSpec.ProtoReflect.Descriptor instead.
+func (*SandboxSpec) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{13}
+}
+
+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() *sandboxv1.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) GetResourceRequirements() *ResourceRequirements {
+ if x != nil {
+ return x.ResourceRequirements
+ }
+ return nil
+}
+
+type ResourceRequirements struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // GPU requirements for the sandbox. Presence indicates a GPU request.
+ Gpu *GpuResourceRequirements `protobuf:"bytes,1,opt,name=gpu,proto3" json:"gpu,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ResourceRequirements) Reset() {
+ *x = ResourceRequirements{}
+ mi := &file_openshell_proto_msgTypes[14]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ResourceRequirements) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ResourceRequirements) ProtoMessage() {}
+
+func (x *ResourceRequirements) 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 ResourceRequirements.ProtoReflect.Descriptor instead.
+func (*ResourceRequirements) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{14}
+}
+
+func (x *ResourceRequirements) GetGpu() *GpuResourceRequirements {
+ if x != nil {
+ return x.Gpu
+ }
+ return nil
+}
+
+// Public GPU resource requirements.
+type GpuResourceRequirements struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Optional number of GPUs requested. When omitted, the request is for one
+ // GPU using the selected driver's default assignment behavior.
+ Count *uint32 `protobuf:"varint,1,opt,name=count,proto3,oneof" json:"count,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GpuResourceRequirements) Reset() {
+ *x = GpuResourceRequirements{}
+ mi := &file_openshell_proto_msgTypes[15]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GpuResourceRequirements) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GpuResourceRequirements) ProtoMessage() {}
+
+func (x *GpuResourceRequirements) 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 GpuResourceRequirements.ProtoReflect.Descriptor instead.
+func (*GpuResourceRequirements) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{15}
+}
+
+func (x *GpuResourceRequirements) GetCount() uint32 {
+ if x != nil && x.Count != nil {
+ return *x.Count
+ }
+ return 0
+}
+
+// Public sandbox template mapped onto compute-driver template inputs.
+type SandboxTemplate struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Fully-qualified OCI image reference used to boot the sandbox.
+ Image string `protobuf:"bytes,1,opt,name=image,proto3" json:"image,omitempty"`
+ // Optional runtime class name requested from the compute platform.
+ RuntimeClassName string `protobuf:"bytes,2,opt,name=runtime_class_name,json=runtimeClassName,proto3" json:"runtime_class_name,omitempty"`
+ // Optional agent socket path exposed to the workload.
+ AgentSocket string `protobuf:"bytes,3,opt,name=agent_socket,json=agentSocket,proto3" json:"agent_socket,omitempty"`
+ // Labels applied to compute-platform resources for this sandbox.
+ 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 applied to compute-platform resources for this sandbox.
+ 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"`
+ // Additional environment variables injected by the template.
+ 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"`
+ // Platform-specific compute resource requirements and limits.
+ Resources *structpb.Struct `protobuf:"bytes,7,opt,name=resources,proto3" json:"resources,omitempty"`
+ // Enable Kubernetes user namespace isolation (hostUsers: false).
+ // When true, container UID 0 maps to a non-root host UID and capabilities
+ // become namespaced. Requires Kubernetes 1.33+ with user namespace support
+ // available (beta through 1.35, GA in 1.36+) and a supporting runtime.
+ // When unset, the cluster-wide default is used.
+ UserNamespaces *bool `protobuf:"varint,10,opt,name=user_namespaces,json=userNamespaces,proto3,oneof" json:"user_namespaces,omitempty"`
+ // Driver-keyed opaque config envelope supplied by the caller.
+ // The gateway selects the block matching the active compute driver and
+ // forwards only that inner Struct to DriverSandboxTemplate.driver_config.
+ // The selected driver owns nested schema validation.
+ DriverConfig *structpb.Struct `protobuf:"bytes,11,opt,name=driver_config,json=driverConfig,proto3" json:"driver_config,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SandboxTemplate) Reset() {
+ *x = SandboxTemplate{}
+ mi := &file_openshell_proto_msgTypes[16]
+ 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_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 SandboxTemplate.ProtoReflect.Descriptor instead.
+func (*SandboxTemplate) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{16}
+}
+
+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) GetUserNamespaces() bool {
+ if x != nil && x.UserNamespaces != nil {
+ return *x.UserNamespaces
+ }
+ return false
+}
+
+func (x *SandboxTemplate) GetDriverConfig() *structpb.Struct {
+ if x != nil {
+ return x.DriverConfig
+ }
+ return nil
+}
+
+// User-facing sandbox status derived by the gateway from compute-driver observations.
+//
+// Public status does not embed driver-only flags such as `deleting`.
+type SandboxStatus struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Compute-platform sandbox object name.
+ SandboxName string `protobuf:"bytes,1,opt,name=sandbox_name,json=sandboxName,proto3" json:"sandbox_name,omitempty"`
+ // Name of the agent pod or equivalent runtime instance.
+ AgentPod string `protobuf:"bytes,2,opt,name=agent_pod,json=agentPod,proto3" json:"agent_pod,omitempty"`
+ // File descriptor or endpoint for reaching the agent service, when available.
+ AgentFd string `protobuf:"bytes,3,opt,name=agent_fd,json=agentFd,proto3" json:"agent_fd,omitempty"`
+ // File descriptor or endpoint for reaching the sandbox service, when available.
+ SandboxFd string `protobuf:"bytes,4,opt,name=sandbox_fd,json=sandboxFd,proto3" json:"sandbox_fd,omitempty"`
+ // Latest user-facing readiness and lifecycle conditions.
+ Conditions []*SandboxCondition `protobuf:"bytes,5,rep,name=conditions,proto3" json:"conditions,omitempty"`
+ // Gateway-derived lifecycle summary.
+ Phase SandboxPhase `protobuf:"varint,6,opt,name=phase,proto3,enum=openshell.v1.SandboxPhase" json:"phase,omitempty"`
+ // Currently active policy version (updated when sandbox reports loaded).
+ CurrentPolicyVersion uint32 `protobuf:"varint,7,opt,name=current_policy_version,json=currentPolicyVersion,proto3" json:"current_policy_version,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SandboxStatus) Reset() {
+ *x = SandboxStatus{}
+ mi := &file_openshell_proto_msgTypes[17]
+ 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_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 SandboxStatus.ProtoReflect.Descriptor instead.
+func (*SandboxStatus) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{17}
+}
+
+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
+}
+
+func (x *SandboxStatus) GetPhase() SandboxPhase {
+ if x != nil {
+ return x.Phase
+ }
+ return SandboxPhase_SANDBOX_PHASE_UNSPECIFIED
+}
+
+func (x *SandboxStatus) GetCurrentPolicyVersion() uint32 {
+ if x != nil {
+ return x.CurrentPolicyVersion
+ }
+ return 0
+}
+
+// User-facing sandbox condition derived from driver-native conditions.
+type SandboxCondition struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Condition class, typically mirroring the underlying platform condition type.
+ Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
+ // Condition status value such as `True`, `False`, or `Unknown`.
+ Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"`
+ // Short machine-readable reason associated with the condition.
+ Reason string `protobuf:"bytes,3,opt,name=reason,proto3" json:"reason,omitempty"`
+ // Human-readable condition message.
+ Message string `protobuf:"bytes,4,opt,name=message,proto3" json:"message,omitempty"`
+ // Timestamp reported by the underlying platform for the last transition.
+ 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_openshell_proto_msgTypes[18]
+ 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_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 SandboxCondition.ProtoReflect.Descriptor instead.
+func (*SandboxCondition) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{18}
+}
+
+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 ""
+}
+
+// Public platform event exposed on the sandbox watch stream.
+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[19]
+ 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[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 PlatformEvent.ProtoReflect.Descriptor instead.
+func (*PlatformEvent) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{19}
+}
+
+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
+}
+
+// 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"`
+ // Optional labels for the sandbox (key-value metadata).
+ Labels map[string]string `protobuf:"bytes,3,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ // Optional annotations for the sandbox (non-selector metadata).
+ Annotations map[string]string `protobuf:"bytes,4,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ // Workspace for the sandbox. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,5,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *CreateSandboxRequest) Reset() {
+ *x = CreateSandboxRequest{}
+ mi := &file_openshell_proto_msgTypes[20]
+ 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[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 CreateSandboxRequest.ProtoReflect.Descriptor instead.
+func (*CreateSandboxRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{20}
+}
+
+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 ""
+}
+
+func (x *CreateSandboxRequest) GetLabels() map[string]string {
+ if x != nil {
+ return x.Labels
+ }
+ return nil
+}
+
+func (x *CreateSandboxRequest) GetAnnotations() map[string]string {
+ if x != nil {
+ return x.Annotations
+ }
+ return nil
+}
+
+func (x *CreateSandboxRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ 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"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,2,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetSandboxRequest) Reset() {
+ *x = GetSandboxRequest{}
+ mi := &file_openshell_proto_msgTypes[21]
+ 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[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 GetSandboxRequest.ProtoReflect.Descriptor instead.
+func (*GetSandboxRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{21}
+}
+
+func (x *GetSandboxRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *GetSandboxRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ 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"`
+ // Optional label selector for filtering (format: "key1=value1,key2=value2").
+ LabelSelector string `protobuf:"bytes,3,opt,name=label_selector,json=labelSelector,proto3" json:"label_selector,omitempty"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,4,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ // List across all workspaces. Mutually exclusive with workspace.
+ AllWorkspaces bool `protobuf:"varint,5,opt,name=all_workspaces,json=allWorkspaces,proto3" json:"all_workspaces,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ListSandboxesRequest) Reset() {
+ *x = ListSandboxesRequest{}
+ mi := &file_openshell_proto_msgTypes[22]
+ 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[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 ListSandboxesRequest.ProtoReflect.Descriptor instead.
+func (*ListSandboxesRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{22}
+}
+
+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
+}
+
+func (x *ListSandboxesRequest) GetLabelSelector() string {
+ if x != nil {
+ return x.LabelSelector
+ }
+ return ""
+}
+
+func (x *ListSandboxesRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+func (x *ListSandboxesRequest) GetAllWorkspaces() bool {
+ if x != nil {
+ return x.AllWorkspaces
+ }
+ return false
+}
+
+// List providers attached to a sandbox request.
+type ListSandboxProvidersRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Sandbox name (canonical lookup key).
+ SandboxName string `protobuf:"bytes,1,opt,name=sandbox_name,json=sandboxName,proto3" json:"sandbox_name,omitempty"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,2,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ListSandboxProvidersRequest) Reset() {
+ *x = ListSandboxProvidersRequest{}
+ mi := &file_openshell_proto_msgTypes[23]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ListSandboxProvidersRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListSandboxProvidersRequest) ProtoMessage() {}
+
+func (x *ListSandboxProvidersRequest) 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 ListSandboxProvidersRequest.ProtoReflect.Descriptor instead.
+func (*ListSandboxProvidersRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{23}
+}
+
+func (x *ListSandboxProvidersRequest) GetSandboxName() string {
+ if x != nil {
+ return x.SandboxName
+ }
+ return ""
+}
+
+func (x *ListSandboxProvidersRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+// Attach provider to sandbox request.
+type AttachSandboxProviderRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Sandbox name (canonical lookup key).
+ SandboxName string `protobuf:"bytes,1,opt,name=sandbox_name,json=sandboxName,proto3" json:"sandbox_name,omitempty"`
+ // Provider name to attach.
+ ProviderName string `protobuf:"bytes,2,opt,name=provider_name,json=providerName,proto3" json:"provider_name,omitempty"`
+ // Expected resource version for optimistic concurrency control.
+ // If 0, the server uses the current version (backward compatibility).
+ // If non-zero, the server validates that the sandbox's current resource_version
+ // matches this value before applying the mutation, returning ABORTED on mismatch.
+ ExpectedResourceVersion uint64 `protobuf:"varint,3,opt,name=expected_resource_version,json=expectedResourceVersion,proto3" json:"expected_resource_version,omitempty"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,4,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *AttachSandboxProviderRequest) Reset() {
+ *x = AttachSandboxProviderRequest{}
+ mi := &file_openshell_proto_msgTypes[24]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *AttachSandboxProviderRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AttachSandboxProviderRequest) ProtoMessage() {}
+
+func (x *AttachSandboxProviderRequest) 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 AttachSandboxProviderRequest.ProtoReflect.Descriptor instead.
+func (*AttachSandboxProviderRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{24}
+}
+
+func (x *AttachSandboxProviderRequest) GetSandboxName() string {
+ if x != nil {
+ return x.SandboxName
+ }
+ return ""
+}
+
+func (x *AttachSandboxProviderRequest) GetProviderName() string {
+ if x != nil {
+ return x.ProviderName
+ }
+ return ""
+}
+
+func (x *AttachSandboxProviderRequest) GetExpectedResourceVersion() uint64 {
+ if x != nil {
+ return x.ExpectedResourceVersion
+ }
+ return 0
+}
+
+func (x *AttachSandboxProviderRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+// Detach provider from sandbox request.
+type DetachSandboxProviderRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Sandbox name (canonical lookup key).
+ SandboxName string `protobuf:"bytes,1,opt,name=sandbox_name,json=sandboxName,proto3" json:"sandbox_name,omitempty"`
+ // Provider name to detach.
+ ProviderName string `protobuf:"bytes,2,opt,name=provider_name,json=providerName,proto3" json:"provider_name,omitempty"`
+ // Expected resource version for optimistic concurrency control.
+ // If 0, the server uses the current version (backward compatibility).
+ // If non-zero, the server validates that the sandbox's current resource_version
+ // matches this value before applying the mutation, returning ABORTED on mismatch.
+ ExpectedResourceVersion uint64 `protobuf:"varint,3,opt,name=expected_resource_version,json=expectedResourceVersion,proto3" json:"expected_resource_version,omitempty"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,4,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *DetachSandboxProviderRequest) Reset() {
+ *x = DetachSandboxProviderRequest{}
+ mi := &file_openshell_proto_msgTypes[25]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *DetachSandboxProviderRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DetachSandboxProviderRequest) ProtoMessage() {}
+
+func (x *DetachSandboxProviderRequest) 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 DetachSandboxProviderRequest.ProtoReflect.Descriptor instead.
+func (*DetachSandboxProviderRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{25}
+}
+
+func (x *DetachSandboxProviderRequest) GetSandboxName() string {
+ if x != nil {
+ return x.SandboxName
+ }
+ return ""
+}
+
+func (x *DetachSandboxProviderRequest) GetProviderName() string {
+ if x != nil {
+ return x.ProviderName
+ }
+ return ""
+}
+
+func (x *DetachSandboxProviderRequest) GetExpectedResourceVersion() uint64 {
+ if x != nil {
+ return x.ExpectedResourceVersion
+ }
+ return 0
+}
+
+func (x *DetachSandboxProviderRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+// 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"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,2,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *DeleteSandboxRequest) Reset() {
+ *x = DeleteSandboxRequest{}
+ mi := &file_openshell_proto_msgTypes[26]
+ 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[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 DeleteSandboxRequest.ProtoReflect.Descriptor instead.
+func (*DeleteSandboxRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{26}
+}
+
+func (x *DeleteSandboxRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *DeleteSandboxRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ 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[27]
+ 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[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 SandboxResponse.ProtoReflect.Descriptor instead.
+func (*SandboxResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{27}
+}
+
+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[28]
+ 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[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 ListSandboxesResponse.ProtoReflect.Descriptor instead.
+func (*ListSandboxesResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{28}
+}
+
+func (x *ListSandboxesResponse) GetSandboxes() []*Sandbox {
+ if x != nil {
+ return x.Sandboxes
+ }
+ return nil
+}
+
+// List providers attached to a sandbox response.
+type ListSandboxProvidersResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Providers []*datamodelv1.Provider `protobuf:"bytes,1,rep,name=providers,proto3" json:"providers,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ListSandboxProvidersResponse) Reset() {
+ *x = ListSandboxProvidersResponse{}
+ mi := &file_openshell_proto_msgTypes[29]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ListSandboxProvidersResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListSandboxProvidersResponse) ProtoMessage() {}
+
+func (x *ListSandboxProvidersResponse) 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 ListSandboxProvidersResponse.ProtoReflect.Descriptor instead.
+func (*ListSandboxProvidersResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{29}
+}
+
+func (x *ListSandboxProvidersResponse) GetProviders() []*datamodelv1.Provider {
+ if x != nil {
+ return x.Providers
+ }
+ return nil
+}
+
+// Attach provider to sandbox response.
+type AttachSandboxProviderResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Sandbox *Sandbox `protobuf:"bytes,1,opt,name=sandbox,proto3" json:"sandbox,omitempty"`
+ // True when the provider was newly attached. False means it was already attached.
+ Attached bool `protobuf:"varint,2,opt,name=attached,proto3" json:"attached,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *AttachSandboxProviderResponse) Reset() {
+ *x = AttachSandboxProviderResponse{}
+ mi := &file_openshell_proto_msgTypes[30]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *AttachSandboxProviderResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AttachSandboxProviderResponse) ProtoMessage() {}
+
+func (x *AttachSandboxProviderResponse) 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 AttachSandboxProviderResponse.ProtoReflect.Descriptor instead.
+func (*AttachSandboxProviderResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{30}
+}
+
+func (x *AttachSandboxProviderResponse) GetSandbox() *Sandbox {
+ if x != nil {
+ return x.Sandbox
+ }
+ return nil
+}
+
+func (x *AttachSandboxProviderResponse) GetAttached() bool {
+ if x != nil {
+ return x.Attached
+ }
+ return false
+}
+
+// Detach provider from sandbox response.
+type DetachSandboxProviderResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Sandbox *Sandbox `protobuf:"bytes,1,opt,name=sandbox,proto3" json:"sandbox,omitempty"`
+ // True when the provider was removed. False means it was not attached.
+ Detached bool `protobuf:"varint,2,opt,name=detached,proto3" json:"detached,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *DetachSandboxProviderResponse) Reset() {
+ *x = DetachSandboxProviderResponse{}
+ mi := &file_openshell_proto_msgTypes[31]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *DetachSandboxProviderResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DetachSandboxProviderResponse) ProtoMessage() {}
+
+func (x *DetachSandboxProviderResponse) 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 DetachSandboxProviderResponse.ProtoReflect.Descriptor instead.
+func (*DetachSandboxProviderResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{31}
+}
+
+func (x *DetachSandboxProviderResponse) GetSandbox() *Sandbox {
+ if x != nil {
+ return x.Sandbox
+ }
+ return nil
+}
+
+func (x *DetachSandboxProviderResponse) GetDetached() bool {
+ if x != nil {
+ return x.Detached
+ }
+ return false
+}
+
+// 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[32]
+ 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[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 DeleteSandboxResponse.ProtoReflect.Descriptor instead.
+func (*DeleteSandboxResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{32}
+}
+
+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[33]
+ 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[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 CreateSshSessionRequest.ProtoReflect.Descriptor instead.
+func (*CreateSshSessionRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{33}
+}
+
+func (x *CreateSshSessionRequest) GetSandboxId() string {
+ if x != nil {
+ return x.SandboxId
+ }
+ return ""
+}
+
+// Create SSH session response.
+//
+// Fields are interpolated into an SSH `ProxyCommand` string that OpenSSH
+// executes through `/bin/sh -c` on the caller's workstation. Servers MUST
+// uphold the charset contract below; clients MUST reject responses that
+// violate it. The client's own escaping provides defense-in-depth, but
+// narrow charsets close injection vectors at the trust boundary.
+type CreateSshSessionResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Sandbox id. [A-Za-z0-9._-]{1,128}.
+ SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"`
+ // Session token for the gateway tunnel. URL-safe ASCII
+ // ([A-Za-z0-9._~+/=-]) up to 4096 bytes. No shell metacharacters or
+ // whitespace.
+ Token string `protobuf:"bytes,2,opt,name=token,proto3" json:"token,omitempty"`
+ // Gateway host for SSH proxy connection. IPv4 address, bracketed IPv6
+ // address, or DNS hostname (Punycode-encoded for IDN). Alphanumeric plus
+ // `.-:[]` only, up to 253 bytes.
+ GatewayHost string `protobuf:"bytes,3,opt,name=gateway_host,json=gatewayHost,proto3" json:"gateway_host,omitempty"`
+ // Gateway port for SSH proxy connection. Must be in range 1..=65535.
+ GatewayPort uint32 `protobuf:"varint,4,opt,name=gateway_port,json=gatewayPort,proto3" json:"gateway_port,omitempty"`
+ // Gateway scheme. Must be exactly "http" or "https".
+ GatewayScheme string `protobuf:"bytes,5,opt,name=gateway_scheme,json=gatewayScheme,proto3" json:"gateway_scheme,omitempty"`
+ // Optional host key fingerprint. If non-empty, [A-Za-z0-9:+/=-] only.
+ 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[34]
+ 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[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 CreateSshSessionResponse.ProtoReflect.Descriptor instead.
+func (*CreateSshSessionResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{34}
+}
+
+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) GetHostKeyFingerprint() string {
+ if x != nil {
+ return x.HostKeyFingerprint
+ }
+ return ""
+}
+
+func (x *CreateSshSessionResponse) GetExpiresAtMs() int64 {
+ if x != nil {
+ return x.ExpiresAtMs
+ }
+ return 0
+}
+
+// Request to expose an HTTP service running inside a sandbox.
+type ExposeServiceRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Sandbox name.
+ Sandbox string `protobuf:"bytes,1,opt,name=sandbox,proto3" json:"sandbox,omitempty"`
+ // Service name within the sandbox.
+ Service string `protobuf:"bytes,2,opt,name=service,proto3" json:"service,omitempty"`
+ // Loopback TCP port inside the sandbox.
+ TargetPort uint32 `protobuf:"varint,3,opt,name=target_port,json=targetPort,proto3" json:"target_port,omitempty"`
+ // Whether to print/use the browser-facing service URL.
+ Domain bool `protobuf:"varint,4,opt,name=domain,proto3" json:"domain,omitempty"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,5,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ExposeServiceRequest) Reset() {
+ *x = ExposeServiceRequest{}
+ mi := &file_openshell_proto_msgTypes[35]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ExposeServiceRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ExposeServiceRequest) ProtoMessage() {}
+
+func (x *ExposeServiceRequest) 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 ExposeServiceRequest.ProtoReflect.Descriptor instead.
+func (*ExposeServiceRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{35}
+}
+
+func (x *ExposeServiceRequest) GetSandbox() string {
+ if x != nil {
+ return x.Sandbox
+ }
+ return ""
+}
+
+func (x *ExposeServiceRequest) GetService() string {
+ if x != nil {
+ return x.Service
+ }
+ return ""
+}
+
+func (x *ExposeServiceRequest) GetTargetPort() uint32 {
+ if x != nil {
+ return x.TargetPort
+ }
+ return 0
+}
+
+func (x *ExposeServiceRequest) GetDomain() bool {
+ if x != nil {
+ return x.Domain
+ }
+ return false
+}
+
+func (x *ExposeServiceRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+// Request to fetch an exposed sandbox service endpoint.
+type GetServiceRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Sandbox name.
+ Sandbox string `protobuf:"bytes,1,opt,name=sandbox,proto3" json:"sandbox,omitempty"`
+ // Service name within the sandbox. Empty selects the unnamed endpoint.
+ Service string `protobuf:"bytes,2,opt,name=service,proto3" json:"service,omitempty"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,3,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetServiceRequest) Reset() {
+ *x = GetServiceRequest{}
+ mi := &file_openshell_proto_msgTypes[36]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetServiceRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetServiceRequest) ProtoMessage() {}
+
+func (x *GetServiceRequest) 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 GetServiceRequest.ProtoReflect.Descriptor instead.
+func (*GetServiceRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{36}
+}
+
+func (x *GetServiceRequest) GetSandbox() string {
+ if x != nil {
+ return x.Sandbox
+ }
+ return ""
+}
+
+func (x *GetServiceRequest) GetService() string {
+ if x != nil {
+ return x.Service
+ }
+ return ""
+}
+
+func (x *GetServiceRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+// Request to list exposed sandbox service endpoints.
+type ListServicesRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Optional sandbox name. Empty lists endpoints for all sandboxes.
+ Sandbox string `protobuf:"bytes,1,opt,name=sandbox,proto3" json:"sandbox,omitempty"`
+ // Page size. Zero uses the server default.
+ Limit uint32 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"`
+ // Page offset.
+ Offset uint32 `protobuf:"varint,3,opt,name=offset,proto3" json:"offset,omitempty"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,4,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ // List across all workspaces. Mutually exclusive with workspace.
+ AllWorkspaces bool `protobuf:"varint,5,opt,name=all_workspaces,json=allWorkspaces,proto3" json:"all_workspaces,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ListServicesRequest) Reset() {
+ *x = ListServicesRequest{}
+ mi := &file_openshell_proto_msgTypes[37]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ListServicesRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListServicesRequest) ProtoMessage() {}
+
+func (x *ListServicesRequest) 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 ListServicesRequest.ProtoReflect.Descriptor instead.
+func (*ListServicesRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{37}
+}
+
+func (x *ListServicesRequest) GetSandbox() string {
+ if x != nil {
+ return x.Sandbox
+ }
+ return ""
+}
+
+func (x *ListServicesRequest) GetLimit() uint32 {
+ if x != nil {
+ return x.Limit
+ }
+ return 0
+}
+
+func (x *ListServicesRequest) GetOffset() uint32 {
+ if x != nil {
+ return x.Offset
+ }
+ return 0
+}
+
+func (x *ListServicesRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+func (x *ListServicesRequest) GetAllWorkspaces() bool {
+ if x != nil {
+ return x.AllWorkspaces
+ }
+ return false
+}
+
+// Response containing exposed sandbox service endpoints.
+type ListServicesResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Services []*ServiceEndpointResponse `protobuf:"bytes,1,rep,name=services,proto3" json:"services,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ListServicesResponse) Reset() {
+ *x = ListServicesResponse{}
+ mi := &file_openshell_proto_msgTypes[38]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ListServicesResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListServicesResponse) ProtoMessage() {}
+
+func (x *ListServicesResponse) 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 ListServicesResponse.ProtoReflect.Descriptor instead.
+func (*ListServicesResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{38}
+}
+
+func (x *ListServicesResponse) GetServices() []*ServiceEndpointResponse {
+ if x != nil {
+ return x.Services
+ }
+ return nil
+}
+
+// Request to delete an exposed sandbox service endpoint.
+type DeleteServiceRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Sandbox name.
+ Sandbox string `protobuf:"bytes,1,opt,name=sandbox,proto3" json:"sandbox,omitempty"`
+ // Service name within the sandbox. Empty selects the unnamed endpoint.
+ Service string `protobuf:"bytes,2,opt,name=service,proto3" json:"service,omitempty"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,3,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *DeleteServiceRequest) Reset() {
+ *x = DeleteServiceRequest{}
+ mi := &file_openshell_proto_msgTypes[39]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *DeleteServiceRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeleteServiceRequest) ProtoMessage() {}
+
+func (x *DeleteServiceRequest) 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 DeleteServiceRequest.ProtoReflect.Descriptor instead.
+func (*DeleteServiceRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{39}
+}
+
+func (x *DeleteServiceRequest) GetSandbox() string {
+ if x != nil {
+ return x.Sandbox
+ }
+ return ""
+}
+
+func (x *DeleteServiceRequest) GetService() string {
+ if x != nil {
+ return x.Service
+ }
+ return ""
+}
+
+func (x *DeleteServiceRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+// Response for deleting an exposed sandbox service endpoint.
+type DeleteServiceResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // True when an endpoint existed and was deleted.
+ Deleted bool `protobuf:"varint,1,opt,name=deleted,proto3" json:"deleted,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *DeleteServiceResponse) Reset() {
+ *x = DeleteServiceResponse{}
+ mi := &file_openshell_proto_msgTypes[40]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *DeleteServiceResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeleteServiceResponse) ProtoMessage() {}
+
+func (x *DeleteServiceResponse) 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 DeleteServiceResponse.ProtoReflect.Descriptor instead.
+func (*DeleteServiceResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{40}
+}
+
+func (x *DeleteServiceResponse) GetDeleted() bool {
+ if x != nil {
+ return x.Deleted
+ }
+ return false
+}
+
+// Persisted sandbox service endpoint.
+type ServiceEndpoint struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Kubernetes-style metadata.
+ Metadata *datamodelv1.ObjectMeta `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"`
+ // Sandbox object ID.
+ SandboxId string `protobuf:"bytes,2,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"`
+ // Sandbox name.
+ SandboxName string `protobuf:"bytes,3,opt,name=sandbox_name,json=sandboxName,proto3" json:"sandbox_name,omitempty"`
+ // Service name within the sandbox.
+ ServiceName string `protobuf:"bytes,4,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"`
+ // Loopback TCP port inside the sandbox.
+ TargetPort uint32 `protobuf:"varint,5,opt,name=target_port,json=targetPort,proto3" json:"target_port,omitempty"`
+ // Whether browser-facing service routing is enabled for this endpoint.
+ Domain bool `protobuf:"varint,6,opt,name=domain,proto3" json:"domain,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ServiceEndpoint) Reset() {
+ *x = ServiceEndpoint{}
+ mi := &file_openshell_proto_msgTypes[41]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ServiceEndpoint) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ServiceEndpoint) ProtoMessage() {}
+
+func (x *ServiceEndpoint) 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 ServiceEndpoint.ProtoReflect.Descriptor instead.
+func (*ServiceEndpoint) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{41}
+}
+
+func (x *ServiceEndpoint) GetMetadata() *datamodelv1.ObjectMeta {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+func (x *ServiceEndpoint) GetSandboxId() string {
+ if x != nil {
+ return x.SandboxId
+ }
+ return ""
+}
+
+func (x *ServiceEndpoint) GetSandboxName() string {
+ if x != nil {
+ return x.SandboxName
+ }
+ return ""
+}
+
+func (x *ServiceEndpoint) GetServiceName() string {
+ if x != nil {
+ return x.ServiceName
+ }
+ return ""
+}
+
+func (x *ServiceEndpoint) GetTargetPort() uint32 {
+ if x != nil {
+ return x.TargetPort
+ }
+ return 0
+}
+
+func (x *ServiceEndpoint) GetDomain() bool {
+ if x != nil {
+ return x.Domain
+ }
+ return false
+}
+
+// Response containing a service endpoint and, when available, its local URL.
+type ServiceEndpointResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Endpoint *ServiceEndpoint `protobuf:"bytes,1,opt,name=endpoint,proto3" json:"endpoint,omitempty"`
+ Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ServiceEndpointResponse) Reset() {
+ *x = ServiceEndpointResponse{}
+ mi := &file_openshell_proto_msgTypes[42]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ServiceEndpointResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ServiceEndpointResponse) ProtoMessage() {}
+
+func (x *ServiceEndpointResponse) 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 ServiceEndpointResponse.ProtoReflect.Descriptor instead.
+func (*ServiceEndpointResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{42}
+}
+
+func (x *ServiceEndpointResponse) GetEndpoint() *ServiceEndpoint {
+ if x != nil {
+ return x.Endpoint
+ }
+ return nil
+}
+
+func (x *ServiceEndpointResponse) GetUrl() string {
+ if x != nil {
+ return x.Url
+ }
+ return ""
+}
+
+// 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[43]
+ 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[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 RevokeSshSessionRequest.ProtoReflect.Descriptor instead.
+func (*RevokeSshSessionRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{43}
+}
+
+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[44]
+ 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[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 RevokeSshSessionResponse.ProtoReflect.Descriptor instead.
+func (*RevokeSshSessionResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{44}
+}
+
+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"`
+ // Request a pseudo-terminal for the remote command.
+ Tty bool `protobuf:"varint,7,opt,name=tty,proto3" json:"tty,omitempty"`
+ // Initial terminal columns (used when tty=true, 0 = use default).
+ Cols uint32 `protobuf:"varint,8,opt,name=cols,proto3" json:"cols,omitempty"`
+ // Initial terminal rows (used when tty=true, 0 = use default).
+ Rows uint32 `protobuf:"varint,9,opt,name=rows,proto3" json:"rows,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ExecSandboxRequest) Reset() {
+ *x = ExecSandboxRequest{}
+ mi := &file_openshell_proto_msgTypes[45]
+ 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[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 ExecSandboxRequest.ProtoReflect.Descriptor instead.
+func (*ExecSandboxRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{45}
+}
+
+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
+}
+
+func (x *ExecSandboxRequest) GetTty() bool {
+ if x != nil {
+ return x.Tty
+ }
+ return false
+}
+
+func (x *ExecSandboxRequest) GetCols() uint32 {
+ if x != nil {
+ return x.Cols
+ }
+ return 0
+}
+
+func (x *ExecSandboxRequest) GetRows() uint32 {
+ if x != nil {
+ return x.Rows
+ }
+ return 0
+}
+
+// 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[46]
+ 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[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 ExecSandboxStdout.ProtoReflect.Descriptor instead.
+func (*ExecSandboxStdout) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{46}
+}
+
+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[47]
+ 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[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 ExecSandboxStderr.ProtoReflect.Descriptor instead.
+func (*ExecSandboxStderr) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{47}
+}
+
+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[48]
+ 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[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 ExecSandboxExit.ProtoReflect.Descriptor instead.
+func (*ExecSandboxExit) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{48}
+}
+
+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[49]
+ 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[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 ExecSandboxEvent.ProtoReflect.Descriptor instead.
+func (*ExecSandboxEvent) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{49}
+}
+
+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() {}
+
+// Initial frame for one TCP forward stream.
+type TcpForwardInit 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"`
+ // Optional service identifier for audit/correlation.
+ ServiceId string `protobuf:"bytes,4,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"`
+ // Target the gateway should request from the supervisor.
+ //
+ // Types that are valid to be assigned to Target:
+ //
+ // *TcpForwardInit_Ssh
+ // *TcpForwardInit_Tcp
+ Target isTcpForwardInit_Target `protobuf_oneof:"target"`
+ // Optional target-specific authorization token. SSH targets use this as the
+ // short-lived SSH session token issued by CreateSshSession.
+ AuthorizationToken string `protobuf:"bytes,7,opt,name=authorization_token,json=authorizationToken,proto3" json:"authorization_token,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *TcpForwardInit) Reset() {
+ *x = TcpForwardInit{}
+ mi := &file_openshell_proto_msgTypes[50]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *TcpForwardInit) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TcpForwardInit) ProtoMessage() {}
+
+func (x *TcpForwardInit) 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 TcpForwardInit.ProtoReflect.Descriptor instead.
+func (*TcpForwardInit) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{50}
+}
+
+func (x *TcpForwardInit) GetSandboxId() string {
+ if x != nil {
+ return x.SandboxId
+ }
+ return ""
+}
+
+func (x *TcpForwardInit) GetServiceId() string {
+ if x != nil {
+ return x.ServiceId
+ }
+ return ""
+}
+
+func (x *TcpForwardInit) GetTarget() isTcpForwardInit_Target {
+ if x != nil {
+ return x.Target
+ }
+ return nil
+}
+
+func (x *TcpForwardInit) GetSsh() *SshRelayTarget {
+ if x != nil {
+ if x, ok := x.Target.(*TcpForwardInit_Ssh); ok {
+ return x.Ssh
+ }
+ }
+ return nil
+}
+
+func (x *TcpForwardInit) GetTcp() *TcpRelayTarget {
+ if x != nil {
+ if x, ok := x.Target.(*TcpForwardInit_Tcp); ok {
+ return x.Tcp
+ }
+ }
+ return nil
+}
+
+func (x *TcpForwardInit) GetAuthorizationToken() string {
+ if x != nil {
+ return x.AuthorizationToken
+ }
+ return ""
+}
+
+type isTcpForwardInit_Target interface {
+ isTcpForwardInit_Target()
+}
+
+type TcpForwardInit_Ssh struct {
+ Ssh *SshRelayTarget `protobuf:"bytes,5,opt,name=ssh,proto3,oneof"`
+}
+
+type TcpForwardInit_Tcp struct {
+ Tcp *TcpRelayTarget `protobuf:"bytes,6,opt,name=tcp,proto3,oneof"`
+}
+
+func (*TcpForwardInit_Ssh) isTcpForwardInit_Target() {}
+
+func (*TcpForwardInit_Tcp) isTcpForwardInit_Target() {}
+
+// A single frame on the CLI-to-gateway TCP forward stream.
+type TcpForwardFrame struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Types that are valid to be assigned to Payload:
+ //
+ // *TcpForwardFrame_Init
+ // *TcpForwardFrame_Data
+ Payload isTcpForwardFrame_Payload `protobuf_oneof:"payload"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *TcpForwardFrame) Reset() {
+ *x = TcpForwardFrame{}
+ mi := &file_openshell_proto_msgTypes[51]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *TcpForwardFrame) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TcpForwardFrame) ProtoMessage() {}
+
+func (x *TcpForwardFrame) 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 TcpForwardFrame.ProtoReflect.Descriptor instead.
+func (*TcpForwardFrame) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{51}
+}
+
+func (x *TcpForwardFrame) GetPayload() isTcpForwardFrame_Payload {
+ if x != nil {
+ return x.Payload
+ }
+ return nil
+}
+
+func (x *TcpForwardFrame) GetInit() *TcpForwardInit {
+ if x != nil {
+ if x, ok := x.Payload.(*TcpForwardFrame_Init); ok {
+ return x.Init
+ }
+ }
+ return nil
+}
+
+func (x *TcpForwardFrame) GetData() []byte {
+ if x != nil {
+ if x, ok := x.Payload.(*TcpForwardFrame_Data); ok {
+ return x.Data
+ }
+ }
+ return nil
+}
+
+type isTcpForwardFrame_Payload interface {
+ isTcpForwardFrame_Payload()
+}
+
+type TcpForwardFrame_Init struct {
+ Init *TcpForwardInit `protobuf:"bytes,1,opt,name=init,proto3,oneof"`
+}
+
+type TcpForwardFrame_Data struct {
+ Data []byte `protobuf:"bytes,2,opt,name=data,proto3,oneof"`
+}
+
+func (*TcpForwardFrame_Init) isTcpForwardFrame_Payload() {}
+
+func (*TcpForwardFrame_Data) isTcpForwardFrame_Payload() {}
+
+// Client-to-server message for interactive exec.
+type ExecSandboxInput struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Types that are valid to be assigned to Payload:
+ //
+ // *ExecSandboxInput_Start
+ // *ExecSandboxInput_Stdin
+ // *ExecSandboxInput_Resize
+ Payload isExecSandboxInput_Payload `protobuf_oneof:"payload"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ExecSandboxInput) Reset() {
+ *x = ExecSandboxInput{}
+ mi := &file_openshell_proto_msgTypes[52]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ExecSandboxInput) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ExecSandboxInput) ProtoMessage() {}
+
+func (x *ExecSandboxInput) 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 ExecSandboxInput.ProtoReflect.Descriptor instead.
+func (*ExecSandboxInput) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{52}
+}
+
+func (x *ExecSandboxInput) GetPayload() isExecSandboxInput_Payload {
+ if x != nil {
+ return x.Payload
+ }
+ return nil
+}
+
+func (x *ExecSandboxInput) GetStart() *ExecSandboxRequest {
+ if x != nil {
+ if x, ok := x.Payload.(*ExecSandboxInput_Start); ok {
+ return x.Start
+ }
+ }
+ return nil
+}
+
+func (x *ExecSandboxInput) GetStdin() []byte {
+ if x != nil {
+ if x, ok := x.Payload.(*ExecSandboxInput_Stdin); ok {
+ return x.Stdin
+ }
+ }
+ return nil
+}
+
+func (x *ExecSandboxInput) GetResize() *ExecSandboxWindowResize {
+ if x != nil {
+ if x, ok := x.Payload.(*ExecSandboxInput_Resize); ok {
+ return x.Resize
+ }
+ }
+ return nil
+}
+
+type isExecSandboxInput_Payload interface {
+ isExecSandboxInput_Payload()
+}
+
+type ExecSandboxInput_Start struct {
+ // First message: exec request metadata.
+ Start *ExecSandboxRequest `protobuf:"bytes,1,opt,name=start,proto3,oneof"`
+}
+
+type ExecSandboxInput_Stdin struct {
+ // Subsequent messages: raw stdin bytes.
+ Stdin []byte `protobuf:"bytes,2,opt,name=stdin,proto3,oneof"`
+}
+
+type ExecSandboxInput_Resize struct {
+ // Terminal window size change.
+ Resize *ExecSandboxWindowResize `protobuf:"bytes,3,opt,name=resize,proto3,oneof"`
+}
+
+func (*ExecSandboxInput_Start) isExecSandboxInput_Payload() {}
+
+func (*ExecSandboxInput_Stdin) isExecSandboxInput_Payload() {}
+
+func (*ExecSandboxInput_Resize) isExecSandboxInput_Payload() {}
+
+// Terminal window resize event for interactive exec.
+type ExecSandboxWindowResize struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Cols uint32 `protobuf:"varint,1,opt,name=cols,proto3" json:"cols,omitempty"`
+ Rows uint32 `protobuf:"varint,2,opt,name=rows,proto3" json:"rows,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ExecSandboxWindowResize) Reset() {
+ *x = ExecSandboxWindowResize{}
+ mi := &file_openshell_proto_msgTypes[53]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ExecSandboxWindowResize) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ExecSandboxWindowResize) ProtoMessage() {}
+
+func (x *ExecSandboxWindowResize) 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 ExecSandboxWindowResize.ProtoReflect.Descriptor instead.
+func (*ExecSandboxWindowResize) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{53}
+}
+
+func (x *ExecSandboxWindowResize) GetCols() uint32 {
+ if x != nil {
+ return x.Cols
+ }
+ return 0
+}
+
+func (x *ExecSandboxWindowResize) GetRows() uint32 {
+ if x != nil {
+ return x.Rows
+ }
+ return 0
+}
+
+// SSH session record stored in persistence.
+type SshSession struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Kubernetes-style metadata (id, name, labels, timestamps, resource version).
+ Metadata *datamodelv1.ObjectMeta `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,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"`
+ // Expiry timestamp in milliseconds since epoch. 0 means no expiry
+ // (backward-compatible default for sessions created before this field existed).
+ ExpiresAtMs int64 `protobuf:"varint,4,opt,name=expires_at_ms,json=expiresAtMs,proto3" json:"expires_at_ms,omitempty"`
+ // Revoked flag.
+ Revoked bool `protobuf:"varint,5,opt,name=revoked,proto3" json:"revoked,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SshSession) Reset() {
+ *x = SshSession{}
+ mi := &file_openshell_proto_msgTypes[54]
+ 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[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 SshSession.ProtoReflect.Descriptor instead.
+func (*SshSession) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{54}
+}
+
+func (x *SshSession) GetMetadata() *datamodelv1.ObjectMeta {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+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) GetExpiresAtMs() int64 {
+ if x != nil {
+ return x.ExpiresAtMs
+ }
+ return 0
+}
+
+func (x *SshSession) GetRevoked() bool {
+ if x != nil {
+ return x.Revoked
+ }
+ return false
+}
+
+// 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[55]
+ 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[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 WatchSandboxRequest.ProtoReflect.Descriptor instead.
+func (*WatchSandboxRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{55}
+}
+
+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[56]
+ 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[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 SandboxStreamEvent.ProtoReflect.Descriptor instead.
+func (*SandboxStreamEvent) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{56}
+}
+
+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[57]
+ 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[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 SandboxLogLine.ProtoReflect.Descriptor instead.
+func (*SandboxLogLine) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{57}
+}
+
+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
+}
+
+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[58]
+ 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[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 SandboxStreamWarning.ProtoReflect.Descriptor instead.
+func (*SandboxStreamWarning) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{58}
+}
+
+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 *datamodelv1.Provider `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"`
+ // Workspace for the provider. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,2,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *CreateProviderRequest) Reset() {
+ *x = CreateProviderRequest{}
+ mi := &file_openshell_proto_msgTypes[59]
+ 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[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 CreateProviderRequest.ProtoReflect.Descriptor instead.
+func (*CreateProviderRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{59}
+}
+
+func (x *CreateProviderRequest) GetProvider() *datamodelv1.Provider {
+ if x != nil {
+ return x.Provider
+ }
+ return nil
+}
+
+func (x *CreateProviderRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+// Get provider request.
+type GetProviderRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,2,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetProviderRequest) Reset() {
+ *x = GetProviderRequest{}
+ mi := &file_openshell_proto_msgTypes[60]
+ 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[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 GetProviderRequest.ProtoReflect.Descriptor instead.
+func (*GetProviderRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{60}
+}
+
+func (x *GetProviderRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *GetProviderRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ 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"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,3,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ // List across all workspaces. Mutually exclusive with workspace.
+ AllWorkspaces bool `protobuf:"varint,4,opt,name=all_workspaces,json=allWorkspaces,proto3" json:"all_workspaces,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ListProvidersRequest) Reset() {
+ *x = ListProvidersRequest{}
+ mi := &file_openshell_proto_msgTypes[61]
+ 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[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 ListProvidersRequest.ProtoReflect.Descriptor instead.
+func (*ListProvidersRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{61}
+}
+
+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
+}
+
+func (x *ListProvidersRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+func (x *ListProvidersRequest) GetAllWorkspaces() bool {
+ if x != nil {
+ return x.AllWorkspaces
+ }
+ return false
+}
+
+// Update provider request.
+type UpdateProviderRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Provider *datamodelv1.Provider `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"`
+ // Optional per-credential expiry timestamps to merge into the provider.
+ // A zero value removes the expiry for that credential.
+ CredentialExpiresAtMs map[string]int64 `protobuf:"bytes,2,rep,name=credential_expires_at_ms,json=credentialExpiresAtMs,proto3" json:"credential_expires_at_ms,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,3,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *UpdateProviderRequest) Reset() {
+ *x = UpdateProviderRequest{}
+ mi := &file_openshell_proto_msgTypes[62]
+ 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[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 UpdateProviderRequest.ProtoReflect.Descriptor instead.
+func (*UpdateProviderRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{62}
+}
+
+func (x *UpdateProviderRequest) GetProvider() *datamodelv1.Provider {
+ if x != nil {
+ return x.Provider
+ }
+ return nil
+}
+
+func (x *UpdateProviderRequest) GetCredentialExpiresAtMs() map[string]int64 {
+ if x != nil {
+ return x.CredentialExpiresAtMs
+ }
+ return nil
+}
+
+func (x *UpdateProviderRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+// Delete provider request.
+type DeleteProviderRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,2,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *DeleteProviderRequest) Reset() {
+ *x = DeleteProviderRequest{}
+ mi := &file_openshell_proto_msgTypes[63]
+ 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[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 DeleteProviderRequest.ProtoReflect.Descriptor instead.
+func (*DeleteProviderRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{63}
+}
+
+func (x *DeleteProviderRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *DeleteProviderRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+// Provider response.
+type ProviderResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Provider *datamodelv1.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[64]
+ 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[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 ProviderResponse.ProtoReflect.Descriptor instead.
+func (*ProviderResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{64}
+}
+
+func (x *ProviderResponse) GetProvider() *datamodelv1.Provider {
+ if x != nil {
+ return x.Provider
+ }
+ return nil
+}
+
+// List providers response.
+type ListProvidersResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Providers []*datamodelv1.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[65]
+ 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[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 ListProvidersResponse.ProtoReflect.Descriptor instead.
+func (*ListProvidersResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{65}
+}
+
+func (x *ListProvidersResponse) GetProviders() []*datamodelv1.Provider {
+ if x != nil {
+ return x.Providers
+ }
+ return nil
+}
+
+// List provider type profiles request.
+type ListProviderProfilesRequest 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"`
+ // Workspace scope. When set, returns workspace-scoped + built-in profiles.
+ // When empty, returns platform-scoped + built-in only.
+ Workspace string `protobuf:"bytes,3,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ListProviderProfilesRequest) Reset() {
+ *x = ListProviderProfilesRequest{}
+ mi := &file_openshell_proto_msgTypes[66]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ListProviderProfilesRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListProviderProfilesRequest) ProtoMessage() {}
+
+func (x *ListProviderProfilesRequest) 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 ListProviderProfilesRequest.ProtoReflect.Descriptor instead.
+func (*ListProviderProfilesRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{66}
+}
+
+func (x *ListProviderProfilesRequest) GetLimit() uint32 {
+ if x != nil {
+ return x.Limit
+ }
+ return 0
+}
+
+func (x *ListProviderProfilesRequest) GetOffset() uint32 {
+ if x != nil {
+ return x.Offset
+ }
+ return 0
+}
+
+func (x *ListProviderProfilesRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+// Fetch provider type profile request.
+type GetProviderProfileRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+ // Workspace scope for two-tier profile resolution. When set, checks
+ // workspace-scoped profiles first, then platform-scoped, then built-in.
+ // When empty, checks platform-scoped then built-in only.
+ Workspace string `protobuf:"bytes,2,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetProviderProfileRequest) Reset() {
+ *x = GetProviderProfileRequest{}
+ mi := &file_openshell_proto_msgTypes[67]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetProviderProfileRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetProviderProfileRequest) ProtoMessage() {}
+
+func (x *GetProviderProfileRequest) 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 GetProviderProfileRequest.ProtoReflect.Descriptor instead.
+func (*GetProviderProfileRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{67}
+}
+
+func (x *GetProviderProfileRequest) GetId() string {
+ if x != nil {
+ return x.Id
+ }
+ return ""
+}
+
+func (x *GetProviderProfileRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+// Provider profile payload with optional source metadata for diagnostics.
+type ProviderProfileImportItem struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Profile *ProviderProfile `protobuf:"bytes,1,opt,name=profile,proto3" json:"profile,omitempty"`
+ Source string `protobuf:"bytes,2,opt,name=source,proto3" json:"source,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ProviderProfileImportItem) Reset() {
+ *x = ProviderProfileImportItem{}
+ mi := &file_openshell_proto_msgTypes[68]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ProviderProfileImportItem) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProviderProfileImportItem) ProtoMessage() {}
+
+func (x *ProviderProfileImportItem) 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 ProviderProfileImportItem.ProtoReflect.Descriptor instead.
+func (*ProviderProfileImportItem) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{68}
+}
+
+func (x *ProviderProfileImportItem) GetProfile() *ProviderProfile {
+ if x != nil {
+ return x.Profile
+ }
+ return nil
+}
+
+func (x *ProviderProfileImportItem) GetSource() string {
+ if x != nil {
+ return x.Source
+ }
+ return ""
+}
+
+// Provider profile validation diagnostic.
+type ProviderProfileDiagnostic struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Source string `protobuf:"bytes,1,opt,name=source,proto3" json:"source,omitempty"`
+ ProfileId string `protobuf:"bytes,2,opt,name=profile_id,json=profileId,proto3" json:"profile_id,omitempty"`
+ Field string `protobuf:"bytes,3,opt,name=field,proto3" json:"field,omitempty"`
+ Message string `protobuf:"bytes,4,opt,name=message,proto3" json:"message,omitempty"`
+ Severity string `protobuf:"bytes,5,opt,name=severity,proto3" json:"severity,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ProviderProfileDiagnostic) Reset() {
+ *x = ProviderProfileDiagnostic{}
+ mi := &file_openshell_proto_msgTypes[69]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ProviderProfileDiagnostic) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProviderProfileDiagnostic) ProtoMessage() {}
+
+func (x *ProviderProfileDiagnostic) 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 ProviderProfileDiagnostic.ProtoReflect.Descriptor instead.
+func (*ProviderProfileDiagnostic) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{69}
+}
+
+func (x *ProviderProfileDiagnostic) GetSource() string {
+ if x != nil {
+ return x.Source
+ }
+ return ""
+}
+
+func (x *ProviderProfileDiagnostic) GetProfileId() string {
+ if x != nil {
+ return x.ProfileId
+ }
+ return ""
+}
+
+func (x *ProviderProfileDiagnostic) GetField() string {
+ if x != nil {
+ return x.Field
+ }
+ return ""
+}
+
+func (x *ProviderProfileDiagnostic) GetMessage() string {
+ if x != nil {
+ return x.Message
+ }
+ return ""
+}
+
+func (x *ProviderProfileDiagnostic) GetSeverity() string {
+ if x != nil {
+ return x.Severity
+ }
+ return ""
+}
+
+// Endpoint selector for token grant audience overrides.
+type ProviderCredentialTokenGrantAudienceOverride struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Optional: endpoint host selector. If omitted, inherits the profile endpoint host.
+ Host string `protobuf:"bytes,1,opt,name=host,proto3" json:"host,omitempty"`
+ // Optional: endpoint port selector. If omitted, matches the expanded profile endpoint port.
+ Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
+ // Optional: endpoint path selector. If omitted, inherits the profile endpoint path.
+ Path string `protobuf:"bytes,3,opt,name=path,proto3" json:"path,omitempty"`
+ // Resource audience to request for matching endpoints.
+ Audience string `protobuf:"bytes,4,opt,name=audience,proto3" json:"audience,omitempty"`
+ // Optional: OAuth2 scopes to request. If omitted, inherits the token grant scopes.
+ Scopes []string `protobuf:"bytes,5,rep,name=scopes,proto3" json:"scopes,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ProviderCredentialTokenGrantAudienceOverride) Reset() {
+ *x = ProviderCredentialTokenGrantAudienceOverride{}
+ mi := &file_openshell_proto_msgTypes[70]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ProviderCredentialTokenGrantAudienceOverride) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProviderCredentialTokenGrantAudienceOverride) ProtoMessage() {}
+
+func (x *ProviderCredentialTokenGrantAudienceOverride) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[70]
+ 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 ProviderCredentialTokenGrantAudienceOverride.ProtoReflect.Descriptor instead.
+func (*ProviderCredentialTokenGrantAudienceOverride) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{70}
+}
+
+func (x *ProviderCredentialTokenGrantAudienceOverride) GetHost() string {
+ if x != nil {
+ return x.Host
+ }
+ return ""
+}
+
+func (x *ProviderCredentialTokenGrantAudienceOverride) GetPort() uint32 {
+ if x != nil {
+ return x.Port
+ }
+ return 0
+}
+
+func (x *ProviderCredentialTokenGrantAudienceOverride) GetPath() string {
+ if x != nil {
+ return x.Path
+ }
+ return ""
+}
+
+func (x *ProviderCredentialTokenGrantAudienceOverride) GetAudience() string {
+ if x != nil {
+ return x.Audience
+ }
+ return ""
+}
+
+func (x *ProviderCredentialTokenGrantAudienceOverride) GetScopes() []string {
+ if x != nil {
+ return x.Scopes
+ }
+ return nil
+}
+
+// Provider credential token grant configuration.
+// When present, the credential is obtained dynamically via OAuth2 grant when needed.
+type ProviderCredentialTokenGrant struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // OAuth2 token endpoint URL (e.g., https://keycloak.example.com/realms/my-realm/protocol/openid-connect/token)
+ TokenEndpoint string `protobuf:"bytes,1,opt,name=token_endpoint,json=tokenEndpoint,proto3" json:"token_endpoint,omitempty"`
+ // Optional: default resource audience to request from the token service
+ Audience string `protobuf:"bytes,2,opt,name=audience,proto3" json:"audience,omitempty"`
+ // Optional: audience to request when fetching the JWT-SVID from SPIRE.
+ // If omitted, the sandbox derives this from token_endpoint.
+ JwtSvidAudience string `protobuf:"bytes,6,opt,name=jwt_svid_audience,json=jwtSvidAudience,proto3" json:"jwt_svid_audience,omitempty"`
+ // Optional: OAuth2 scopes to request
+ Scopes []string `protobuf:"bytes,3,rep,name=scopes,proto3" json:"scopes,omitempty"`
+ // Optional: override token cache TTL (seconds)
+ // If 0 or omitted, use expires_in from token response
+ CacheTtlSeconds int64 `protobuf:"varint,4,opt,name=cache_ttl_seconds,json=cacheTtlSeconds,proto3" json:"cache_ttl_seconds,omitempty"`
+ // Optional: endpoint-specific resource audience overrides.
+ AudienceOverrides []*ProviderCredentialTokenGrantAudienceOverride `protobuf:"bytes,5,rep,name=audience_overrides,json=audienceOverrides,proto3" json:"audience_overrides,omitempty"`
+ // Optional: OAuth2 client_assertion_type value. If omitted, OpenShell uses
+ // urn:ietf:params:oauth:client-assertion-type:jwt-bearer.
+ ClientAssertionType string `protobuf:"bytes,7,opt,name=client_assertion_type,json=clientAssertionType,proto3" json:"client_assertion_type,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ProviderCredentialTokenGrant) Reset() {
+ *x = ProviderCredentialTokenGrant{}
+ mi := &file_openshell_proto_msgTypes[71]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ProviderCredentialTokenGrant) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProviderCredentialTokenGrant) ProtoMessage() {}
+
+func (x *ProviderCredentialTokenGrant) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[71]
+ 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 ProviderCredentialTokenGrant.ProtoReflect.Descriptor instead.
+func (*ProviderCredentialTokenGrant) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{71}
+}
+
+func (x *ProviderCredentialTokenGrant) GetTokenEndpoint() string {
+ if x != nil {
+ return x.TokenEndpoint
+ }
+ return ""
+}
+
+func (x *ProviderCredentialTokenGrant) GetAudience() string {
+ if x != nil {
+ return x.Audience
+ }
+ return ""
+}
+
+func (x *ProviderCredentialTokenGrant) GetJwtSvidAudience() string {
+ if x != nil {
+ return x.JwtSvidAudience
+ }
+ return ""
+}
+
+func (x *ProviderCredentialTokenGrant) GetScopes() []string {
+ if x != nil {
+ return x.Scopes
+ }
+ return nil
+}
+
+func (x *ProviderCredentialTokenGrant) GetCacheTtlSeconds() int64 {
+ if x != nil {
+ return x.CacheTtlSeconds
+ }
+ return 0
+}
+
+func (x *ProviderCredentialTokenGrant) GetAudienceOverrides() []*ProviderCredentialTokenGrantAudienceOverride {
+ if x != nil {
+ return x.AudienceOverrides
+ }
+ return nil
+}
+
+func (x *ProviderCredentialTokenGrant) GetClientAssertionType() string {
+ if x != nil {
+ return x.ClientAssertionType
+ }
+ return ""
+}
+
+// Provider credential declaration.
+type ProviderProfileCredential struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
+ EnvVars []string `protobuf:"bytes,3,rep,name=env_vars,json=envVars,proto3" json:"env_vars,omitempty"`
+ Required bool `protobuf:"varint,4,opt,name=required,proto3" json:"required,omitempty"`
+ AuthStyle string `protobuf:"bytes,5,opt,name=auth_style,json=authStyle,proto3" json:"auth_style,omitempty"`
+ HeaderName string `protobuf:"bytes,6,opt,name=header_name,json=headerName,proto3" json:"header_name,omitempty"`
+ QueryParam string `protobuf:"bytes,7,opt,name=query_param,json=queryParam,proto3" json:"query_param,omitempty"`
+ Refresh *ProviderCredentialRefresh `protobuf:"bytes,8,opt,name=refresh,proto3" json:"refresh,omitempty"`
+ PathTemplate string `protobuf:"bytes,9,opt,name=path_template,json=pathTemplate,proto3" json:"path_template,omitempty"`
+ TokenGrant *ProviderCredentialTokenGrant `protobuf:"bytes,10,opt,name=token_grant,json=tokenGrant,proto3" json:"token_grant,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ProviderProfileCredential) Reset() {
+ *x = ProviderProfileCredential{}
+ mi := &file_openshell_proto_msgTypes[72]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ProviderProfileCredential) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProviderProfileCredential) ProtoMessage() {}
+
+func (x *ProviderProfileCredential) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[72]
+ 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 ProviderProfileCredential.ProtoReflect.Descriptor instead.
+func (*ProviderProfileCredential) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{72}
+}
+
+func (x *ProviderProfileCredential) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *ProviderProfileCredential) GetDescription() string {
+ if x != nil {
+ return x.Description
+ }
+ return ""
+}
+
+func (x *ProviderProfileCredential) GetEnvVars() []string {
+ if x != nil {
+ return x.EnvVars
+ }
+ return nil
+}
+
+func (x *ProviderProfileCredential) GetRequired() bool {
+ if x != nil {
+ return x.Required
+ }
+ return false
+}
+
+func (x *ProviderProfileCredential) GetAuthStyle() string {
+ if x != nil {
+ return x.AuthStyle
+ }
+ return ""
+}
+
+func (x *ProviderProfileCredential) GetHeaderName() string {
+ if x != nil {
+ return x.HeaderName
+ }
+ return ""
+}
+
+func (x *ProviderProfileCredential) GetQueryParam() string {
+ if x != nil {
+ return x.QueryParam
+ }
+ return ""
+}
+
+func (x *ProviderProfileCredential) GetRefresh() *ProviderCredentialRefresh {
+ if x != nil {
+ return x.Refresh
+ }
+ return nil
+}
+
+func (x *ProviderProfileCredential) GetPathTemplate() string {
+ if x != nil {
+ return x.PathTemplate
+ }
+ return ""
+}
+
+func (x *ProviderProfileCredential) GetTokenGrant() *ProviderCredentialTokenGrant {
+ if x != nil {
+ return x.TokenGrant
+ }
+ return nil
+}
+
+type ProviderCredentialRefreshMaterial struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
+ Required bool `protobuf:"varint,3,opt,name=required,proto3" json:"required,omitempty"`
+ Secret bool `protobuf:"varint,4,opt,name=secret,proto3" json:"secret,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ProviderCredentialRefreshMaterial) Reset() {
+ *x = ProviderCredentialRefreshMaterial{}
+ mi := &file_openshell_proto_msgTypes[73]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ProviderCredentialRefreshMaterial) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProviderCredentialRefreshMaterial) ProtoMessage() {}
+
+func (x *ProviderCredentialRefreshMaterial) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[73]
+ 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 ProviderCredentialRefreshMaterial.ProtoReflect.Descriptor instead.
+func (*ProviderCredentialRefreshMaterial) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{73}
+}
+
+func (x *ProviderCredentialRefreshMaterial) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *ProviderCredentialRefreshMaterial) GetDescription() string {
+ if x != nil {
+ return x.Description
+ }
+ return ""
+}
+
+func (x *ProviderCredentialRefreshMaterial) GetRequired() bool {
+ if x != nil {
+ return x.Required
+ }
+ return false
+}
+
+func (x *ProviderCredentialRefreshMaterial) GetSecret() bool {
+ if x != nil {
+ return x.Secret
+ }
+ return false
+}
+
+// Declares that a single refresh operation mints more than one credential.
+// The refresh is attached to a primary credential; each additional output
+// maps a strategy-defined semantic output id to a sibling credential whose
+// env_vars receive the minted value.
+type ProviderCredentialRefreshOutput struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Output string `protobuf:"bytes,1,opt,name=output,proto3" json:"output,omitempty"` // strategy-defined semantic output id (e.g. "session_token")
+ Credential string `protobuf:"bytes,2,opt,name=credential,proto3" json:"credential,omitempty"` // sibling credential name whose env_vars receive this output
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ProviderCredentialRefreshOutput) Reset() {
+ *x = ProviderCredentialRefreshOutput{}
+ mi := &file_openshell_proto_msgTypes[74]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ProviderCredentialRefreshOutput) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProviderCredentialRefreshOutput) ProtoMessage() {}
+
+func (x *ProviderCredentialRefreshOutput) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[74]
+ 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 ProviderCredentialRefreshOutput.ProtoReflect.Descriptor instead.
+func (*ProviderCredentialRefreshOutput) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{74}
+}
+
+func (x *ProviderCredentialRefreshOutput) GetOutput() string {
+ if x != nil {
+ return x.Output
+ }
+ return ""
+}
+
+func (x *ProviderCredentialRefreshOutput) GetCredential() string {
+ if x != nil {
+ return x.Credential
+ }
+ return ""
+}
+
+type ProviderCredentialRefresh struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Strategy ProviderCredentialRefreshStrategy `protobuf:"varint,1,opt,name=strategy,proto3,enum=openshell.v1.ProviderCredentialRefreshStrategy" json:"strategy,omitempty"`
+ TokenUrl string `protobuf:"bytes,2,opt,name=token_url,json=tokenUrl,proto3" json:"token_url,omitempty"`
+ Scopes []string `protobuf:"bytes,3,rep,name=scopes,proto3" json:"scopes,omitempty"`
+ RefreshBeforeSeconds int64 `protobuf:"varint,4,opt,name=refresh_before_seconds,json=refreshBeforeSeconds,proto3" json:"refresh_before_seconds,omitempty"`
+ MaxLifetimeSeconds int64 `protobuf:"varint,5,opt,name=max_lifetime_seconds,json=maxLifetimeSeconds,proto3" json:"max_lifetime_seconds,omitempty"`
+ Material []*ProviderCredentialRefreshMaterial `protobuf:"bytes,6,rep,name=material,proto3" json:"material,omitempty"`
+ AdditionalOutputs []*ProviderCredentialRefreshOutput `protobuf:"bytes,7,rep,name=additional_outputs,json=additionalOutputs,proto3" json:"additional_outputs,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ProviderCredentialRefresh) Reset() {
+ *x = ProviderCredentialRefresh{}
+ mi := &file_openshell_proto_msgTypes[75]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ProviderCredentialRefresh) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProviderCredentialRefresh) ProtoMessage() {}
+
+func (x *ProviderCredentialRefresh) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[75]
+ 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 ProviderCredentialRefresh.ProtoReflect.Descriptor instead.
+func (*ProviderCredentialRefresh) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{75}
+}
+
+func (x *ProviderCredentialRefresh) GetStrategy() ProviderCredentialRefreshStrategy {
+ if x != nil {
+ return x.Strategy
+ }
+ return ProviderCredentialRefreshStrategy_PROVIDER_CREDENTIAL_REFRESH_STRATEGY_UNSPECIFIED
+}
+
+func (x *ProviderCredentialRefresh) GetTokenUrl() string {
+ if x != nil {
+ return x.TokenUrl
+ }
+ return ""
+}
+
+func (x *ProviderCredentialRefresh) GetScopes() []string {
+ if x != nil {
+ return x.Scopes
+ }
+ return nil
+}
+
+func (x *ProviderCredentialRefresh) GetRefreshBeforeSeconds() int64 {
+ if x != nil {
+ return x.RefreshBeforeSeconds
+ }
+ return 0
+}
+
+func (x *ProviderCredentialRefresh) GetMaxLifetimeSeconds() int64 {
+ if x != nil {
+ return x.MaxLifetimeSeconds
+ }
+ return 0
+}
+
+func (x *ProviderCredentialRefresh) GetMaterial() []*ProviderCredentialRefreshMaterial {
+ if x != nil {
+ return x.Material
+ }
+ return nil
+}
+
+func (x *ProviderCredentialRefresh) GetAdditionalOutputs() []*ProviderCredentialRefreshOutput {
+ if x != nil {
+ return x.AdditionalOutputs
+ }
+ return nil
+}
+
+type ProviderCredentialRefreshStatus struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ ProviderName string `protobuf:"bytes,1,opt,name=provider_name,json=providerName,proto3" json:"provider_name,omitempty"`
+ ProviderId string `protobuf:"bytes,2,opt,name=provider_id,json=providerId,proto3" json:"provider_id,omitempty"`
+ CredentialKey string `protobuf:"bytes,3,opt,name=credential_key,json=credentialKey,proto3" json:"credential_key,omitempty"`
+ Strategy ProviderCredentialRefreshStrategy `protobuf:"varint,4,opt,name=strategy,proto3,enum=openshell.v1.ProviderCredentialRefreshStrategy" json:"strategy,omitempty"`
+ Status string `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"`
+ ExpiresAtMs int64 `protobuf:"varint,6,opt,name=expires_at_ms,json=expiresAtMs,proto3" json:"expires_at_ms,omitempty"`
+ NextRefreshAtMs int64 `protobuf:"varint,7,opt,name=next_refresh_at_ms,json=nextRefreshAtMs,proto3" json:"next_refresh_at_ms,omitempty"`
+ LastRefreshAtMs int64 `protobuf:"varint,8,opt,name=last_refresh_at_ms,json=lastRefreshAtMs,proto3" json:"last_refresh_at_ms,omitempty"`
+ LastError string `protobuf:"bytes,9,opt,name=last_error,json=lastError,proto3" json:"last_error,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ProviderCredentialRefreshStatus) Reset() {
+ *x = ProviderCredentialRefreshStatus{}
+ mi := &file_openshell_proto_msgTypes[76]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ProviderCredentialRefreshStatus) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProviderCredentialRefreshStatus) ProtoMessage() {}
+
+func (x *ProviderCredentialRefreshStatus) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[76]
+ 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 ProviderCredentialRefreshStatus.ProtoReflect.Descriptor instead.
+func (*ProviderCredentialRefreshStatus) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{76}
+}
+
+func (x *ProviderCredentialRefreshStatus) GetProviderName() string {
+ if x != nil {
+ return x.ProviderName
+ }
+ return ""
+}
+
+func (x *ProviderCredentialRefreshStatus) GetProviderId() string {
+ if x != nil {
+ return x.ProviderId
+ }
+ return ""
+}
+
+func (x *ProviderCredentialRefreshStatus) GetCredentialKey() string {
+ if x != nil {
+ return x.CredentialKey
+ }
+ return ""
+}
+
+func (x *ProviderCredentialRefreshStatus) GetStrategy() ProviderCredentialRefreshStrategy {
+ if x != nil {
+ return x.Strategy
+ }
+ return ProviderCredentialRefreshStrategy_PROVIDER_CREDENTIAL_REFRESH_STRATEGY_UNSPECIFIED
+}
+
+func (x *ProviderCredentialRefreshStatus) GetStatus() string {
+ if x != nil {
+ return x.Status
+ }
+ return ""
+}
+
+func (x *ProviderCredentialRefreshStatus) GetExpiresAtMs() int64 {
+ if x != nil {
+ return x.ExpiresAtMs
+ }
+ return 0
+}
+
+func (x *ProviderCredentialRefreshStatus) GetNextRefreshAtMs() int64 {
+ if x != nil {
+ return x.NextRefreshAtMs
+ }
+ return 0
+}
+
+func (x *ProviderCredentialRefreshStatus) GetLastRefreshAtMs() int64 {
+ if x != nil {
+ return x.LastRefreshAtMs
+ }
+ return 0
+}
+
+func (x *ProviderCredentialRefreshStatus) GetLastError() string {
+ if x != nil {
+ return x.LastError
+ }
+ return ""
+}
+
+// Provider profile local discovery declaration.
+type ProviderProfileDiscovery struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Credential names from ProviderProfile.credentials eligible for local discovery.
+ Credentials []string `protobuf:"bytes,1,rep,name=credentials,proto3" json:"credentials,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ProviderProfileDiscovery) Reset() {
+ *x = ProviderProfileDiscovery{}
+ mi := &file_openshell_proto_msgTypes[77]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ProviderProfileDiscovery) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProviderProfileDiscovery) ProtoMessage() {}
+
+func (x *ProviderProfileDiscovery) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[77]
+ 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 ProviderProfileDiscovery.ProtoReflect.Descriptor instead.
+func (*ProviderProfileDiscovery) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{77}
+}
+
+func (x *ProviderProfileDiscovery) GetCredentials() []string {
+ if x != nil {
+ return x.Credentials
+ }
+ return nil
+}
+
+type StoredProviderCredentialRefreshState struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Metadata *datamodelv1.ObjectMeta `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"`
+ ProviderId string `protobuf:"bytes,2,opt,name=provider_id,json=providerId,proto3" json:"provider_id,omitempty"`
+ ProviderName string `protobuf:"bytes,3,opt,name=provider_name,json=providerName,proto3" json:"provider_name,omitempty"`
+ CredentialKey string `protobuf:"bytes,4,opt,name=credential_key,json=credentialKey,proto3" json:"credential_key,omitempty"`
+ Strategy ProviderCredentialRefreshStrategy `protobuf:"varint,5,opt,name=strategy,proto3,enum=openshell.v1.ProviderCredentialRefreshStrategy" json:"strategy,omitempty"`
+ Material map[string]string `protobuf:"bytes,6,rep,name=material,proto3" json:"material,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ SecretMaterialKeys []string `protobuf:"bytes,7,rep,name=secret_material_keys,json=secretMaterialKeys,proto3" json:"secret_material_keys,omitempty"`
+ ExpiresAtMs int64 `protobuf:"varint,8,opt,name=expires_at_ms,json=expiresAtMs,proto3" json:"expires_at_ms,omitempty"`
+ NextRefreshAtMs int64 `protobuf:"varint,9,opt,name=next_refresh_at_ms,json=nextRefreshAtMs,proto3" json:"next_refresh_at_ms,omitempty"`
+ LastRefreshAtMs int64 `protobuf:"varint,10,opt,name=last_refresh_at_ms,json=lastRefreshAtMs,proto3" json:"last_refresh_at_ms,omitempty"`
+ Status string `protobuf:"bytes,11,opt,name=status,proto3" json:"status,omitempty"`
+ LastError string `protobuf:"bytes,12,opt,name=last_error,json=lastError,proto3" json:"last_error,omitempty"`
+ TokenUrl string `protobuf:"bytes,13,opt,name=token_url,json=tokenUrl,proto3" json:"token_url,omitempty"`
+ Scopes []string `protobuf:"bytes,14,rep,name=scopes,proto3" json:"scopes,omitempty"`
+ RefreshBeforeSeconds int64 `protobuf:"varint,15,opt,name=refresh_before_seconds,json=refreshBeforeSeconds,proto3" json:"refresh_before_seconds,omitempty"`
+ MaxLifetimeSeconds int64 `protobuf:"varint,16,opt,name=max_lifetime_seconds,json=maxLifetimeSeconds,proto3" json:"max_lifetime_seconds,omitempty"`
+ // Resolved mapping of strategy-defined output id -> concrete env key, pinned
+ // at configure time from the profile's additional_outputs. Read by minting,
+ // collision reservation, and env-key surfacing so later profile edits cannot
+ // silently redirect writes.
+ AdditionalOutputKeys map[string]string `protobuf:"bytes,17,rep,name=additional_output_keys,json=additionalOutputKeys,proto3" json:"additional_output_keys,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *StoredProviderCredentialRefreshState) Reset() {
+ *x = StoredProviderCredentialRefreshState{}
+ mi := &file_openshell_proto_msgTypes[78]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *StoredProviderCredentialRefreshState) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StoredProviderCredentialRefreshState) ProtoMessage() {}
+
+func (x *StoredProviderCredentialRefreshState) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[78]
+ 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 StoredProviderCredentialRefreshState.ProtoReflect.Descriptor instead.
+func (*StoredProviderCredentialRefreshState) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{78}
+}
+
+func (x *StoredProviderCredentialRefreshState) GetMetadata() *datamodelv1.ObjectMeta {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+func (x *StoredProviderCredentialRefreshState) GetProviderId() string {
+ if x != nil {
+ return x.ProviderId
+ }
+ return ""
+}
+
+func (x *StoredProviderCredentialRefreshState) GetProviderName() string {
+ if x != nil {
+ return x.ProviderName
+ }
+ return ""
+}
+
+func (x *StoredProviderCredentialRefreshState) GetCredentialKey() string {
+ if x != nil {
+ return x.CredentialKey
+ }
+ return ""
+}
+
+func (x *StoredProviderCredentialRefreshState) GetStrategy() ProviderCredentialRefreshStrategy {
+ if x != nil {
+ return x.Strategy
+ }
+ return ProviderCredentialRefreshStrategy_PROVIDER_CREDENTIAL_REFRESH_STRATEGY_UNSPECIFIED
+}
+
+func (x *StoredProviderCredentialRefreshState) GetMaterial() map[string]string {
+ if x != nil {
+ return x.Material
+ }
+ return nil
+}
+
+func (x *StoredProviderCredentialRefreshState) GetSecretMaterialKeys() []string {
+ if x != nil {
+ return x.SecretMaterialKeys
+ }
+ return nil
+}
+
+func (x *StoredProviderCredentialRefreshState) GetExpiresAtMs() int64 {
+ if x != nil {
+ return x.ExpiresAtMs
+ }
+ return 0
+}
+
+func (x *StoredProviderCredentialRefreshState) GetNextRefreshAtMs() int64 {
+ if x != nil {
+ return x.NextRefreshAtMs
+ }
+ return 0
+}
+
+func (x *StoredProviderCredentialRefreshState) GetLastRefreshAtMs() int64 {
+ if x != nil {
+ return x.LastRefreshAtMs
+ }
+ return 0
+}
+
+func (x *StoredProviderCredentialRefreshState) GetStatus() string {
+ if x != nil {
+ return x.Status
+ }
+ return ""
+}
+
+func (x *StoredProviderCredentialRefreshState) GetLastError() string {
+ if x != nil {
+ return x.LastError
+ }
+ return ""
+}
+
+func (x *StoredProviderCredentialRefreshState) GetTokenUrl() string {
+ if x != nil {
+ return x.TokenUrl
+ }
+ return ""
+}
+
+func (x *StoredProviderCredentialRefreshState) GetScopes() []string {
+ if x != nil {
+ return x.Scopes
+ }
+ return nil
+}
+
+func (x *StoredProviderCredentialRefreshState) GetRefreshBeforeSeconds() int64 {
+ if x != nil {
+ return x.RefreshBeforeSeconds
+ }
+ return 0
+}
+
+func (x *StoredProviderCredentialRefreshState) GetMaxLifetimeSeconds() int64 {
+ if x != nil {
+ return x.MaxLifetimeSeconds
+ }
+ return 0
+}
+
+func (x *StoredProviderCredentialRefreshState) GetAdditionalOutputKeys() map[string]string {
+ if x != nil {
+ return x.AdditionalOutputKeys
+ }
+ return nil
+}
+
+type GetProviderRefreshStatusRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Provider string `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"`
+ CredentialKey string `protobuf:"bytes,2,opt,name=credential_key,json=credentialKey,proto3" json:"credential_key,omitempty"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,3,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetProviderRefreshStatusRequest) Reset() {
+ *x = GetProviderRefreshStatusRequest{}
+ mi := &file_openshell_proto_msgTypes[79]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetProviderRefreshStatusRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetProviderRefreshStatusRequest) ProtoMessage() {}
+
+func (x *GetProviderRefreshStatusRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[79]
+ 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 GetProviderRefreshStatusRequest.ProtoReflect.Descriptor instead.
+func (*GetProviderRefreshStatusRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{79}
+}
+
+func (x *GetProviderRefreshStatusRequest) GetProvider() string {
+ if x != nil {
+ return x.Provider
+ }
+ return ""
+}
+
+func (x *GetProviderRefreshStatusRequest) GetCredentialKey() string {
+ if x != nil {
+ return x.CredentialKey
+ }
+ return ""
+}
+
+func (x *GetProviderRefreshStatusRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+type GetProviderRefreshStatusResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Credentials []*ProviderCredentialRefreshStatus `protobuf:"bytes,1,rep,name=credentials,proto3" json:"credentials,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetProviderRefreshStatusResponse) Reset() {
+ *x = GetProviderRefreshStatusResponse{}
+ mi := &file_openshell_proto_msgTypes[80]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetProviderRefreshStatusResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetProviderRefreshStatusResponse) ProtoMessage() {}
+
+func (x *GetProviderRefreshStatusResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[80]
+ 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 GetProviderRefreshStatusResponse.ProtoReflect.Descriptor instead.
+func (*GetProviderRefreshStatusResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{80}
+}
+
+func (x *GetProviderRefreshStatusResponse) GetCredentials() []*ProviderCredentialRefreshStatus {
+ if x != nil {
+ return x.Credentials
+ }
+ return nil
+}
+
+type ConfigureProviderRefreshRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Provider string `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"`
+ CredentialKey string `protobuf:"bytes,2,opt,name=credential_key,json=credentialKey,proto3" json:"credential_key,omitempty"`
+ Strategy ProviderCredentialRefreshStrategy `protobuf:"varint,3,opt,name=strategy,proto3,enum=openshell.v1.ProviderCredentialRefreshStrategy" json:"strategy,omitempty"`
+ Material map[string]string `protobuf:"bytes,4,rep,name=material,proto3" json:"material,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ SecretMaterialKeys []string `protobuf:"bytes,5,rep,name=secret_material_keys,json=secretMaterialKeys,proto3" json:"secret_material_keys,omitempty"`
+ ExpiresAtMs *int64 `protobuf:"varint,6,opt,name=expires_at_ms,json=expiresAtMs,proto3,oneof" json:"expires_at_ms,omitempty"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,7,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ConfigureProviderRefreshRequest) Reset() {
+ *x = ConfigureProviderRefreshRequest{}
+ mi := &file_openshell_proto_msgTypes[81]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ConfigureProviderRefreshRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ConfigureProviderRefreshRequest) ProtoMessage() {}
+
+func (x *ConfigureProviderRefreshRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[81]
+ 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 ConfigureProviderRefreshRequest.ProtoReflect.Descriptor instead.
+func (*ConfigureProviderRefreshRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{81}
+}
+
+func (x *ConfigureProviderRefreshRequest) GetProvider() string {
+ if x != nil {
+ return x.Provider
+ }
+ return ""
+}
+
+func (x *ConfigureProviderRefreshRequest) GetCredentialKey() string {
+ if x != nil {
+ return x.CredentialKey
+ }
+ return ""
+}
+
+func (x *ConfigureProviderRefreshRequest) GetStrategy() ProviderCredentialRefreshStrategy {
+ if x != nil {
+ return x.Strategy
+ }
+ return ProviderCredentialRefreshStrategy_PROVIDER_CREDENTIAL_REFRESH_STRATEGY_UNSPECIFIED
+}
+
+func (x *ConfigureProviderRefreshRequest) GetMaterial() map[string]string {
+ if x != nil {
+ return x.Material
+ }
+ return nil
+}
+
+func (x *ConfigureProviderRefreshRequest) GetSecretMaterialKeys() []string {
+ if x != nil {
+ return x.SecretMaterialKeys
+ }
+ return nil
+}
+
+func (x *ConfigureProviderRefreshRequest) GetExpiresAtMs() int64 {
+ if x != nil && x.ExpiresAtMs != nil {
+ return *x.ExpiresAtMs
+ }
+ return 0
+}
+
+func (x *ConfigureProviderRefreshRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+type ConfigureProviderRefreshResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Status *ProviderCredentialRefreshStatus `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ConfigureProviderRefreshResponse) Reset() {
+ *x = ConfigureProviderRefreshResponse{}
+ mi := &file_openshell_proto_msgTypes[82]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ConfigureProviderRefreshResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ConfigureProviderRefreshResponse) ProtoMessage() {}
+
+func (x *ConfigureProviderRefreshResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[82]
+ 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 ConfigureProviderRefreshResponse.ProtoReflect.Descriptor instead.
+func (*ConfigureProviderRefreshResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{82}
+}
+
+func (x *ConfigureProviderRefreshResponse) GetStatus() *ProviderCredentialRefreshStatus {
+ if x != nil {
+ return x.Status
+ }
+ return nil
+}
+
+type RotateProviderCredentialRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Provider string `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"`
+ CredentialKey string `protobuf:"bytes,2,opt,name=credential_key,json=credentialKey,proto3" json:"credential_key,omitempty"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,3,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RotateProviderCredentialRequest) Reset() {
+ *x = RotateProviderCredentialRequest{}
+ mi := &file_openshell_proto_msgTypes[83]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RotateProviderCredentialRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RotateProviderCredentialRequest) ProtoMessage() {}
+
+func (x *RotateProviderCredentialRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[83]
+ 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 RotateProviderCredentialRequest.ProtoReflect.Descriptor instead.
+func (*RotateProviderCredentialRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{83}
+}
+
+func (x *RotateProviderCredentialRequest) GetProvider() string {
+ if x != nil {
+ return x.Provider
+ }
+ return ""
+}
+
+func (x *RotateProviderCredentialRequest) GetCredentialKey() string {
+ if x != nil {
+ return x.CredentialKey
+ }
+ return ""
+}
+
+func (x *RotateProviderCredentialRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+type RotateProviderCredentialResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Status *ProviderCredentialRefreshStatus `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RotateProviderCredentialResponse) Reset() {
+ *x = RotateProviderCredentialResponse{}
+ mi := &file_openshell_proto_msgTypes[84]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RotateProviderCredentialResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RotateProviderCredentialResponse) ProtoMessage() {}
+
+func (x *RotateProviderCredentialResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[84]
+ 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 RotateProviderCredentialResponse.ProtoReflect.Descriptor instead.
+func (*RotateProviderCredentialResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{84}
+}
+
+func (x *RotateProviderCredentialResponse) GetStatus() *ProviderCredentialRefreshStatus {
+ if x != nil {
+ return x.Status
+ }
+ return nil
+}
+
+type DeleteProviderRefreshRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Provider string `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"`
+ CredentialKey string `protobuf:"bytes,2,opt,name=credential_key,json=credentialKey,proto3" json:"credential_key,omitempty"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,3,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *DeleteProviderRefreshRequest) Reset() {
+ *x = DeleteProviderRefreshRequest{}
+ mi := &file_openshell_proto_msgTypes[85]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *DeleteProviderRefreshRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeleteProviderRefreshRequest) ProtoMessage() {}
+
+func (x *DeleteProviderRefreshRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[85]
+ 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 DeleteProviderRefreshRequest.ProtoReflect.Descriptor instead.
+func (*DeleteProviderRefreshRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{85}
+}
+
+func (x *DeleteProviderRefreshRequest) GetProvider() string {
+ if x != nil {
+ return x.Provider
+ }
+ return ""
+}
+
+func (x *DeleteProviderRefreshRequest) GetCredentialKey() string {
+ if x != nil {
+ return x.CredentialKey
+ }
+ return ""
+}
+
+func (x *DeleteProviderRefreshRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+type DeleteProviderRefreshResponse 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 *DeleteProviderRefreshResponse) Reset() {
+ *x = DeleteProviderRefreshResponse{}
+ mi := &file_openshell_proto_msgTypes[86]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *DeleteProviderRefreshResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeleteProviderRefreshResponse) ProtoMessage() {}
+
+func (x *DeleteProviderRefreshResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[86]
+ 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 DeleteProviderRefreshResponse.ProtoReflect.Descriptor instead.
+func (*DeleteProviderRefreshResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{86}
+}
+
+func (x *DeleteProviderRefreshResponse) GetDeleted() bool {
+ if x != nil {
+ return x.Deleted
+ }
+ return false
+}
+
+// Provider type profile metadata exposed to clients.
+type ProviderProfile struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+ DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"`
+ Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"`
+ Category ProviderProfileCategory `protobuf:"varint,4,opt,name=category,proto3,enum=openshell.v1.ProviderProfileCategory" json:"category,omitempty"`
+ Credentials []*ProviderProfileCredential `protobuf:"bytes,5,rep,name=credentials,proto3" json:"credentials,omitempty"`
+ Endpoints []*sandboxv1.NetworkEndpoint `protobuf:"bytes,6,rep,name=endpoints,proto3" json:"endpoints,omitempty"`
+ Binaries []*sandboxv1.NetworkBinary `protobuf:"bytes,7,rep,name=binaries,proto3" json:"binaries,omitempty"`
+ InferenceCapable bool `protobuf:"varint,8,opt,name=inference_capable,json=inferenceCapable,proto3" json:"inference_capable,omitempty"`
+ Discovery *ProviderProfileDiscovery `protobuf:"bytes,9,opt,name=discovery,proto3" json:"discovery,omitempty"`
+ // Storage resource version for custom profiles. Built-in profiles and new
+ // profile files use 0. Gateway responses set this for stored custom profiles.
+ // Update calls use this for optimistic concurrency.
+ ResourceVersion uint64 `protobuf:"varint,10,opt,name=resource_version,json=resourceVersion,proto3" json:"resource_version,omitempty"`
+ // Optional non-secret annotations attached by profile sources or importers.
+ Annotations map[string]string `protobuf:"bytes,11,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ // Server-set provenance: "builtin", "user", or "interceptor/{name}".
+ // Ignored on import/update payloads.
+ Source string `protobuf:"bytes,12,opt,name=source,proto3" json:"source,omitempty"`
+ // Server-set visibility: "platform", "workspace", or empty for
+ // non-scoped sources. Ignored on import/update payloads.
+ Scope string `protobuf:"bytes,13,opt,name=scope,proto3" json:"scope,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ProviderProfile) Reset() {
+ *x = ProviderProfile{}
+ mi := &file_openshell_proto_msgTypes[87]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ProviderProfile) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProviderProfile) ProtoMessage() {}
+
+func (x *ProviderProfile) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[87]
+ 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 ProviderProfile.ProtoReflect.Descriptor instead.
+func (*ProviderProfile) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{87}
+}
+
+func (x *ProviderProfile) GetId() string {
+ if x != nil {
+ return x.Id
+ }
+ return ""
+}
+
+func (x *ProviderProfile) GetDisplayName() string {
+ if x != nil {
+ return x.DisplayName
+ }
+ return ""
+}
+
+func (x *ProviderProfile) GetDescription() string {
+ if x != nil {
+ return x.Description
+ }
+ return ""
+}
+
+func (x *ProviderProfile) GetCategory() ProviderProfileCategory {
+ if x != nil {
+ return x.Category
+ }
+ return ProviderProfileCategory_PROVIDER_PROFILE_CATEGORY_UNSPECIFIED
+}
+
+func (x *ProviderProfile) GetCredentials() []*ProviderProfileCredential {
+ if x != nil {
+ return x.Credentials
+ }
+ return nil
+}
+
+func (x *ProviderProfile) GetEndpoints() []*sandboxv1.NetworkEndpoint {
+ if x != nil {
+ return x.Endpoints
+ }
+ return nil
+}
+
+func (x *ProviderProfile) GetBinaries() []*sandboxv1.NetworkBinary {
+ if x != nil {
+ return x.Binaries
+ }
+ return nil
+}
+
+func (x *ProviderProfile) GetInferenceCapable() bool {
+ if x != nil {
+ return x.InferenceCapable
+ }
+ return false
+}
+
+func (x *ProviderProfile) GetDiscovery() *ProviderProfileDiscovery {
+ if x != nil {
+ return x.Discovery
+ }
+ return nil
+}
+
+func (x *ProviderProfile) GetResourceVersion() uint64 {
+ if x != nil {
+ return x.ResourceVersion
+ }
+ return 0
+}
+
+func (x *ProviderProfile) GetAnnotations() map[string]string {
+ if x != nil {
+ return x.Annotations
+ }
+ return nil
+}
+
+func (x *ProviderProfile) GetSource() string {
+ if x != nil {
+ return x.Source
+ }
+ return ""
+}
+
+func (x *ProviderProfile) GetScope() string {
+ if x != nil {
+ return x.Scope
+ }
+ return ""
+}
+
+// Stored custom provider profile object.
+type StoredProviderProfile struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Metadata *datamodelv1.ObjectMeta `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"`
+ Profile *ProviderProfile `protobuf:"bytes,2,opt,name=profile,proto3" json:"profile,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *StoredProviderProfile) Reset() {
+ *x = StoredProviderProfile{}
+ mi := &file_openshell_proto_msgTypes[88]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *StoredProviderProfile) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StoredProviderProfile) ProtoMessage() {}
+
+func (x *StoredProviderProfile) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[88]
+ 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 StoredProviderProfile.ProtoReflect.Descriptor instead.
+func (*StoredProviderProfile) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{88}
+}
+
+func (x *StoredProviderProfile) GetMetadata() *datamodelv1.ObjectMeta {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+func (x *StoredProviderProfile) GetProfile() *ProviderProfile {
+ if x != nil {
+ return x.Profile
+ }
+ return nil
+}
+
+// Provider profile response.
+type ProviderProfileResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Profile *ProviderProfile `protobuf:"bytes,1,opt,name=profile,proto3" json:"profile,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ProviderProfileResponse) Reset() {
+ *x = ProviderProfileResponse{}
+ mi := &file_openshell_proto_msgTypes[89]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ProviderProfileResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProviderProfileResponse) ProtoMessage() {}
+
+func (x *ProviderProfileResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[89]
+ 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 ProviderProfileResponse.ProtoReflect.Descriptor instead.
+func (*ProviderProfileResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{89}
+}
+
+func (x *ProviderProfileResponse) GetProfile() *ProviderProfile {
+ if x != nil {
+ return x.Profile
+ }
+ return nil
+}
+
+// List provider profiles response.
+type ListProviderProfilesResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Profiles []*ProviderProfile `protobuf:"bytes,1,rep,name=profiles,proto3" json:"profiles,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ListProviderProfilesResponse) Reset() {
+ *x = ListProviderProfilesResponse{}
+ mi := &file_openshell_proto_msgTypes[90]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ListProviderProfilesResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListProviderProfilesResponse) ProtoMessage() {}
+
+func (x *ListProviderProfilesResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[90]
+ 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 ListProviderProfilesResponse.ProtoReflect.Descriptor instead.
+func (*ListProviderProfilesResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{90}
+}
+
+func (x *ListProviderProfilesResponse) GetProfiles() []*ProviderProfile {
+ if x != nil {
+ return x.Profiles
+ }
+ return nil
+}
+
+// Import custom provider profiles request.
+type ImportProviderProfilesRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Profiles []*ProviderProfileImportItem `protobuf:"bytes,1,rep,name=profiles,proto3" json:"profiles,omitempty"`
+ // Workspace scope. When set, profiles are workspace-scoped (Workspace Admin).
+ // When empty, profiles are platform-scoped (Platform Admin).
+ Workspace string `protobuf:"bytes,2,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ImportProviderProfilesRequest) Reset() {
+ *x = ImportProviderProfilesRequest{}
+ mi := &file_openshell_proto_msgTypes[91]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ImportProviderProfilesRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ImportProviderProfilesRequest) ProtoMessage() {}
+
+func (x *ImportProviderProfilesRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[91]
+ 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 ImportProviderProfilesRequest.ProtoReflect.Descriptor instead.
+func (*ImportProviderProfilesRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{91}
+}
+
+func (x *ImportProviderProfilesRequest) GetProfiles() []*ProviderProfileImportItem {
+ if x != nil {
+ return x.Profiles
+ }
+ return nil
+}
+
+func (x *ImportProviderProfilesRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+// Import custom provider profiles response.
+type ImportProviderProfilesResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Diagnostics []*ProviderProfileDiagnostic `protobuf:"bytes,1,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+ Profiles []*ProviderProfile `protobuf:"bytes,2,rep,name=profiles,proto3" json:"profiles,omitempty"`
+ Imported bool `protobuf:"varint,3,opt,name=imported,proto3" json:"imported,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ImportProviderProfilesResponse) Reset() {
+ *x = ImportProviderProfilesResponse{}
+ mi := &file_openshell_proto_msgTypes[92]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ImportProviderProfilesResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ImportProviderProfilesResponse) ProtoMessage() {}
+
+func (x *ImportProviderProfilesResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[92]
+ 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 ImportProviderProfilesResponse.ProtoReflect.Descriptor instead.
+func (*ImportProviderProfilesResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{92}
+}
+
+func (x *ImportProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic {
+ if x != nil {
+ return x.Diagnostics
+ }
+ return nil
+}
+
+func (x *ImportProviderProfilesResponse) GetProfiles() []*ProviderProfile {
+ if x != nil {
+ return x.Profiles
+ }
+ return nil
+}
+
+func (x *ImportProviderProfilesResponse) GetImported() bool {
+ if x != nil {
+ return x.Imported
+ }
+ return false
+}
+
+// Update one custom provider profile request.
+type UpdateProviderProfilesRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Profile *ProviderProfileImportItem `protobuf:"bytes,1,opt,name=profile,proto3" json:"profile,omitempty"`
+ // Expected storage resource version for optimistic concurrency control.
+ // If 0, the server uses the resource_version embedded in profile.profile.
+ // Updates without a non-zero version are rejected to prevent stale files from
+ // silently overwriting newer profile definitions.
+ ExpectedResourceVersion uint64 `protobuf:"varint,2,opt,name=expected_resource_version,json=expectedResourceVersion,proto3" json:"expected_resource_version,omitempty"`
+ // Existing custom provider profile ID to update. The payload ID must match.
+ Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"`
+ // Workspace scope. When set, targets workspace-scoped profile. When empty,
+ // targets platform-scoped profile.
+ Workspace string `protobuf:"bytes,4,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *UpdateProviderProfilesRequest) Reset() {
+ *x = UpdateProviderProfilesRequest{}
+ mi := &file_openshell_proto_msgTypes[93]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *UpdateProviderProfilesRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateProviderProfilesRequest) ProtoMessage() {}
+
+func (x *UpdateProviderProfilesRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[93]
+ 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 UpdateProviderProfilesRequest.ProtoReflect.Descriptor instead.
+func (*UpdateProviderProfilesRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{93}
+}
+
+func (x *UpdateProviderProfilesRequest) GetProfile() *ProviderProfileImportItem {
+ if x != nil {
+ return x.Profile
+ }
+ return nil
+}
+
+func (x *UpdateProviderProfilesRequest) GetExpectedResourceVersion() uint64 {
+ if x != nil {
+ return x.ExpectedResourceVersion
+ }
+ return 0
+}
+
+func (x *UpdateProviderProfilesRequest) GetId() string {
+ if x != nil {
+ return x.Id
+ }
+ return ""
+}
+
+func (x *UpdateProviderProfilesRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+// Update one custom provider profile response.
+type UpdateProviderProfilesResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Diagnostics []*ProviderProfileDiagnostic `protobuf:"bytes,1,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+ Profile *ProviderProfile `protobuf:"bytes,2,opt,name=profile,proto3" json:"profile,omitempty"`
+ Updated bool `protobuf:"varint,3,opt,name=updated,proto3" json:"updated,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *UpdateProviderProfilesResponse) Reset() {
+ *x = UpdateProviderProfilesResponse{}
+ mi := &file_openshell_proto_msgTypes[94]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *UpdateProviderProfilesResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateProviderProfilesResponse) ProtoMessage() {}
+
+func (x *UpdateProviderProfilesResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[94]
+ 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 UpdateProviderProfilesResponse.ProtoReflect.Descriptor instead.
+func (*UpdateProviderProfilesResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{94}
+}
+
+func (x *UpdateProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic {
+ if x != nil {
+ return x.Diagnostics
+ }
+ return nil
+}
+
+func (x *UpdateProviderProfilesResponse) GetProfile() *ProviderProfile {
+ if x != nil {
+ return x.Profile
+ }
+ return nil
+}
+
+func (x *UpdateProviderProfilesResponse) GetUpdated() bool {
+ if x != nil {
+ return x.Updated
+ }
+ return false
+}
+
+// Lint provider profiles request.
+type LintProviderProfilesRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Profiles []*ProviderProfileImportItem `protobuf:"bytes,1,rep,name=profiles,proto3" json:"profiles,omitempty"`
+ // Workspace scope. Used to check for conflicts against existing profiles
+ // in the target workspace.
+ Workspace string `protobuf:"bytes,2,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *LintProviderProfilesRequest) Reset() {
+ *x = LintProviderProfilesRequest{}
+ mi := &file_openshell_proto_msgTypes[95]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *LintProviderProfilesRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*LintProviderProfilesRequest) ProtoMessage() {}
+
+func (x *LintProviderProfilesRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[95]
+ 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 LintProviderProfilesRequest.ProtoReflect.Descriptor instead.
+func (*LintProviderProfilesRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{95}
+}
+
+func (x *LintProviderProfilesRequest) GetProfiles() []*ProviderProfileImportItem {
+ if x != nil {
+ return x.Profiles
+ }
+ return nil
+}
+
+func (x *LintProviderProfilesRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+// Lint provider profiles response.
+type LintProviderProfilesResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Diagnostics []*ProviderProfileDiagnostic `protobuf:"bytes,1,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+ Valid bool `protobuf:"varint,2,opt,name=valid,proto3" json:"valid,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *LintProviderProfilesResponse) Reset() {
+ *x = LintProviderProfilesResponse{}
+ mi := &file_openshell_proto_msgTypes[96]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *LintProviderProfilesResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*LintProviderProfilesResponse) ProtoMessage() {}
+
+func (x *LintProviderProfilesResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[96]
+ 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 LintProviderProfilesResponse.ProtoReflect.Descriptor instead.
+func (*LintProviderProfilesResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{96}
+}
+
+func (x *LintProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic {
+ if x != nil {
+ return x.Diagnostics
+ }
+ return nil
+}
+
+func (x *LintProviderProfilesResponse) GetValid() bool {
+ if x != nil {
+ return x.Valid
+ }
+ return false
+}
+
+// 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[97]
+ 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[97]
+ 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{97}
+}
+
+func (x *DeleteProviderResponse) GetDeleted() bool {
+ if x != nil {
+ return x.Deleted
+ }
+ return false
+}
+
+// Delete custom provider profile request.
+type DeleteProviderProfileRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+ // Workspace scope. When set, targets workspace-scoped profile. When empty,
+ // targets platform-scoped profile.
+ Workspace string `protobuf:"bytes,2,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *DeleteProviderProfileRequest) Reset() {
+ *x = DeleteProviderProfileRequest{}
+ mi := &file_openshell_proto_msgTypes[98]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *DeleteProviderProfileRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeleteProviderProfileRequest) ProtoMessage() {}
+
+func (x *DeleteProviderProfileRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[98]
+ 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 DeleteProviderProfileRequest.ProtoReflect.Descriptor instead.
+func (*DeleteProviderProfileRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{98}
+}
+
+func (x *DeleteProviderProfileRequest) GetId() string {
+ if x != nil {
+ return x.Id
+ }
+ return ""
+}
+
+func (x *DeleteProviderProfileRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+// Delete custom provider profile response.
+type DeleteProviderProfileResponse 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 *DeleteProviderProfileResponse) Reset() {
+ *x = DeleteProviderProfileResponse{}
+ mi := &file_openshell_proto_msgTypes[99]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *DeleteProviderProfileResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeleteProviderProfileResponse) ProtoMessage() {}
+
+func (x *DeleteProviderProfileResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[99]
+ 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 DeleteProviderProfileResponse.ProtoReflect.Descriptor instead.
+func (*DeleteProviderProfileResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{99}
+}
+
+func (x *DeleteProviderProfileResponse) 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[100]
+ 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[100]
+ 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{100}
+}
+
+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"`
+ // Fingerprint for the provider credential inputs that produced environment.
+ ProviderEnvRevision uint64 `protobuf:"varint,2,opt,name=provider_env_revision,json=providerEnvRevision,proto3" json:"provider_env_revision,omitempty"`
+ // Expiration timestamps for returned environment variables.
+ CredentialExpiresAtMs map[string]int64 `protobuf:"bytes,3,rep,name=credential_expires_at_ms,json=credentialExpiresAtMs,proto3" json:"credential_expires_at_ms,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"`
+ // Dynamic credentials that require token grants or other runtime injection.
+ // Maps endpoint-bound provider metadata to credential metadata.
+ // Supervisor uses this to inject Authorization headers for token grant credentials.
+ DynamicCredentials map[string]*ProviderProfileCredential `protobuf:"bytes,4,rep,name=dynamic_credentials,json=dynamicCredentials,proto3" json:"dynamic_credentials,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[101]
+ 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[101]
+ 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{101}
+}
+
+func (x *GetSandboxProviderEnvironmentResponse) GetEnvironment() map[string]string {
+ if x != nil {
+ return x.Environment
+ }
+ return nil
+}
+
+func (x *GetSandboxProviderEnvironmentResponse) GetProviderEnvRevision() uint64 {
+ if x != nil {
+ return x.ProviderEnvRevision
+ }
+ return 0
+}
+
+func (x *GetSandboxProviderEnvironmentResponse) GetCredentialExpiresAtMs() map[string]int64 {
+ if x != nil {
+ return x.CredentialExpiresAtMs
+ }
+ return nil
+}
+
+func (x *GetSandboxProviderEnvironmentResponse) GetDynamicCredentials() map[string]*ProviderProfileCredential {
+ if x != nil {
+ return x.DynamicCredentials
+ }
+ return nil
+}
+
+// Update sandbox policy request.
+type UpdateConfigRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Sandbox name (canonical lookup key). Required for sandbox-scoped updates.
+ // Not required when `global=true`.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // 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).
+ Policy *sandboxv1.SandboxPolicy `protobuf:"bytes,2,opt,name=policy,proto3" json:"policy,omitempty"`
+ // Optional single setting key to mutate.
+ SettingKey string `protobuf:"bytes,3,opt,name=setting_key,json=settingKey,proto3" json:"setting_key,omitempty"`
+ // Setting value for upsert operations.
+ SettingValue *sandboxv1.SettingValue `protobuf:"bytes,4,opt,name=setting_value,json=settingValue,proto3" json:"setting_value,omitempty"`
+ // Delete the setting key from scope.
+ // Sandbox-scoped deletes are rejected; only global delete is supported.
+ DeleteSetting bool `protobuf:"varint,5,opt,name=delete_setting,json=deleteSetting,proto3" json:"delete_setting,omitempty"`
+ // Apply mutation at gateway-global scope.
+ Global bool `protobuf:"varint,6,opt,name=global,proto3" json:"global,omitempty"`
+ // Batched incremental policy merge operations. Sandbox-scoped only.
+ MergeOperations []*PolicyMergeOperation `protobuf:"bytes,7,rep,name=merge_operations,json=mergeOperations,proto3" json:"merge_operations,omitempty"`
+ // Expected resource version for optimistic concurrency control (sandbox-scoped only).
+ // If 0, the server uses the current version (backward compatibility).
+ // If non-zero, the server validates that the sandbox's current resource_version
+ // matches this value before applying the mutation, returning ABORTED on mismatch.
+ // Ignored for global-scoped updates.
+ ExpectedResourceVersion uint64 `protobuf:"varint,8,opt,name=expected_resource_version,json=expectedResourceVersion,proto3" json:"expected_resource_version,omitempty"`
+ // Caller-provided annotations associated with a sandbox-scoped update. Values
+ // must not contain secrets; the gateway treats them as opaque metadata and does
+ // not interpret or verify their semantics. For policy updates, the gateway
+ // stores the annotations immutably with the revision and merges them into
+ // sandbox metadata as a convenience projection. For setting-only updates, it
+ // only merges them into sandbox metadata.
+ Annotations map[string]string `protobuf:"bytes,9,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ // Workspace scope. Empty defaults to "default". Ignored for global-scoped updates.
+ Workspace string `protobuf:"bytes,10,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *UpdateConfigRequest) Reset() {
+ *x = UpdateConfigRequest{}
+ mi := &file_openshell_proto_msgTypes[102]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *UpdateConfigRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateConfigRequest) ProtoMessage() {}
+
+func (x *UpdateConfigRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[102]
+ 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 UpdateConfigRequest.ProtoReflect.Descriptor instead.
+func (*UpdateConfigRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{102}
+}
+
+func (x *UpdateConfigRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *UpdateConfigRequest) GetPolicy() *sandboxv1.SandboxPolicy {
+ if x != nil {
+ return x.Policy
+ }
+ return nil
+}
+
+func (x *UpdateConfigRequest) GetSettingKey() string {
+ if x != nil {
+ return x.SettingKey
+ }
+ return ""
+}
+
+func (x *UpdateConfigRequest) GetSettingValue() *sandboxv1.SettingValue {
+ if x != nil {
+ return x.SettingValue
+ }
+ return nil
+}
+
+func (x *UpdateConfigRequest) GetDeleteSetting() bool {
+ if x != nil {
+ return x.DeleteSetting
+ }
+ return false
+}
+
+func (x *UpdateConfigRequest) GetGlobal() bool {
+ if x != nil {
+ return x.Global
+ }
+ return false
+}
+
+func (x *UpdateConfigRequest) GetMergeOperations() []*PolicyMergeOperation {
+ if x != nil {
+ return x.MergeOperations
+ }
+ return nil
+}
+
+func (x *UpdateConfigRequest) GetExpectedResourceVersion() uint64 {
+ if x != nil {
+ return x.ExpectedResourceVersion
+ }
+ return 0
+}
+
+func (x *UpdateConfigRequest) GetAnnotations() map[string]string {
+ if x != nil {
+ return x.Annotations
+ }
+ return nil
+}
+
+func (x *UpdateConfigRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+type PolicyMergeOperation struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Types that are valid to be assigned to Operation:
+ //
+ // *PolicyMergeOperation_AddRule
+ // *PolicyMergeOperation_RemoveEndpoint
+ // *PolicyMergeOperation_RemoveRule
+ // *PolicyMergeOperation_AddDenyRules
+ // *PolicyMergeOperation_AddAllowRules
+ // *PolicyMergeOperation_RemoveBinary
+ Operation isPolicyMergeOperation_Operation `protobuf_oneof:"operation"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *PolicyMergeOperation) Reset() {
+ *x = PolicyMergeOperation{}
+ mi := &file_openshell_proto_msgTypes[103]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *PolicyMergeOperation) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PolicyMergeOperation) ProtoMessage() {}
+
+func (x *PolicyMergeOperation) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[103]
+ 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 PolicyMergeOperation.ProtoReflect.Descriptor instead.
+func (*PolicyMergeOperation) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{103}
+}
+
+func (x *PolicyMergeOperation) GetOperation() isPolicyMergeOperation_Operation {
+ if x != nil {
+ return x.Operation
+ }
+ return nil
+}
+
+func (x *PolicyMergeOperation) GetAddRule() *AddNetworkRule {
+ if x != nil {
+ if x, ok := x.Operation.(*PolicyMergeOperation_AddRule); ok {
+ return x.AddRule
+ }
+ }
+ return nil
+}
+
+func (x *PolicyMergeOperation) GetRemoveEndpoint() *RemoveNetworkEndpoint {
+ if x != nil {
+ if x, ok := x.Operation.(*PolicyMergeOperation_RemoveEndpoint); ok {
+ return x.RemoveEndpoint
+ }
+ }
+ return nil
+}
+
+func (x *PolicyMergeOperation) GetRemoveRule() *RemoveNetworkRule {
+ if x != nil {
+ if x, ok := x.Operation.(*PolicyMergeOperation_RemoveRule); ok {
+ return x.RemoveRule
+ }
+ }
+ return nil
+}
+
+func (x *PolicyMergeOperation) GetAddDenyRules() *AddDenyRules {
+ if x != nil {
+ if x, ok := x.Operation.(*PolicyMergeOperation_AddDenyRules); ok {
+ return x.AddDenyRules
+ }
+ }
+ return nil
+}
+
+func (x *PolicyMergeOperation) GetAddAllowRules() *AddAllowRules {
+ if x != nil {
+ if x, ok := x.Operation.(*PolicyMergeOperation_AddAllowRules); ok {
+ return x.AddAllowRules
+ }
+ }
+ return nil
+}
+
+func (x *PolicyMergeOperation) GetRemoveBinary() *RemoveNetworkBinary {
+ if x != nil {
+ if x, ok := x.Operation.(*PolicyMergeOperation_RemoveBinary); ok {
+ return x.RemoveBinary
+ }
+ }
+ return nil
+}
+
+type isPolicyMergeOperation_Operation interface {
+ isPolicyMergeOperation_Operation()
+}
+
+type PolicyMergeOperation_AddRule struct {
+ AddRule *AddNetworkRule `protobuf:"bytes,1,opt,name=add_rule,json=addRule,proto3,oneof"`
+}
+
+type PolicyMergeOperation_RemoveEndpoint struct {
+ RemoveEndpoint *RemoveNetworkEndpoint `protobuf:"bytes,2,opt,name=remove_endpoint,json=removeEndpoint,proto3,oneof"`
+}
+
+type PolicyMergeOperation_RemoveRule struct {
+ RemoveRule *RemoveNetworkRule `protobuf:"bytes,3,opt,name=remove_rule,json=removeRule,proto3,oneof"`
+}
+
+type PolicyMergeOperation_AddDenyRules struct {
+ AddDenyRules *AddDenyRules `protobuf:"bytes,4,opt,name=add_deny_rules,json=addDenyRules,proto3,oneof"`
+}
+
+type PolicyMergeOperation_AddAllowRules struct {
+ AddAllowRules *AddAllowRules `protobuf:"bytes,5,opt,name=add_allow_rules,json=addAllowRules,proto3,oneof"`
+}
+
+type PolicyMergeOperation_RemoveBinary struct {
+ RemoveBinary *RemoveNetworkBinary `protobuf:"bytes,6,opt,name=remove_binary,json=removeBinary,proto3,oneof"`
+}
+
+func (*PolicyMergeOperation_AddRule) isPolicyMergeOperation_Operation() {}
+
+func (*PolicyMergeOperation_RemoveEndpoint) isPolicyMergeOperation_Operation() {}
+
+func (*PolicyMergeOperation_RemoveRule) isPolicyMergeOperation_Operation() {}
+
+func (*PolicyMergeOperation_AddDenyRules) isPolicyMergeOperation_Operation() {}
+
+func (*PolicyMergeOperation_AddAllowRules) isPolicyMergeOperation_Operation() {}
+
+func (*PolicyMergeOperation_RemoveBinary) isPolicyMergeOperation_Operation() {}
+
+type AddNetworkRule struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ RuleName string `protobuf:"bytes,1,opt,name=rule_name,json=ruleName,proto3" json:"rule_name,omitempty"`
+ Rule *sandboxv1.NetworkPolicyRule `protobuf:"bytes,2,opt,name=rule,proto3" json:"rule,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *AddNetworkRule) Reset() {
+ *x = AddNetworkRule{}
+ mi := &file_openshell_proto_msgTypes[104]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *AddNetworkRule) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AddNetworkRule) ProtoMessage() {}
+
+func (x *AddNetworkRule) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[104]
+ 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 AddNetworkRule.ProtoReflect.Descriptor instead.
+func (*AddNetworkRule) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{104}
+}
+
+func (x *AddNetworkRule) GetRuleName() string {
+ if x != nil {
+ return x.RuleName
+ }
+ return ""
+}
+
+func (x *AddNetworkRule) GetRule() *sandboxv1.NetworkPolicyRule {
+ if x != nil {
+ return x.Rule
+ }
+ return nil
+}
+
+type RemoveNetworkEndpoint struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ RuleName string `protobuf:"bytes,1,opt,name=rule_name,json=ruleName,proto3" json:"rule_name,omitempty"`
+ Host string `protobuf:"bytes,2,opt,name=host,proto3" json:"host,omitempty"`
+ Port uint32 `protobuf:"varint,3,opt,name=port,proto3" json:"port,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RemoveNetworkEndpoint) Reset() {
+ *x = RemoveNetworkEndpoint{}
+ mi := &file_openshell_proto_msgTypes[105]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RemoveNetworkEndpoint) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RemoveNetworkEndpoint) ProtoMessage() {}
+
+func (x *RemoveNetworkEndpoint) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[105]
+ 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 RemoveNetworkEndpoint.ProtoReflect.Descriptor instead.
+func (*RemoveNetworkEndpoint) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{105}
+}
+
+func (x *RemoveNetworkEndpoint) GetRuleName() string {
+ if x != nil {
+ return x.RuleName
+ }
+ return ""
+}
+
+func (x *RemoveNetworkEndpoint) GetHost() string {
+ if x != nil {
+ return x.Host
+ }
+ return ""
+}
+
+func (x *RemoveNetworkEndpoint) GetPort() uint32 {
+ if x != nil {
+ return x.Port
+ }
+ return 0
+}
+
+type RemoveNetworkRule struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ RuleName string `protobuf:"bytes,1,opt,name=rule_name,json=ruleName,proto3" json:"rule_name,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RemoveNetworkRule) Reset() {
+ *x = RemoveNetworkRule{}
+ mi := &file_openshell_proto_msgTypes[106]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RemoveNetworkRule) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RemoveNetworkRule) ProtoMessage() {}
+
+func (x *RemoveNetworkRule) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[106]
+ 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 RemoveNetworkRule.ProtoReflect.Descriptor instead.
+func (*RemoveNetworkRule) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{106}
+}
+
+func (x *RemoveNetworkRule) GetRuleName() string {
+ if x != nil {
+ return x.RuleName
+ }
+ return ""
+}
+
+type AddDenyRules struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Host string `protobuf:"bytes,1,opt,name=host,proto3" json:"host,omitempty"`
+ Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
+ DenyRules []*sandboxv1.L7DenyRule `protobuf:"bytes,3,rep,name=deny_rules,json=denyRules,proto3" json:"deny_rules,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *AddDenyRules) Reset() {
+ *x = AddDenyRules{}
+ mi := &file_openshell_proto_msgTypes[107]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *AddDenyRules) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AddDenyRules) ProtoMessage() {}
+
+func (x *AddDenyRules) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[107]
+ 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 AddDenyRules.ProtoReflect.Descriptor instead.
+func (*AddDenyRules) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{107}
+}
+
+func (x *AddDenyRules) GetHost() string {
+ if x != nil {
+ return x.Host
+ }
+ return ""
+}
+
+func (x *AddDenyRules) GetPort() uint32 {
+ if x != nil {
+ return x.Port
+ }
+ return 0
+}
+
+func (x *AddDenyRules) GetDenyRules() []*sandboxv1.L7DenyRule {
+ if x != nil {
+ return x.DenyRules
+ }
+ return nil
+}
+
+type AddAllowRules struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Host string `protobuf:"bytes,1,opt,name=host,proto3" json:"host,omitempty"`
+ Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
+ Rules []*sandboxv1.L7Rule `protobuf:"bytes,3,rep,name=rules,proto3" json:"rules,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *AddAllowRules) Reset() {
+ *x = AddAllowRules{}
+ mi := &file_openshell_proto_msgTypes[108]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *AddAllowRules) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AddAllowRules) ProtoMessage() {}
+
+func (x *AddAllowRules) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[108]
+ 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 AddAllowRules.ProtoReflect.Descriptor instead.
+func (*AddAllowRules) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{108}
+}
+
+func (x *AddAllowRules) GetHost() string {
+ if x != nil {
+ return x.Host
+ }
+ return ""
+}
+
+func (x *AddAllowRules) GetPort() uint32 {
+ if x != nil {
+ return x.Port
+ }
+ return 0
+}
+
+func (x *AddAllowRules) GetRules() []*sandboxv1.L7Rule {
+ if x != nil {
+ return x.Rules
+ }
+ return nil
+}
+
+type RemoveNetworkBinary struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ RuleName string `protobuf:"bytes,1,opt,name=rule_name,json=ruleName,proto3" json:"rule_name,omitempty"`
+ BinaryPath string `protobuf:"bytes,2,opt,name=binary_path,json=binaryPath,proto3" json:"binary_path,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RemoveNetworkBinary) Reset() {
+ *x = RemoveNetworkBinary{}
+ mi := &file_openshell_proto_msgTypes[109]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RemoveNetworkBinary) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RemoveNetworkBinary) ProtoMessage() {}
+
+func (x *RemoveNetworkBinary) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[109]
+ 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 RemoveNetworkBinary.ProtoReflect.Descriptor instead.
+func (*RemoveNetworkBinary) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{109}
+}
+
+func (x *RemoveNetworkBinary) GetRuleName() string {
+ if x != nil {
+ return x.RuleName
+ }
+ return ""
+}
+
+func (x *RemoveNetworkBinary) GetBinaryPath() string {
+ if x != nil {
+ return x.BinaryPath
+ }
+ return ""
+}
+
+// Update sandbox policy response.
+type UpdateConfigResponse 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"`
+ // Settings revision for the scope that was modified.
+ SettingsRevision uint64 `protobuf:"varint,3,opt,name=settings_revision,json=settingsRevision,proto3" json:"settings_revision,omitempty"`
+ // True when a setting delete operation removed an existing key.
+ Deleted bool `protobuf:"varint,4,opt,name=deleted,proto3" json:"deleted,omitempty"`
+ // Sandbox metadata annotations after the update. Empty for global updates.
+ 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"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *UpdateConfigResponse) Reset() {
+ *x = UpdateConfigResponse{}
+ mi := &file_openshell_proto_msgTypes[110]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *UpdateConfigResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateConfigResponse) ProtoMessage() {}
+
+func (x *UpdateConfigResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[110]
+ 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 UpdateConfigResponse.ProtoReflect.Descriptor instead.
+func (*UpdateConfigResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{110}
+}
+
+func (x *UpdateConfigResponse) GetVersion() uint32 {
+ if x != nil {
+ return x.Version
+ }
+ return 0
+}
+
+func (x *UpdateConfigResponse) GetPolicyHash() string {
+ if x != nil {
+ return x.PolicyHash
+ }
+ return ""
+}
+
+func (x *UpdateConfigResponse) GetSettingsRevision() uint64 {
+ if x != nil {
+ return x.SettingsRevision
+ }
+ return 0
+}
+
+func (x *UpdateConfigResponse) GetDeleted() bool {
+ if x != nil {
+ return x.Deleted
+ }
+ return false
+}
+
+func (x *UpdateConfigResponse) GetAnnotations() map[string]string {
+ if x != nil {
+ return x.Annotations
+ }
+ return nil
+}
+
+// Get sandbox policy status request.
+type GetSandboxPolicyStatusRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Sandbox name (canonical lookup key). Ignored when global is true.
+ 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"`
+ // Query global policy revisions instead of a sandbox-scoped one.
+ Global bool `protobuf:"varint,3,opt,name=global,proto3" json:"global,omitempty"`
+ // Workspace scope. Empty defaults to "default". Ignored when global is true.
+ Workspace string `protobuf:"bytes,4,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetSandboxPolicyStatusRequest) Reset() {
+ *x = GetSandboxPolicyStatusRequest{}
+ mi := &file_openshell_proto_msgTypes[111]
+ 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[111]
+ 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{111}
+}
+
+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
+}
+
+func (x *GetSandboxPolicyStatusRequest) GetGlobal() bool {
+ if x != nil {
+ return x.Global
+ }
+ return false
+}
+
+func (x *GetSandboxPolicyStatusRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+// 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[112]
+ 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[112]
+ 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{112}
+}
+
+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). Ignored when global is true.
+ 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"`
+ // List global policy revisions instead of sandbox-scoped ones.
+ Global bool `protobuf:"varint,4,opt,name=global,proto3" json:"global,omitempty"`
+ // Workspace scope. Empty defaults to "default". Ignored when global is true.
+ Workspace string `protobuf:"bytes,5,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ListSandboxPoliciesRequest) Reset() {
+ *x = ListSandboxPoliciesRequest{}
+ mi := &file_openshell_proto_msgTypes[113]
+ 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[113]
+ 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{113}
+}
+
+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
+}
+
+func (x *ListSandboxPoliciesRequest) GetGlobal() bool {
+ if x != nil {
+ return x.Global
+ }
+ return false
+}
+
+func (x *ListSandboxPoliciesRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+// 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[114]
+ 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[114]
+ 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{114}
+}
+
+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[115]
+ 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[115]
+ 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{115}
+}
+
+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[116]
+ 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[116]
+ 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{116}
+}
+
+// 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 *sandboxv1.SandboxPolicy `protobuf:"bytes,7,opt,name=policy,proto3" json:"policy,omitempty"`
+ // Immutable provenance supplied with this policy revision.
+ Provenance map[string]string `protobuf:"bytes,8,rep,name=provenance,proto3" json:"provenance,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SandboxPolicyRevision) Reset() {
+ *x = SandboxPolicyRevision{}
+ mi := &file_openshell_proto_msgTypes[117]
+ 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[117]
+ 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{117}
+}
+
+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() *sandboxv1.SandboxPolicy {
+ if x != nil {
+ return x.Policy
+ }
+ return nil
+}
+
+func (x *SandboxPolicyRevision) GetProvenance() map[string]string {
+ if x != nil {
+ return x.Provenance
+ }
+ 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"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,6,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetSandboxLogsRequest) Reset() {
+ *x = GetSandboxLogsRequest{}
+ mi := &file_openshell_proto_msgTypes[118]
+ 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[118]
+ 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{118}
+}
+
+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 ""
+}
+
+func (x *GetSandboxLogsRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ 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[119]
+ 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[119]
+ 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{119}
+}
+
+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[120]
+ 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[120]
+ 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{120}
+}
+
+// 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[121]
+ 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[121]
+ 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{121}
+}
+
+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
+}
+
+// Envelope for supervisor-to-gateway messages on the ConnectSupervisor stream.
+type SupervisorMessage struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Types that are valid to be assigned to Payload:
+ //
+ // *SupervisorMessage_Hello
+ // *SupervisorMessage_Heartbeat
+ // *SupervisorMessage_RelayOpenResult
+ // *SupervisorMessage_RelayClose
+ Payload isSupervisorMessage_Payload `protobuf_oneof:"payload"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SupervisorMessage) Reset() {
+ *x = SupervisorMessage{}
+ mi := &file_openshell_proto_msgTypes[122]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SupervisorMessage) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SupervisorMessage) ProtoMessage() {}
+
+func (x *SupervisorMessage) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[122]
+ 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 SupervisorMessage.ProtoReflect.Descriptor instead.
+func (*SupervisorMessage) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{122}
+}
+
+func (x *SupervisorMessage) GetPayload() isSupervisorMessage_Payload {
+ if x != nil {
+ return x.Payload
+ }
+ return nil
+}
+
+func (x *SupervisorMessage) GetHello() *SupervisorHello {
+ if x != nil {
+ if x, ok := x.Payload.(*SupervisorMessage_Hello); ok {
+ return x.Hello
+ }
+ }
+ return nil
+}
+
+func (x *SupervisorMessage) GetHeartbeat() *SupervisorHeartbeat {
+ if x != nil {
+ if x, ok := x.Payload.(*SupervisorMessage_Heartbeat); ok {
+ return x.Heartbeat
+ }
+ }
+ return nil
+}
+
+func (x *SupervisorMessage) GetRelayOpenResult() *RelayOpenResult {
+ if x != nil {
+ if x, ok := x.Payload.(*SupervisorMessage_RelayOpenResult); ok {
+ return x.RelayOpenResult
+ }
+ }
+ return nil
+}
+
+func (x *SupervisorMessage) GetRelayClose() *RelayClose {
+ if x != nil {
+ if x, ok := x.Payload.(*SupervisorMessage_RelayClose); ok {
+ return x.RelayClose
+ }
+ }
+ return nil
+}
+
+type isSupervisorMessage_Payload interface {
+ isSupervisorMessage_Payload()
+}
+
+type SupervisorMessage_Hello struct {
+ Hello *SupervisorHello `protobuf:"bytes,1,opt,name=hello,proto3,oneof"`
+}
+
+type SupervisorMessage_Heartbeat struct {
+ Heartbeat *SupervisorHeartbeat `protobuf:"bytes,2,opt,name=heartbeat,proto3,oneof"`
+}
+
+type SupervisorMessage_RelayOpenResult struct {
+ RelayOpenResult *RelayOpenResult `protobuf:"bytes,3,opt,name=relay_open_result,json=relayOpenResult,proto3,oneof"`
+}
+
+type SupervisorMessage_RelayClose struct {
+ RelayClose *RelayClose `protobuf:"bytes,4,opt,name=relay_close,json=relayClose,proto3,oneof"`
+}
+
+func (*SupervisorMessage_Hello) isSupervisorMessage_Payload() {}
+
+func (*SupervisorMessage_Heartbeat) isSupervisorMessage_Payload() {}
+
+func (*SupervisorMessage_RelayOpenResult) isSupervisorMessage_Payload() {}
+
+func (*SupervisorMessage_RelayClose) isSupervisorMessage_Payload() {}
+
+// Envelope for gateway-to-supervisor messages on the ConnectSupervisor stream.
+type GatewayMessage struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Types that are valid to be assigned to Payload:
+ //
+ // *GatewayMessage_SessionAccepted
+ // *GatewayMessage_SessionRejected
+ // *GatewayMessage_Heartbeat
+ // *GatewayMessage_RelayOpen
+ // *GatewayMessage_RelayClose
+ Payload isGatewayMessage_Payload `protobuf_oneof:"payload"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GatewayMessage) Reset() {
+ *x = GatewayMessage{}
+ mi := &file_openshell_proto_msgTypes[123]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GatewayMessage) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GatewayMessage) ProtoMessage() {}
+
+func (x *GatewayMessage) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[123]
+ 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 GatewayMessage.ProtoReflect.Descriptor instead.
+func (*GatewayMessage) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{123}
+}
+
+func (x *GatewayMessage) GetPayload() isGatewayMessage_Payload {
+ if x != nil {
+ return x.Payload
+ }
+ return nil
+}
+
+func (x *GatewayMessage) GetSessionAccepted() *SessionAccepted {
+ if x != nil {
+ if x, ok := x.Payload.(*GatewayMessage_SessionAccepted); ok {
+ return x.SessionAccepted
+ }
+ }
+ return nil
+}
+
+func (x *GatewayMessage) GetSessionRejected() *SessionRejected {
+ if x != nil {
+ if x, ok := x.Payload.(*GatewayMessage_SessionRejected); ok {
+ return x.SessionRejected
+ }
+ }
+ return nil
+}
+
+func (x *GatewayMessage) GetHeartbeat() *GatewayHeartbeat {
+ if x != nil {
+ if x, ok := x.Payload.(*GatewayMessage_Heartbeat); ok {
+ return x.Heartbeat
+ }
+ }
+ return nil
+}
+
+func (x *GatewayMessage) GetRelayOpen() *RelayOpen {
+ if x != nil {
+ if x, ok := x.Payload.(*GatewayMessage_RelayOpen); ok {
+ return x.RelayOpen
+ }
+ }
+ return nil
+}
+
+func (x *GatewayMessage) GetRelayClose() *RelayClose {
+ if x != nil {
+ if x, ok := x.Payload.(*GatewayMessage_RelayClose); ok {
+ return x.RelayClose
+ }
+ }
+ return nil
+}
+
+type isGatewayMessage_Payload interface {
+ isGatewayMessage_Payload()
+}
+
+type GatewayMessage_SessionAccepted struct {
+ SessionAccepted *SessionAccepted `protobuf:"bytes,1,opt,name=session_accepted,json=sessionAccepted,proto3,oneof"`
+}
+
+type GatewayMessage_SessionRejected struct {
+ SessionRejected *SessionRejected `protobuf:"bytes,2,opt,name=session_rejected,json=sessionRejected,proto3,oneof"`
+}
+
+type GatewayMessage_Heartbeat struct {
+ Heartbeat *GatewayHeartbeat `protobuf:"bytes,3,opt,name=heartbeat,proto3,oneof"`
+}
+
+type GatewayMessage_RelayOpen struct {
+ RelayOpen *RelayOpen `protobuf:"bytes,4,opt,name=relay_open,json=relayOpen,proto3,oneof"`
+}
+
+type GatewayMessage_RelayClose struct {
+ RelayClose *RelayClose `protobuf:"bytes,5,opt,name=relay_close,json=relayClose,proto3,oneof"`
+}
+
+func (*GatewayMessage_SessionAccepted) isGatewayMessage_Payload() {}
+
+func (*GatewayMessage_SessionRejected) isGatewayMessage_Payload() {}
+
+func (*GatewayMessage_Heartbeat) isGatewayMessage_Payload() {}
+
+func (*GatewayMessage_RelayOpen) isGatewayMessage_Payload() {}
+
+func (*GatewayMessage_RelayClose) isGatewayMessage_Payload() {}
+
+// Supervisor identifies itself and the sandbox it manages.
+type SupervisorHello struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Sandbox ID this supervisor manages.
+ SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"`
+ // Supervisor instance ID (e.g. boot id or process epoch).
+ InstanceId string `protobuf:"bytes,2,opt,name=instance_id,json=instanceId,proto3" json:"instance_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SupervisorHello) Reset() {
+ *x = SupervisorHello{}
+ mi := &file_openshell_proto_msgTypes[124]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SupervisorHello) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SupervisorHello) ProtoMessage() {}
+
+func (x *SupervisorHello) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[124]
+ 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 SupervisorHello.ProtoReflect.Descriptor instead.
+func (*SupervisorHello) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{124}
+}
+
+func (x *SupervisorHello) GetSandboxId() string {
+ if x != nil {
+ return x.SandboxId
+ }
+ return ""
+}
+
+func (x *SupervisorHello) GetInstanceId() string {
+ if x != nil {
+ return x.InstanceId
+ }
+ return ""
+}
+
+// Gateway accepts the supervisor session.
+type SessionAccepted struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Gateway-assigned session ID for this connection.
+ SessionId string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"`
+ // Recommended heartbeat interval in seconds.
+ HeartbeatIntervalSecs uint32 `protobuf:"varint,2,opt,name=heartbeat_interval_secs,json=heartbeatIntervalSecs,proto3" json:"heartbeat_interval_secs,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SessionAccepted) Reset() {
+ *x = SessionAccepted{}
+ mi := &file_openshell_proto_msgTypes[125]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SessionAccepted) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SessionAccepted) ProtoMessage() {}
+
+func (x *SessionAccepted) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[125]
+ 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 SessionAccepted.ProtoReflect.Descriptor instead.
+func (*SessionAccepted) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{125}
+}
+
+func (x *SessionAccepted) GetSessionId() string {
+ if x != nil {
+ return x.SessionId
+ }
+ return ""
+}
+
+func (x *SessionAccepted) GetHeartbeatIntervalSecs() uint32 {
+ if x != nil {
+ return x.HeartbeatIntervalSecs
+ }
+ return 0
+}
+
+// Gateway rejects the supervisor session.
+type SessionRejected struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Human-readable rejection reason.
+ Reason string `protobuf:"bytes,1,opt,name=reason,proto3" json:"reason,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SessionRejected) Reset() {
+ *x = SessionRejected{}
+ mi := &file_openshell_proto_msgTypes[126]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SessionRejected) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SessionRejected) ProtoMessage() {}
+
+func (x *SessionRejected) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[126]
+ 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 SessionRejected.ProtoReflect.Descriptor instead.
+func (*SessionRejected) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{126}
+}
+
+func (x *SessionRejected) GetReason() string {
+ if x != nil {
+ return x.Reason
+ }
+ return ""
+}
+
+// Supervisor heartbeat.
+type SupervisorHeartbeat struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SupervisorHeartbeat) Reset() {
+ *x = SupervisorHeartbeat{}
+ mi := &file_openshell_proto_msgTypes[127]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SupervisorHeartbeat) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SupervisorHeartbeat) ProtoMessage() {}
+
+func (x *SupervisorHeartbeat) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[127]
+ 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 SupervisorHeartbeat.ProtoReflect.Descriptor instead.
+func (*SupervisorHeartbeat) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{127}
+}
+
+// Gateway heartbeat.
+type GatewayHeartbeat struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GatewayHeartbeat) Reset() {
+ *x = GatewayHeartbeat{}
+ mi := &file_openshell_proto_msgTypes[128]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GatewayHeartbeat) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GatewayHeartbeat) ProtoMessage() {}
+
+func (x *GatewayHeartbeat) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[128]
+ 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 GatewayHeartbeat.ProtoReflect.Descriptor instead.
+func (*GatewayHeartbeat) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{128}
+}
+
+// Gateway requests the supervisor to open a relay channel.
+//
+// On receiving this, the supervisor should initiate a RelayStream RPC to
+// the gateway, sending a RelayInit in the first RelayFrame to associate
+// the new HTTP/2 stream with the pending relay slot. The supervisor
+// bridges that stream to the requested local target.
+type RelayOpen struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Gateway-allocated channel identifier (UUID).
+ ChannelId string `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
+ // Target the supervisor should dial inside the sandbox.
+ // If absent, supervisors treat the relay as SSH for compatibility.
+ //
+ // Types that are valid to be assigned to Target:
+ //
+ // *RelayOpen_Ssh
+ // *RelayOpen_Tcp
+ Target isRelayOpen_Target `protobuf_oneof:"target"`
+ // Optional service identifier for audit/correlation.
+ ServiceId string `protobuf:"bytes,5,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RelayOpen) Reset() {
+ *x = RelayOpen{}
+ mi := &file_openshell_proto_msgTypes[129]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RelayOpen) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RelayOpen) ProtoMessage() {}
+
+func (x *RelayOpen) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[129]
+ 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 RelayOpen.ProtoReflect.Descriptor instead.
+func (*RelayOpen) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{129}
+}
+
+func (x *RelayOpen) GetChannelId() string {
+ if x != nil {
+ return x.ChannelId
+ }
+ return ""
+}
+
+func (x *RelayOpen) GetTarget() isRelayOpen_Target {
+ if x != nil {
+ return x.Target
+ }
+ return nil
+}
+
+func (x *RelayOpen) GetSsh() *SshRelayTarget {
+ if x != nil {
+ if x, ok := x.Target.(*RelayOpen_Ssh); ok {
+ return x.Ssh
+ }
+ }
+ return nil
+}
+
+func (x *RelayOpen) GetTcp() *TcpRelayTarget {
+ if x != nil {
+ if x, ok := x.Target.(*RelayOpen_Tcp); ok {
+ return x.Tcp
+ }
+ }
+ return nil
+}
+
+func (x *RelayOpen) GetServiceId() string {
+ if x != nil {
+ return x.ServiceId
+ }
+ return ""
+}
+
+type isRelayOpen_Target interface {
+ isRelayOpen_Target()
+}
+
+type RelayOpen_Ssh struct {
+ Ssh *SshRelayTarget `protobuf:"bytes,2,opt,name=ssh,proto3,oneof"`
+}
+
+type RelayOpen_Tcp struct {
+ Tcp *TcpRelayTarget `protobuf:"bytes,3,opt,name=tcp,proto3,oneof"`
+}
+
+func (*RelayOpen_Ssh) isRelayOpen_Target() {}
+
+func (*RelayOpen_Tcp) isRelayOpen_Target() {}
+
+// Built-in SSH relay target.
+type SshRelayTarget struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SshRelayTarget) Reset() {
+ *x = SshRelayTarget{}
+ mi := &file_openshell_proto_msgTypes[130]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SshRelayTarget) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SshRelayTarget) ProtoMessage() {}
+
+func (x *SshRelayTarget) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[130]
+ 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 SshRelayTarget.ProtoReflect.Descriptor instead.
+func (*SshRelayTarget) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{130}
+}
+
+// TCP target dialed by the supervisor from inside the sandbox.
+type TcpRelayTarget struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Phase 1 accepts loopback only: 127.0.0.1, ::1, or localhost.
+ Host string `protobuf:"bytes,1,opt,name=host,proto3" json:"host,omitempty"`
+ // Target port. Must fit in u16 and be non-zero.
+ Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *TcpRelayTarget) Reset() {
+ *x = TcpRelayTarget{}
+ mi := &file_openshell_proto_msgTypes[131]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *TcpRelayTarget) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TcpRelayTarget) ProtoMessage() {}
+
+func (x *TcpRelayTarget) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[131]
+ 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 TcpRelayTarget.ProtoReflect.Descriptor instead.
+func (*TcpRelayTarget) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{131}
+}
+
+func (x *TcpRelayTarget) GetHost() string {
+ if x != nil {
+ return x.Host
+ }
+ return ""
+}
+
+func (x *TcpRelayTarget) GetPort() uint32 {
+ if x != nil {
+ return x.Port
+ }
+ return 0
+}
+
+// Initial RelayStream frame sent by the supervisor to claim a pending relay.
+type RelayInit struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Gateway-allocated channel identifier (UUID).
+ ChannelId string `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RelayInit) Reset() {
+ *x = RelayInit{}
+ mi := &file_openshell_proto_msgTypes[132]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RelayInit) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RelayInit) ProtoMessage() {}
+
+func (x *RelayInit) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[132]
+ 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 RelayInit.ProtoReflect.Descriptor instead.
+func (*RelayInit) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{132}
+}
+
+func (x *RelayInit) GetChannelId() string {
+ if x != nil {
+ return x.ChannelId
+ }
+ return ""
+}
+
+// A single frame on the RelayStream RPC.
+//
+// The supervisor MUST send `init` as the first frame. All subsequent frames
+// in either direction carry raw bytes in `data`.
+type RelayFrame struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Types that are valid to be assigned to Payload:
+ //
+ // *RelayFrame_Init
+ // *RelayFrame_Data
+ Payload isRelayFrame_Payload `protobuf_oneof:"payload"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RelayFrame) Reset() {
+ *x = RelayFrame{}
+ mi := &file_openshell_proto_msgTypes[133]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RelayFrame) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RelayFrame) ProtoMessage() {}
+
+func (x *RelayFrame) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[133]
+ 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 RelayFrame.ProtoReflect.Descriptor instead.
+func (*RelayFrame) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{133}
+}
+
+func (x *RelayFrame) GetPayload() isRelayFrame_Payload {
+ if x != nil {
+ return x.Payload
+ }
+ return nil
+}
+
+func (x *RelayFrame) GetInit() *RelayInit {
+ if x != nil {
+ if x, ok := x.Payload.(*RelayFrame_Init); ok {
+ return x.Init
+ }
+ }
+ return nil
+}
+
+func (x *RelayFrame) GetData() []byte {
+ if x != nil {
+ if x, ok := x.Payload.(*RelayFrame_Data); ok {
+ return x.Data
+ }
+ }
+ return nil
+}
+
+type isRelayFrame_Payload interface {
+ isRelayFrame_Payload()
+}
+
+type RelayFrame_Init struct {
+ Init *RelayInit `protobuf:"bytes,1,opt,name=init,proto3,oneof"`
+}
+
+type RelayFrame_Data struct {
+ Data []byte `protobuf:"bytes,2,opt,name=data,proto3,oneof"`
+}
+
+func (*RelayFrame_Init) isRelayFrame_Payload() {}
+
+func (*RelayFrame_Data) isRelayFrame_Payload() {}
+
+// Supervisor reports the result of a relay open request.
+type RelayOpenResult struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Channel identifier from the RelayOpen request.
+ ChannelId string `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
+ // True if the relay was successfully established.
+ Success bool `protobuf:"varint,2,opt,name=success,proto3" json:"success,omitempty"`
+ // Error message if success is false.
+ Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RelayOpenResult) Reset() {
+ *x = RelayOpenResult{}
+ mi := &file_openshell_proto_msgTypes[134]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RelayOpenResult) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RelayOpenResult) ProtoMessage() {}
+
+func (x *RelayOpenResult) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[134]
+ 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 RelayOpenResult.ProtoReflect.Descriptor instead.
+func (*RelayOpenResult) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{134}
+}
+
+func (x *RelayOpenResult) GetChannelId() string {
+ if x != nil {
+ return x.ChannelId
+ }
+ return ""
+}
+
+func (x *RelayOpenResult) GetSuccess() bool {
+ if x != nil {
+ return x.Success
+ }
+ return false
+}
+
+func (x *RelayOpenResult) GetError() string {
+ if x != nil {
+ return x.Error
+ }
+ return ""
+}
+
+// Either side requests closure of a relay channel.
+type RelayClose struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Channel identifier to close.
+ ChannelId string `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
+ // Optional reason for closure.
+ Reason string `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RelayClose) Reset() {
+ *x = RelayClose{}
+ mi := &file_openshell_proto_msgTypes[135]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RelayClose) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RelayClose) ProtoMessage() {}
+
+func (x *RelayClose) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[135]
+ 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 RelayClose.ProtoReflect.Descriptor instead.
+func (*RelayClose) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{135}
+}
+
+func (x *RelayClose) GetChannelId() string {
+ if x != nil {
+ return x.ChannelId
+ }
+ return ""
+}
+
+func (x *RelayClose) GetReason() string {
+ if x != nil {
+ return x.Reason
+ }
+ return ""
+}
+
+// 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[136]
+ 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[136]
+ 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{136}
+}
+
+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[137]
+ 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[137]
+ 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{137}
+}
+
+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
+}
+
+// Count of denied actions grouped only by sanitized telemetry category.
+type DenialGroupCount struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Sanitized denial category, e.g. "connect_policy", "l7_policy", "ssrf".
+ DenyGroup string `protobuf:"bytes,1,opt,name=deny_group,json=denyGroup,proto3" json:"deny_group,omitempty"`
+ // Number of denied actions in this category.
+ DeniedCount uint32 `protobuf:"varint,2,opt,name=denied_count,json=deniedCount,proto3" json:"denied_count,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *DenialGroupCount) Reset() {
+ *x = DenialGroupCount{}
+ mi := &file_openshell_proto_msgTypes[138]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *DenialGroupCount) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DenialGroupCount) ProtoMessage() {}
+
+func (x *DenialGroupCount) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[138]
+ 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 DenialGroupCount.ProtoReflect.Descriptor instead.
+func (*DenialGroupCount) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{138}
+}
+
+func (x *DenialGroupCount) GetDenyGroup() string {
+ if x != nil {
+ return x.DenyGroup
+ }
+ return ""
+}
+
+func (x *DenialGroupCount) GetDeniedCount() uint32 {
+ if x != nil {
+ return x.DeniedCount
+ }
+ return 0
+}
+
+// Anonymous sandbox network activity counters. This intentionally excludes
+// hosts, paths, binaries, raw deny reasons, sandbox IDs, and user content.
+type NetworkActivitySummary struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Total observed network activities in the current window.
+ NetworkActivityCount uint32 `protobuf:"varint,1,opt,name=network_activity_count,json=networkActivityCount,proto3" json:"network_activity_count,omitempty"`
+ // Total denied actions in the current window.
+ DeniedActionCount uint32 `protobuf:"varint,2,opt,name=denied_action_count,json=deniedActionCount,proto3" json:"denied_action_count,omitempty"`
+ // Denied action counts grouped by sanitized category.
+ DenialsByGroup []*DenialGroupCount `protobuf:"bytes,3,rep,name=denials_by_group,json=denialsByGroup,proto3" json:"denials_by_group,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *NetworkActivitySummary) Reset() {
+ *x = NetworkActivitySummary{}
+ mi := &file_openshell_proto_msgTypes[139]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *NetworkActivitySummary) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*NetworkActivitySummary) ProtoMessage() {}
+
+func (x *NetworkActivitySummary) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[139]
+ 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 NetworkActivitySummary.ProtoReflect.Descriptor instead.
+func (*NetworkActivitySummary) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{139}
+}
+
+func (x *NetworkActivitySummary) GetNetworkActivityCount() uint32 {
+ if x != nil {
+ return x.NetworkActivityCount
+ }
+ return 0
+}
+
+func (x *NetworkActivitySummary) GetDeniedActionCount() uint32 {
+ if x != nil {
+ return x.DeniedActionCount
+ }
+ return 0
+}
+
+func (x *NetworkActivitySummary) GetDenialsByGroup() []*DenialGroupCount {
+ if x != nil {
+ return x.DenialsByGroup
+ }
+ return nil
+}
+
+// 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 *sandboxv1.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"`
+ // Validation verdict from gateway-side static checks (prover output).
+ // Free-form summary string for human consumption in the inbox card.
+ // Empty until the prover has run for this chunk.
+ ValidationResult string `protobuf:"bytes,17,opt,name=validation_result,json=validationResult,proto3" json:"validation_result,omitempty"`
+ // Operator-supplied free-form text accompanying a rejection. Populated
+ // when the reviewer rejects via `RejectDraftChunkRequest.reason`; surfaced
+ // back to the in-sandbox agent so it can revise the proposal.
+ // Empty for non-rejected chunks.
+ RejectionReason string `protobuf:"bytes,18,opt,name=rejection_reason,json=rejectionReason,proto3" json:"rejection_reason,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *PolicyChunk) Reset() {
+ *x = PolicyChunk{}
+ mi := &file_openshell_proto_msgTypes[140]
+ 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[140]
+ 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{140}
+}
+
+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() *sandboxv1.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 ""
+}
+
+func (x *PolicyChunk) GetValidationResult() string {
+ if x != nil {
+ return x.ValidationResult
+ }
+ return ""
+}
+
+func (x *PolicyChunk) GetRejectionReason() string {
+ if x != nil {
+ return x.RejectionReason
+ }
+ 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[141]
+ 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[141]
+ 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{141}
+}
+
+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` is the observation-driven path from the
+ // denial aggregator — chunks targeting the same host|port|binary fold
+ // into one row with hit_count incremented. `agent_authored` is an
+ // intentional proposal from an in-sandbox agent — each submission lands
+ // as its own chunk so the redraft-after-rejection loop has a stable id
+ // to watch. Other values are treated as agent-style (no dedup) so a new
+ // mode does not silently collapse proposals.
+ 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"`
+ // Anonymous network activity counters.
+ NetworkActivitySummaries []*NetworkActivitySummary `protobuf:"bytes,5,rep,name=network_activity_summaries,json=networkActivitySummaries,proto3" json:"network_activity_summaries,omitempty"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,6,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SubmitPolicyAnalysisRequest) Reset() {
+ *x = SubmitPolicyAnalysisRequest{}
+ mi := &file_openshell_proto_msgTypes[142]
+ 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[142]
+ 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{142}
+}
+
+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 ""
+}
+
+func (x *SubmitPolicyAnalysisRequest) GetNetworkActivitySummaries() []*NetworkActivitySummary {
+ if x != nil {
+ return x.NetworkActivitySummaries
+ }
+ return nil
+}
+
+func (x *SubmitPolicyAnalysisRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ 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"`
+ // Server-assigned chunk IDs for the accepted chunks, in submission order.
+ // Agents use these to watch proposal state via policy.local's
+ // GET /v1/proposals/{id} and /wait endpoints.
+ AcceptedChunkIds []string `protobuf:"bytes,4,rep,name=accepted_chunk_ids,json=acceptedChunkIds,proto3" json:"accepted_chunk_ids,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SubmitPolicyAnalysisResponse) Reset() {
+ *x = SubmitPolicyAnalysisResponse{}
+ mi := &file_openshell_proto_msgTypes[143]
+ 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[143]
+ 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{143}
+}
+
+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
+}
+
+func (x *SubmitPolicyAnalysisResponse) GetAcceptedChunkIds() []string {
+ if x != nil {
+ return x.AcceptedChunkIds
+ }
+ 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"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,3,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetDraftPolicyRequest) Reset() {
+ *x = GetDraftPolicyRequest{}
+ mi := &file_openshell_proto_msgTypes[144]
+ 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[144]
+ 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{144}
+}
+
+func (x *GetDraftPolicyRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *GetDraftPolicyRequest) GetStatusFilter() string {
+ if x != nil {
+ return x.StatusFilter
+ }
+ return ""
+}
+
+func (x *GetDraftPolicyRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ 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[145]
+ 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[145]
+ 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{145}
+}
+
+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"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,3,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ApproveDraftChunkRequest) Reset() {
+ *x = ApproveDraftChunkRequest{}
+ mi := &file_openshell_proto_msgTypes[146]
+ 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[146]
+ 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{146}
+}
+
+func (x *ApproveDraftChunkRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *ApproveDraftChunkRequest) GetChunkId() string {
+ if x != nil {
+ return x.ChunkId
+ }
+ return ""
+}
+
+func (x *ApproveDraftChunkRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ 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[147]
+ 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[147]
+ 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{147}
+}
+
+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"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,4,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RejectDraftChunkRequest) Reset() {
+ *x = RejectDraftChunkRequest{}
+ mi := &file_openshell_proto_msgTypes[148]
+ 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[148]
+ 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{148}
+}
+
+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 ""
+}
+
+func (x *RejectDraftChunkRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ 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[149]
+ 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[149]
+ 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{149}
+}
+
+// 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"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,3,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ApproveAllDraftChunksRequest) Reset() {
+ *x = ApproveAllDraftChunksRequest{}
+ mi := &file_openshell_proto_msgTypes[150]
+ 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[150]
+ 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{150}
+}
+
+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
+}
+
+func (x *ApproveAllDraftChunksRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+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[151]
+ 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[151]
+ 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{151}
+}
+
+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 *sandboxv1.NetworkPolicyRule `protobuf:"bytes,3,opt,name=proposed_rule,json=proposedRule,proto3" json:"proposed_rule,omitempty"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,4,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *EditDraftChunkRequest) Reset() {
+ *x = EditDraftChunkRequest{}
+ mi := &file_openshell_proto_msgTypes[152]
+ 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[152]
+ 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{152}
+}
+
+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() *sandboxv1.NetworkPolicyRule {
+ if x != nil {
+ return x.ProposedRule
+ }
+ return nil
+}
+
+func (x *EditDraftChunkRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+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[153]
+ 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[153]
+ 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{153}
+}
+
+// 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"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,3,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *UndoDraftChunkRequest) Reset() {
+ *x = UndoDraftChunkRequest{}
+ mi := &file_openshell_proto_msgTypes[154]
+ 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[154]
+ 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{154}
+}
+
+func (x *UndoDraftChunkRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *UndoDraftChunkRequest) GetChunkId() string {
+ if x != nil {
+ return x.ChunkId
+ }
+ return ""
+}
+
+func (x *UndoDraftChunkRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ 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[155]
+ 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[155]
+ 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{155}
+}
+
+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"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,2,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ClearDraftChunksRequest) Reset() {
+ *x = ClearDraftChunksRequest{}
+ mi := &file_openshell_proto_msgTypes[156]
+ 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[156]
+ 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{156}
+}
+
+func (x *ClearDraftChunksRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *ClearDraftChunksRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ 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[157]
+ 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[157]
+ 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{157}
+}
+
+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"`
+ // Workspace scope. Empty defaults to "default".
+ Workspace string `protobuf:"bytes,2,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetDraftHistoryRequest) Reset() {
+ *x = GetDraftHistoryRequest{}
+ mi := &file_openshell_proto_msgTypes[158]
+ 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[158]
+ 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{158}
+}
+
+func (x *GetDraftHistoryRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *GetDraftHistoryRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ 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[159]
+ 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[159]
+ 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{159}
+}
+
+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[160]
+ 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[160]
+ 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{160}
+}
+
+func (x *GetDraftHistoryResponse) GetEntries() []*DraftHistoryEntry {
+ if x != nil {
+ return x.Entries
+ }
+ return nil
+}
+
+// Stored payload for a policy revision row in the generic objects table.
+type PolicyRevisionPayload struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Serialized policy contents.
+ Policy *sandboxv1.SandboxPolicy `protobuf:"bytes,1,opt,name=policy,proto3" json:"policy,omitempty"`
+ // Deterministic hash of the policy payload.
+ Hash string `protobuf:"bytes,2,opt,name=hash,proto3" json:"hash,omitempty"`
+ // Load error reported by the sandbox, if any.
+ LoadError string `protobuf:"bytes,3,opt,name=load_error,json=loadError,proto3" json:"load_error,omitempty"`
+ // When the policy version was reported as loaded (ms since epoch). 0 if unset.
+ LoadedAtMs int64 `protobuf:"varint,4,opt,name=loaded_at_ms,json=loadedAtMs,proto3" json:"loaded_at_ms,omitempty"`
+ // Immutable provenance supplied when this revision was created.
+ Provenance map[string]string `protobuf:"bytes,5,rep,name=provenance,proto3" json:"provenance,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *PolicyRevisionPayload) Reset() {
+ *x = PolicyRevisionPayload{}
+ mi := &file_openshell_proto_msgTypes[161]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *PolicyRevisionPayload) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PolicyRevisionPayload) ProtoMessage() {}
+
+func (x *PolicyRevisionPayload) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[161]
+ 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 PolicyRevisionPayload.ProtoReflect.Descriptor instead.
+func (*PolicyRevisionPayload) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{161}
+}
+
+func (x *PolicyRevisionPayload) GetPolicy() *sandboxv1.SandboxPolicy {
+ if x != nil {
+ return x.Policy
+ }
+ return nil
+}
+
+func (x *PolicyRevisionPayload) GetHash() string {
+ if x != nil {
+ return x.Hash
+ }
+ return ""
+}
+
+func (x *PolicyRevisionPayload) GetLoadError() string {
+ if x != nil {
+ return x.LoadError
+ }
+ return ""
+}
+
+func (x *PolicyRevisionPayload) GetLoadedAtMs() int64 {
+ if x != nil {
+ return x.LoadedAtMs
+ }
+ return 0
+}
+
+func (x *PolicyRevisionPayload) GetProvenance() map[string]string {
+ if x != nil {
+ return x.Provenance
+ }
+ return nil
+}
+
+// Stored payload for a draft policy chunk row in the generic objects table.
+type DraftChunkPayload struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Proposed network_policies map key.
+ RuleName string `protobuf:"bytes,1,opt,name=rule_name,json=ruleName,proto3" json:"rule_name,omitempty"`
+ // Proposed network policy rule.
+ ProposedRule *sandboxv1.NetworkPolicyRule `protobuf:"bytes,2,opt,name=proposed_rule,json=proposedRule,proto3" json:"proposed_rule,omitempty"`
+ // Human-readable explanation of why this rule is proposed.
+ Rationale string `protobuf:"bytes,3,opt,name=rationale,proto3" json:"rationale,omitempty"`
+ // Security concerns flagged by analysis (empty if none).
+ SecurityNotes string `protobuf:"bytes,4,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,5,opt,name=confidence,proto3" json:"confidence,omitempty"`
+ // When the user approved/rejected (ms since epoch). 0 if undecided.
+ DecidedAtMs int64 `protobuf:"varint,6,opt,name=decided_at_ms,json=decidedAtMs,proto3" json:"decided_at_ms,omitempty"`
+ // Denormalized endpoint host for dedup and display.
+ Host string `protobuf:"bytes,7,opt,name=host,proto3" json:"host,omitempty"`
+ // Denormalized endpoint port for dedup and display.
+ Port int32 `protobuf:"varint,8,opt,name=port,proto3" json:"port,omitempty"`
+ // Binary path that triggered the denial.
+ Binary string `protobuf:"bytes,9,opt,name=binary,proto3" json:"binary,omitempty"`
+ // Current draft version for the owning sandbox.
+ DraftVersion int64 `protobuf:"varint,10,opt,name=draft_version,json=draftVersion,proto3" json:"draft_version,omitempty"`
+ // Gateway prover verdict for this chunk; empty until prover runs.
+ // Mirrors PolicyChunk.validation_result.
+ ValidationResult string `protobuf:"bytes,11,opt,name=validation_result,json=validationResult,proto3" json:"validation_result,omitempty"`
+ // Operator-supplied free-form rejection text; empty for non-rejected
+ // chunks. Mirrors PolicyChunk.rejection_reason.
+ RejectionReason string `protobuf:"bytes,12,opt,name=rejection_reason,json=rejectionReason,proto3" json:"rejection_reason,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *DraftChunkPayload) Reset() {
+ *x = DraftChunkPayload{}
+ mi := &file_openshell_proto_msgTypes[162]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *DraftChunkPayload) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DraftChunkPayload) ProtoMessage() {}
+
+func (x *DraftChunkPayload) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[162]
+ 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 DraftChunkPayload.ProtoReflect.Descriptor instead.
+func (*DraftChunkPayload) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{162}
+}
+
+func (x *DraftChunkPayload) GetRuleName() string {
+ if x != nil {
+ return x.RuleName
+ }
+ return ""
+}
+
+func (x *DraftChunkPayload) GetProposedRule() *sandboxv1.NetworkPolicyRule {
+ if x != nil {
+ return x.ProposedRule
+ }
+ return nil
+}
+
+func (x *DraftChunkPayload) GetRationale() string {
+ if x != nil {
+ return x.Rationale
+ }
+ return ""
+}
+
+func (x *DraftChunkPayload) GetSecurityNotes() string {
+ if x != nil {
+ return x.SecurityNotes
+ }
+ return ""
+}
+
+func (x *DraftChunkPayload) GetConfidence() float32 {
+ if x != nil {
+ return x.Confidence
+ }
+ return 0
+}
+
+func (x *DraftChunkPayload) GetDecidedAtMs() int64 {
+ if x != nil {
+ return x.DecidedAtMs
+ }
+ return 0
+}
+
+func (x *DraftChunkPayload) GetHost() string {
+ if x != nil {
+ return x.Host
+ }
+ return ""
+}
+
+func (x *DraftChunkPayload) GetPort() int32 {
+ if x != nil {
+ return x.Port
+ }
+ return 0
+}
+
+func (x *DraftChunkPayload) GetBinary() string {
+ if x != nil {
+ return x.Binary
+ }
+ return ""
+}
+
+func (x *DraftChunkPayload) GetDraftVersion() int64 {
+ if x != nil {
+ return x.DraftVersion
+ }
+ return 0
+}
+
+func (x *DraftChunkPayload) GetValidationResult() string {
+ if x != nil {
+ return x.ValidationResult
+ }
+ return ""
+}
+
+func (x *DraftChunkPayload) GetRejectionReason() string {
+ if x != nil {
+ return x.RejectionReason
+ }
+ return ""
+}
+
+// Internal stored policy revision row materialized from the generic objects table.
+type StoredPolicyRevision struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+ SandboxId string `protobuf:"bytes,2,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"`
+ Version int64 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"`
+ PolicyPayload []byte `protobuf:"bytes,4,opt,name=policy_payload,json=policyPayload,proto3" json:"policy_payload,omitempty"`
+ PolicyHash string `protobuf:"bytes,5,opt,name=policy_hash,json=policyHash,proto3" json:"policy_hash,omitempty"`
+ Status string `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"`
+ LoadError *string `protobuf:"bytes,7,opt,name=load_error,json=loadError,proto3,oneof" json:"load_error,omitempty"`
+ CreatedAtMs int64 `protobuf:"varint,8,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"`
+ LoadedAtMs *int64 `protobuf:"varint,9,opt,name=loaded_at_ms,json=loadedAtMs,proto3,oneof" json:"loaded_at_ms,omitempty"`
+ Provenance map[string]string `protobuf:"bytes,10,rep,name=provenance,proto3" json:"provenance,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *StoredPolicyRevision) Reset() {
+ *x = StoredPolicyRevision{}
+ mi := &file_openshell_proto_msgTypes[163]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *StoredPolicyRevision) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StoredPolicyRevision) ProtoMessage() {}
+
+func (x *StoredPolicyRevision) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[163]
+ 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 StoredPolicyRevision.ProtoReflect.Descriptor instead.
+func (*StoredPolicyRevision) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{163}
+}
+
+func (x *StoredPolicyRevision) GetId() string {
+ if x != nil {
+ return x.Id
+ }
+ return ""
+}
+
+func (x *StoredPolicyRevision) GetSandboxId() string {
+ if x != nil {
+ return x.SandboxId
+ }
+ return ""
+}
+
+func (x *StoredPolicyRevision) GetVersion() int64 {
+ if x != nil {
+ return x.Version
+ }
+ return 0
+}
+
+func (x *StoredPolicyRevision) GetPolicyPayload() []byte {
+ if x != nil {
+ return x.PolicyPayload
+ }
+ return nil
+}
+
+func (x *StoredPolicyRevision) GetPolicyHash() string {
+ if x != nil {
+ return x.PolicyHash
+ }
+ return ""
+}
+
+func (x *StoredPolicyRevision) GetStatus() string {
+ if x != nil {
+ return x.Status
+ }
+ return ""
+}
+
+func (x *StoredPolicyRevision) GetLoadError() string {
+ if x != nil && x.LoadError != nil {
+ return *x.LoadError
+ }
+ return ""
+}
+
+func (x *StoredPolicyRevision) GetCreatedAtMs() int64 {
+ if x != nil {
+ return x.CreatedAtMs
+ }
+ return 0
+}
+
+func (x *StoredPolicyRevision) GetLoadedAtMs() int64 {
+ if x != nil && x.LoadedAtMs != nil {
+ return *x.LoadedAtMs
+ }
+ return 0
+}
+
+func (x *StoredPolicyRevision) GetProvenance() map[string]string {
+ if x != nil {
+ return x.Provenance
+ }
+ return nil
+}
+
+// Internal stored draft chunk row materialized from the generic objects table.
+type StoredDraftChunk struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+ SandboxId string `protobuf:"bytes,2,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"`
+ DraftVersion int64 `protobuf:"varint,3,opt,name=draft_version,json=draftVersion,proto3" json:"draft_version,omitempty"`
+ Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"`
+ RuleName string `protobuf:"bytes,5,opt,name=rule_name,json=ruleName,proto3" json:"rule_name,omitempty"`
+ ProposedRule []byte `protobuf:"bytes,6,opt,name=proposed_rule,json=proposedRule,proto3" json:"proposed_rule,omitempty"`
+ Rationale string `protobuf:"bytes,7,opt,name=rationale,proto3" json:"rationale,omitempty"`
+ SecurityNotes string `protobuf:"bytes,8,opt,name=security_notes,json=securityNotes,proto3" json:"security_notes,omitempty"`
+ Confidence float64 `protobuf:"fixed64,9,opt,name=confidence,proto3" json:"confidence,omitempty"`
+ CreatedAtMs int64 `protobuf:"varint,10,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"`
+ DecidedAtMs *int64 `protobuf:"varint,11,opt,name=decided_at_ms,json=decidedAtMs,proto3,oneof" json:"decided_at_ms,omitempty"`
+ Host string `protobuf:"bytes,12,opt,name=host,proto3" json:"host,omitempty"`
+ Port int32 `protobuf:"varint,13,opt,name=port,proto3" json:"port,omitempty"`
+ Binary string `protobuf:"bytes,14,opt,name=binary,proto3" json:"binary,omitempty"`
+ HitCount int32 `protobuf:"varint,15,opt,name=hit_count,json=hitCount,proto3" json:"hit_count,omitempty"`
+ FirstSeenMs int64 `protobuf:"varint,16,opt,name=first_seen_ms,json=firstSeenMs,proto3" json:"first_seen_ms,omitempty"`
+ LastSeenMs int64 `protobuf:"varint,17,opt,name=last_seen_ms,json=lastSeenMs,proto3" json:"last_seen_ms,omitempty"`
+ // Gateway prover verdict; empty until the prover runs. See PolicyChunk.
+ ValidationResult string `protobuf:"bytes,18,opt,name=validation_result,json=validationResult,proto3" json:"validation_result,omitempty"`
+ // Operator-supplied free-form rejection text. See PolicyChunk.
+ RejectionReason string `protobuf:"bytes,19,opt,name=rejection_reason,json=rejectionReason,proto3" json:"rejection_reason,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *StoredDraftChunk) Reset() {
+ *x = StoredDraftChunk{}
+ mi := &file_openshell_proto_msgTypes[164]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *StoredDraftChunk) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StoredDraftChunk) ProtoMessage() {}
+
+func (x *StoredDraftChunk) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[164]
+ 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 StoredDraftChunk.ProtoReflect.Descriptor instead.
+func (*StoredDraftChunk) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{164}
+}
+
+func (x *StoredDraftChunk) GetId() string {
+ if x != nil {
+ return x.Id
+ }
+ return ""
+}
+
+func (x *StoredDraftChunk) GetSandboxId() string {
+ if x != nil {
+ return x.SandboxId
+ }
+ return ""
+}
+
+func (x *StoredDraftChunk) GetDraftVersion() int64 {
+ if x != nil {
+ return x.DraftVersion
+ }
+ return 0
+}
+
+func (x *StoredDraftChunk) GetStatus() string {
+ if x != nil {
+ return x.Status
+ }
+ return ""
+}
+
+func (x *StoredDraftChunk) GetRuleName() string {
+ if x != nil {
+ return x.RuleName
+ }
+ return ""
+}
+
+func (x *StoredDraftChunk) GetProposedRule() []byte {
+ if x != nil {
+ return x.ProposedRule
+ }
+ return nil
+}
+
+func (x *StoredDraftChunk) GetRationale() string {
+ if x != nil {
+ return x.Rationale
+ }
+ return ""
+}
+
+func (x *StoredDraftChunk) GetSecurityNotes() string {
+ if x != nil {
+ return x.SecurityNotes
+ }
+ return ""
+}
+
+func (x *StoredDraftChunk) GetConfidence() float64 {
+ if x != nil {
+ return x.Confidence
+ }
+ return 0
+}
+
+func (x *StoredDraftChunk) GetCreatedAtMs() int64 {
+ if x != nil {
+ return x.CreatedAtMs
+ }
+ return 0
+}
+
+func (x *StoredDraftChunk) GetDecidedAtMs() int64 {
+ if x != nil && x.DecidedAtMs != nil {
+ return *x.DecidedAtMs
+ }
+ return 0
+}
+
+func (x *StoredDraftChunk) GetHost() string {
+ if x != nil {
+ return x.Host
+ }
+ return ""
+}
+
+func (x *StoredDraftChunk) GetPort() int32 {
+ if x != nil {
+ return x.Port
+ }
+ return 0
+}
+
+func (x *StoredDraftChunk) GetBinary() string {
+ if x != nil {
+ return x.Binary
+ }
+ return ""
+}
+
+func (x *StoredDraftChunk) GetHitCount() int32 {
+ if x != nil {
+ return x.HitCount
+ }
+ return 0
+}
+
+func (x *StoredDraftChunk) GetFirstSeenMs() int64 {
+ if x != nil {
+ return x.FirstSeenMs
+ }
+ return 0
+}
+
+func (x *StoredDraftChunk) GetLastSeenMs() int64 {
+ if x != nil {
+ return x.LastSeenMs
+ }
+ return 0
+}
+
+func (x *StoredDraftChunk) GetValidationResult() string {
+ if x != nil {
+ return x.ValidationResult
+ }
+ return ""
+}
+
+func (x *StoredDraftChunk) GetRejectionReason() string {
+ if x != nil {
+ return x.RejectionReason
+ }
+ return ""
+}
+
+// Create workspace request.
+type CreateWorkspaceRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Workspace name. Must be a valid DNS-1123 label.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // Optional labels for the workspace (key-value metadata).
+ Labels map[string]string `protobuf:"bytes,2,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *CreateWorkspaceRequest) Reset() {
+ *x = CreateWorkspaceRequest{}
+ mi := &file_openshell_proto_msgTypes[165]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *CreateWorkspaceRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CreateWorkspaceRequest) ProtoMessage() {}
+
+func (x *CreateWorkspaceRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[165]
+ 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 CreateWorkspaceRequest.ProtoReflect.Descriptor instead.
+func (*CreateWorkspaceRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{165}
+}
+
+func (x *CreateWorkspaceRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *CreateWorkspaceRequest) GetLabels() map[string]string {
+ if x != nil {
+ return x.Labels
+ }
+ return nil
+}
+
+// Create workspace response.
+type CreateWorkspaceResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Workspace *datamodelv1.Workspace `protobuf:"bytes,1,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *CreateWorkspaceResponse) Reset() {
+ *x = CreateWorkspaceResponse{}
+ mi := &file_openshell_proto_msgTypes[166]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *CreateWorkspaceResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CreateWorkspaceResponse) ProtoMessage() {}
+
+func (x *CreateWorkspaceResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[166]
+ 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 CreateWorkspaceResponse.ProtoReflect.Descriptor instead.
+func (*CreateWorkspaceResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{166}
+}
+
+func (x *CreateWorkspaceResponse) GetWorkspace() *datamodelv1.Workspace {
+ if x != nil {
+ return x.Workspace
+ }
+ return nil
+}
+
+// Get workspace request.
+type GetWorkspaceRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Workspace name (canonical lookup key).
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetWorkspaceRequest) Reset() {
+ *x = GetWorkspaceRequest{}
+ mi := &file_openshell_proto_msgTypes[167]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetWorkspaceRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetWorkspaceRequest) ProtoMessage() {}
+
+func (x *GetWorkspaceRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[167]
+ 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 GetWorkspaceRequest.ProtoReflect.Descriptor instead.
+func (*GetWorkspaceRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{167}
+}
+
+func (x *GetWorkspaceRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+// Get workspace response.
+type GetWorkspaceResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Workspace *datamodelv1.Workspace `protobuf:"bytes,1,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetWorkspaceResponse) Reset() {
+ *x = GetWorkspaceResponse{}
+ mi := &file_openshell_proto_msgTypes[168]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetWorkspaceResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetWorkspaceResponse) ProtoMessage() {}
+
+func (x *GetWorkspaceResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[168]
+ 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 GetWorkspaceResponse.ProtoReflect.Descriptor instead.
+func (*GetWorkspaceResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{168}
+}
+
+func (x *GetWorkspaceResponse) GetWorkspace() *datamodelv1.Workspace {
+ if x != nil {
+ return x.Workspace
+ }
+ return nil
+}
+
+// List workspaces request.
+type ListWorkspacesRequest 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"`
+ // Optional label selector for filtering (format: "key1=value1,key2=value2").
+ LabelSelector string `protobuf:"bytes,3,opt,name=label_selector,json=labelSelector,proto3" json:"label_selector,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ListWorkspacesRequest) Reset() {
+ *x = ListWorkspacesRequest{}
+ mi := &file_openshell_proto_msgTypes[169]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ListWorkspacesRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListWorkspacesRequest) ProtoMessage() {}
+
+func (x *ListWorkspacesRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[169]
+ 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 ListWorkspacesRequest.ProtoReflect.Descriptor instead.
+func (*ListWorkspacesRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{169}
+}
+
+func (x *ListWorkspacesRequest) GetLimit() uint32 {
+ if x != nil {
+ return x.Limit
+ }
+ return 0
+}
+
+func (x *ListWorkspacesRequest) GetOffset() uint32 {
+ if x != nil {
+ return x.Offset
+ }
+ return 0
+}
+
+func (x *ListWorkspacesRequest) GetLabelSelector() string {
+ if x != nil {
+ return x.LabelSelector
+ }
+ return ""
+}
+
+// List workspaces response.
+type ListWorkspacesResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Workspaces []*datamodelv1.Workspace `protobuf:"bytes,1,rep,name=workspaces,proto3" json:"workspaces,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ListWorkspacesResponse) Reset() {
+ *x = ListWorkspacesResponse{}
+ mi := &file_openshell_proto_msgTypes[170]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ListWorkspacesResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListWorkspacesResponse) ProtoMessage() {}
+
+func (x *ListWorkspacesResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[170]
+ 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 ListWorkspacesResponse.ProtoReflect.Descriptor instead.
+func (*ListWorkspacesResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{170}
+}
+
+func (x *ListWorkspacesResponse) GetWorkspaces() []*datamodelv1.Workspace {
+ if x != nil {
+ return x.Workspaces
+ }
+ return nil
+}
+
+// Delete workspace request.
+type DeleteWorkspaceRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Workspace name (canonical lookup key).
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *DeleteWorkspaceRequest) Reset() {
+ *x = DeleteWorkspaceRequest{}
+ mi := &file_openshell_proto_msgTypes[171]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *DeleteWorkspaceRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeleteWorkspaceRequest) ProtoMessage() {}
+
+func (x *DeleteWorkspaceRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[171]
+ 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 DeleteWorkspaceRequest.ProtoReflect.Descriptor instead.
+func (*DeleteWorkspaceRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{171}
+}
+
+func (x *DeleteWorkspaceRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+// Delete workspace response.
+type DeleteWorkspaceResponse 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 *DeleteWorkspaceResponse) Reset() {
+ *x = DeleteWorkspaceResponse{}
+ mi := &file_openshell_proto_msgTypes[172]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *DeleteWorkspaceResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeleteWorkspaceResponse) ProtoMessage() {}
+
+func (x *DeleteWorkspaceResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[172]
+ 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 DeleteWorkspaceResponse.ProtoReflect.Descriptor instead.
+func (*DeleteWorkspaceResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{172}
+}
+
+func (x *DeleteWorkspaceResponse) GetDeleted() bool {
+ if x != nil {
+ return x.Deleted
+ }
+ return false
+}
+
+// Workspace membership record.
+type WorkspaceMember struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Metadata *datamodelv1.ObjectMeta `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"`
+ // OIDC subject claim identifying the principal.
+ PrincipalSubject string `protobuf:"bytes,2,opt,name=principal_subject,json=principalSubject,proto3" json:"principal_subject,omitempty"`
+ // Role assigned to the principal within the workspace.
+ Role WorkspaceRole `protobuf:"varint,3,opt,name=role,proto3,enum=openshell.v1.WorkspaceRole" json:"role,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *WorkspaceMember) Reset() {
+ *x = WorkspaceMember{}
+ mi := &file_openshell_proto_msgTypes[173]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *WorkspaceMember) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*WorkspaceMember) ProtoMessage() {}
+
+func (x *WorkspaceMember) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[173]
+ 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 WorkspaceMember.ProtoReflect.Descriptor instead.
+func (*WorkspaceMember) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{173}
+}
+
+func (x *WorkspaceMember) GetMetadata() *datamodelv1.ObjectMeta {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+func (x *WorkspaceMember) GetPrincipalSubject() string {
+ if x != nil {
+ return x.PrincipalSubject
+ }
+ return ""
+}
+
+func (x *WorkspaceMember) GetRole() WorkspaceRole {
+ if x != nil {
+ return x.Role
+ }
+ return WorkspaceRole_WORKSPACE_ROLE_UNSPECIFIED
+}
+
+// Add workspace member request.
+type AddWorkspaceMemberRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Workspace name.
+ Workspace string `protobuf:"bytes,1,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ // OIDC subject claim identifying the principal.
+ PrincipalSubject string `protobuf:"bytes,2,opt,name=principal_subject,json=principalSubject,proto3" json:"principal_subject,omitempty"`
+ // Role to assign.
+ Role WorkspaceRole `protobuf:"varint,3,opt,name=role,proto3,enum=openshell.v1.WorkspaceRole" json:"role,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *AddWorkspaceMemberRequest) Reset() {
+ *x = AddWorkspaceMemberRequest{}
+ mi := &file_openshell_proto_msgTypes[174]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *AddWorkspaceMemberRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AddWorkspaceMemberRequest) ProtoMessage() {}
+
+func (x *AddWorkspaceMemberRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[174]
+ 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 AddWorkspaceMemberRequest.ProtoReflect.Descriptor instead.
+func (*AddWorkspaceMemberRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{174}
+}
+
+func (x *AddWorkspaceMemberRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+func (x *AddWorkspaceMemberRequest) GetPrincipalSubject() string {
+ if x != nil {
+ return x.PrincipalSubject
+ }
+ return ""
+}
+
+func (x *AddWorkspaceMemberRequest) GetRole() WorkspaceRole {
+ if x != nil {
+ return x.Role
+ }
+ return WorkspaceRole_WORKSPACE_ROLE_UNSPECIFIED
+}
+
+// Add workspace member response.
+type AddWorkspaceMemberResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Member *WorkspaceMember `protobuf:"bytes,1,opt,name=member,proto3" json:"member,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *AddWorkspaceMemberResponse) Reset() {
+ *x = AddWorkspaceMemberResponse{}
+ mi := &file_openshell_proto_msgTypes[175]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *AddWorkspaceMemberResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AddWorkspaceMemberResponse) ProtoMessage() {}
+
+func (x *AddWorkspaceMemberResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[175]
+ 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 AddWorkspaceMemberResponse.ProtoReflect.Descriptor instead.
+func (*AddWorkspaceMemberResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{175}
+}
+
+func (x *AddWorkspaceMemberResponse) GetMember() *WorkspaceMember {
+ if x != nil {
+ return x.Member
+ }
+ return nil
+}
+
+// Remove workspace member request.
+type RemoveWorkspaceMemberRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Workspace name.
+ Workspace string `protobuf:"bytes,1,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ // OIDC subject claim identifying the principal to remove.
+ PrincipalSubject string `protobuf:"bytes,2,opt,name=principal_subject,json=principalSubject,proto3" json:"principal_subject,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RemoveWorkspaceMemberRequest) Reset() {
+ *x = RemoveWorkspaceMemberRequest{}
+ mi := &file_openshell_proto_msgTypes[176]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RemoveWorkspaceMemberRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RemoveWorkspaceMemberRequest) ProtoMessage() {}
+
+func (x *RemoveWorkspaceMemberRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[176]
+ 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 RemoveWorkspaceMemberRequest.ProtoReflect.Descriptor instead.
+func (*RemoveWorkspaceMemberRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{176}
+}
+
+func (x *RemoveWorkspaceMemberRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+func (x *RemoveWorkspaceMemberRequest) GetPrincipalSubject() string {
+ if x != nil {
+ return x.PrincipalSubject
+ }
+ return ""
+}
+
+// Remove workspace member response.
+type RemoveWorkspaceMemberResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Removed bool `protobuf:"varint,1,opt,name=removed,proto3" json:"removed,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RemoveWorkspaceMemberResponse) Reset() {
+ *x = RemoveWorkspaceMemberResponse{}
+ mi := &file_openshell_proto_msgTypes[177]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RemoveWorkspaceMemberResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RemoveWorkspaceMemberResponse) ProtoMessage() {}
+
+func (x *RemoveWorkspaceMemberResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[177]
+ 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 RemoveWorkspaceMemberResponse.ProtoReflect.Descriptor instead.
+func (*RemoveWorkspaceMemberResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{177}
+}
+
+func (x *RemoveWorkspaceMemberResponse) GetRemoved() bool {
+ if x != nil {
+ return x.Removed
+ }
+ return false
+}
+
+// List workspace members request.
+type ListWorkspaceMembersRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Workspace name.
+ Workspace string `protobuf:"bytes,1,opt,name=workspace,proto3" json:"workspace,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 *ListWorkspaceMembersRequest) Reset() {
+ *x = ListWorkspaceMembersRequest{}
+ mi := &file_openshell_proto_msgTypes[178]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ListWorkspaceMembersRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListWorkspaceMembersRequest) ProtoMessage() {}
+
+func (x *ListWorkspaceMembersRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[178]
+ 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 ListWorkspaceMembersRequest.ProtoReflect.Descriptor instead.
+func (*ListWorkspaceMembersRequest) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{178}
+}
+
+func (x *ListWorkspaceMembersRequest) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+func (x *ListWorkspaceMembersRequest) GetLimit() uint32 {
+ if x != nil {
+ return x.Limit
+ }
+ return 0
+}
+
+func (x *ListWorkspaceMembersRequest) GetOffset() uint32 {
+ if x != nil {
+ return x.Offset
+ }
+ return 0
+}
+
+// List workspace members response.
+type ListWorkspaceMembersResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Members []*WorkspaceMember `protobuf:"bytes,1,rep,name=members,proto3" json:"members,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ListWorkspaceMembersResponse) Reset() {
+ *x = ListWorkspaceMembersResponse{}
+ mi := &file_openshell_proto_msgTypes[179]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ListWorkspaceMembersResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListWorkspaceMembersResponse) ProtoMessage() {}
+
+func (x *ListWorkspaceMembersResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_openshell_proto_msgTypes[179]
+ 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 ListWorkspaceMembersResponse.ProtoReflect.Descriptor instead.
+func (*ListWorkspaceMembersResponse) Descriptor() ([]byte, []int) {
+ return file_openshell_proto_rawDescGZIP(), []int{179}
+}
+
+func (x *ListWorkspaceMembersResponse) GetMembers() []*WorkspaceMember {
+ if x != nil {
+ return x.Members
+ }
+ return nil
+}
+
+var File_openshell_proto protoreflect.FileDescriptor
+
+const file_openshell_proto_rawDesc = "" +
+ "\n" +
+ "\x0fopenshell.proto\x12\fopenshell.v1\x1a\x0fdatamodel.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\roptions.proto\x1a\rsandbox.proto\"\x1a\n" +
+ "\x18IssueSandboxTokenRequest\"[\n" +
+ "\x19IssueSandboxTokenResponse\x12\x1a\n" +
+ "\x05token\x18\x01 \x01(\tB\x04\x88\xb5\x18\x01R\x05token\x12\"\n" +
+ "\rexpires_at_ms\x18\x02 \x01(\x03R\vexpiresAtMs\"\x1c\n" +
+ "\x1aRefreshSandboxTokenRequest\"]\n" +
+ "\x1bRefreshSandboxTokenResponse\x12\x1a\n" +
+ "\x05token\x18\x01 \x01(\tB\x04\x88\xb5\x18\x01R\x05token\x12\"\n" +
+ "\rexpires_at_ms\x18\x02 \x01(\x03R\vexpiresAtMs\"\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\"\x17\n" +
+ "\x15GetCurrentUserRequest\"\xb0\x01\n" +
+ "\x16GetCurrentUserResponse\x12\x18\n" +
+ "\asubject\x18\x01 \x01(\tR\asubject\x12!\n" +
+ "\fdisplay_name\x18\x02 \x01(\tR\vdisplayName\x12\x14\n" +
+ "\x05roles\x18\x03 \x03(\tR\x05roles\x12\x16\n" +
+ "\x06scopes\x18\x04 \x03(\tR\x06scopes\x12+\n" +
+ "\x11identity_provider\x18\x05 \x01(\tR\x10identityProvider\"\x17\n" +
+ "\x15GetGatewayInfoRequest\"\xc0\x01\n" +
+ "\x16GetGatewayInfoResponse\x123\n" +
+ "\x06status\x18\x01 \x01(\x0e2\x1b.openshell.v1.ServiceStatusR\x06status\x12'\n" +
+ "\x0fgateway_version\x18\x02 \x01(\tR\x0egatewayVersion\x12H\n" +
+ "\x0fcompute_drivers\x18\x03 \x03(\v2\x1f.openshell.v1.ComputeDriverInfoR\x0ecomputeDrivers\"t\n" +
+ "\x11ComputeDriverInfo\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12K\n" +
+ "\fcapabilities\x18\x02 \x01(\v2'.openshell.v1.ComputeDriverCapabilitiesR\fcapabilities\"c\n" +
+ "\x19ComputeDriverCapabilities\x12\x1f\n" +
+ "\vdriver_name\x18\x01 \x01(\tR\n" +
+ "driverName\x12%\n" +
+ "\x0edriver_version\x18\x02 \x01(\tR\rdriverVersion\"\xd8\x01\n" +
+ "\aSandbox\x12>\n" +
+ "\bmetadata\x18\x01 \x01(\v2\".openshell.datamodel.v1.ObjectMetaR\bmetadata\x12-\n" +
+ "\x04spec\x18\x02 \x01(\v2\x19.openshell.v1.SandboxSpecR\x04spec\x123\n" +
+ "\x06status\x18\x03 \x01(\v2\x1b.openshell.v1.SandboxStatusR\x06statusJ\x04\b\x04\x10\x05J\x04\b\x05\x10\x06R\x05phaseR\x16current_policy_version\"\xd7\x03\n" +
+ "\vSandboxSpec\x12\x1b\n" +
+ "\tlog_level\x18\x01 \x01(\tR\blogLevel\x12L\n" +
+ "\venvironment\x18\x05 \x03(\v2*.openshell.v1.SandboxSpec.EnvironmentEntryR\venvironment\x129\n" +
+ "\btemplate\x18\x06 \x01(\v2\x1d.openshell.v1.SandboxTemplateR\btemplate\x12;\n" +
+ "\x06policy\x18\a \x01(\v2#.openshell.sandbox.v1.SandboxPolicyR\x06policy\x12\x1c\n" +
+ "\tproviders\x18\b \x03(\tR\tproviders\x12W\n" +
+ "\x15resource_requirements\x18\t \x01(\v2\".openshell.v1.ResourceRequirementsR\x14resourceRequirements\x1a>\n" +
+ "\x10EnvironmentEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01J\x04\b\n" +
+ "\x10\vJ\x04\b\v\x10\fR\n" +
+ "gpu_deviceR\x16proposal_approval_mode\"O\n" +
+ "\x14ResourceRequirements\x127\n" +
+ "\x03gpu\x18\x01 \x01(\v2%.openshell.v1.GpuResourceRequirementsR\x03gpu\">\n" +
+ "\x17GpuResourceRequirements\x12\x19\n" +
+ "\x05count\x18\x01 \x01(\rH\x00R\x05count\x88\x01\x01B\b\n" +
+ "\x06_count\"\xef\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\x12A\n" +
+ "\x06labels\x18\x04 \x03(\v2).openshell.v1.SandboxTemplate.LabelsEntryR\x06labels\x12P\n" +
+ "\vannotations\x18\x05 \x03(\v2..openshell.v1.SandboxTemplate.AnnotationsEntryR\vannotations\x12P\n" +
+ "\venvironment\x18\x06 \x03(\v2..openshell.v1.SandboxTemplate.EnvironmentEntryR\venvironment\x125\n" +
+ "\tresources\x18\a \x01(\v2\x17.google.protobuf.StructR\tresources\x12,\n" +
+ "\x0fuser_namespaces\x18\n" +
+ " \x01(\bH\x00R\x0euserNamespaces\x88\x01\x01\x12<\n" +
+ "\rdriver_config\x18\v \x01(\v2\x17.google.protobuf.StructR\fdriverConfig\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\x01B\x12\n" +
+ "\x10_user_namespacesJ\x04\b\t\x10\n" +
+ "R\x16volume_claim_templates\"\xb1\x02\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\x12>\n" +
+ "\n" +
+ "conditions\x18\x05 \x03(\v2\x1e.openshell.v1.SandboxConditionR\n" +
+ "conditions\x120\n" +
+ "\x05phase\x18\x06 \x01(\x0e2\x1a.openshell.v1.SandboxPhaseR\x05phase\x124\n" +
+ "\x16current_policy_version\x18\a \x01(\rR\x14currentPolicyVersion\"\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\"\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\"\x91\x03\n" +
+ "\x14CreateSandboxRequest\x12-\n" +
+ "\x04spec\x18\x01 \x01(\v2\x19.openshell.v1.SandboxSpecR\x04spec\x12\x12\n" +
+ "\x04name\x18\x02 \x01(\tR\x04name\x12F\n" +
+ "\x06labels\x18\x03 \x03(\v2..openshell.v1.CreateSandboxRequest.LabelsEntryR\x06labels\x12U\n" +
+ "\vannotations\x18\x04 \x03(\v23.openshell.v1.CreateSandboxRequest.AnnotationsEntryR\vannotations\x12\x1c\n" +
+ "\tworkspace\x18\x05 \x01(\tR\tworkspace\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\"E\n" +
+ "\x11GetSandboxRequest\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12\x1c\n" +
+ "\tworkspace\x18\x02 \x01(\tR\tworkspace\"\xb0\x01\n" +
+ "\x14ListSandboxesRequest\x12\x14\n" +
+ "\x05limit\x18\x01 \x01(\rR\x05limit\x12\x16\n" +
+ "\x06offset\x18\x02 \x01(\rR\x06offset\x12%\n" +
+ "\x0elabel_selector\x18\x03 \x01(\tR\rlabelSelector\x12\x1c\n" +
+ "\tworkspace\x18\x04 \x01(\tR\tworkspace\x12%\n" +
+ "\x0eall_workspaces\x18\x05 \x01(\bR\rallWorkspaces\"^\n" +
+ "\x1bListSandboxProvidersRequest\x12!\n" +
+ "\fsandbox_name\x18\x01 \x01(\tR\vsandboxName\x12\x1c\n" +
+ "\tworkspace\x18\x02 \x01(\tR\tworkspace\"\xc0\x01\n" +
+ "\x1cAttachSandboxProviderRequest\x12!\n" +
+ "\fsandbox_name\x18\x01 \x01(\tR\vsandboxName\x12#\n" +
+ "\rprovider_name\x18\x02 \x01(\tR\fproviderName\x12:\n" +
+ "\x19expected_resource_version\x18\x03 \x01(\x04R\x17expectedResourceVersion\x12\x1c\n" +
+ "\tworkspace\x18\x04 \x01(\tR\tworkspace\"\xc0\x01\n" +
+ "\x1cDetachSandboxProviderRequest\x12!\n" +
+ "\fsandbox_name\x18\x01 \x01(\tR\vsandboxName\x12#\n" +
+ "\rprovider_name\x18\x02 \x01(\tR\fproviderName\x12:\n" +
+ "\x19expected_resource_version\x18\x03 \x01(\x04R\x17expectedResourceVersion\x12\x1c\n" +
+ "\tworkspace\x18\x04 \x01(\tR\tworkspace\"H\n" +
+ "\x14DeleteSandboxRequest\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12\x1c\n" +
+ "\tworkspace\x18\x02 \x01(\tR\tworkspace\"B\n" +
+ "\x0fSandboxResponse\x12/\n" +
+ "\asandbox\x18\x01 \x01(\v2\x15.openshell.v1.SandboxR\asandbox\"L\n" +
+ "\x15ListSandboxesResponse\x123\n" +
+ "\tsandboxes\x18\x01 \x03(\v2\x15.openshell.v1.SandboxR\tsandboxes\"^\n" +
+ "\x1cListSandboxProvidersResponse\x12>\n" +
+ "\tproviders\x18\x01 \x03(\v2 .openshell.datamodel.v1.ProviderR\tproviders\"l\n" +
+ "\x1dAttachSandboxProviderResponse\x12/\n" +
+ "\asandbox\x18\x01 \x01(\v2\x15.openshell.v1.SandboxR\asandbox\x12\x1a\n" +
+ "\battached\x18\x02 \x01(\bR\battached\"l\n" +
+ "\x1dDetachSandboxProviderResponse\x12/\n" +
+ "\asandbox\x18\x01 \x01(\v2\x15.openshell.v1.SandboxR\asandbox\x12\x1a\n" +
+ "\bdetached\x18\x02 \x01(\bR\bdetached\"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\"\x98\x02\n" +
+ "\x18CreateSshSessionResponse\x12\x1d\n" +
+ "\n" +
+ "sandbox_id\x18\x01 \x01(\tR\tsandboxId\x12\x1a\n" +
+ "\x05token\x18\x02 \x01(\tB\x04\x88\xb5\x18\x01R\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\x120\n" +
+ "\x14host_key_fingerprint\x18\a \x01(\tR\x12hostKeyFingerprint\x12\"\n" +
+ "\rexpires_at_ms\x18\b \x01(\x03R\vexpiresAtMs\"\xa1\x01\n" +
+ "\x14ExposeServiceRequest\x12\x18\n" +
+ "\asandbox\x18\x01 \x01(\tR\asandbox\x12\x18\n" +
+ "\aservice\x18\x02 \x01(\tR\aservice\x12\x1f\n" +
+ "\vtarget_port\x18\x03 \x01(\rR\n" +
+ "targetPort\x12\x16\n" +
+ "\x06domain\x18\x04 \x01(\bR\x06domain\x12\x1c\n" +
+ "\tworkspace\x18\x05 \x01(\tR\tworkspace\"e\n" +
+ "\x11GetServiceRequest\x12\x18\n" +
+ "\asandbox\x18\x01 \x01(\tR\asandbox\x12\x18\n" +
+ "\aservice\x18\x02 \x01(\tR\aservice\x12\x1c\n" +
+ "\tworkspace\x18\x03 \x01(\tR\tworkspace\"\xa2\x01\n" +
+ "\x13ListServicesRequest\x12\x18\n" +
+ "\asandbox\x18\x01 \x01(\tR\asandbox\x12\x14\n" +
+ "\x05limit\x18\x02 \x01(\rR\x05limit\x12\x16\n" +
+ "\x06offset\x18\x03 \x01(\rR\x06offset\x12\x1c\n" +
+ "\tworkspace\x18\x04 \x01(\tR\tworkspace\x12%\n" +
+ "\x0eall_workspaces\x18\x05 \x01(\bR\rallWorkspaces\"Y\n" +
+ "\x14ListServicesResponse\x12A\n" +
+ "\bservices\x18\x01 \x03(\v2%.openshell.v1.ServiceEndpointResponseR\bservices\"h\n" +
+ "\x14DeleteServiceRequest\x12\x18\n" +
+ "\asandbox\x18\x01 \x01(\tR\asandbox\x12\x18\n" +
+ "\aservice\x18\x02 \x01(\tR\aservice\x12\x1c\n" +
+ "\tworkspace\x18\x03 \x01(\tR\tworkspace\"1\n" +
+ "\x15DeleteServiceResponse\x12\x18\n" +
+ "\adeleted\x18\x01 \x01(\bR\adeleted\"\xef\x01\n" +
+ "\x0fServiceEndpoint\x12>\n" +
+ "\bmetadata\x18\x01 \x01(\v2\".openshell.datamodel.v1.ObjectMetaR\bmetadata\x12\x1d\n" +
+ "\n" +
+ "sandbox_id\x18\x02 \x01(\tR\tsandboxId\x12!\n" +
+ "\fsandbox_name\x18\x03 \x01(\tR\vsandboxName\x12!\n" +
+ "\fservice_name\x18\x04 \x01(\tR\vserviceName\x12\x1f\n" +
+ "\vtarget_port\x18\x05 \x01(\rR\n" +
+ "targetPort\x12\x16\n" +
+ "\x06domain\x18\x06 \x01(\bR\x06domain\"f\n" +
+ "\x17ServiceEndpointResponse\x129\n" +
+ "\bendpoint\x18\x01 \x01(\v2\x1d.openshell.v1.ServiceEndpointR\bendpoint\x12\x10\n" +
+ "\x03url\x18\x02 \x01(\tR\x03url\"5\n" +
+ "\x17RevokeSshSessionRequest\x12\x1a\n" +
+ "\x05token\x18\x01 \x01(\tB\x04\x88\xb5\x18\x01R\x05token\"4\n" +
+ "\x18RevokeSshSessionResponse\x12\x18\n" +
+ "\arevoked\x18\x01 \x01(\bR\arevoked\"\xf5\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\x12\x10\n" +
+ "\x03tty\x18\a \x01(\bR\x03tty\x12\x12\n" +
+ "\x04cols\x18\b \x01(\rR\x04cols\x12\x12\n" +
+ "\x04rows\x18\t \x01(\rR\x04rows\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\"\xf3\x01\n" +
+ "\x0eTcpForwardInit\x12\x1d\n" +
+ "\n" +
+ "sandbox_id\x18\x01 \x01(\tR\tsandboxId\x12\x1d\n" +
+ "\n" +
+ "service_id\x18\x04 \x01(\tR\tserviceId\x120\n" +
+ "\x03ssh\x18\x05 \x01(\v2\x1c.openshell.v1.SshRelayTargetH\x00R\x03ssh\x120\n" +
+ "\x03tcp\x18\x06 \x01(\v2\x1c.openshell.v1.TcpRelayTargetH\x00R\x03tcp\x125\n" +
+ "\x13authorization_token\x18\a \x01(\tB\x04\x88\xb5\x18\x01R\x12authorizationTokenB\b\n" +
+ "\x06target\"f\n" +
+ "\x0fTcpForwardFrame\x122\n" +
+ "\x04init\x18\x01 \x01(\v2\x1c.openshell.v1.TcpForwardInitH\x00R\x04init\x12\x14\n" +
+ "\x04data\x18\x02 \x01(\fH\x00R\x04dataB\t\n" +
+ "\apayload\"\xb0\x01\n" +
+ "\x10ExecSandboxInput\x128\n" +
+ "\x05start\x18\x01 \x01(\v2 .openshell.v1.ExecSandboxRequestH\x00R\x05start\x12\x16\n" +
+ "\x05stdin\x18\x02 \x01(\fH\x00R\x05stdin\x12?\n" +
+ "\x06resize\x18\x03 \x01(\v2%.openshell.v1.ExecSandboxWindowResizeH\x00R\x06resizeB\t\n" +
+ "\apayload\"A\n" +
+ "\x17ExecSandboxWindowResize\x12\x12\n" +
+ "\x04cols\x18\x01 \x01(\rR\x04cols\x12\x12\n" +
+ "\x04rows\x18\x02 \x01(\rR\x04rows\"\xc5\x01\n" +
+ "\n" +
+ "SshSession\x12>\n" +
+ "\bmetadata\x18\x01 \x01(\v2\".openshell.datamodel.v1.ObjectMetaR\bmetadata\x12\x1d\n" +
+ "\n" +
+ "sandbox_id\x18\x02 \x01(\tR\tsandboxId\x12\x1a\n" +
+ "\x05token\x18\x03 \x01(\tB\x04\x88\xb5\x18\x01R\x05token\x12\"\n" +
+ "\rexpires_at_ms\x18\x04 \x01(\x03R\vexpiresAtMs\x12\x18\n" +
+ "\arevoked\x18\x05 \x01(\bR\arevoked\"\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\"\xcc\x02\n" +
+ "\x12SandboxStreamEvent\x121\n" +
+ "\asandbox\x18\x01 \x01(\v2\x15.openshell.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\"0\n" +
+ "\x14SandboxStreamWarning\x12\x18\n" +
+ "\amessage\x18\x01 \x01(\tR\amessage\"s\n" +
+ "\x15CreateProviderRequest\x12<\n" +
+ "\bprovider\x18\x01 \x01(\v2 .openshell.datamodel.v1.ProviderR\bprovider\x12\x1c\n" +
+ "\tworkspace\x18\x02 \x01(\tR\tworkspace\"F\n" +
+ "\x12GetProviderRequest\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12\x1c\n" +
+ "\tworkspace\x18\x02 \x01(\tR\tworkspace\"\x89\x01\n" +
+ "\x14ListProvidersRequest\x12\x14\n" +
+ "\x05limit\x18\x01 \x01(\rR\x05limit\x12\x16\n" +
+ "\x06offset\x18\x02 \x01(\rR\x06offset\x12\x1c\n" +
+ "\tworkspace\x18\x03 \x01(\tR\tworkspace\x12%\n" +
+ "\x0eall_workspaces\x18\x04 \x01(\bR\rallWorkspaces\"\xb6\x02\n" +
+ "\x15UpdateProviderRequest\x12<\n" +
+ "\bprovider\x18\x01 \x01(\v2 .openshell.datamodel.v1.ProviderR\bprovider\x12w\n" +
+ "\x18credential_expires_at_ms\x18\x02 \x03(\v2>.openshell.v1.UpdateProviderRequest.CredentialExpiresAtMsEntryR\x15credentialExpiresAtMs\x12\x1c\n" +
+ "\tworkspace\x18\x03 \x01(\tR\tworkspace\x1aH\n" +
+ "\x1aCredentialExpiresAtMsEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\x03R\x05value:\x028\x01\"I\n" +
+ "\x15DeleteProviderRequest\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12\x1c\n" +
+ "\tworkspace\x18\x02 \x01(\tR\tworkspace\"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\"i\n" +
+ "\x1bListProviderProfilesRequest\x12\x14\n" +
+ "\x05limit\x18\x01 \x01(\rR\x05limit\x12\x16\n" +
+ "\x06offset\x18\x02 \x01(\rR\x06offset\x12\x1c\n" +
+ "\tworkspace\x18\x03 \x01(\tR\tworkspace\"I\n" +
+ "\x19GetProviderProfileRequest\x12\x0e\n" +
+ "\x02id\x18\x01 \x01(\tR\x02id\x12\x1c\n" +
+ "\tworkspace\x18\x02 \x01(\tR\tworkspace\"l\n" +
+ "\x19ProviderProfileImportItem\x127\n" +
+ "\aprofile\x18\x01 \x01(\v2\x1d.openshell.v1.ProviderProfileR\aprofile\x12\x16\n" +
+ "\x06source\x18\x02 \x01(\tR\x06source\"\x9e\x01\n" +
+ "\x19ProviderProfileDiagnostic\x12\x16\n" +
+ "\x06source\x18\x01 \x01(\tR\x06source\x12\x1d\n" +
+ "\n" +
+ "profile_id\x18\x02 \x01(\tR\tprofileId\x12\x14\n" +
+ "\x05field\x18\x03 \x01(\tR\x05field\x12\x18\n" +
+ "\amessage\x18\x04 \x01(\tR\amessage\x12\x1a\n" +
+ "\bseverity\x18\x05 \x01(\tR\bseverity\"\x9e\x01\n" +
+ ",ProviderCredentialTokenGrantAudienceOverride\x12\x12\n" +
+ "\x04host\x18\x01 \x01(\tR\x04host\x12\x12\n" +
+ "\x04port\x18\x02 \x01(\rR\x04port\x12\x12\n" +
+ "\x04path\x18\x03 \x01(\tR\x04path\x12\x1a\n" +
+ "\baudience\x18\x04 \x01(\tR\baudience\x12\x16\n" +
+ "\x06scopes\x18\x05 \x03(\tR\x06scopes\"\xf0\x02\n" +
+ "\x1cProviderCredentialTokenGrant\x12%\n" +
+ "\x0etoken_endpoint\x18\x01 \x01(\tR\rtokenEndpoint\x12\x1a\n" +
+ "\baudience\x18\x02 \x01(\tR\baudience\x12*\n" +
+ "\x11jwt_svid_audience\x18\x06 \x01(\tR\x0fjwtSvidAudience\x12\x16\n" +
+ "\x06scopes\x18\x03 \x03(\tR\x06scopes\x12*\n" +
+ "\x11cache_ttl_seconds\x18\x04 \x01(\x03R\x0fcacheTtlSeconds\x12i\n" +
+ "\x12audience_overrides\x18\x05 \x03(\v2:.openshell.v1.ProviderCredentialTokenGrantAudienceOverrideR\x11audienceOverrides\x122\n" +
+ "\x15client_assertion_type\x18\a \x01(\tR\x13clientAssertionType\"\x9e\x03\n" +
+ "\x19ProviderProfileCredential\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12 \n" +
+ "\vdescription\x18\x02 \x01(\tR\vdescription\x12\x19\n" +
+ "\benv_vars\x18\x03 \x03(\tR\aenvVars\x12\x1a\n" +
+ "\brequired\x18\x04 \x01(\bR\brequired\x12\x1d\n" +
+ "\n" +
+ "auth_style\x18\x05 \x01(\tR\tauthStyle\x12\x1f\n" +
+ "\vheader_name\x18\x06 \x01(\tR\n" +
+ "headerName\x12\x1f\n" +
+ "\vquery_param\x18\a \x01(\tR\n" +
+ "queryParam\x12A\n" +
+ "\arefresh\x18\b \x01(\v2'.openshell.v1.ProviderCredentialRefreshR\arefresh\x12#\n" +
+ "\rpath_template\x18\t \x01(\tR\fpathTemplate\x12K\n" +
+ "\vtoken_grant\x18\n" +
+ " \x01(\v2*.openshell.v1.ProviderCredentialTokenGrantR\n" +
+ "tokenGrant\"\x8d\x01\n" +
+ "!ProviderCredentialRefreshMaterial\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12 \n" +
+ "\vdescription\x18\x02 \x01(\tR\vdescription\x12\x1a\n" +
+ "\brequired\x18\x03 \x01(\bR\brequired\x12\x16\n" +
+ "\x06secret\x18\x04 \x01(\bR\x06secret\"Y\n" +
+ "\x1fProviderCredentialRefreshOutput\x12\x16\n" +
+ "\x06output\x18\x01 \x01(\tR\x06output\x12\x1e\n" +
+ "\n" +
+ "credential\x18\x02 \x01(\tR\n" +
+ "credential\"\xb0\x03\n" +
+ "\x19ProviderCredentialRefresh\x12K\n" +
+ "\bstrategy\x18\x01 \x01(\x0e2/.openshell.v1.ProviderCredentialRefreshStrategyR\bstrategy\x12\x1b\n" +
+ "\ttoken_url\x18\x02 \x01(\tR\btokenUrl\x12\x16\n" +
+ "\x06scopes\x18\x03 \x03(\tR\x06scopes\x124\n" +
+ "\x16refresh_before_seconds\x18\x04 \x01(\x03R\x14refreshBeforeSeconds\x120\n" +
+ "\x14max_lifetime_seconds\x18\x05 \x01(\x03R\x12maxLifetimeSeconds\x12K\n" +
+ "\bmaterial\x18\x06 \x03(\v2/.openshell.v1.ProviderCredentialRefreshMaterialR\bmaterial\x12\\\n" +
+ "\x12additional_outputs\x18\a \x03(\v2-.openshell.v1.ProviderCredentialRefreshOutputR\x11additionalOutputs\"\x90\x03\n" +
+ "\x1fProviderCredentialRefreshStatus\x12#\n" +
+ "\rprovider_name\x18\x01 \x01(\tR\fproviderName\x12\x1f\n" +
+ "\vprovider_id\x18\x02 \x01(\tR\n" +
+ "providerId\x12%\n" +
+ "\x0ecredential_key\x18\x03 \x01(\tR\rcredentialKey\x12K\n" +
+ "\bstrategy\x18\x04 \x01(\x0e2/.openshell.v1.ProviderCredentialRefreshStrategyR\bstrategy\x12\x16\n" +
+ "\x06status\x18\x05 \x01(\tR\x06status\x12\"\n" +
+ "\rexpires_at_ms\x18\x06 \x01(\x03R\vexpiresAtMs\x12+\n" +
+ "\x12next_refresh_at_ms\x18\a \x01(\x03R\x0fnextRefreshAtMs\x12+\n" +
+ "\x12last_refresh_at_ms\x18\b \x01(\x03R\x0flastRefreshAtMs\x12\x1d\n" +
+ "\n" +
+ "last_error\x18\t \x01(\tR\tlastError\"<\n" +
+ "\x18ProviderProfileDiscovery\x12 \n" +
+ "\vcredentials\x18\x01 \x03(\tR\vcredentials\"\x93\b\n" +
+ "$StoredProviderCredentialRefreshState\x12>\n" +
+ "\bmetadata\x18\x01 \x01(\v2\".openshell.datamodel.v1.ObjectMetaR\bmetadata\x12\x1f\n" +
+ "\vprovider_id\x18\x02 \x01(\tR\n" +
+ "providerId\x12#\n" +
+ "\rprovider_name\x18\x03 \x01(\tR\fproviderName\x12%\n" +
+ "\x0ecredential_key\x18\x04 \x01(\tR\rcredentialKey\x12K\n" +
+ "\bstrategy\x18\x05 \x01(\x0e2/.openshell.v1.ProviderCredentialRefreshStrategyR\bstrategy\x12b\n" +
+ "\bmaterial\x18\x06 \x03(\v2@.openshell.v1.StoredProviderCredentialRefreshState.MaterialEntryB\x04\x88\xb5\x18\x01R\bmaterial\x120\n" +
+ "\x14secret_material_keys\x18\a \x03(\tR\x12secretMaterialKeys\x12\"\n" +
+ "\rexpires_at_ms\x18\b \x01(\x03R\vexpiresAtMs\x12+\n" +
+ "\x12next_refresh_at_ms\x18\t \x01(\x03R\x0fnextRefreshAtMs\x12+\n" +
+ "\x12last_refresh_at_ms\x18\n" +
+ " \x01(\x03R\x0flastRefreshAtMs\x12\x16\n" +
+ "\x06status\x18\v \x01(\tR\x06status\x12\x1d\n" +
+ "\n" +
+ "last_error\x18\f \x01(\tR\tlastError\x12\x1b\n" +
+ "\ttoken_url\x18\r \x01(\tR\btokenUrl\x12\x16\n" +
+ "\x06scopes\x18\x0e \x03(\tR\x06scopes\x124\n" +
+ "\x16refresh_before_seconds\x18\x0f \x01(\x03R\x14refreshBeforeSeconds\x120\n" +
+ "\x14max_lifetime_seconds\x18\x10 \x01(\x03R\x12maxLifetimeSeconds\x12\x82\x01\n" +
+ "\x16additional_output_keys\x18\x11 \x03(\v2L.openshell.v1.StoredProviderCredentialRefreshState.AdditionalOutputKeysEntryR\x14additionalOutputKeys\x1a;\n" +
+ "\rMaterialEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\x1aG\n" +
+ "\x19AdditionalOutputKeysEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\x82\x01\n" +
+ "\x1fGetProviderRefreshStatusRequest\x12\x1a\n" +
+ "\bprovider\x18\x01 \x01(\tR\bprovider\x12%\n" +
+ "\x0ecredential_key\x18\x02 \x01(\tR\rcredentialKey\x12\x1c\n" +
+ "\tworkspace\x18\x03 \x01(\tR\tworkspace\"s\n" +
+ " GetProviderRefreshStatusResponse\x12O\n" +
+ "\vcredentials\x18\x01 \x03(\v2-.openshell.v1.ProviderCredentialRefreshStatusR\vcredentials\"\xd8\x03\n" +
+ "\x1fConfigureProviderRefreshRequest\x12\x1a\n" +
+ "\bprovider\x18\x01 \x01(\tR\bprovider\x12%\n" +
+ "\x0ecredential_key\x18\x02 \x01(\tR\rcredentialKey\x12K\n" +
+ "\bstrategy\x18\x03 \x01(\x0e2/.openshell.v1.ProviderCredentialRefreshStrategyR\bstrategy\x12]\n" +
+ "\bmaterial\x18\x04 \x03(\v2;.openshell.v1.ConfigureProviderRefreshRequest.MaterialEntryB\x04\x88\xb5\x18\x01R\bmaterial\x120\n" +
+ "\x14secret_material_keys\x18\x05 \x03(\tR\x12secretMaterialKeys\x12'\n" +
+ "\rexpires_at_ms\x18\x06 \x01(\x03H\x00R\vexpiresAtMs\x88\x01\x01\x12\x1c\n" +
+ "\tworkspace\x18\a \x01(\tR\tworkspace\x1a;\n" +
+ "\rMaterialEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01B\x10\n" +
+ "\x0e_expires_at_ms\"i\n" +
+ " ConfigureProviderRefreshResponse\x12E\n" +
+ "\x06status\x18\x01 \x01(\v2-.openshell.v1.ProviderCredentialRefreshStatusR\x06status\"\x82\x01\n" +
+ "\x1fRotateProviderCredentialRequest\x12\x1a\n" +
+ "\bprovider\x18\x01 \x01(\tR\bprovider\x12%\n" +
+ "\x0ecredential_key\x18\x02 \x01(\tR\rcredentialKey\x12\x1c\n" +
+ "\tworkspace\x18\x03 \x01(\tR\tworkspace\"i\n" +
+ " RotateProviderCredentialResponse\x12E\n" +
+ "\x06status\x18\x01 \x01(\v2-.openshell.v1.ProviderCredentialRefreshStatusR\x06status\"\x7f\n" +
+ "\x1cDeleteProviderRefreshRequest\x12\x1a\n" +
+ "\bprovider\x18\x01 \x01(\tR\bprovider\x12%\n" +
+ "\x0ecredential_key\x18\x02 \x01(\tR\rcredentialKey\x12\x1c\n" +
+ "\tworkspace\x18\x03 \x01(\tR\tworkspace\"9\n" +
+ "\x1dDeleteProviderRefreshResponse\x12\x18\n" +
+ "\adeleted\x18\x01 \x01(\bR\adeleted\"\xd8\x05\n" +
+ "\x0fProviderProfile\x12\x0e\n" +
+ "\x02id\x18\x01 \x01(\tR\x02id\x12!\n" +
+ "\fdisplay_name\x18\x02 \x01(\tR\vdisplayName\x12 \n" +
+ "\vdescription\x18\x03 \x01(\tR\vdescription\x12A\n" +
+ "\bcategory\x18\x04 \x01(\x0e2%.openshell.v1.ProviderProfileCategoryR\bcategory\x12I\n" +
+ "\vcredentials\x18\x05 \x03(\v2'.openshell.v1.ProviderProfileCredentialR\vcredentials\x12C\n" +
+ "\tendpoints\x18\x06 \x03(\v2%.openshell.sandbox.v1.NetworkEndpointR\tendpoints\x12?\n" +
+ "\bbinaries\x18\a \x03(\v2#.openshell.sandbox.v1.NetworkBinaryR\bbinaries\x12+\n" +
+ "\x11inference_capable\x18\b \x01(\bR\x10inferenceCapable\x12D\n" +
+ "\tdiscovery\x18\t \x01(\v2&.openshell.v1.ProviderProfileDiscoveryR\tdiscovery\x12)\n" +
+ "\x10resource_version\x18\n" +
+ " \x01(\x04R\x0fresourceVersion\x12P\n" +
+ "\vannotations\x18\v \x03(\v2..openshell.v1.ProviderProfile.AnnotationsEntryR\vannotations\x12\x16\n" +
+ "\x06source\x18\f \x01(\tR\x06source\x12\x14\n" +
+ "\x05scope\x18\r \x01(\tR\x05scope\x1a>\n" +
+ "\x10AnnotationsEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\x90\x01\n" +
+ "\x15StoredProviderProfile\x12>\n" +
+ "\bmetadata\x18\x01 \x01(\v2\".openshell.datamodel.v1.ObjectMetaR\bmetadata\x127\n" +
+ "\aprofile\x18\x02 \x01(\v2\x1d.openshell.v1.ProviderProfileR\aprofile\"R\n" +
+ "\x17ProviderProfileResponse\x127\n" +
+ "\aprofile\x18\x01 \x01(\v2\x1d.openshell.v1.ProviderProfileR\aprofile\"Y\n" +
+ "\x1cListProviderProfilesResponse\x129\n" +
+ "\bprofiles\x18\x01 \x03(\v2\x1d.openshell.v1.ProviderProfileR\bprofiles\"\x82\x01\n" +
+ "\x1dImportProviderProfilesRequest\x12C\n" +
+ "\bprofiles\x18\x01 \x03(\v2'.openshell.v1.ProviderProfileImportItemR\bprofiles\x12\x1c\n" +
+ "\tworkspace\x18\x02 \x01(\tR\tworkspace\"\xc2\x01\n" +
+ "\x1eImportProviderProfilesResponse\x12I\n" +
+ "\vdiagnostics\x18\x01 \x03(\v2'.openshell.v1.ProviderProfileDiagnosticR\vdiagnostics\x129\n" +
+ "\bprofiles\x18\x02 \x03(\v2\x1d.openshell.v1.ProviderProfileR\bprofiles\x12\x1a\n" +
+ "\bimported\x18\x03 \x01(\bR\bimported\"\xcc\x01\n" +
+ "\x1dUpdateProviderProfilesRequest\x12A\n" +
+ "\aprofile\x18\x01 \x01(\v2'.openshell.v1.ProviderProfileImportItemR\aprofile\x12:\n" +
+ "\x19expected_resource_version\x18\x02 \x01(\x04R\x17expectedResourceVersion\x12\x0e\n" +
+ "\x02id\x18\x03 \x01(\tR\x02id\x12\x1c\n" +
+ "\tworkspace\x18\x04 \x01(\tR\tworkspace\"\xbe\x01\n" +
+ "\x1eUpdateProviderProfilesResponse\x12I\n" +
+ "\vdiagnostics\x18\x01 \x03(\v2'.openshell.v1.ProviderProfileDiagnosticR\vdiagnostics\x127\n" +
+ "\aprofile\x18\x02 \x01(\v2\x1d.openshell.v1.ProviderProfileR\aprofile\x12\x18\n" +
+ "\aupdated\x18\x03 \x01(\bR\aupdated\"\x80\x01\n" +
+ "\x1bLintProviderProfilesRequest\x12C\n" +
+ "\bprofiles\x18\x01 \x03(\v2'.openshell.v1.ProviderProfileImportItemR\bprofiles\x12\x1c\n" +
+ "\tworkspace\x18\x02 \x01(\tR\tworkspace\"\x7f\n" +
+ "\x1cLintProviderProfilesResponse\x12I\n" +
+ "\vdiagnostics\x18\x01 \x03(\v2'.openshell.v1.ProviderProfileDiagnosticR\vdiagnostics\x12\x14\n" +
+ "\x05valid\x18\x02 \x01(\bR\x05valid\"2\n" +
+ "\x16DeleteProviderResponse\x12\x18\n" +
+ "\adeleted\x18\x01 \x01(\bR\adeleted\"L\n" +
+ "\x1cDeleteProviderProfileRequest\x12\x0e\n" +
+ "\x02id\x18\x01 \x01(\tR\x02id\x12\x1c\n" +
+ "\tworkspace\x18\x02 \x01(\tR\tworkspace\"9\n" +
+ "\x1dDeleteProviderProfileResponse\x12\x18\n" +
+ "\adeleted\x18\x01 \x01(\bR\adeleted\"E\n" +
+ "$GetSandboxProviderEnvironmentRequest\x12\x1d\n" +
+ "\n" +
+ "sandbox_id\x18\x01 \x01(\tR\tsandboxId\"\xcb\x05\n" +
+ "%GetSandboxProviderEnvironmentResponse\x12l\n" +
+ "\venvironment\x18\x01 \x03(\v2D.openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntryB\x04\x88\xb5\x18\x01R\venvironment\x122\n" +
+ "\x15provider_env_revision\x18\x02 \x01(\x04R\x13providerEnvRevision\x12\x87\x01\n" +
+ "\x18credential_expires_at_ms\x18\x03 \x03(\v2N.openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpiresAtMsEntryR\x15credentialExpiresAtMs\x12|\n" +
+ "\x13dynamic_credentials\x18\x04 \x03(\v2K.openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntryR\x12dynamicCredentials\x1a>\n" +
+ "\x10EnvironmentEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\x1aH\n" +
+ "\x1aCredentialExpiresAtMsEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\x03R\x05value:\x028\x01\x1an\n" +
+ "\x17DynamicCredentialsEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12=\n" +
+ "\x05value\x18\x02 \x01(\v2'.openshell.v1.ProviderProfileCredentialR\x05value:\x028\x01\"\xce\x04\n" +
+ "\x13UpdateConfigRequest\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12;\n" +
+ "\x06policy\x18\x02 \x01(\v2#.openshell.sandbox.v1.SandboxPolicyR\x06policy\x12\x1f\n" +
+ "\vsetting_key\x18\x03 \x01(\tR\n" +
+ "settingKey\x12G\n" +
+ "\rsetting_value\x18\x04 \x01(\v2\".openshell.sandbox.v1.SettingValueR\fsettingValue\x12%\n" +
+ "\x0edelete_setting\x18\x05 \x01(\bR\rdeleteSetting\x12\x16\n" +
+ "\x06global\x18\x06 \x01(\bR\x06global\x12M\n" +
+ "\x10merge_operations\x18\a \x03(\v2\".openshell.v1.PolicyMergeOperationR\x0fmergeOperations\x12:\n" +
+ "\x19expected_resource_version\x18\b \x01(\x04R\x17expectedResourceVersion\x12T\n" +
+ "\vannotations\x18\t \x03(\v22.openshell.v1.UpdateConfigRequest.AnnotationsEntryR\vannotations\x12\x1c\n" +
+ "\tworkspace\x18\n" +
+ " \x01(\tR\tworkspace\x1a>\n" +
+ "\x10AnnotationsEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xc7\x03\n" +
+ "\x14PolicyMergeOperation\x129\n" +
+ "\badd_rule\x18\x01 \x01(\v2\x1c.openshell.v1.AddNetworkRuleH\x00R\aaddRule\x12N\n" +
+ "\x0fremove_endpoint\x18\x02 \x01(\v2#.openshell.v1.RemoveNetworkEndpointH\x00R\x0eremoveEndpoint\x12B\n" +
+ "\vremove_rule\x18\x03 \x01(\v2\x1f.openshell.v1.RemoveNetworkRuleH\x00R\n" +
+ "removeRule\x12B\n" +
+ "\x0eadd_deny_rules\x18\x04 \x01(\v2\x1a.openshell.v1.AddDenyRulesH\x00R\faddDenyRules\x12E\n" +
+ "\x0fadd_allow_rules\x18\x05 \x01(\v2\x1b.openshell.v1.AddAllowRulesH\x00R\raddAllowRules\x12H\n" +
+ "\rremove_binary\x18\x06 \x01(\v2!.openshell.v1.RemoveNetworkBinaryH\x00R\fremoveBinaryB\v\n" +
+ "\toperation\"j\n" +
+ "\x0eAddNetworkRule\x12\x1b\n" +
+ "\trule_name\x18\x01 \x01(\tR\bruleName\x12;\n" +
+ "\x04rule\x18\x02 \x01(\v2'.openshell.sandbox.v1.NetworkPolicyRuleR\x04rule\"\\\n" +
+ "\x15RemoveNetworkEndpoint\x12\x1b\n" +
+ "\trule_name\x18\x01 \x01(\tR\bruleName\x12\x12\n" +
+ "\x04host\x18\x02 \x01(\tR\x04host\x12\x12\n" +
+ "\x04port\x18\x03 \x01(\rR\x04port\"0\n" +
+ "\x11RemoveNetworkRule\x12\x1b\n" +
+ "\trule_name\x18\x01 \x01(\tR\bruleName\"w\n" +
+ "\fAddDenyRules\x12\x12\n" +
+ "\x04host\x18\x01 \x01(\tR\x04host\x12\x12\n" +
+ "\x04port\x18\x02 \x01(\rR\x04port\x12?\n" +
+ "\n" +
+ "deny_rules\x18\x03 \x03(\v2 .openshell.sandbox.v1.L7DenyRuleR\tdenyRules\"k\n" +
+ "\rAddAllowRules\x12\x12\n" +
+ "\x04host\x18\x01 \x01(\tR\x04host\x12\x12\n" +
+ "\x04port\x18\x02 \x01(\rR\x04port\x122\n" +
+ "\x05rules\x18\x03 \x03(\v2\x1c.openshell.sandbox.v1.L7RuleR\x05rules\"S\n" +
+ "\x13RemoveNetworkBinary\x12\x1b\n" +
+ "\trule_name\x18\x01 \x01(\tR\bruleName\x12\x1f\n" +
+ "\vbinary_path\x18\x02 \x01(\tR\n" +
+ "binaryPath\"\xaf\x02\n" +
+ "\x14UpdateConfigResponse\x12\x18\n" +
+ "\aversion\x18\x01 \x01(\rR\aversion\x12\x1f\n" +
+ "\vpolicy_hash\x18\x02 \x01(\tR\n" +
+ "policyHash\x12+\n" +
+ "\x11settings_revision\x18\x03 \x01(\x04R\x10settingsRevision\x12\x18\n" +
+ "\adeleted\x18\x04 \x01(\bR\adeleted\x12U\n" +
+ "\vannotations\x18\x05 \x03(\v23.openshell.v1.UpdateConfigResponse.AnnotationsEntryR\vannotations\x1a>\n" +
+ "\x10AnnotationsEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\x83\x01\n" +
+ "\x1dGetSandboxPolicyStatusRequest\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12\x18\n" +
+ "\aversion\x18\x02 \x01(\rR\aversion\x12\x16\n" +
+ "\x06global\x18\x03 \x01(\bR\x06global\x12\x1c\n" +
+ "\tworkspace\x18\x04 \x01(\tR\tworkspace\"\x88\x01\n" +
+ "\x1eGetSandboxPolicyStatusResponse\x12?\n" +
+ "\brevision\x18\x01 \x01(\v2#.openshell.v1.SandboxPolicyRevisionR\brevision\x12%\n" +
+ "\x0eactive_version\x18\x02 \x01(\rR\ractiveVersion\"\x94\x01\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\x12\x16\n" +
+ "\x06global\x18\x04 \x01(\bR\x06global\x12\x1c\n" +
+ "\tworkspace\x18\x05 \x01(\tR\tworkspace\"`\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\"\xbc\x03\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\x12S\n" +
+ "\n" +
+ "provenance\x18\b \x03(\v23.openshell.v1.SandboxPolicyRevision.ProvenanceEntryR\n" +
+ "provenance\x1a=\n" +
+ "\x0fProvenanceEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xbc\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\x12\x1c\n" +
+ "\tworkspace\x18\x06 \x01(\tR\tworkspace\"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\"\xa2\x02\n" +
+ "\x11SupervisorMessage\x125\n" +
+ "\x05hello\x18\x01 \x01(\v2\x1d.openshell.v1.SupervisorHelloH\x00R\x05hello\x12A\n" +
+ "\theartbeat\x18\x02 \x01(\v2!.openshell.v1.SupervisorHeartbeatH\x00R\theartbeat\x12K\n" +
+ "\x11relay_open_result\x18\x03 \x01(\v2\x1d.openshell.v1.RelayOpenResultH\x00R\x0frelayOpenResult\x12;\n" +
+ "\vrelay_close\x18\x04 \x01(\v2\x18.openshell.v1.RelayCloseH\x00R\n" +
+ "relayCloseB\t\n" +
+ "\apayload\"\xea\x02\n" +
+ "\x0eGatewayMessage\x12J\n" +
+ "\x10session_accepted\x18\x01 \x01(\v2\x1d.openshell.v1.SessionAcceptedH\x00R\x0fsessionAccepted\x12J\n" +
+ "\x10session_rejected\x18\x02 \x01(\v2\x1d.openshell.v1.SessionRejectedH\x00R\x0fsessionRejected\x12>\n" +
+ "\theartbeat\x18\x03 \x01(\v2\x1e.openshell.v1.GatewayHeartbeatH\x00R\theartbeat\x128\n" +
+ "\n" +
+ "relay_open\x18\x04 \x01(\v2\x17.openshell.v1.RelayOpenH\x00R\trelayOpen\x12;\n" +
+ "\vrelay_close\x18\x05 \x01(\v2\x18.openshell.v1.RelayCloseH\x00R\n" +
+ "relayCloseB\t\n" +
+ "\apayload\"Q\n" +
+ "\x0fSupervisorHello\x12\x1d\n" +
+ "\n" +
+ "sandbox_id\x18\x01 \x01(\tR\tsandboxId\x12\x1f\n" +
+ "\vinstance_id\x18\x02 \x01(\tR\n" +
+ "instanceId\"h\n" +
+ "\x0fSessionAccepted\x12\x1d\n" +
+ "\n" +
+ "session_id\x18\x01 \x01(\tR\tsessionId\x126\n" +
+ "\x17heartbeat_interval_secs\x18\x02 \x01(\rR\x15heartbeatIntervalSecs\")\n" +
+ "\x0fSessionRejected\x12\x16\n" +
+ "\x06reason\x18\x01 \x01(\tR\x06reason\"\x15\n" +
+ "\x13SupervisorHeartbeat\"\x12\n" +
+ "\x10GatewayHeartbeat\"\xb7\x01\n" +
+ "\tRelayOpen\x12\x1d\n" +
+ "\n" +
+ "channel_id\x18\x01 \x01(\tR\tchannelId\x120\n" +
+ "\x03ssh\x18\x02 \x01(\v2\x1c.openshell.v1.SshRelayTargetH\x00R\x03ssh\x120\n" +
+ "\x03tcp\x18\x03 \x01(\v2\x1c.openshell.v1.TcpRelayTargetH\x00R\x03tcp\x12\x1d\n" +
+ "\n" +
+ "service_id\x18\x05 \x01(\tR\tserviceIdB\b\n" +
+ "\x06target\"\x10\n" +
+ "\x0eSshRelayTarget\"8\n" +
+ "\x0eTcpRelayTarget\x12\x12\n" +
+ "\x04host\x18\x01 \x01(\tR\x04host\x12\x12\n" +
+ "\x04port\x18\x02 \x01(\rR\x04port\"*\n" +
+ "\tRelayInit\x12\x1d\n" +
+ "\n" +
+ "channel_id\x18\x01 \x01(\tR\tchannelId\"\\\n" +
+ "\n" +
+ "RelayFrame\x12-\n" +
+ "\x04init\x18\x01 \x01(\v2\x17.openshell.v1.RelayInitH\x00R\x04init\x12\x14\n" +
+ "\x04data\x18\x02 \x01(\fH\x00R\x04dataB\t\n" +
+ "\apayload\"`\n" +
+ "\x0fRelayOpenResult\x12\x1d\n" +
+ "\n" +
+ "channel_id\x18\x01 \x01(\tR\tchannelId\x12\x18\n" +
+ "\asuccess\x18\x02 \x01(\bR\asuccess\x12\x14\n" +
+ "\x05error\x18\x03 \x01(\tR\x05error\"C\n" +
+ "\n" +
+ "RelayClose\x12\x1d\n" +
+ "\n" +
+ "channel_id\x18\x01 \x01(\tR\tchannelId\x12\x16\n" +
+ "\x06reason\x18\x02 \x01(\tR\x06reason\"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\"T\n" +
+ "\x10DenialGroupCount\x12\x1d\n" +
+ "\n" +
+ "deny_group\x18\x01 \x01(\tR\tdenyGroup\x12!\n" +
+ "\fdenied_count\x18\x02 \x01(\rR\vdeniedCount\"\xc8\x01\n" +
+ "\x16NetworkActivitySummary\x124\n" +
+ "\x16network_activity_count\x18\x01 \x01(\rR\x14networkActivityCount\x12.\n" +
+ "\x13denied_action_count\x18\x02 \x01(\rR\x11deniedActionCount\x12H\n" +
+ "\x10denials_by_group\x18\x03 \x03(\v2\x1e.openshell.v1.DenialGroupCountR\x0edenialsByGroup\"\x94\x05\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\x12+\n" +
+ "\x11validation_result\x18\x11 \x01(\tR\x10validationResult\x12)\n" +
+ "\x10rejection_reason\x18\x12 \x01(\tR\x0frejectionReason\"\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\"\xd7\x02\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\x12b\n" +
+ "\x1anetwork_activity_summaries\x18\x05 \x03(\v2$.openshell.v1.NetworkActivitySummaryR\x18networkActivitySummaries\x12\x1c\n" +
+ "\tworkspace\x18\x06 \x01(\tR\tworkspace\"\xcb\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\x12,\n" +
+ "\x12accepted_chunk_ids\x18\x04 \x03(\tR\x10acceptedChunkIds\"n\n" +
+ "\x15GetDraftPolicyRequest\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12#\n" +
+ "\rstatus_filter\x18\x02 \x01(\tR\fstatusFilter\x12\x1c\n" +
+ "\tworkspace\x18\x03 \x01(\tR\tworkspace\"\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\"g\n" +
+ "\x18ApproveDraftChunkRequest\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12\x19\n" +
+ "\bchunk_id\x18\x02 \x01(\tR\achunkId\x12\x1c\n" +
+ "\tworkspace\x18\x03 \x01(\tR\tworkspace\"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\x12\x1c\n" +
+ "\tworkspace\x18\x04 \x01(\tR\tworkspace\"\x1a\n" +
+ "\x18RejectDraftChunkResponse\"\x8a\x01\n" +
+ "\x1cApproveAllDraftChunksRequest\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x128\n" +
+ "\x18include_security_flagged\x18\x02 \x01(\bR\x16includeSecurityFlagged\x12\x1c\n" +
+ "\tworkspace\x18\x03 \x01(\tR\tworkspace\"\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\"\xb2\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\x12\x1c\n" +
+ "\tworkspace\x18\x04 \x01(\tR\tworkspace\"\x18\n" +
+ "\x16EditDraftChunkResponse\"d\n" +
+ "\x15UndoDraftChunkRequest\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12\x19\n" +
+ "\bchunk_id\x18\x02 \x01(\tR\achunkId\x12\x1c\n" +
+ "\tworkspace\x18\x03 \x01(\tR\tworkspace\"`\n" +
+ "\x16UndoDraftChunkResponse\x12%\n" +
+ "\x0epolicy_version\x18\x01 \x01(\rR\rpolicyVersion\x12\x1f\n" +
+ "\vpolicy_hash\x18\x02 \x01(\tR\n" +
+ "policyHash\"K\n" +
+ "\x17ClearDraftChunksRequest\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12\x1c\n" +
+ "\tworkspace\x18\x02 \x01(\tR\tworkspace\"A\n" +
+ "\x18ClearDraftChunksResponse\x12%\n" +
+ "\x0echunks_cleared\x18\x01 \x01(\rR\rchunksCleared\"J\n" +
+ "\x16GetDraftHistoryRequest\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12\x1c\n" +
+ "\tworkspace\x18\x02 \x01(\tR\tworkspace\"\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\"\xbd\x02\n" +
+ "\x15PolicyRevisionPayload\x12;\n" +
+ "\x06policy\x18\x01 \x01(\v2#.openshell.sandbox.v1.SandboxPolicyR\x06policy\x12\x12\n" +
+ "\x04hash\x18\x02 \x01(\tR\x04hash\x12\x1d\n" +
+ "\n" +
+ "load_error\x18\x03 \x01(\tR\tloadError\x12 \n" +
+ "\floaded_at_ms\x18\x04 \x01(\x03R\n" +
+ "loadedAtMs\x12S\n" +
+ "\n" +
+ "provenance\x18\x05 \x03(\v23.openshell.v1.PolicyRevisionPayload.ProvenanceEntryR\n" +
+ "provenance\x1a=\n" +
+ "\x0fProvenanceEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xc4\x03\n" +
+ "\x11DraftChunkPayload\x12\x1b\n" +
+ "\trule_name\x18\x01 \x01(\tR\bruleName\x12L\n" +
+ "\rproposed_rule\x18\x02 \x01(\v2'.openshell.sandbox.v1.NetworkPolicyRuleR\fproposedRule\x12\x1c\n" +
+ "\trationale\x18\x03 \x01(\tR\trationale\x12%\n" +
+ "\x0esecurity_notes\x18\x04 \x01(\tR\rsecurityNotes\x12\x1e\n" +
+ "\n" +
+ "confidence\x18\x05 \x01(\x02R\n" +
+ "confidence\x12\"\n" +
+ "\rdecided_at_ms\x18\x06 \x01(\x03R\vdecidedAtMs\x12\x12\n" +
+ "\x04host\x18\a \x01(\tR\x04host\x12\x12\n" +
+ "\x04port\x18\b \x01(\x05R\x04port\x12\x16\n" +
+ "\x06binary\x18\t \x01(\tR\x06binary\x12#\n" +
+ "\rdraft_version\x18\n" +
+ " \x01(\x03R\fdraftVersion\x12+\n" +
+ "\x11validation_result\x18\v \x01(\tR\x10validationResult\x12)\n" +
+ "\x10rejection_reason\x18\f \x01(\tR\x0frejectionReason\"\xe1\x03\n" +
+ "\x14StoredPolicyRevision\x12\x0e\n" +
+ "\x02id\x18\x01 \x01(\tR\x02id\x12\x1d\n" +
+ "\n" +
+ "sandbox_id\x18\x02 \x01(\tR\tsandboxId\x12\x18\n" +
+ "\aversion\x18\x03 \x01(\x03R\aversion\x12%\n" +
+ "\x0epolicy_payload\x18\x04 \x01(\fR\rpolicyPayload\x12\x1f\n" +
+ "\vpolicy_hash\x18\x05 \x01(\tR\n" +
+ "policyHash\x12\x16\n" +
+ "\x06status\x18\x06 \x01(\tR\x06status\x12\"\n" +
+ "\n" +
+ "load_error\x18\a \x01(\tH\x00R\tloadError\x88\x01\x01\x12\"\n" +
+ "\rcreated_at_ms\x18\b \x01(\x03R\vcreatedAtMs\x12%\n" +
+ "\floaded_at_ms\x18\t \x01(\x03H\x01R\n" +
+ "loadedAtMs\x88\x01\x01\x12R\n" +
+ "\n" +
+ "provenance\x18\n" +
+ " \x03(\v22.openshell.v1.StoredPolicyRevision.ProvenanceEntryR\n" +
+ "provenance\x1a=\n" +
+ "\x0fProvenanceEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01B\r\n" +
+ "\v_load_errorB\x0f\n" +
+ "\r_loaded_at_ms\"\xff\x04\n" +
+ "\x10StoredDraftChunk\x12\x0e\n" +
+ "\x02id\x18\x01 \x01(\tR\x02id\x12\x1d\n" +
+ "\n" +
+ "sandbox_id\x18\x02 \x01(\tR\tsandboxId\x12#\n" +
+ "\rdraft_version\x18\x03 \x01(\x03R\fdraftVersion\x12\x16\n" +
+ "\x06status\x18\x04 \x01(\tR\x06status\x12\x1b\n" +
+ "\trule_name\x18\x05 \x01(\tR\bruleName\x12#\n" +
+ "\rproposed_rule\x18\x06 \x01(\fR\fproposedRule\x12\x1c\n" +
+ "\trationale\x18\a \x01(\tR\trationale\x12%\n" +
+ "\x0esecurity_notes\x18\b \x01(\tR\rsecurityNotes\x12\x1e\n" +
+ "\n" +
+ "confidence\x18\t \x01(\x01R\n" +
+ "confidence\x12\"\n" +
+ "\rcreated_at_ms\x18\n" +
+ " \x01(\x03R\vcreatedAtMs\x12'\n" +
+ "\rdecided_at_ms\x18\v \x01(\x03H\x00R\vdecidedAtMs\x88\x01\x01\x12\x12\n" +
+ "\x04host\x18\f \x01(\tR\x04host\x12\x12\n" +
+ "\x04port\x18\r \x01(\x05R\x04port\x12\x16\n" +
+ "\x06binary\x18\x0e \x01(\tR\x06binary\x12\x1b\n" +
+ "\thit_count\x18\x0f \x01(\x05R\bhitCount\x12\"\n" +
+ "\rfirst_seen_ms\x18\x10 \x01(\x03R\vfirstSeenMs\x12 \n" +
+ "\flast_seen_ms\x18\x11 \x01(\x03R\n" +
+ "lastSeenMs\x12+\n" +
+ "\x11validation_result\x18\x12 \x01(\tR\x10validationResult\x12)\n" +
+ "\x10rejection_reason\x18\x13 \x01(\tR\x0frejectionReasonB\x10\n" +
+ "\x0e_decided_at_ms\"\xb1\x01\n" +
+ "\x16CreateWorkspaceRequest\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12H\n" +
+ "\x06labels\x18\x02 \x03(\v20.openshell.v1.CreateWorkspaceRequest.LabelsEntryR\x06labels\x1a9\n" +
+ "\vLabelsEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"Z\n" +
+ "\x17CreateWorkspaceResponse\x12?\n" +
+ "\tworkspace\x18\x01 \x01(\v2!.openshell.datamodel.v1.WorkspaceR\tworkspace\")\n" +
+ "\x13GetWorkspaceRequest\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\"W\n" +
+ "\x14GetWorkspaceResponse\x12?\n" +
+ "\tworkspace\x18\x01 \x01(\v2!.openshell.datamodel.v1.WorkspaceR\tworkspace\"l\n" +
+ "\x15ListWorkspacesRequest\x12\x14\n" +
+ "\x05limit\x18\x01 \x01(\rR\x05limit\x12\x16\n" +
+ "\x06offset\x18\x02 \x01(\rR\x06offset\x12%\n" +
+ "\x0elabel_selector\x18\x03 \x01(\tR\rlabelSelector\"[\n" +
+ "\x16ListWorkspacesResponse\x12A\n" +
+ "\n" +
+ "workspaces\x18\x01 \x03(\v2!.openshell.datamodel.v1.WorkspaceR\n" +
+ "workspaces\",\n" +
+ "\x16DeleteWorkspaceRequest\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\"3\n" +
+ "\x17DeleteWorkspaceResponse\x12\x18\n" +
+ "\adeleted\x18\x01 \x01(\bR\adeleted\"\xaf\x01\n" +
+ "\x0fWorkspaceMember\x12>\n" +
+ "\bmetadata\x18\x01 \x01(\v2\".openshell.datamodel.v1.ObjectMetaR\bmetadata\x12+\n" +
+ "\x11principal_subject\x18\x02 \x01(\tR\x10principalSubject\x12/\n" +
+ "\x04role\x18\x03 \x01(\x0e2\x1b.openshell.v1.WorkspaceRoleR\x04role\"\x97\x01\n" +
+ "\x19AddWorkspaceMemberRequest\x12\x1c\n" +
+ "\tworkspace\x18\x01 \x01(\tR\tworkspace\x12+\n" +
+ "\x11principal_subject\x18\x02 \x01(\tR\x10principalSubject\x12/\n" +
+ "\x04role\x18\x03 \x01(\x0e2\x1b.openshell.v1.WorkspaceRoleR\x04role\"S\n" +
+ "\x1aAddWorkspaceMemberResponse\x125\n" +
+ "\x06member\x18\x01 \x01(\v2\x1d.openshell.v1.WorkspaceMemberR\x06member\"i\n" +
+ "\x1cRemoveWorkspaceMemberRequest\x12\x1c\n" +
+ "\tworkspace\x18\x01 \x01(\tR\tworkspace\x12+\n" +
+ "\x11principal_subject\x18\x02 \x01(\tR\x10principalSubject\"9\n" +
+ "\x1dRemoveWorkspaceMemberResponse\x12\x18\n" +
+ "\aremoved\x18\x01 \x01(\bR\aremoved\"i\n" +
+ "\x1bListWorkspaceMembersRequest\x12\x1c\n" +
+ "\tworkspace\x18\x01 \x01(\tR\tworkspace\x12\x14\n" +
+ "\x05limit\x18\x02 \x01(\rR\x05limit\x12\x16\n" +
+ "\x06offset\x18\x03 \x01(\rR\x06offset\"W\n" +
+ "\x1cListWorkspaceMembersResponse\x127\n" +
+ "\amembers\x18\x01 \x03(\v2\x1d.openshell.v1.WorkspaceMemberR\amembers*\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\x05*\xc3\x03\n" +
+ "!ProviderCredentialRefreshStrategy\x124\n" +
+ "0PROVIDER_CREDENTIAL_REFRESH_STRATEGY_UNSPECIFIED\x10\x00\x12/\n" +
+ "+PROVIDER_CREDENTIAL_REFRESH_STRATEGY_STATIC\x10\x01\x121\n" +
+ "-PROVIDER_CREDENTIAL_REFRESH_STRATEGY_EXTERNAL\x10\x02\x12=\n" +
+ "9PROVIDER_CREDENTIAL_REFRESH_STRATEGY_OAUTH2_REFRESH_TOKEN\x10\x03\x12B\n" +
+ ">PROVIDER_CREDENTIAL_REFRESH_STRATEGY_OAUTH2_CLIENT_CREDENTIALS\x10\x04\x12C\n" +
+ "?PROVIDER_CREDENTIAL_REFRESH_STRATEGY_GOOGLE_SERVICE_ACCOUNT_JWT\x10\x05\x12<\n" +
+ "8PROVIDER_CREDENTIAL_REFRESH_STRATEGY_AWS_STS_ASSUME_ROLE\x10\x06*\xdb\x02\n" +
+ "\x17ProviderProfileCategory\x12)\n" +
+ "%PROVIDER_PROFILE_CATEGORY_UNSPECIFIED\x10\x00\x12#\n" +
+ "\x1fPROVIDER_PROFILE_CATEGORY_OTHER\x10\x01\x12'\n" +
+ "#PROVIDER_PROFILE_CATEGORY_INFERENCE\x10\x02\x12#\n" +
+ "\x1fPROVIDER_PROFILE_CATEGORY_AGENT\x10\x03\x12,\n" +
+ "(PROVIDER_PROFILE_CATEGORY_SOURCE_CONTROL\x10\x04\x12'\n" +
+ "#PROVIDER_PROFILE_CATEGORY_MESSAGING\x10\x05\x12\"\n" +
+ "\x1ePROVIDER_PROFILE_CATEGORY_DATA\x10\x06\x12'\n" +
+ "#PROVIDER_PROFILE_CATEGORY_KNOWLEDGE\x10\a*\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\x03*b\n" +
+ "\rWorkspaceRole\x12\x1e\n" +
+ "\x1aWORKSPACE_ROLE_UNSPECIFIED\x10\x00\x12\x17\n" +
+ "\x13WORKSPACE_ROLE_USER\x10\x01\x12\x18\n" +
+ "\x14WORKSPACE_ROLE_ADMIN\x10\x022\xacB\n" +
+ "\tOpenShell\x12Z\n" +
+ "\x06Health\x12\x1b.openshell.v1.HealthRequest\x1a\x1c.openshell.v1.HealthResponse\"\x15\x82\xb5\x18\x11\n" +
+ "\x0funauthenticated\x12i\n" +
+ "\x0eGetCurrentUser\x12#.openshell.v1.GetCurrentUserRequest\x1a$.openshell.v1.GetCurrentUserResponse\"\f\x82\xb5\x18\b\n" +
+ "\x06bearer\x12\x86\x01\n" +
+ "\x0eGetGatewayInfo\x12#.openshell.v1.GetGatewayInfoRequest\x1a$.openshell.v1.GetGatewayInfoResponse\")\x82\xb5\x18%\n" +
+ "\x06bearer\x1a\x0eplatform_admin\"\vconfig:read\x12u\n" +
+ "\rCreateSandbox\x12\".openshell.v1.CreateSandboxRequest\x1a\x1d.openshell.v1.SandboxResponse\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x04user\"\rsandbox:write\x12n\n" +
+ "\n" +
+ "GetSandbox\x12\x1f.openshell.v1.GetSandboxRequest\x1a\x1d.openshell.v1.SandboxResponse\" \x82\xb5\x18\x1c\n" +
+ "\x06bearer\x12\x04user\"\fsandbox:read\x12z\n" +
+ "\rListSandboxes\x12\".openshell.v1.ListSandboxesRequest\x1a#.openshell.v1.ListSandboxesResponse\" \x82\xb5\x18\x1c\n" +
+ "\x06bearer\x12\x04user\"\fsandbox:read\x12\x8f\x01\n" +
+ "\x14ListSandboxProviders\x12).openshell.v1.ListSandboxProvidersRequest\x1a*.openshell.v1.ListSandboxProvidersResponse\" \x82\xb5\x18\x1c\n" +
+ "\x06bearer\x12\x04user\"\fsandbox:read\x12\x93\x01\n" +
+ "\x15AttachSandboxProvider\x12*.openshell.v1.AttachSandboxProviderRequest\x1a+.openshell.v1.AttachSandboxProviderResponse\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x04user\"\rsandbox:write\x12\x93\x01\n" +
+ "\x15DetachSandboxProvider\x12*.openshell.v1.DetachSandboxProviderRequest\x1a+.openshell.v1.DetachSandboxProviderResponse\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x04user\"\rsandbox:write\x12{\n" +
+ "\rDeleteSandbox\x12\".openshell.v1.DeleteSandboxRequest\x1a#.openshell.v1.DeleteSandboxResponse\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x04user\"\rsandbox:write\x12\x84\x01\n" +
+ "\x10CreateSshSession\x12%.openshell.v1.CreateSshSessionRequest\x1a&.openshell.v1.CreateSshSessionResponse\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x04user\"\rsandbox:write\x12}\n" +
+ "\rExposeService\x12\".openshell.v1.ExposeServiceRequest\x1a%.openshell.v1.ServiceEndpointResponse\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x04user\"\rsandbox:write\x12v\n" +
+ "\n" +
+ "GetService\x12\x1f.openshell.v1.GetServiceRequest\x1a%.openshell.v1.ServiceEndpointResponse\" \x82\xb5\x18\x1c\n" +
+ "\x06bearer\x12\x04user\"\fsandbox:read\x12w\n" +
+ "\fListServices\x12!.openshell.v1.ListServicesRequest\x1a\".openshell.v1.ListServicesResponse\" \x82\xb5\x18\x1c\n" +
+ "\x06bearer\x12\x04user\"\fsandbox:read\x12{\n" +
+ "\rDeleteService\x12\".openshell.v1.DeleteServiceRequest\x1a#.openshell.v1.DeleteServiceResponse\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x04user\"\rsandbox:write\x12\x84\x01\n" +
+ "\x10RevokeSshSession\x12%.openshell.v1.RevokeSshSessionRequest\x1a&.openshell.v1.RevokeSshSessionResponse\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x04user\"\rsandbox:write\x12t\n" +
+ "\vExecSandbox\x12 .openshell.v1.ExecSandboxRequest\x1a\x1e.openshell.v1.ExecSandboxEvent\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x04user\"\rsandbox:write0\x01\x12q\n" +
+ "\n" +
+ "ForwardTcp\x12\x1d.openshell.v1.TcpForwardFrame\x1a\x1d.openshell.v1.TcpForwardFrame\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x04user\"\rsandbox:write(\x010\x01\x12\x7f\n" +
+ "\x16ExecSandboxInteractive\x12\x1e.openshell.v1.ExecSandboxInput\x1a\x1e.openshell.v1.ExecSandboxEvent\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x04user\"\rsandbox:write(\x010\x01\x12z\n" +
+ "\x0eCreateProvider\x12#.openshell.v1.CreateProviderRequest\x1a\x1e.openshell.v1.ProviderResponse\"#\x82\xb5\x18\x1f\n" +
+ "\x06bearer\x12\x05admin\"\x0eprovider:write\x12r\n" +
+ "\vGetProvider\x12 .openshell.v1.GetProviderRequest\x1a\x1e.openshell.v1.ProviderResponse\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x04user\"\rprovider:read\x12{\n" +
+ "\rListProviders\x12\".openshell.v1.ListProvidersRequest\x1a#.openshell.v1.ListProvidersResponse\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x04user\"\rprovider:read\x12\x90\x01\n" +
+ "\x14ListProviderProfiles\x12).openshell.v1.ListProviderProfilesRequest\x1a*.openshell.v1.ListProviderProfilesResponse\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x04user\"\rprovider:read\x12\x87\x01\n" +
+ "\x12GetProviderProfile\x12'.openshell.v1.GetProviderProfileRequest\x1a%.openshell.v1.ProviderProfileResponse\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x04user\"\rprovider:read\x12\x98\x01\n" +
+ "\x16ImportProviderProfiles\x12+.openshell.v1.ImportProviderProfilesRequest\x1a,.openshell.v1.ImportProviderProfilesResponse\"#\x82\xb5\x18\x1f\n" +
+ "\x06bearer\x12\x05admin\"\x0eprovider:write\x12\x98\x01\n" +
+ "\x16UpdateProviderProfiles\x12+.openshell.v1.UpdateProviderProfilesRequest\x1a,.openshell.v1.UpdateProviderProfilesResponse\"#\x82\xb5\x18\x1f\n" +
+ "\x06bearer\x12\x05admin\"\x0eprovider:write\x12\x90\x01\n" +
+ "\x14LintProviderProfiles\x12).openshell.v1.LintProviderProfilesRequest\x1a*.openshell.v1.LintProviderProfilesResponse\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x04user\"\rprovider:read\x12z\n" +
+ "\x0eUpdateProvider\x12#.openshell.v1.UpdateProviderRequest\x1a\x1e.openshell.v1.ProviderResponse\"#\x82\xb5\x18\x1f\n" +
+ "\x06bearer\x12\x05admin\"\x0eprovider:write\x12\x9c\x01\n" +
+ "\x18GetProviderRefreshStatus\x12-.openshell.v1.GetProviderRefreshStatusRequest\x1a..openshell.v1.GetProviderRefreshStatusResponse\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x04user\"\rprovider:read\x12\x9e\x01\n" +
+ "\x18ConfigureProviderRefresh\x12-.openshell.v1.ConfigureProviderRefreshRequest\x1a..openshell.v1.ConfigureProviderRefreshResponse\"#\x82\xb5\x18\x1f\n" +
+ "\x06bearer\x12\x05admin\"\x0eprovider:write\x12\x9e\x01\n" +
+ "\x18RotateProviderCredential\x12-.openshell.v1.RotateProviderCredentialRequest\x1a..openshell.v1.RotateProviderCredentialResponse\"#\x82\xb5\x18\x1f\n" +
+ "\x06bearer\x12\x05admin\"\x0eprovider:write\x12\x95\x01\n" +
+ "\x15DeleteProviderRefresh\x12*.openshell.v1.DeleteProviderRefreshRequest\x1a+.openshell.v1.DeleteProviderRefreshResponse\"#\x82\xb5\x18\x1f\n" +
+ "\x06bearer\x12\x05admin\"\x0eprovider:write\x12\x80\x01\n" +
+ "\x0eDeleteProvider\x12#.openshell.v1.DeleteProviderRequest\x1a$.openshell.v1.DeleteProviderResponse\"#\x82\xb5\x18\x1f\n" +
+ "\x06bearer\x12\x05admin\"\x0eprovider:write\x12\x95\x01\n" +
+ "\x15DeleteProviderProfile\x12*.openshell.v1.DeleteProviderProfileRequest\x1a+.openshell.v1.DeleteProviderProfileResponse\"#\x82\xb5\x18\x1f\n" +
+ "\x06bearer\x12\x05admin\"\x0eprovider:write\x12\x90\x01\n" +
+ "\x10GetSandboxConfig\x12-.openshell.sandbox.v1.GetSandboxConfigRequest\x1a..openshell.sandbox.v1.GetSandboxConfigResponse\"\x1d\x82\xb5\x18\x19\n" +
+ "\x04dual\x12\x04user\"\vconfig:read\x12\x8c\x01\n" +
+ "\x10GetGatewayConfig\x12-.openshell.sandbox.v1.GetGatewayConfigRequest\x1a..openshell.sandbox.v1.GetGatewayConfigResponse\"\x19\x82\xb5\x18\x15\n" +
+ "\x06bearer\"\vconfig:read\x12v\n" +
+ "\fUpdateConfig\x12!.openshell.v1.UpdateConfigRequest\x1a\".openshell.v1.UpdateConfigResponse\"\x1f\x82\xb5\x18\x1b\n" +
+ "\x04dual\x12\x05admin\"\fconfig:write\x12\x95\x01\n" +
+ "\x16GetSandboxPolicyStatus\x12+.openshell.v1.GetSandboxPolicyStatusRequest\x1a,.openshell.v1.GetSandboxPolicyStatusResponse\" \x82\xb5\x18\x1c\n" +
+ "\x06bearer\x12\x04user\"\fsandbox:read\x12\x8c\x01\n" +
+ "\x13ListSandboxPolicies\x12(.openshell.v1.ListSandboxPoliciesRequest\x1a).openshell.v1.ListSandboxPoliciesResponse\" \x82\xb5\x18\x1c\n" +
+ "\x06bearer\x12\x04user\"\fsandbox:read\x12v\n" +
+ "\x12ReportPolicyStatus\x12'.openshell.v1.ReportPolicyStatusRequest\x1a(.openshell.v1.ReportPolicyStatusResponse\"\r\x82\xb5\x18\t\n" +
+ "\asandbox\x12\x97\x01\n" +
+ "\x1dGetSandboxProviderEnvironment\x122.openshell.v1.GetSandboxProviderEnvironmentRequest\x1a3.openshell.v1.GetSandboxProviderEnvironmentResponse\"\r\x82\xb5\x18\t\n" +
+ "\asandbox\x12}\n" +
+ "\x0eGetSandboxLogs\x12#.openshell.v1.GetSandboxLogsRequest\x1a$.openshell.v1.GetSandboxLogsResponse\" \x82\xb5\x18\x1c\n" +
+ "\x06bearer\x12\x04user\"\fsandbox:read\x12o\n" +
+ "\x0fPushSandboxLogs\x12$.openshell.v1.PushSandboxLogsRequest\x1a%.openshell.v1.PushSandboxLogsResponse\"\r\x82\xb5\x18\t\n" +
+ "\asandbox(\x01\x12e\n" +
+ "\x11ConnectSupervisor\x12\x1f.openshell.v1.SupervisorMessage\x1a\x1c.openshell.v1.GatewayMessage\"\r\x82\xb5\x18\t\n" +
+ "\asandbox(\x010\x01\x12T\n" +
+ "\vRelayStream\x12\x18.openshell.v1.RelayFrame\x1a\x18.openshell.v1.RelayFrame\"\r\x82\xb5\x18\t\n" +
+ "\asandbox(\x010\x01\x12w\n" +
+ "\fWatchSandbox\x12!.openshell.v1.WatchSandboxRequest\x1a .openshell.v1.SandboxStreamEvent\" \x82\xb5\x18\x1c\n" +
+ "\x06bearer\x12\x04user\"\fsandbox:read0\x01\x12|\n" +
+ "\x14SubmitPolicyAnalysis\x12).openshell.v1.SubmitPolicyAnalysisRequest\x1a*.openshell.v1.SubmitPolicyAnalysisResponse\"\r\x82\xb5\x18\t\n" +
+ "\asandbox\x12z\n" +
+ "\x0eGetDraftPolicy\x12#.openshell.v1.GetDraftPolicyRequest\x1a$.openshell.v1.GetDraftPolicyResponse\"\x1d\x82\xb5\x18\x19\n" +
+ "\x04dual\x12\x04user\"\vconfig:read\x12\x87\x01\n" +
+ "\x11ApproveDraftChunk\x12&.openshell.v1.ApproveDraftChunkRequest\x1a'.openshell.v1.ApproveDraftChunkResponse\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x05admin\"\fconfig:write\x12\x84\x01\n" +
+ "\x10RejectDraftChunk\x12%.openshell.v1.RejectDraftChunkRequest\x1a&.openshell.v1.RejectDraftChunkResponse\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x05admin\"\fconfig:write\x12\x93\x01\n" +
+ "\x15ApproveAllDraftChunks\x12*.openshell.v1.ApproveAllDraftChunksRequest\x1a+.openshell.v1.ApproveAllDraftChunksResponse\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x05admin\"\fconfig:write\x12~\n" +
+ "\x0eEditDraftChunk\x12#.openshell.v1.EditDraftChunkRequest\x1a$.openshell.v1.EditDraftChunkResponse\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x05admin\"\fconfig:write\x12~\n" +
+ "\x0eUndoDraftChunk\x12#.openshell.v1.UndoDraftChunkRequest\x1a$.openshell.v1.UndoDraftChunkResponse\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x05admin\"\fconfig:write\x12\x84\x01\n" +
+ "\x10ClearDraftChunks\x12%.openshell.v1.ClearDraftChunksRequest\x1a&.openshell.v1.ClearDraftChunksResponse\"!\x82\xb5\x18\x1d\n" +
+ "\x06bearer\x12\x05admin\"\fconfig:write\x12\x7f\n" +
+ "\x0fGetDraftHistory\x12$.openshell.v1.GetDraftHistoryRequest\x1a%.openshell.v1.GetDraftHistoryResponse\"\x1f\x82\xb5\x18\x1b\n" +
+ "\x06bearer\x12\x04user\"\vconfig:read\x12s\n" +
+ "\x11IssueSandboxToken\x12&.openshell.v1.IssueSandboxTokenRequest\x1a'.openshell.v1.IssueSandboxTokenResponse\"\r\x82\xb5\x18\t\n" +
+ "\asandbox\x12y\n" +
+ "\x13RefreshSandboxToken\x12(.openshell.v1.RefreshSandboxTokenRequest\x1a).openshell.v1.RefreshSandboxTokenResponse\"\r\x82\xb5\x18\t\n" +
+ "\asandbox\x12\x8d\x01\n" +
+ "\x0fCreateWorkspace\x12$.openshell.v1.CreateWorkspaceRequest\x1a%.openshell.v1.CreateWorkspaceResponse\"-\x82\xb5\x18)\n" +
+ "\x06bearer\x1a\x0eplatform_admin\"\x0fworkspace:write\x12y\n" +
+ "\fGetWorkspace\x12!.openshell.v1.GetWorkspaceRequest\x1a\".openshell.v1.GetWorkspaceResponse\"\"\x82\xb5\x18\x1e\n" +
+ "\x06bearer\x12\x04user\"\x0eworkspace:read\x12\x7f\n" +
+ "\x0eListWorkspaces\x12#.openshell.v1.ListWorkspacesRequest\x1a$.openshell.v1.ListWorkspacesResponse\"\"\x82\xb5\x18\x1e\n" +
+ "\x06bearer\x12\x04user\"\x0eworkspace:read\x12\x8d\x01\n" +
+ "\x0fDeleteWorkspace\x12$.openshell.v1.DeleteWorkspaceRequest\x1a%.openshell.v1.DeleteWorkspaceResponse\"-\x82\xb5\x18)\n" +
+ "\x06bearer\x1a\x0eplatform_admin\"\x0fworkspace:write\x12\x8d\x01\n" +
+ "\x12AddWorkspaceMember\x12'.openshell.v1.AddWorkspaceMemberRequest\x1a(.openshell.v1.AddWorkspaceMemberResponse\"$\x82\xb5\x18 \n" +
+ "\x06bearer\x12\x05admin\"\x0fworkspace:write\x12\x96\x01\n" +
+ "\x15RemoveWorkspaceMember\x12*.openshell.v1.RemoveWorkspaceMemberRequest\x1a+.openshell.v1.RemoveWorkspaceMemberResponse\"$\x82\xb5\x18 \n" +
+ "\x06bearer\x12\x05admin\"\x0fworkspace:write\x12\x91\x01\n" +
+ "\x14ListWorkspaceMembers\x12).openshell.v1.ListWorkspaceMembersRequest\x1a*.openshell.v1.ListWorkspaceMembersResponse\"\"\x82\xb5\x18\x1e\n" +
+ "\x06bearer\x12\x04user\"\x0eworkspace:readb\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, 6)
+var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 203)
+var file_openshell_proto_goTypes = []any{
+ (SandboxPhase)(0), // 0: openshell.v1.SandboxPhase
+ (ProviderCredentialRefreshStrategy)(0), // 1: openshell.v1.ProviderCredentialRefreshStrategy
+ (ProviderProfileCategory)(0), // 2: openshell.v1.ProviderProfileCategory
+ (PolicyStatus)(0), // 3: openshell.v1.PolicyStatus
+ (ServiceStatus)(0), // 4: openshell.v1.ServiceStatus
+ (WorkspaceRole)(0), // 5: openshell.v1.WorkspaceRole
+ (*IssueSandboxTokenRequest)(nil), // 6: openshell.v1.IssueSandboxTokenRequest
+ (*IssueSandboxTokenResponse)(nil), // 7: openshell.v1.IssueSandboxTokenResponse
+ (*RefreshSandboxTokenRequest)(nil), // 8: openshell.v1.RefreshSandboxTokenRequest
+ (*RefreshSandboxTokenResponse)(nil), // 9: openshell.v1.RefreshSandboxTokenResponse
+ (*HealthRequest)(nil), // 10: openshell.v1.HealthRequest
+ (*HealthResponse)(nil), // 11: openshell.v1.HealthResponse
+ (*GetCurrentUserRequest)(nil), // 12: openshell.v1.GetCurrentUserRequest
+ (*GetCurrentUserResponse)(nil), // 13: openshell.v1.GetCurrentUserResponse
+ (*GetGatewayInfoRequest)(nil), // 14: openshell.v1.GetGatewayInfoRequest
+ (*GetGatewayInfoResponse)(nil), // 15: openshell.v1.GetGatewayInfoResponse
+ (*ComputeDriverInfo)(nil), // 16: openshell.v1.ComputeDriverInfo
+ (*ComputeDriverCapabilities)(nil), // 17: openshell.v1.ComputeDriverCapabilities
+ (*Sandbox)(nil), // 18: openshell.v1.Sandbox
+ (*SandboxSpec)(nil), // 19: openshell.v1.SandboxSpec
+ (*ResourceRequirements)(nil), // 20: openshell.v1.ResourceRequirements
+ (*GpuResourceRequirements)(nil), // 21: openshell.v1.GpuResourceRequirements
+ (*SandboxTemplate)(nil), // 22: openshell.v1.SandboxTemplate
+ (*SandboxStatus)(nil), // 23: openshell.v1.SandboxStatus
+ (*SandboxCondition)(nil), // 24: openshell.v1.SandboxCondition
+ (*PlatformEvent)(nil), // 25: openshell.v1.PlatformEvent
+ (*CreateSandboxRequest)(nil), // 26: openshell.v1.CreateSandboxRequest
+ (*GetSandboxRequest)(nil), // 27: openshell.v1.GetSandboxRequest
+ (*ListSandboxesRequest)(nil), // 28: openshell.v1.ListSandboxesRequest
+ (*ListSandboxProvidersRequest)(nil), // 29: openshell.v1.ListSandboxProvidersRequest
+ (*AttachSandboxProviderRequest)(nil), // 30: openshell.v1.AttachSandboxProviderRequest
+ (*DetachSandboxProviderRequest)(nil), // 31: openshell.v1.DetachSandboxProviderRequest
+ (*DeleteSandboxRequest)(nil), // 32: openshell.v1.DeleteSandboxRequest
+ (*SandboxResponse)(nil), // 33: openshell.v1.SandboxResponse
+ (*ListSandboxesResponse)(nil), // 34: openshell.v1.ListSandboxesResponse
+ (*ListSandboxProvidersResponse)(nil), // 35: openshell.v1.ListSandboxProvidersResponse
+ (*AttachSandboxProviderResponse)(nil), // 36: openshell.v1.AttachSandboxProviderResponse
+ (*DetachSandboxProviderResponse)(nil), // 37: openshell.v1.DetachSandboxProviderResponse
+ (*DeleteSandboxResponse)(nil), // 38: openshell.v1.DeleteSandboxResponse
+ (*CreateSshSessionRequest)(nil), // 39: openshell.v1.CreateSshSessionRequest
+ (*CreateSshSessionResponse)(nil), // 40: openshell.v1.CreateSshSessionResponse
+ (*ExposeServiceRequest)(nil), // 41: openshell.v1.ExposeServiceRequest
+ (*GetServiceRequest)(nil), // 42: openshell.v1.GetServiceRequest
+ (*ListServicesRequest)(nil), // 43: openshell.v1.ListServicesRequest
+ (*ListServicesResponse)(nil), // 44: openshell.v1.ListServicesResponse
+ (*DeleteServiceRequest)(nil), // 45: openshell.v1.DeleteServiceRequest
+ (*DeleteServiceResponse)(nil), // 46: openshell.v1.DeleteServiceResponse
+ (*ServiceEndpoint)(nil), // 47: openshell.v1.ServiceEndpoint
+ (*ServiceEndpointResponse)(nil), // 48: openshell.v1.ServiceEndpointResponse
+ (*RevokeSshSessionRequest)(nil), // 49: openshell.v1.RevokeSshSessionRequest
+ (*RevokeSshSessionResponse)(nil), // 50: openshell.v1.RevokeSshSessionResponse
+ (*ExecSandboxRequest)(nil), // 51: openshell.v1.ExecSandboxRequest
+ (*ExecSandboxStdout)(nil), // 52: openshell.v1.ExecSandboxStdout
+ (*ExecSandboxStderr)(nil), // 53: openshell.v1.ExecSandboxStderr
+ (*ExecSandboxExit)(nil), // 54: openshell.v1.ExecSandboxExit
+ (*ExecSandboxEvent)(nil), // 55: openshell.v1.ExecSandboxEvent
+ (*TcpForwardInit)(nil), // 56: openshell.v1.TcpForwardInit
+ (*TcpForwardFrame)(nil), // 57: openshell.v1.TcpForwardFrame
+ (*ExecSandboxInput)(nil), // 58: openshell.v1.ExecSandboxInput
+ (*ExecSandboxWindowResize)(nil), // 59: openshell.v1.ExecSandboxWindowResize
+ (*SshSession)(nil), // 60: openshell.v1.SshSession
+ (*WatchSandboxRequest)(nil), // 61: openshell.v1.WatchSandboxRequest
+ (*SandboxStreamEvent)(nil), // 62: openshell.v1.SandboxStreamEvent
+ (*SandboxLogLine)(nil), // 63: openshell.v1.SandboxLogLine
+ (*SandboxStreamWarning)(nil), // 64: openshell.v1.SandboxStreamWarning
+ (*CreateProviderRequest)(nil), // 65: openshell.v1.CreateProviderRequest
+ (*GetProviderRequest)(nil), // 66: openshell.v1.GetProviderRequest
+ (*ListProvidersRequest)(nil), // 67: openshell.v1.ListProvidersRequest
+ (*UpdateProviderRequest)(nil), // 68: openshell.v1.UpdateProviderRequest
+ (*DeleteProviderRequest)(nil), // 69: openshell.v1.DeleteProviderRequest
+ (*ProviderResponse)(nil), // 70: openshell.v1.ProviderResponse
+ (*ListProvidersResponse)(nil), // 71: openshell.v1.ListProvidersResponse
+ (*ListProviderProfilesRequest)(nil), // 72: openshell.v1.ListProviderProfilesRequest
+ (*GetProviderProfileRequest)(nil), // 73: openshell.v1.GetProviderProfileRequest
+ (*ProviderProfileImportItem)(nil), // 74: openshell.v1.ProviderProfileImportItem
+ (*ProviderProfileDiagnostic)(nil), // 75: openshell.v1.ProviderProfileDiagnostic
+ (*ProviderCredentialTokenGrantAudienceOverride)(nil), // 76: openshell.v1.ProviderCredentialTokenGrantAudienceOverride
+ (*ProviderCredentialTokenGrant)(nil), // 77: openshell.v1.ProviderCredentialTokenGrant
+ (*ProviderProfileCredential)(nil), // 78: openshell.v1.ProviderProfileCredential
+ (*ProviderCredentialRefreshMaterial)(nil), // 79: openshell.v1.ProviderCredentialRefreshMaterial
+ (*ProviderCredentialRefreshOutput)(nil), // 80: openshell.v1.ProviderCredentialRefreshOutput
+ (*ProviderCredentialRefresh)(nil), // 81: openshell.v1.ProviderCredentialRefresh
+ (*ProviderCredentialRefreshStatus)(nil), // 82: openshell.v1.ProviderCredentialRefreshStatus
+ (*ProviderProfileDiscovery)(nil), // 83: openshell.v1.ProviderProfileDiscovery
+ (*StoredProviderCredentialRefreshState)(nil), // 84: openshell.v1.StoredProviderCredentialRefreshState
+ (*GetProviderRefreshStatusRequest)(nil), // 85: openshell.v1.GetProviderRefreshStatusRequest
+ (*GetProviderRefreshStatusResponse)(nil), // 86: openshell.v1.GetProviderRefreshStatusResponse
+ (*ConfigureProviderRefreshRequest)(nil), // 87: openshell.v1.ConfigureProviderRefreshRequest
+ (*ConfigureProviderRefreshResponse)(nil), // 88: openshell.v1.ConfigureProviderRefreshResponse
+ (*RotateProviderCredentialRequest)(nil), // 89: openshell.v1.RotateProviderCredentialRequest
+ (*RotateProviderCredentialResponse)(nil), // 90: openshell.v1.RotateProviderCredentialResponse
+ (*DeleteProviderRefreshRequest)(nil), // 91: openshell.v1.DeleteProviderRefreshRequest
+ (*DeleteProviderRefreshResponse)(nil), // 92: openshell.v1.DeleteProviderRefreshResponse
+ (*ProviderProfile)(nil), // 93: openshell.v1.ProviderProfile
+ (*StoredProviderProfile)(nil), // 94: openshell.v1.StoredProviderProfile
+ (*ProviderProfileResponse)(nil), // 95: openshell.v1.ProviderProfileResponse
+ (*ListProviderProfilesResponse)(nil), // 96: openshell.v1.ListProviderProfilesResponse
+ (*ImportProviderProfilesRequest)(nil), // 97: openshell.v1.ImportProviderProfilesRequest
+ (*ImportProviderProfilesResponse)(nil), // 98: openshell.v1.ImportProviderProfilesResponse
+ (*UpdateProviderProfilesRequest)(nil), // 99: openshell.v1.UpdateProviderProfilesRequest
+ (*UpdateProviderProfilesResponse)(nil), // 100: openshell.v1.UpdateProviderProfilesResponse
+ (*LintProviderProfilesRequest)(nil), // 101: openshell.v1.LintProviderProfilesRequest
+ (*LintProviderProfilesResponse)(nil), // 102: openshell.v1.LintProviderProfilesResponse
+ (*DeleteProviderResponse)(nil), // 103: openshell.v1.DeleteProviderResponse
+ (*DeleteProviderProfileRequest)(nil), // 104: openshell.v1.DeleteProviderProfileRequest
+ (*DeleteProviderProfileResponse)(nil), // 105: openshell.v1.DeleteProviderProfileResponse
+ (*GetSandboxProviderEnvironmentRequest)(nil), // 106: openshell.v1.GetSandboxProviderEnvironmentRequest
+ (*GetSandboxProviderEnvironmentResponse)(nil), // 107: openshell.v1.GetSandboxProviderEnvironmentResponse
+ (*UpdateConfigRequest)(nil), // 108: openshell.v1.UpdateConfigRequest
+ (*PolicyMergeOperation)(nil), // 109: openshell.v1.PolicyMergeOperation
+ (*AddNetworkRule)(nil), // 110: openshell.v1.AddNetworkRule
+ (*RemoveNetworkEndpoint)(nil), // 111: openshell.v1.RemoveNetworkEndpoint
+ (*RemoveNetworkRule)(nil), // 112: openshell.v1.RemoveNetworkRule
+ (*AddDenyRules)(nil), // 113: openshell.v1.AddDenyRules
+ (*AddAllowRules)(nil), // 114: openshell.v1.AddAllowRules
+ (*RemoveNetworkBinary)(nil), // 115: openshell.v1.RemoveNetworkBinary
+ (*UpdateConfigResponse)(nil), // 116: openshell.v1.UpdateConfigResponse
+ (*GetSandboxPolicyStatusRequest)(nil), // 117: openshell.v1.GetSandboxPolicyStatusRequest
+ (*GetSandboxPolicyStatusResponse)(nil), // 118: openshell.v1.GetSandboxPolicyStatusResponse
+ (*ListSandboxPoliciesRequest)(nil), // 119: openshell.v1.ListSandboxPoliciesRequest
+ (*ListSandboxPoliciesResponse)(nil), // 120: openshell.v1.ListSandboxPoliciesResponse
+ (*ReportPolicyStatusRequest)(nil), // 121: openshell.v1.ReportPolicyStatusRequest
+ (*ReportPolicyStatusResponse)(nil), // 122: openshell.v1.ReportPolicyStatusResponse
+ (*SandboxPolicyRevision)(nil), // 123: openshell.v1.SandboxPolicyRevision
+ (*GetSandboxLogsRequest)(nil), // 124: openshell.v1.GetSandboxLogsRequest
+ (*PushSandboxLogsRequest)(nil), // 125: openshell.v1.PushSandboxLogsRequest
+ (*PushSandboxLogsResponse)(nil), // 126: openshell.v1.PushSandboxLogsResponse
+ (*GetSandboxLogsResponse)(nil), // 127: openshell.v1.GetSandboxLogsResponse
+ (*SupervisorMessage)(nil), // 128: openshell.v1.SupervisorMessage
+ (*GatewayMessage)(nil), // 129: openshell.v1.GatewayMessage
+ (*SupervisorHello)(nil), // 130: openshell.v1.SupervisorHello
+ (*SessionAccepted)(nil), // 131: openshell.v1.SessionAccepted
+ (*SessionRejected)(nil), // 132: openshell.v1.SessionRejected
+ (*SupervisorHeartbeat)(nil), // 133: openshell.v1.SupervisorHeartbeat
+ (*GatewayHeartbeat)(nil), // 134: openshell.v1.GatewayHeartbeat
+ (*RelayOpen)(nil), // 135: openshell.v1.RelayOpen
+ (*SshRelayTarget)(nil), // 136: openshell.v1.SshRelayTarget
+ (*TcpRelayTarget)(nil), // 137: openshell.v1.TcpRelayTarget
+ (*RelayInit)(nil), // 138: openshell.v1.RelayInit
+ (*RelayFrame)(nil), // 139: openshell.v1.RelayFrame
+ (*RelayOpenResult)(nil), // 140: openshell.v1.RelayOpenResult
+ (*RelayClose)(nil), // 141: openshell.v1.RelayClose
+ (*L7RequestSample)(nil), // 142: openshell.v1.L7RequestSample
+ (*DenialSummary)(nil), // 143: openshell.v1.DenialSummary
+ (*DenialGroupCount)(nil), // 144: openshell.v1.DenialGroupCount
+ (*NetworkActivitySummary)(nil), // 145: openshell.v1.NetworkActivitySummary
+ (*PolicyChunk)(nil), // 146: openshell.v1.PolicyChunk
+ (*DraftPolicyUpdate)(nil), // 147: openshell.v1.DraftPolicyUpdate
+ (*SubmitPolicyAnalysisRequest)(nil), // 148: openshell.v1.SubmitPolicyAnalysisRequest
+ (*SubmitPolicyAnalysisResponse)(nil), // 149: openshell.v1.SubmitPolicyAnalysisResponse
+ (*GetDraftPolicyRequest)(nil), // 150: openshell.v1.GetDraftPolicyRequest
+ (*GetDraftPolicyResponse)(nil), // 151: openshell.v1.GetDraftPolicyResponse
+ (*ApproveDraftChunkRequest)(nil), // 152: openshell.v1.ApproveDraftChunkRequest
+ (*ApproveDraftChunkResponse)(nil), // 153: openshell.v1.ApproveDraftChunkResponse
+ (*RejectDraftChunkRequest)(nil), // 154: openshell.v1.RejectDraftChunkRequest
+ (*RejectDraftChunkResponse)(nil), // 155: openshell.v1.RejectDraftChunkResponse
+ (*ApproveAllDraftChunksRequest)(nil), // 156: openshell.v1.ApproveAllDraftChunksRequest
+ (*ApproveAllDraftChunksResponse)(nil), // 157: openshell.v1.ApproveAllDraftChunksResponse
+ (*EditDraftChunkRequest)(nil), // 158: openshell.v1.EditDraftChunkRequest
+ (*EditDraftChunkResponse)(nil), // 159: openshell.v1.EditDraftChunkResponse
+ (*UndoDraftChunkRequest)(nil), // 160: openshell.v1.UndoDraftChunkRequest
+ (*UndoDraftChunkResponse)(nil), // 161: openshell.v1.UndoDraftChunkResponse
+ (*ClearDraftChunksRequest)(nil), // 162: openshell.v1.ClearDraftChunksRequest
+ (*ClearDraftChunksResponse)(nil), // 163: openshell.v1.ClearDraftChunksResponse
+ (*GetDraftHistoryRequest)(nil), // 164: openshell.v1.GetDraftHistoryRequest
+ (*DraftHistoryEntry)(nil), // 165: openshell.v1.DraftHistoryEntry
+ (*GetDraftHistoryResponse)(nil), // 166: openshell.v1.GetDraftHistoryResponse
+ (*PolicyRevisionPayload)(nil), // 167: openshell.v1.PolicyRevisionPayload
+ (*DraftChunkPayload)(nil), // 168: openshell.v1.DraftChunkPayload
+ (*StoredPolicyRevision)(nil), // 169: openshell.v1.StoredPolicyRevision
+ (*StoredDraftChunk)(nil), // 170: openshell.v1.StoredDraftChunk
+ (*CreateWorkspaceRequest)(nil), // 171: openshell.v1.CreateWorkspaceRequest
+ (*CreateWorkspaceResponse)(nil), // 172: openshell.v1.CreateWorkspaceResponse
+ (*GetWorkspaceRequest)(nil), // 173: openshell.v1.GetWorkspaceRequest
+ (*GetWorkspaceResponse)(nil), // 174: openshell.v1.GetWorkspaceResponse
+ (*ListWorkspacesRequest)(nil), // 175: openshell.v1.ListWorkspacesRequest
+ (*ListWorkspacesResponse)(nil), // 176: openshell.v1.ListWorkspacesResponse
+ (*DeleteWorkspaceRequest)(nil), // 177: openshell.v1.DeleteWorkspaceRequest
+ (*DeleteWorkspaceResponse)(nil), // 178: openshell.v1.DeleteWorkspaceResponse
+ (*WorkspaceMember)(nil), // 179: openshell.v1.WorkspaceMember
+ (*AddWorkspaceMemberRequest)(nil), // 180: openshell.v1.AddWorkspaceMemberRequest
+ (*AddWorkspaceMemberResponse)(nil), // 181: openshell.v1.AddWorkspaceMemberResponse
+ (*RemoveWorkspaceMemberRequest)(nil), // 182: openshell.v1.RemoveWorkspaceMemberRequest
+ (*RemoveWorkspaceMemberResponse)(nil), // 183: openshell.v1.RemoveWorkspaceMemberResponse
+ (*ListWorkspaceMembersRequest)(nil), // 184: openshell.v1.ListWorkspaceMembersRequest
+ (*ListWorkspaceMembersResponse)(nil), // 185: openshell.v1.ListWorkspaceMembersResponse
+ nil, // 186: openshell.v1.SandboxSpec.EnvironmentEntry
+ nil, // 187: openshell.v1.SandboxTemplate.LabelsEntry
+ nil, // 188: openshell.v1.SandboxTemplate.AnnotationsEntry
+ nil, // 189: openshell.v1.SandboxTemplate.EnvironmentEntry
+ nil, // 190: openshell.v1.PlatformEvent.MetadataEntry
+ nil, // 191: openshell.v1.CreateSandboxRequest.LabelsEntry
+ nil, // 192: openshell.v1.CreateSandboxRequest.AnnotationsEntry
+ nil, // 193: openshell.v1.ExecSandboxRequest.EnvironmentEntry
+ nil, // 194: openshell.v1.SandboxLogLine.FieldsEntry
+ nil, // 195: openshell.v1.UpdateProviderRequest.CredentialExpiresAtMsEntry
+ nil, // 196: openshell.v1.StoredProviderCredentialRefreshState.MaterialEntry
+ nil, // 197: openshell.v1.StoredProviderCredentialRefreshState.AdditionalOutputKeysEntry
+ nil, // 198: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry
+ nil, // 199: openshell.v1.ProviderProfile.AnnotationsEntry
+ nil, // 200: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry
+ nil, // 201: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpiresAtMsEntry
+ nil, // 202: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry
+ nil, // 203: openshell.v1.UpdateConfigRequest.AnnotationsEntry
+ nil, // 204: openshell.v1.UpdateConfigResponse.AnnotationsEntry
+ nil, // 205: openshell.v1.SandboxPolicyRevision.ProvenanceEntry
+ nil, // 206: openshell.v1.PolicyRevisionPayload.ProvenanceEntry
+ nil, // 207: openshell.v1.StoredPolicyRevision.ProvenanceEntry
+ nil, // 208: openshell.v1.CreateWorkspaceRequest.LabelsEntry
+ (*datamodelv1.ObjectMeta)(nil), // 209: openshell.datamodel.v1.ObjectMeta
+ (*sandboxv1.SandboxPolicy)(nil), // 210: openshell.sandbox.v1.SandboxPolicy
+ (*structpb.Struct)(nil), // 211: google.protobuf.Struct
+ (*datamodelv1.Provider)(nil), // 212: openshell.datamodel.v1.Provider
+ (*sandboxv1.NetworkEndpoint)(nil), // 213: openshell.sandbox.v1.NetworkEndpoint
+ (*sandboxv1.NetworkBinary)(nil), // 214: openshell.sandbox.v1.NetworkBinary
+ (*sandboxv1.SettingValue)(nil), // 215: openshell.sandbox.v1.SettingValue
+ (*sandboxv1.NetworkPolicyRule)(nil), // 216: openshell.sandbox.v1.NetworkPolicyRule
+ (*sandboxv1.L7DenyRule)(nil), // 217: openshell.sandbox.v1.L7DenyRule
+ (*sandboxv1.L7Rule)(nil), // 218: openshell.sandbox.v1.L7Rule
+ (*datamodelv1.Workspace)(nil), // 219: openshell.datamodel.v1.Workspace
+ (*sandboxv1.GetSandboxConfigRequest)(nil), // 220: openshell.sandbox.v1.GetSandboxConfigRequest
+ (*sandboxv1.GetGatewayConfigRequest)(nil), // 221: openshell.sandbox.v1.GetGatewayConfigRequest
+ (*sandboxv1.GetSandboxConfigResponse)(nil), // 222: openshell.sandbox.v1.GetSandboxConfigResponse
+ (*sandboxv1.GetGatewayConfigResponse)(nil), // 223: openshell.sandbox.v1.GetGatewayConfigResponse
+}
+var file_openshell_proto_depIdxs = []int32{
+ 4, // 0: openshell.v1.HealthResponse.status:type_name -> openshell.v1.ServiceStatus
+ 4, // 1: openshell.v1.GetGatewayInfoResponse.status:type_name -> openshell.v1.ServiceStatus
+ 16, // 2: openshell.v1.GetGatewayInfoResponse.compute_drivers:type_name -> openshell.v1.ComputeDriverInfo
+ 17, // 3: openshell.v1.ComputeDriverInfo.capabilities:type_name -> openshell.v1.ComputeDriverCapabilities
+ 209, // 4: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta
+ 19, // 5: openshell.v1.Sandbox.spec:type_name -> openshell.v1.SandboxSpec
+ 23, // 6: openshell.v1.Sandbox.status:type_name -> openshell.v1.SandboxStatus
+ 186, // 7: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry
+ 22, // 8: openshell.v1.SandboxSpec.template:type_name -> openshell.v1.SandboxTemplate
+ 210, // 9: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy
+ 20, // 10: openshell.v1.SandboxSpec.resource_requirements:type_name -> openshell.v1.ResourceRequirements
+ 21, // 11: openshell.v1.ResourceRequirements.gpu:type_name -> openshell.v1.GpuResourceRequirements
+ 187, // 12: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry
+ 188, // 13: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry
+ 189, // 14: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry
+ 211, // 15: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct
+ 211, // 16: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct
+ 24, // 17: openshell.v1.SandboxStatus.conditions:type_name -> openshell.v1.SandboxCondition
+ 0, // 18: openshell.v1.SandboxStatus.phase:type_name -> openshell.v1.SandboxPhase
+ 190, // 19: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry
+ 19, // 20: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.v1.SandboxSpec
+ 191, // 21: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry
+ 192, // 22: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry
+ 18, // 23: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox
+ 18, // 24: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox
+ 212, // 25: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider
+ 18, // 26: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox
+ 18, // 27: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox
+ 48, // 28: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse
+ 209, // 29: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta
+ 47, // 30: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint
+ 193, // 31: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry
+ 52, // 32: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout
+ 53, // 33: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr
+ 54, // 34: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit
+ 136, // 35: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget
+ 137, // 36: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget
+ 56, // 37: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit
+ 51, // 38: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest
+ 59, // 39: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize
+ 209, // 40: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta
+ 18, // 41: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox
+ 63, // 42: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine
+ 25, // 43: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent
+ 64, // 44: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning
+ 147, // 45: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate
+ 194, // 46: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry
+ 212, // 47: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider
+ 212, // 48: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider
+ 195, // 49: openshell.v1.UpdateProviderRequest.credential_expires_at_ms:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpiresAtMsEntry
+ 212, // 50: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider
+ 212, // 51: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider
+ 93, // 52: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile
+ 76, // 53: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride
+ 81, // 54: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh
+ 77, // 55: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant
+ 1, // 56: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy
+ 79, // 57: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial
+ 80, // 58: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput
+ 1, // 59: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy
+ 209, // 60: openshell.v1.StoredProviderCredentialRefreshState.metadata:type_name -> openshell.datamodel.v1.ObjectMeta
+ 1, // 61: openshell.v1.StoredProviderCredentialRefreshState.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy
+ 196, // 62: openshell.v1.StoredProviderCredentialRefreshState.material:type_name -> openshell.v1.StoredProviderCredentialRefreshState.MaterialEntry
+ 197, // 63: openshell.v1.StoredProviderCredentialRefreshState.additional_output_keys:type_name -> openshell.v1.StoredProviderCredentialRefreshState.AdditionalOutputKeysEntry
+ 82, // 64: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus
+ 1, // 65: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy
+ 198, // 66: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry
+ 82, // 67: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus
+ 82, // 68: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus
+ 2, // 69: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory
+ 78, // 70: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential
+ 213, // 71: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint
+ 214, // 72: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary
+ 83, // 73: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery
+ 199, // 74: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry
+ 209, // 75: openshell.v1.StoredProviderProfile.metadata:type_name -> openshell.datamodel.v1.ObjectMeta
+ 93, // 76: openshell.v1.StoredProviderProfile.profile:type_name -> openshell.v1.ProviderProfile
+ 93, // 77: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile
+ 93, // 78: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile
+ 74, // 79: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem
+ 75, // 80: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic
+ 93, // 81: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile
+ 74, // 82: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem
+ 75, // 83: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic
+ 93, // 84: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile
+ 74, // 85: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem
+ 75, // 86: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic
+ 200, // 87: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry
+ 201, // 88: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expires_at_ms:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpiresAtMsEntry
+ 202, // 89: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry
+ 210, // 90: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy
+ 215, // 91: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue
+ 109, // 92: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation
+ 203, // 93: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry
+ 110, // 94: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule
+ 111, // 95: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint
+ 112, // 96: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule
+ 113, // 97: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules
+ 114, // 98: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules
+ 115, // 99: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary
+ 216, // 100: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule
+ 217, // 101: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule
+ 218, // 102: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule
+ 204, // 103: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry
+ 123, // 104: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision
+ 123, // 105: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision
+ 3, // 106: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus
+ 3, // 107: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus
+ 210, // 108: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy
+ 205, // 109: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry
+ 63, // 110: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine
+ 63, // 111: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine
+ 130, // 112: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello
+ 133, // 113: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat
+ 140, // 114: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult
+ 141, // 115: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose
+ 131, // 116: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted
+ 132, // 117: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected
+ 134, // 118: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat
+ 135, // 119: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen
+ 141, // 120: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose
+ 136, // 121: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget
+ 137, // 122: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget
+ 138, // 123: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit
+ 142, // 124: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample
+ 144, // 125: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount
+ 216, // 126: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule
+ 143, // 127: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary
+ 146, // 128: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk
+ 145, // 129: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary
+ 146, // 130: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk
+ 216, // 131: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule
+ 165, // 132: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry
+ 210, // 133: openshell.v1.PolicyRevisionPayload.policy:type_name -> openshell.sandbox.v1.SandboxPolicy
+ 206, // 134: openshell.v1.PolicyRevisionPayload.provenance:type_name -> openshell.v1.PolicyRevisionPayload.ProvenanceEntry
+ 216, // 135: openshell.v1.DraftChunkPayload.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule
+ 207, // 136: openshell.v1.StoredPolicyRevision.provenance:type_name -> openshell.v1.StoredPolicyRevision.ProvenanceEntry
+ 208, // 137: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry
+ 219, // 138: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace
+ 219, // 139: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace
+ 219, // 140: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace
+ 209, // 141: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta
+ 5, // 142: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole
+ 5, // 143: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole
+ 179, // 144: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember
+ 179, // 145: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember
+ 78, // 146: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential
+ 10, // 147: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest
+ 12, // 148: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest
+ 14, // 149: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest
+ 26, // 150: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest
+ 27, // 151: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest
+ 28, // 152: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest
+ 29, // 153: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest
+ 30, // 154: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest
+ 31, // 155: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest
+ 32, // 156: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest
+ 39, // 157: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest
+ 41, // 158: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest
+ 42, // 159: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest
+ 43, // 160: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest
+ 45, // 161: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest
+ 49, // 162: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest
+ 51, // 163: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest
+ 57, // 164: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame
+ 58, // 165: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput
+ 65, // 166: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest
+ 66, // 167: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest
+ 67, // 168: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest
+ 72, // 169: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest
+ 73, // 170: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest
+ 97, // 171: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest
+ 99, // 172: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest
+ 101, // 173: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest
+ 68, // 174: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest
+ 85, // 175: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest
+ 87, // 176: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest
+ 89, // 177: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest
+ 91, // 178: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest
+ 69, // 179: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest
+ 104, // 180: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest
+ 220, // 181: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest
+ 221, // 182: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest
+ 108, // 183: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest
+ 117, // 184: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest
+ 119, // 185: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest
+ 121, // 186: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest
+ 106, // 187: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest
+ 124, // 188: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest
+ 125, // 189: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest
+ 128, // 190: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage
+ 139, // 191: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame
+ 61, // 192: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest
+ 148, // 193: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest
+ 150, // 194: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest
+ 152, // 195: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest
+ 154, // 196: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest
+ 156, // 197: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest
+ 158, // 198: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest
+ 160, // 199: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest
+ 162, // 200: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest
+ 164, // 201: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest
+ 6, // 202: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest
+ 8, // 203: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest
+ 171, // 204: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest
+ 173, // 205: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest
+ 175, // 206: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest
+ 177, // 207: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest
+ 180, // 208: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest
+ 182, // 209: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest
+ 184, // 210: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest
+ 11, // 211: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse
+ 13, // 212: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse
+ 15, // 213: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse
+ 33, // 214: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse
+ 33, // 215: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse
+ 34, // 216: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse
+ 35, // 217: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse
+ 36, // 218: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse
+ 37, // 219: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse
+ 38, // 220: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse
+ 40, // 221: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse
+ 48, // 222: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse
+ 48, // 223: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse
+ 44, // 224: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse
+ 46, // 225: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse
+ 50, // 226: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse
+ 55, // 227: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent
+ 57, // 228: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame
+ 55, // 229: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent
+ 70, // 230: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse
+ 70, // 231: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse
+ 71, // 232: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse
+ 96, // 233: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse
+ 95, // 234: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse
+ 98, // 235: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse
+ 100, // 236: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse
+ 102, // 237: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse
+ 70, // 238: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse
+ 86, // 239: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse
+ 88, // 240: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse
+ 90, // 241: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse
+ 92, // 242: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse
+ 103, // 243: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse
+ 105, // 244: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse
+ 222, // 245: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse
+ 223, // 246: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse
+ 116, // 247: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse
+ 118, // 248: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse
+ 120, // 249: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse
+ 122, // 250: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse
+ 107, // 251: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse
+ 127, // 252: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse
+ 126, // 253: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse
+ 129, // 254: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage
+ 139, // 255: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame
+ 62, // 256: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent
+ 149, // 257: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse
+ 151, // 258: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse
+ 153, // 259: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse
+ 155, // 260: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse
+ 157, // 261: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse
+ 159, // 262: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse
+ 161, // 263: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse
+ 163, // 264: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse
+ 166, // 265: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse
+ 7, // 266: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse
+ 9, // 267: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse
+ 172, // 268: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse
+ 174, // 269: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse
+ 176, // 270: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse
+ 178, // 271: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse
+ 181, // 272: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse
+ 183, // 273: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse
+ 185, // 274: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse
+ 211, // [211:275] is the sub-list for method output_type
+ 147, // [147:211] is the sub-list for method input_type
+ 147, // [147:147] is the sub-list for extension type_name
+ 147, // [147:147] is the sub-list for extension extendee
+ 0, // [0:147] 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_openshell_proto_msgTypes[15].OneofWrappers = []any{}
+ file_openshell_proto_msgTypes[16].OneofWrappers = []any{}
+ file_openshell_proto_msgTypes[49].OneofWrappers = []any{
+ (*ExecSandboxEvent_Stdout)(nil),
+ (*ExecSandboxEvent_Stderr)(nil),
+ (*ExecSandboxEvent_Exit)(nil),
+ }
+ file_openshell_proto_msgTypes[50].OneofWrappers = []any{
+ (*TcpForwardInit_Ssh)(nil),
+ (*TcpForwardInit_Tcp)(nil),
+ }
+ file_openshell_proto_msgTypes[51].OneofWrappers = []any{
+ (*TcpForwardFrame_Init)(nil),
+ (*TcpForwardFrame_Data)(nil),
+ }
+ file_openshell_proto_msgTypes[52].OneofWrappers = []any{
+ (*ExecSandboxInput_Start)(nil),
+ (*ExecSandboxInput_Stdin)(nil),
+ (*ExecSandboxInput_Resize)(nil),
+ }
+ file_openshell_proto_msgTypes[56].OneofWrappers = []any{
+ (*SandboxStreamEvent_Sandbox)(nil),
+ (*SandboxStreamEvent_Log)(nil),
+ (*SandboxStreamEvent_Event)(nil),
+ (*SandboxStreamEvent_Warning)(nil),
+ (*SandboxStreamEvent_DraftPolicyUpdate)(nil),
+ }
+ file_openshell_proto_msgTypes[81].OneofWrappers = []any{}
+ file_openshell_proto_msgTypes[103].OneofWrappers = []any{
+ (*PolicyMergeOperation_AddRule)(nil),
+ (*PolicyMergeOperation_RemoveEndpoint)(nil),
+ (*PolicyMergeOperation_RemoveRule)(nil),
+ (*PolicyMergeOperation_AddDenyRules)(nil),
+ (*PolicyMergeOperation_AddAllowRules)(nil),
+ (*PolicyMergeOperation_RemoveBinary)(nil),
+ }
+ file_openshell_proto_msgTypes[122].OneofWrappers = []any{
+ (*SupervisorMessage_Hello)(nil),
+ (*SupervisorMessage_Heartbeat)(nil),
+ (*SupervisorMessage_RelayOpenResult)(nil),
+ (*SupervisorMessage_RelayClose)(nil),
+ }
+ file_openshell_proto_msgTypes[123].OneofWrappers = []any{
+ (*GatewayMessage_SessionAccepted)(nil),
+ (*GatewayMessage_SessionRejected)(nil),
+ (*GatewayMessage_Heartbeat)(nil),
+ (*GatewayMessage_RelayOpen)(nil),
+ (*GatewayMessage_RelayClose)(nil),
+ }
+ file_openshell_proto_msgTypes[129].OneofWrappers = []any{
+ (*RelayOpen_Ssh)(nil),
+ (*RelayOpen_Tcp)(nil),
+ }
+ file_openshell_proto_msgTypes[133].OneofWrappers = []any{
+ (*RelayFrame_Init)(nil),
+ (*RelayFrame_Data)(nil),
+ }
+ file_openshell_proto_msgTypes[163].OneofWrappers = []any{}
+ file_openshell_proto_msgTypes[164].OneofWrappers = []any{}
+ 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: 6,
+ NumMessages: 203,
+ 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/sdk/go/proto/openshellv1/openshell_grpc.pb.go b/sdk/go/proto/openshellv1/openshell_grpc.pb.go
new file mode 100644
index 000000000..40d625a39
--- /dev/null
+++ b/sdk/go/proto/openshellv1/openshell_grpc.pb.go
@@ -0,0 +1,2719 @@
+// 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.2
+// - protoc (unknown)
+// source: openshell.proto
+
+package openshellv1
+
+import (
+ context "context"
+ sandboxv1 "github.com/NVIDIA/OpenShell/sdk/go/proto/sandboxv1"
+ 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_GetCurrentUser_FullMethodName = "/openshell.v1.OpenShell/GetCurrentUser"
+ OpenShell_GetGatewayInfo_FullMethodName = "/openshell.v1.OpenShell/GetGatewayInfo"
+ OpenShell_CreateSandbox_FullMethodName = "/openshell.v1.OpenShell/CreateSandbox"
+ OpenShell_GetSandbox_FullMethodName = "/openshell.v1.OpenShell/GetSandbox"
+ OpenShell_ListSandboxes_FullMethodName = "/openshell.v1.OpenShell/ListSandboxes"
+ OpenShell_ListSandboxProviders_FullMethodName = "/openshell.v1.OpenShell/ListSandboxProviders"
+ OpenShell_AttachSandboxProvider_FullMethodName = "/openshell.v1.OpenShell/AttachSandboxProvider"
+ OpenShell_DetachSandboxProvider_FullMethodName = "/openshell.v1.OpenShell/DetachSandboxProvider"
+ OpenShell_DeleteSandbox_FullMethodName = "/openshell.v1.OpenShell/DeleteSandbox"
+ OpenShell_CreateSshSession_FullMethodName = "/openshell.v1.OpenShell/CreateSshSession"
+ OpenShell_ExposeService_FullMethodName = "/openshell.v1.OpenShell/ExposeService"
+ OpenShell_GetService_FullMethodName = "/openshell.v1.OpenShell/GetService"
+ OpenShell_ListServices_FullMethodName = "/openshell.v1.OpenShell/ListServices"
+ OpenShell_DeleteService_FullMethodName = "/openshell.v1.OpenShell/DeleteService"
+ OpenShell_RevokeSshSession_FullMethodName = "/openshell.v1.OpenShell/RevokeSshSession"
+ OpenShell_ExecSandbox_FullMethodName = "/openshell.v1.OpenShell/ExecSandbox"
+ OpenShell_ForwardTcp_FullMethodName = "/openshell.v1.OpenShell/ForwardTcp"
+ OpenShell_ExecSandboxInteractive_FullMethodName = "/openshell.v1.OpenShell/ExecSandboxInteractive"
+ OpenShell_CreateProvider_FullMethodName = "/openshell.v1.OpenShell/CreateProvider"
+ OpenShell_GetProvider_FullMethodName = "/openshell.v1.OpenShell/GetProvider"
+ OpenShell_ListProviders_FullMethodName = "/openshell.v1.OpenShell/ListProviders"
+ OpenShell_ListProviderProfiles_FullMethodName = "/openshell.v1.OpenShell/ListProviderProfiles"
+ OpenShell_GetProviderProfile_FullMethodName = "/openshell.v1.OpenShell/GetProviderProfile"
+ OpenShell_ImportProviderProfiles_FullMethodName = "/openshell.v1.OpenShell/ImportProviderProfiles"
+ OpenShell_UpdateProviderProfiles_FullMethodName = "/openshell.v1.OpenShell/UpdateProviderProfiles"
+ OpenShell_LintProviderProfiles_FullMethodName = "/openshell.v1.OpenShell/LintProviderProfiles"
+ OpenShell_UpdateProvider_FullMethodName = "/openshell.v1.OpenShell/UpdateProvider"
+ OpenShell_GetProviderRefreshStatus_FullMethodName = "/openshell.v1.OpenShell/GetProviderRefreshStatus"
+ OpenShell_ConfigureProviderRefresh_FullMethodName = "/openshell.v1.OpenShell/ConfigureProviderRefresh"
+ OpenShell_RotateProviderCredential_FullMethodName = "/openshell.v1.OpenShell/RotateProviderCredential"
+ OpenShell_DeleteProviderRefresh_FullMethodName = "/openshell.v1.OpenShell/DeleteProviderRefresh"
+ OpenShell_DeleteProvider_FullMethodName = "/openshell.v1.OpenShell/DeleteProvider"
+ OpenShell_DeleteProviderProfile_FullMethodName = "/openshell.v1.OpenShell/DeleteProviderProfile"
+ OpenShell_GetSandboxConfig_FullMethodName = "/openshell.v1.OpenShell/GetSandboxConfig"
+ OpenShell_GetGatewayConfig_FullMethodName = "/openshell.v1.OpenShell/GetGatewayConfig"
+ OpenShell_UpdateConfig_FullMethodName = "/openshell.v1.OpenShell/UpdateConfig"
+ 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_ConnectSupervisor_FullMethodName = "/openshell.v1.OpenShell/ConnectSupervisor"
+ OpenShell_RelayStream_FullMethodName = "/openshell.v1.OpenShell/RelayStream"
+ 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"
+ OpenShell_IssueSandboxToken_FullMethodName = "/openshell.v1.OpenShell/IssueSandboxToken"
+ OpenShell_RefreshSandboxToken_FullMethodName = "/openshell.v1.OpenShell/RefreshSandboxToken"
+ OpenShell_CreateWorkspace_FullMethodName = "/openshell.v1.OpenShell/CreateWorkspace"
+ OpenShell_GetWorkspace_FullMethodName = "/openshell.v1.OpenShell/GetWorkspace"
+ OpenShell_ListWorkspaces_FullMethodName = "/openshell.v1.OpenShell/ListWorkspaces"
+ OpenShell_DeleteWorkspace_FullMethodName = "/openshell.v1.OpenShell/DeleteWorkspace"
+ OpenShell_AddWorkspaceMember_FullMethodName = "/openshell.v1.OpenShell/AddWorkspaceMember"
+ OpenShell_RemoveWorkspaceMember_FullMethodName = "/openshell.v1.OpenShell/RemoveWorkspaceMember"
+ OpenShell_ListWorkspaceMembers_FullMethodName = "/openshell.v1.OpenShell/ListWorkspaceMembers"
+)
+
+// 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.
+//
+// Conventions:
+// - This file owns the public API resource model exposed to OpenShell clients.
+// - `Sandbox`, `SandboxSpec`, `SandboxStatus`, and `SandboxPhase` are gateway-owned
+// public types. Internal compute drivers must not import or return them directly.
+// - The gateway translates internal compute-driver observations into these public
+// resource messages before persisting or returning them to clients.
+type OpenShellClient interface {
+ // Check the health of the service.
+ Health(ctx context.Context, in *HealthRequest, opts ...grpc.CallOption) (*HealthResponse, error)
+ // Return the authenticated caller identity established by the gateway.
+ GetCurrentUser(ctx context.Context, in *GetCurrentUserRequest, opts ...grpc.CallOption) (*GetCurrentUserResponse, error)
+ // Fetch elevated live gateway runtime metadata.
+ GetGatewayInfo(ctx context.Context, in *GetGatewayInfoRequest, opts ...grpc.CallOption) (*GetGatewayInfoResponse, 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)
+ // List provider records attached to a sandbox.
+ ListSandboxProviders(ctx context.Context, in *ListSandboxProvidersRequest, opts ...grpc.CallOption) (*ListSandboxProvidersResponse, error)
+ // Attach a provider record to an existing sandbox.
+ AttachSandboxProvider(ctx context.Context, in *AttachSandboxProviderRequest, opts ...grpc.CallOption) (*AttachSandboxProviderResponse, error)
+ // Detach a provider record from an existing sandbox.
+ DetachSandboxProvider(ctx context.Context, in *DetachSandboxProviderRequest, opts ...grpc.CallOption) (*DetachSandboxProviderResponse, 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)
+ // Create or update a sandbox HTTP service endpoint for local routing.
+ ExposeService(ctx context.Context, in *ExposeServiceRequest, opts ...grpc.CallOption) (*ServiceEndpointResponse, error)
+ // Fetch one sandbox HTTP service endpoint.
+ GetService(ctx context.Context, in *GetServiceRequest, opts ...grpc.CallOption) (*ServiceEndpointResponse, error)
+ // List sandbox HTTP service endpoints.
+ ListServices(ctx context.Context, in *ListServicesRequest, opts ...grpc.CallOption) (*ListServicesResponse, error)
+ // Delete one sandbox HTTP service endpoint.
+ DeleteService(ctx context.Context, in *DeleteServiceRequest, opts ...grpc.CallOption) (*DeleteServiceResponse, 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)
+ // Forward one CLI-side TCP connection to a loopback TCP target in a sandbox.
+ ForwardTcp(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[TcpForwardFrame, TcpForwardFrame], error)
+ // Execute an interactive command with bidirectional stdin/stdout streaming.
+ // The first client message MUST carry an ExecSandboxInput with the start
+ // variant. Subsequent messages carry stdin bytes or window resize events.
+ ExecSandboxInteractive(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[ExecSandboxInput, 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)
+ // List available provider type profiles.
+ ListProviderProfiles(ctx context.Context, in *ListProviderProfilesRequest, opts ...grpc.CallOption) (*ListProviderProfilesResponse, error)
+ // Fetch one provider type profile by id.
+ GetProviderProfile(ctx context.Context, in *GetProviderProfileRequest, opts ...grpc.CallOption) (*ProviderProfileResponse, error)
+ // Import custom provider type profiles.
+ ImportProviderProfiles(ctx context.Context, in *ImportProviderProfilesRequest, opts ...grpc.CallOption) (*ImportProviderProfilesResponse, error)
+ // Update an existing custom provider type profile.
+ UpdateProviderProfiles(ctx context.Context, in *UpdateProviderProfilesRequest, opts ...grpc.CallOption) (*UpdateProviderProfilesResponse, error)
+ // Validate provider type profiles without registering them.
+ LintProviderProfiles(ctx context.Context, in *LintProviderProfilesRequest, opts ...grpc.CallOption) (*LintProviderProfilesResponse, error)
+ // Update an existing provider by name.
+ UpdateProvider(ctx context.Context, in *UpdateProviderRequest, opts ...grpc.CallOption) (*ProviderResponse, error)
+ // Fetch refresh status for one provider or provider credential.
+ GetProviderRefreshStatus(ctx context.Context, in *GetProviderRefreshStatusRequest, opts ...grpc.CallOption) (*GetProviderRefreshStatusResponse, error)
+ // Configure gateway-owned refresh material for one provider credential.
+ ConfigureProviderRefresh(ctx context.Context, in *ConfigureProviderRefreshRequest, opts ...grpc.CallOption) (*ConfigureProviderRefreshResponse, error)
+ // Record a gateway-owned refresh request for one provider credential.
+ RotateProviderCredential(ctx context.Context, in *RotateProviderCredentialRequest, opts ...grpc.CallOption) (*RotateProviderCredentialResponse, error)
+ // Delete gateway-owned refresh configuration for one provider credential.
+ DeleteProviderRefresh(ctx context.Context, in *DeleteProviderRefreshRequest, opts ...grpc.CallOption) (*DeleteProviderRefreshResponse, error)
+ // Delete a provider by name.
+ DeleteProvider(ctx context.Context, in *DeleteProviderRequest, opts ...grpc.CallOption) (*DeleteProviderResponse, error)
+ // Delete a custom provider type profile by id.
+ DeleteProviderProfile(ctx context.Context, in *DeleteProviderProfileRequest, opts ...grpc.CallOption) (*DeleteProviderProfileResponse, error)
+ // Get sandbox settings by id (called by sandbox entrypoint and poll loop).
+ GetSandboxConfig(ctx context.Context, in *sandboxv1.GetSandboxConfigRequest, opts ...grpc.CallOption) (*sandboxv1.GetSandboxConfigResponse, error)
+ // Get gateway-global settings (read-only feature flags; any authenticated
+ // user may read these so the CLI and TUI can discover capabilities like
+ // providers_v2_enabled without requiring Platform Admin).
+ //
+ // Scope-only (no role): scopes are granted by the IdP at token issuance,
+ // orthogonal to workspace membership. Deployments that enable scope
+ // enforcement configure the IdP to grant config:read (or openshell:all)
+ // to all sandbox users, so this does not block least-privilege flows.
+ GetGatewayConfig(ctx context.Context, in *sandboxv1.GetGatewayConfigRequest, opts ...grpc.CallOption) (*sandboxv1.GetGatewayConfigResponse, error)
+ // Update settings or policy at sandbox or global scope.
+ UpdateConfig(ctx context.Context, in *UpdateConfigRequest, opts ...grpc.CallOption) (*UpdateConfigResponse, 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)
+ // Persistent supervisor-to-gateway session (bidirectional streaming).
+ //
+ // The supervisor opens this stream at startup and keeps it alive for the
+ // sandbox lifetime. The gateway uses it to coordinate relay channels for
+ // SSH connect, ExecSandbox, and targetable sandbox services. Raw service
+ // bytes flow over RelayStream calls (separate HTTP/2 streams on the same
+ // connection), not over this stream.
+ ConnectSupervisor(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[SupervisorMessage, GatewayMessage], error)
+ // Raw byte relay between supervisor and gateway.
+ //
+ // The supervisor initiates this call after receiving a RelayOpen message
+ // on its ConnectSupervisor stream. The first RelayFrame carries a
+ // RelayInit with the channel_id to associate the new HTTP/2 stream with
+ // the pending relay slot on the gateway. Subsequent frames carry raw bytes in either
+ // direction between the gateway-side waiter (ForwardTcp / exec handler)
+ // and the supervisor-side target bridge.
+ //
+ // This rides the same TCP+TLS+HTTP/2 connection as ConnectSupervisor —
+ // no new TLS handshake, no reverse HTTP CONNECT.
+ RelayStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[RelayFrame, RelayFrame], 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)
+ // Exchange a sandbox-bootstrap credential (e.g. a Kubernetes projected
+ // ServiceAccount token) for a gateway-minted JWT bound to the calling
+ // sandbox's UUID. Used by the Kubernetes driver path; singleplayer
+ // drivers receive the gateway JWT directly from the create-sandbox flow
+ // and never call this RPC.
+ IssueSandboxToken(ctx context.Context, in *IssueSandboxTokenRequest, opts ...grpc.CallOption) (*IssueSandboxTokenResponse, error)
+ // Renew the calling sandbox's gateway JWT. Older tokens remain valid
+ // until their own expiry; deployments should keep token TTLs short to
+ // bound replay exposure. The supervisor calls this from a background
+ // task at ~80% of the token's lifetime; the new token is cached in
+ // memory only — the on-disk bootstrap file is intentionally not
+ // rewritten.
+ RefreshSandboxToken(ctx context.Context, in *RefreshSandboxTokenRequest, opts ...grpc.CallOption) (*RefreshSandboxTokenResponse, error)
+ // Create a workspace.
+ CreateWorkspace(ctx context.Context, in *CreateWorkspaceRequest, opts ...grpc.CallOption) (*CreateWorkspaceResponse, error)
+ // Fetch a workspace by name.
+ GetWorkspace(ctx context.Context, in *GetWorkspaceRequest, opts ...grpc.CallOption) (*GetWorkspaceResponse, error)
+ // List workspaces.
+ ListWorkspaces(ctx context.Context, in *ListWorkspacesRequest, opts ...grpc.CallOption) (*ListWorkspacesResponse, error)
+ // Delete a workspace by name.
+ DeleteWorkspace(ctx context.Context, in *DeleteWorkspaceRequest, opts ...grpc.CallOption) (*DeleteWorkspaceResponse, error)
+ // Add a member to a workspace.
+ AddWorkspaceMember(ctx context.Context, in *AddWorkspaceMemberRequest, opts ...grpc.CallOption) (*AddWorkspaceMemberResponse, error)
+ // Remove a member from a workspace.
+ RemoveWorkspaceMember(ctx context.Context, in *RemoveWorkspaceMemberRequest, opts ...grpc.CallOption) (*RemoveWorkspaceMemberResponse, error)
+ // List members of a workspace.
+ ListWorkspaceMembers(ctx context.Context, in *ListWorkspaceMembersRequest, opts ...grpc.CallOption) (*ListWorkspaceMembersResponse, 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) GetCurrentUser(ctx context.Context, in *GetCurrentUserRequest, opts ...grpc.CallOption) (*GetCurrentUserResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(GetCurrentUserResponse)
+ err := c.cc.Invoke(ctx, OpenShell_GetCurrentUser_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) GetGatewayInfo(ctx context.Context, in *GetGatewayInfoRequest, opts ...grpc.CallOption) (*GetGatewayInfoResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(GetGatewayInfoResponse)
+ err := c.cc.Invoke(ctx, OpenShell_GetGatewayInfo_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) ListSandboxProviders(ctx context.Context, in *ListSandboxProvidersRequest, opts ...grpc.CallOption) (*ListSandboxProvidersResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(ListSandboxProvidersResponse)
+ err := c.cc.Invoke(ctx, OpenShell_ListSandboxProviders_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) AttachSandboxProvider(ctx context.Context, in *AttachSandboxProviderRequest, opts ...grpc.CallOption) (*AttachSandboxProviderResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(AttachSandboxProviderResponse)
+ err := c.cc.Invoke(ctx, OpenShell_AttachSandboxProvider_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) DetachSandboxProvider(ctx context.Context, in *DetachSandboxProviderRequest, opts ...grpc.CallOption) (*DetachSandboxProviderResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(DetachSandboxProviderResponse)
+ err := c.cc.Invoke(ctx, OpenShell_DetachSandboxProvider_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) ExposeService(ctx context.Context, in *ExposeServiceRequest, opts ...grpc.CallOption) (*ServiceEndpointResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(ServiceEndpointResponse)
+ err := c.cc.Invoke(ctx, OpenShell_ExposeService_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) GetService(ctx context.Context, in *GetServiceRequest, opts ...grpc.CallOption) (*ServiceEndpointResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(ServiceEndpointResponse)
+ err := c.cc.Invoke(ctx, OpenShell_GetService_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) ListServices(ctx context.Context, in *ListServicesRequest, opts ...grpc.CallOption) (*ListServicesResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(ListServicesResponse)
+ err := c.cc.Invoke(ctx, OpenShell_ListServices_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) DeleteService(ctx context.Context, in *DeleteServiceRequest, opts ...grpc.CallOption) (*DeleteServiceResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(DeleteServiceResponse)
+ err := c.cc.Invoke(ctx, OpenShell_DeleteService_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) ForwardTcp(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[TcpForwardFrame, TcpForwardFrame], error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ stream, err := c.cc.NewStream(ctx, &OpenShell_ServiceDesc.Streams[1], OpenShell_ForwardTcp_FullMethodName, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &grpc.GenericClientStream[TcpForwardFrame, TcpForwardFrame]{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_ForwardTcpClient = grpc.BidiStreamingClient[TcpForwardFrame, TcpForwardFrame]
+
+func (c *openShellClient) ExecSandboxInteractive(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[ExecSandboxInput, ExecSandboxEvent], error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ stream, err := c.cc.NewStream(ctx, &OpenShell_ServiceDesc.Streams[2], OpenShell_ExecSandboxInteractive_FullMethodName, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &grpc.GenericClientStream[ExecSandboxInput, ExecSandboxEvent]{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_ExecSandboxInteractiveClient = grpc.BidiStreamingClient[ExecSandboxInput, 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) ListProviderProfiles(ctx context.Context, in *ListProviderProfilesRequest, opts ...grpc.CallOption) (*ListProviderProfilesResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(ListProviderProfilesResponse)
+ err := c.cc.Invoke(ctx, OpenShell_ListProviderProfiles_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) GetProviderProfile(ctx context.Context, in *GetProviderProfileRequest, opts ...grpc.CallOption) (*ProviderProfileResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(ProviderProfileResponse)
+ err := c.cc.Invoke(ctx, OpenShell_GetProviderProfile_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) ImportProviderProfiles(ctx context.Context, in *ImportProviderProfilesRequest, opts ...grpc.CallOption) (*ImportProviderProfilesResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(ImportProviderProfilesResponse)
+ err := c.cc.Invoke(ctx, OpenShell_ImportProviderProfiles_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) UpdateProviderProfiles(ctx context.Context, in *UpdateProviderProfilesRequest, opts ...grpc.CallOption) (*UpdateProviderProfilesResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(UpdateProviderProfilesResponse)
+ err := c.cc.Invoke(ctx, OpenShell_UpdateProviderProfiles_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) LintProviderProfiles(ctx context.Context, in *LintProviderProfilesRequest, opts ...grpc.CallOption) (*LintProviderProfilesResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(LintProviderProfilesResponse)
+ err := c.cc.Invoke(ctx, OpenShell_LintProviderProfiles_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) GetProviderRefreshStatus(ctx context.Context, in *GetProviderRefreshStatusRequest, opts ...grpc.CallOption) (*GetProviderRefreshStatusResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(GetProviderRefreshStatusResponse)
+ err := c.cc.Invoke(ctx, OpenShell_GetProviderRefreshStatus_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) ConfigureProviderRefresh(ctx context.Context, in *ConfigureProviderRefreshRequest, opts ...grpc.CallOption) (*ConfigureProviderRefreshResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(ConfigureProviderRefreshResponse)
+ err := c.cc.Invoke(ctx, OpenShell_ConfigureProviderRefresh_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) RotateProviderCredential(ctx context.Context, in *RotateProviderCredentialRequest, opts ...grpc.CallOption) (*RotateProviderCredentialResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(RotateProviderCredentialResponse)
+ err := c.cc.Invoke(ctx, OpenShell_RotateProviderCredential_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) DeleteProviderRefresh(ctx context.Context, in *DeleteProviderRefreshRequest, opts ...grpc.CallOption) (*DeleteProviderRefreshResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(DeleteProviderRefreshResponse)
+ err := c.cc.Invoke(ctx, OpenShell_DeleteProviderRefresh_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) DeleteProviderProfile(ctx context.Context, in *DeleteProviderProfileRequest, opts ...grpc.CallOption) (*DeleteProviderProfileResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(DeleteProviderProfileResponse)
+ err := c.cc.Invoke(ctx, OpenShell_DeleteProviderProfile_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) GetSandboxConfig(ctx context.Context, in *sandboxv1.GetSandboxConfigRequest, opts ...grpc.CallOption) (*sandboxv1.GetSandboxConfigResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(sandboxv1.GetSandboxConfigResponse)
+ err := c.cc.Invoke(ctx, OpenShell_GetSandboxConfig_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) GetGatewayConfig(ctx context.Context, in *sandboxv1.GetGatewayConfigRequest, opts ...grpc.CallOption) (*sandboxv1.GetGatewayConfigResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(sandboxv1.GetGatewayConfigResponse)
+ err := c.cc.Invoke(ctx, OpenShell_GetGatewayConfig_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) UpdateConfig(ctx context.Context, in *UpdateConfigRequest, opts ...grpc.CallOption) (*UpdateConfigResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(UpdateConfigResponse)
+ err := c.cc.Invoke(ctx, OpenShell_UpdateConfig_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[3], 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) ConnectSupervisor(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[SupervisorMessage, GatewayMessage], error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ stream, err := c.cc.NewStream(ctx, &OpenShell_ServiceDesc.Streams[4], OpenShell_ConnectSupervisor_FullMethodName, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &grpc.GenericClientStream[SupervisorMessage, GatewayMessage]{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_ConnectSupervisorClient = grpc.BidiStreamingClient[SupervisorMessage, GatewayMessage]
+
+func (c *openShellClient) RelayStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[RelayFrame, RelayFrame], error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ stream, err := c.cc.NewStream(ctx, &OpenShell_ServiceDesc.Streams[5], OpenShell_RelayStream_FullMethodName, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &grpc.GenericClientStream[RelayFrame, RelayFrame]{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_RelayStreamClient = grpc.BidiStreamingClient[RelayFrame, RelayFrame]
+
+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[6], 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
+}
+
+func (c *openShellClient) IssueSandboxToken(ctx context.Context, in *IssueSandboxTokenRequest, opts ...grpc.CallOption) (*IssueSandboxTokenResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(IssueSandboxTokenResponse)
+ err := c.cc.Invoke(ctx, OpenShell_IssueSandboxToken_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) RefreshSandboxToken(ctx context.Context, in *RefreshSandboxTokenRequest, opts ...grpc.CallOption) (*RefreshSandboxTokenResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(RefreshSandboxTokenResponse)
+ err := c.cc.Invoke(ctx, OpenShell_RefreshSandboxToken_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) CreateWorkspace(ctx context.Context, in *CreateWorkspaceRequest, opts ...grpc.CallOption) (*CreateWorkspaceResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(CreateWorkspaceResponse)
+ err := c.cc.Invoke(ctx, OpenShell_CreateWorkspace_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) GetWorkspace(ctx context.Context, in *GetWorkspaceRequest, opts ...grpc.CallOption) (*GetWorkspaceResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(GetWorkspaceResponse)
+ err := c.cc.Invoke(ctx, OpenShell_GetWorkspace_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) ListWorkspaces(ctx context.Context, in *ListWorkspacesRequest, opts ...grpc.CallOption) (*ListWorkspacesResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(ListWorkspacesResponse)
+ err := c.cc.Invoke(ctx, OpenShell_ListWorkspaces_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) DeleteWorkspace(ctx context.Context, in *DeleteWorkspaceRequest, opts ...grpc.CallOption) (*DeleteWorkspaceResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(DeleteWorkspaceResponse)
+ err := c.cc.Invoke(ctx, OpenShell_DeleteWorkspace_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) AddWorkspaceMember(ctx context.Context, in *AddWorkspaceMemberRequest, opts ...grpc.CallOption) (*AddWorkspaceMemberResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(AddWorkspaceMemberResponse)
+ err := c.cc.Invoke(ctx, OpenShell_AddWorkspaceMember_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) RemoveWorkspaceMember(ctx context.Context, in *RemoveWorkspaceMemberRequest, opts ...grpc.CallOption) (*RemoveWorkspaceMemberResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(RemoveWorkspaceMemberResponse)
+ err := c.cc.Invoke(ctx, OpenShell_RemoveWorkspaceMember_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *openShellClient) ListWorkspaceMembers(ctx context.Context, in *ListWorkspaceMembersRequest, opts ...grpc.CallOption) (*ListWorkspaceMembersResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(ListWorkspaceMembersResponse)
+ err := c.cc.Invoke(ctx, OpenShell_ListWorkspaceMembers_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.
+//
+// Conventions:
+// - This file owns the public API resource model exposed to OpenShell clients.
+// - `Sandbox`, `SandboxSpec`, `SandboxStatus`, and `SandboxPhase` are gateway-owned
+// public types. Internal compute drivers must not import or return them directly.
+// - The gateway translates internal compute-driver observations into these public
+// resource messages before persisting or returning them to clients.
+type OpenShellServer interface {
+ // Check the health of the service.
+ Health(context.Context, *HealthRequest) (*HealthResponse, error)
+ // Return the authenticated caller identity established by the gateway.
+ GetCurrentUser(context.Context, *GetCurrentUserRequest) (*GetCurrentUserResponse, error)
+ // Fetch elevated live gateway runtime metadata.
+ GetGatewayInfo(context.Context, *GetGatewayInfoRequest) (*GetGatewayInfoResponse, 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)
+ // List provider records attached to a sandbox.
+ ListSandboxProviders(context.Context, *ListSandboxProvidersRequest) (*ListSandboxProvidersResponse, error)
+ // Attach a provider record to an existing sandbox.
+ AttachSandboxProvider(context.Context, *AttachSandboxProviderRequest) (*AttachSandboxProviderResponse, error)
+ // Detach a provider record from an existing sandbox.
+ DetachSandboxProvider(context.Context, *DetachSandboxProviderRequest) (*DetachSandboxProviderResponse, 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)
+ // Create or update a sandbox HTTP service endpoint for local routing.
+ ExposeService(context.Context, *ExposeServiceRequest) (*ServiceEndpointResponse, error)
+ // Fetch one sandbox HTTP service endpoint.
+ GetService(context.Context, *GetServiceRequest) (*ServiceEndpointResponse, error)
+ // List sandbox HTTP service endpoints.
+ ListServices(context.Context, *ListServicesRequest) (*ListServicesResponse, error)
+ // Delete one sandbox HTTP service endpoint.
+ DeleteService(context.Context, *DeleteServiceRequest) (*DeleteServiceResponse, 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
+ // Forward one CLI-side TCP connection to a loopback TCP target in a sandbox.
+ ForwardTcp(grpc.BidiStreamingServer[TcpForwardFrame, TcpForwardFrame]) error
+ // Execute an interactive command with bidirectional stdin/stdout streaming.
+ // The first client message MUST carry an ExecSandboxInput with the start
+ // variant. Subsequent messages carry stdin bytes or window resize events.
+ ExecSandboxInteractive(grpc.BidiStreamingServer[ExecSandboxInput, 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)
+ // List available provider type profiles.
+ ListProviderProfiles(context.Context, *ListProviderProfilesRequest) (*ListProviderProfilesResponse, error)
+ // Fetch one provider type profile by id.
+ GetProviderProfile(context.Context, *GetProviderProfileRequest) (*ProviderProfileResponse, error)
+ // Import custom provider type profiles.
+ ImportProviderProfiles(context.Context, *ImportProviderProfilesRequest) (*ImportProviderProfilesResponse, error)
+ // Update an existing custom provider type profile.
+ UpdateProviderProfiles(context.Context, *UpdateProviderProfilesRequest) (*UpdateProviderProfilesResponse, error)
+ // Validate provider type profiles without registering them.
+ LintProviderProfiles(context.Context, *LintProviderProfilesRequest) (*LintProviderProfilesResponse, error)
+ // Update an existing provider by name.
+ UpdateProvider(context.Context, *UpdateProviderRequest) (*ProviderResponse, error)
+ // Fetch refresh status for one provider or provider credential.
+ GetProviderRefreshStatus(context.Context, *GetProviderRefreshStatusRequest) (*GetProviderRefreshStatusResponse, error)
+ // Configure gateway-owned refresh material for one provider credential.
+ ConfigureProviderRefresh(context.Context, *ConfigureProviderRefreshRequest) (*ConfigureProviderRefreshResponse, error)
+ // Record a gateway-owned refresh request for one provider credential.
+ RotateProviderCredential(context.Context, *RotateProviderCredentialRequest) (*RotateProviderCredentialResponse, error)
+ // Delete gateway-owned refresh configuration for one provider credential.
+ DeleteProviderRefresh(context.Context, *DeleteProviderRefreshRequest) (*DeleteProviderRefreshResponse, error)
+ // Delete a provider by name.
+ DeleteProvider(context.Context, *DeleteProviderRequest) (*DeleteProviderResponse, error)
+ // Delete a custom provider type profile by id.
+ DeleteProviderProfile(context.Context, *DeleteProviderProfileRequest) (*DeleteProviderProfileResponse, error)
+ // Get sandbox settings by id (called by sandbox entrypoint and poll loop).
+ GetSandboxConfig(context.Context, *sandboxv1.GetSandboxConfigRequest) (*sandboxv1.GetSandboxConfigResponse, error)
+ // Get gateway-global settings (read-only feature flags; any authenticated
+ // user may read these so the CLI and TUI can discover capabilities like
+ // providers_v2_enabled without requiring Platform Admin).
+ //
+ // Scope-only (no role): scopes are granted by the IdP at token issuance,
+ // orthogonal to workspace membership. Deployments that enable scope
+ // enforcement configure the IdP to grant config:read (or openshell:all)
+ // to all sandbox users, so this does not block least-privilege flows.
+ GetGatewayConfig(context.Context, *sandboxv1.GetGatewayConfigRequest) (*sandboxv1.GetGatewayConfigResponse, error)
+ // Update settings or policy at sandbox or global scope.
+ UpdateConfig(context.Context, *UpdateConfigRequest) (*UpdateConfigResponse, 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
+ // Persistent supervisor-to-gateway session (bidirectional streaming).
+ //
+ // The supervisor opens this stream at startup and keeps it alive for the
+ // sandbox lifetime. The gateway uses it to coordinate relay channels for
+ // SSH connect, ExecSandbox, and targetable sandbox services. Raw service
+ // bytes flow over RelayStream calls (separate HTTP/2 streams on the same
+ // connection), not over this stream.
+ ConnectSupervisor(grpc.BidiStreamingServer[SupervisorMessage, GatewayMessage]) error
+ // Raw byte relay between supervisor and gateway.
+ //
+ // The supervisor initiates this call after receiving a RelayOpen message
+ // on its ConnectSupervisor stream. The first RelayFrame carries a
+ // RelayInit with the channel_id to associate the new HTTP/2 stream with
+ // the pending relay slot on the gateway. Subsequent frames carry raw bytes in either
+ // direction between the gateway-side waiter (ForwardTcp / exec handler)
+ // and the supervisor-side target bridge.
+ //
+ // This rides the same TCP+TLS+HTTP/2 connection as ConnectSupervisor —
+ // no new TLS handshake, no reverse HTTP CONNECT.
+ RelayStream(grpc.BidiStreamingServer[RelayFrame, RelayFrame]) 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)
+ // Exchange a sandbox-bootstrap credential (e.g. a Kubernetes projected
+ // ServiceAccount token) for a gateway-minted JWT bound to the calling
+ // sandbox's UUID. Used by the Kubernetes driver path; singleplayer
+ // drivers receive the gateway JWT directly from the create-sandbox flow
+ // and never call this RPC.
+ IssueSandboxToken(context.Context, *IssueSandboxTokenRequest) (*IssueSandboxTokenResponse, error)
+ // Renew the calling sandbox's gateway JWT. Older tokens remain valid
+ // until their own expiry; deployments should keep token TTLs short to
+ // bound replay exposure. The supervisor calls this from a background
+ // task at ~80% of the token's lifetime; the new token is cached in
+ // memory only — the on-disk bootstrap file is intentionally not
+ // rewritten.
+ RefreshSandboxToken(context.Context, *RefreshSandboxTokenRequest) (*RefreshSandboxTokenResponse, error)
+ // Create a workspace.
+ CreateWorkspace(context.Context, *CreateWorkspaceRequest) (*CreateWorkspaceResponse, error)
+ // Fetch a workspace by name.
+ GetWorkspace(context.Context, *GetWorkspaceRequest) (*GetWorkspaceResponse, error)
+ // List workspaces.
+ ListWorkspaces(context.Context, *ListWorkspacesRequest) (*ListWorkspacesResponse, error)
+ // Delete a workspace by name.
+ DeleteWorkspace(context.Context, *DeleteWorkspaceRequest) (*DeleteWorkspaceResponse, error)
+ // Add a member to a workspace.
+ AddWorkspaceMember(context.Context, *AddWorkspaceMemberRequest) (*AddWorkspaceMemberResponse, error)
+ // Remove a member from a workspace.
+ RemoveWorkspaceMember(context.Context, *RemoveWorkspaceMemberRequest) (*RemoveWorkspaceMemberResponse, error)
+ // List members of a workspace.
+ ListWorkspaceMembers(context.Context, *ListWorkspaceMembersRequest) (*ListWorkspaceMembersResponse, 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) GetCurrentUser(context.Context, *GetCurrentUserRequest) (*GetCurrentUserResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method GetCurrentUser not implemented")
+}
+func (UnimplementedOpenShellServer) GetGatewayInfo(context.Context, *GetGatewayInfoRequest) (*GetGatewayInfoResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method GetGatewayInfo 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) ListSandboxProviders(context.Context, *ListSandboxProvidersRequest) (*ListSandboxProvidersResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method ListSandboxProviders not implemented")
+}
+func (UnimplementedOpenShellServer) AttachSandboxProvider(context.Context, *AttachSandboxProviderRequest) (*AttachSandboxProviderResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method AttachSandboxProvider not implemented")
+}
+func (UnimplementedOpenShellServer) DetachSandboxProvider(context.Context, *DetachSandboxProviderRequest) (*DetachSandboxProviderResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method DetachSandboxProvider 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) ExposeService(context.Context, *ExposeServiceRequest) (*ServiceEndpointResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method ExposeService not implemented")
+}
+func (UnimplementedOpenShellServer) GetService(context.Context, *GetServiceRequest) (*ServiceEndpointResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method GetService not implemented")
+}
+func (UnimplementedOpenShellServer) ListServices(context.Context, *ListServicesRequest) (*ListServicesResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method ListServices not implemented")
+}
+func (UnimplementedOpenShellServer) DeleteService(context.Context, *DeleteServiceRequest) (*DeleteServiceResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method DeleteService 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) ForwardTcp(grpc.BidiStreamingServer[TcpForwardFrame, TcpForwardFrame]) error {
+ return status.Error(codes.Unimplemented, "method ForwardTcp not implemented")
+}
+func (UnimplementedOpenShellServer) ExecSandboxInteractive(grpc.BidiStreamingServer[ExecSandboxInput, ExecSandboxEvent]) error {
+ return status.Error(codes.Unimplemented, "method ExecSandboxInteractive 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) ListProviderProfiles(context.Context, *ListProviderProfilesRequest) (*ListProviderProfilesResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method ListProviderProfiles not implemented")
+}
+func (UnimplementedOpenShellServer) GetProviderProfile(context.Context, *GetProviderProfileRequest) (*ProviderProfileResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method GetProviderProfile not implemented")
+}
+func (UnimplementedOpenShellServer) ImportProviderProfiles(context.Context, *ImportProviderProfilesRequest) (*ImportProviderProfilesResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method ImportProviderProfiles not implemented")
+}
+func (UnimplementedOpenShellServer) UpdateProviderProfiles(context.Context, *UpdateProviderProfilesRequest) (*UpdateProviderProfilesResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method UpdateProviderProfiles not implemented")
+}
+func (UnimplementedOpenShellServer) LintProviderProfiles(context.Context, *LintProviderProfilesRequest) (*LintProviderProfilesResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method LintProviderProfiles not implemented")
+}
+func (UnimplementedOpenShellServer) UpdateProvider(context.Context, *UpdateProviderRequest) (*ProviderResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method UpdateProvider not implemented")
+}
+func (UnimplementedOpenShellServer) GetProviderRefreshStatus(context.Context, *GetProviderRefreshStatusRequest) (*GetProviderRefreshStatusResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method GetProviderRefreshStatus not implemented")
+}
+func (UnimplementedOpenShellServer) ConfigureProviderRefresh(context.Context, *ConfigureProviderRefreshRequest) (*ConfigureProviderRefreshResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method ConfigureProviderRefresh not implemented")
+}
+func (UnimplementedOpenShellServer) RotateProviderCredential(context.Context, *RotateProviderCredentialRequest) (*RotateProviderCredentialResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method RotateProviderCredential not implemented")
+}
+func (UnimplementedOpenShellServer) DeleteProviderRefresh(context.Context, *DeleteProviderRefreshRequest) (*DeleteProviderRefreshResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method DeleteProviderRefresh not implemented")
+}
+func (UnimplementedOpenShellServer) DeleteProvider(context.Context, *DeleteProviderRequest) (*DeleteProviderResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method DeleteProvider not implemented")
+}
+func (UnimplementedOpenShellServer) DeleteProviderProfile(context.Context, *DeleteProviderProfileRequest) (*DeleteProviderProfileResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method DeleteProviderProfile not implemented")
+}
+func (UnimplementedOpenShellServer) GetSandboxConfig(context.Context, *sandboxv1.GetSandboxConfigRequest) (*sandboxv1.GetSandboxConfigResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method GetSandboxConfig not implemented")
+}
+func (UnimplementedOpenShellServer) GetGatewayConfig(context.Context, *sandboxv1.GetGatewayConfigRequest) (*sandboxv1.GetGatewayConfigResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method GetGatewayConfig not implemented")
+}
+func (UnimplementedOpenShellServer) UpdateConfig(context.Context, *UpdateConfigRequest) (*UpdateConfigResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method UpdateConfig 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) ConnectSupervisor(grpc.BidiStreamingServer[SupervisorMessage, GatewayMessage]) error {
+ return status.Error(codes.Unimplemented, "method ConnectSupervisor not implemented")
+}
+func (UnimplementedOpenShellServer) RelayStream(grpc.BidiStreamingServer[RelayFrame, RelayFrame]) error {
+ return status.Error(codes.Unimplemented, "method RelayStream 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) IssueSandboxToken(context.Context, *IssueSandboxTokenRequest) (*IssueSandboxTokenResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method IssueSandboxToken not implemented")
+}
+func (UnimplementedOpenShellServer) RefreshSandboxToken(context.Context, *RefreshSandboxTokenRequest) (*RefreshSandboxTokenResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method RefreshSandboxToken not implemented")
+}
+func (UnimplementedOpenShellServer) CreateWorkspace(context.Context, *CreateWorkspaceRequest) (*CreateWorkspaceResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method CreateWorkspace not implemented")
+}
+func (UnimplementedOpenShellServer) GetWorkspace(context.Context, *GetWorkspaceRequest) (*GetWorkspaceResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method GetWorkspace not implemented")
+}
+func (UnimplementedOpenShellServer) ListWorkspaces(context.Context, *ListWorkspacesRequest) (*ListWorkspacesResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method ListWorkspaces not implemented")
+}
+func (UnimplementedOpenShellServer) DeleteWorkspace(context.Context, *DeleteWorkspaceRequest) (*DeleteWorkspaceResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method DeleteWorkspace not implemented")
+}
+func (UnimplementedOpenShellServer) AddWorkspaceMember(context.Context, *AddWorkspaceMemberRequest) (*AddWorkspaceMemberResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method AddWorkspaceMember not implemented")
+}
+func (UnimplementedOpenShellServer) RemoveWorkspaceMember(context.Context, *RemoveWorkspaceMemberRequest) (*RemoveWorkspaceMemberResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method RemoveWorkspaceMember not implemented")
+}
+func (UnimplementedOpenShellServer) ListWorkspaceMembers(context.Context, *ListWorkspaceMembersRequest) (*ListWorkspaceMembersResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method ListWorkspaceMembers 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_GetCurrentUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetCurrentUserRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).GetCurrentUser(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_GetCurrentUser_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).GetCurrentUser(ctx, req.(*GetCurrentUserRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_GetGatewayInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetGatewayInfoRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).GetGatewayInfo(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_GetGatewayInfo_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).GetGatewayInfo(ctx, req.(*GetGatewayInfoRequest))
+ }
+ 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_ListSandboxProviders_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ListSandboxProvidersRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).ListSandboxProviders(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_ListSandboxProviders_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).ListSandboxProviders(ctx, req.(*ListSandboxProvidersRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_AttachSandboxProvider_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(AttachSandboxProviderRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).AttachSandboxProvider(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_AttachSandboxProvider_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).AttachSandboxProvider(ctx, req.(*AttachSandboxProviderRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_DetachSandboxProvider_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(DetachSandboxProviderRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).DetachSandboxProvider(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_DetachSandboxProvider_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).DetachSandboxProvider(ctx, req.(*DetachSandboxProviderRequest))
+ }
+ 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_ExposeService_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ExposeServiceRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).ExposeService(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_ExposeService_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).ExposeService(ctx, req.(*ExposeServiceRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_GetService_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetServiceRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).GetService(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_GetService_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).GetService(ctx, req.(*GetServiceRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_ListServices_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ListServicesRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).ListServices(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_ListServices_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).ListServices(ctx, req.(*ListServicesRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_DeleteService_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(DeleteServiceRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).DeleteService(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_DeleteService_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).DeleteService(ctx, req.(*DeleteServiceRequest))
+ }
+ 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_ForwardTcp_Handler(srv interface{}, stream grpc.ServerStream) error {
+ return srv.(OpenShellServer).ForwardTcp(&grpc.GenericServerStream[TcpForwardFrame, TcpForwardFrame]{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_ForwardTcpServer = grpc.BidiStreamingServer[TcpForwardFrame, TcpForwardFrame]
+
+func _OpenShell_ExecSandboxInteractive_Handler(srv interface{}, stream grpc.ServerStream) error {
+ return srv.(OpenShellServer).ExecSandboxInteractive(&grpc.GenericServerStream[ExecSandboxInput, 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_ExecSandboxInteractiveServer = grpc.BidiStreamingServer[ExecSandboxInput, 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_ListProviderProfiles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ListProviderProfilesRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).ListProviderProfiles(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_ListProviderProfiles_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).ListProviderProfiles(ctx, req.(*ListProviderProfilesRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_GetProviderProfile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetProviderProfileRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).GetProviderProfile(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_GetProviderProfile_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).GetProviderProfile(ctx, req.(*GetProviderProfileRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_ImportProviderProfiles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ImportProviderProfilesRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).ImportProviderProfiles(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_ImportProviderProfiles_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).ImportProviderProfiles(ctx, req.(*ImportProviderProfilesRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_UpdateProviderProfiles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UpdateProviderProfilesRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).UpdateProviderProfiles(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_UpdateProviderProfiles_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).UpdateProviderProfiles(ctx, req.(*UpdateProviderProfilesRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_LintProviderProfiles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(LintProviderProfilesRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).LintProviderProfiles(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_LintProviderProfiles_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).LintProviderProfiles(ctx, req.(*LintProviderProfilesRequest))
+ }
+ 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_GetProviderRefreshStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetProviderRefreshStatusRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).GetProviderRefreshStatus(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_GetProviderRefreshStatus_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).GetProviderRefreshStatus(ctx, req.(*GetProviderRefreshStatusRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_ConfigureProviderRefresh_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ConfigureProviderRefreshRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).ConfigureProviderRefresh(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_ConfigureProviderRefresh_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).ConfigureProviderRefresh(ctx, req.(*ConfigureProviderRefreshRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_RotateProviderCredential_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(RotateProviderCredentialRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).RotateProviderCredential(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_RotateProviderCredential_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).RotateProviderCredential(ctx, req.(*RotateProviderCredentialRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_DeleteProviderRefresh_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(DeleteProviderRefreshRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).DeleteProviderRefresh(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_DeleteProviderRefresh_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).DeleteProviderRefresh(ctx, req.(*DeleteProviderRefreshRequest))
+ }
+ 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_DeleteProviderProfile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(DeleteProviderProfileRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).DeleteProviderProfile(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_DeleteProviderProfile_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).DeleteProviderProfile(ctx, req.(*DeleteProviderProfileRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_GetSandboxConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(sandboxv1.GetSandboxConfigRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).GetSandboxConfig(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_GetSandboxConfig_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).GetSandboxConfig(ctx, req.(*sandboxv1.GetSandboxConfigRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_GetGatewayConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(sandboxv1.GetGatewayConfigRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).GetGatewayConfig(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_GetGatewayConfig_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).GetGatewayConfig(ctx, req.(*sandboxv1.GetGatewayConfigRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_UpdateConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UpdateConfigRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).UpdateConfig(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_UpdateConfig_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).UpdateConfig(ctx, req.(*UpdateConfigRequest))
+ }
+ 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_ConnectSupervisor_Handler(srv interface{}, stream grpc.ServerStream) error {
+ return srv.(OpenShellServer).ConnectSupervisor(&grpc.GenericServerStream[SupervisorMessage, GatewayMessage]{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_ConnectSupervisorServer = grpc.BidiStreamingServer[SupervisorMessage, GatewayMessage]
+
+func _OpenShell_RelayStream_Handler(srv interface{}, stream grpc.ServerStream) error {
+ return srv.(OpenShellServer).RelayStream(&grpc.GenericServerStream[RelayFrame, RelayFrame]{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_RelayStreamServer = grpc.BidiStreamingServer[RelayFrame, RelayFrame]
+
+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)
+}
+
+func _OpenShell_IssueSandboxToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(IssueSandboxTokenRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).IssueSandboxToken(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_IssueSandboxToken_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).IssueSandboxToken(ctx, req.(*IssueSandboxTokenRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_RefreshSandboxToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(RefreshSandboxTokenRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).RefreshSandboxToken(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_RefreshSandboxToken_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).RefreshSandboxToken(ctx, req.(*RefreshSandboxTokenRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_CreateWorkspace_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(CreateWorkspaceRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).CreateWorkspace(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_CreateWorkspace_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).CreateWorkspace(ctx, req.(*CreateWorkspaceRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_GetWorkspace_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetWorkspaceRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).GetWorkspace(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_GetWorkspace_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).GetWorkspace(ctx, req.(*GetWorkspaceRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_ListWorkspaces_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ListWorkspacesRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).ListWorkspaces(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_ListWorkspaces_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).ListWorkspaces(ctx, req.(*ListWorkspacesRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_DeleteWorkspace_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(DeleteWorkspaceRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).DeleteWorkspace(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_DeleteWorkspace_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).DeleteWorkspace(ctx, req.(*DeleteWorkspaceRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_AddWorkspaceMember_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(AddWorkspaceMemberRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).AddWorkspaceMember(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_AddWorkspaceMember_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).AddWorkspaceMember(ctx, req.(*AddWorkspaceMemberRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_RemoveWorkspaceMember_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(RemoveWorkspaceMemberRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).RemoveWorkspaceMember(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_RemoveWorkspaceMember_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).RemoveWorkspaceMember(ctx, req.(*RemoveWorkspaceMemberRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OpenShell_ListWorkspaceMembers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ListWorkspaceMembersRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OpenShellServer).ListWorkspaceMembers(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OpenShell_ListWorkspaceMembers_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OpenShellServer).ListWorkspaceMembers(ctx, req.(*ListWorkspaceMembersRequest))
+ }
+ 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: "GetCurrentUser",
+ Handler: _OpenShell_GetCurrentUser_Handler,
+ },
+ {
+ MethodName: "GetGatewayInfo",
+ Handler: _OpenShell_GetGatewayInfo_Handler,
+ },
+ {
+ MethodName: "CreateSandbox",
+ Handler: _OpenShell_CreateSandbox_Handler,
+ },
+ {
+ MethodName: "GetSandbox",
+ Handler: _OpenShell_GetSandbox_Handler,
+ },
+ {
+ MethodName: "ListSandboxes",
+ Handler: _OpenShell_ListSandboxes_Handler,
+ },
+ {
+ MethodName: "ListSandboxProviders",
+ Handler: _OpenShell_ListSandboxProviders_Handler,
+ },
+ {
+ MethodName: "AttachSandboxProvider",
+ Handler: _OpenShell_AttachSandboxProvider_Handler,
+ },
+ {
+ MethodName: "DetachSandboxProvider",
+ Handler: _OpenShell_DetachSandboxProvider_Handler,
+ },
+ {
+ MethodName: "DeleteSandbox",
+ Handler: _OpenShell_DeleteSandbox_Handler,
+ },
+ {
+ MethodName: "CreateSshSession",
+ Handler: _OpenShell_CreateSshSession_Handler,
+ },
+ {
+ MethodName: "ExposeService",
+ Handler: _OpenShell_ExposeService_Handler,
+ },
+ {
+ MethodName: "GetService",
+ Handler: _OpenShell_GetService_Handler,
+ },
+ {
+ MethodName: "ListServices",
+ Handler: _OpenShell_ListServices_Handler,
+ },
+ {
+ MethodName: "DeleteService",
+ Handler: _OpenShell_DeleteService_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: "ListProviderProfiles",
+ Handler: _OpenShell_ListProviderProfiles_Handler,
+ },
+ {
+ MethodName: "GetProviderProfile",
+ Handler: _OpenShell_GetProviderProfile_Handler,
+ },
+ {
+ MethodName: "ImportProviderProfiles",
+ Handler: _OpenShell_ImportProviderProfiles_Handler,
+ },
+ {
+ MethodName: "UpdateProviderProfiles",
+ Handler: _OpenShell_UpdateProviderProfiles_Handler,
+ },
+ {
+ MethodName: "LintProviderProfiles",
+ Handler: _OpenShell_LintProviderProfiles_Handler,
+ },
+ {
+ MethodName: "UpdateProvider",
+ Handler: _OpenShell_UpdateProvider_Handler,
+ },
+ {
+ MethodName: "GetProviderRefreshStatus",
+ Handler: _OpenShell_GetProviderRefreshStatus_Handler,
+ },
+ {
+ MethodName: "ConfigureProviderRefresh",
+ Handler: _OpenShell_ConfigureProviderRefresh_Handler,
+ },
+ {
+ MethodName: "RotateProviderCredential",
+ Handler: _OpenShell_RotateProviderCredential_Handler,
+ },
+ {
+ MethodName: "DeleteProviderRefresh",
+ Handler: _OpenShell_DeleteProviderRefresh_Handler,
+ },
+ {
+ MethodName: "DeleteProvider",
+ Handler: _OpenShell_DeleteProvider_Handler,
+ },
+ {
+ MethodName: "DeleteProviderProfile",
+ Handler: _OpenShell_DeleteProviderProfile_Handler,
+ },
+ {
+ MethodName: "GetSandboxConfig",
+ Handler: _OpenShell_GetSandboxConfig_Handler,
+ },
+ {
+ MethodName: "GetGatewayConfig",
+ Handler: _OpenShell_GetGatewayConfig_Handler,
+ },
+ {
+ MethodName: "UpdateConfig",
+ Handler: _OpenShell_UpdateConfig_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,
+ },
+ {
+ MethodName: "IssueSandboxToken",
+ Handler: _OpenShell_IssueSandboxToken_Handler,
+ },
+ {
+ MethodName: "RefreshSandboxToken",
+ Handler: _OpenShell_RefreshSandboxToken_Handler,
+ },
+ {
+ MethodName: "CreateWorkspace",
+ Handler: _OpenShell_CreateWorkspace_Handler,
+ },
+ {
+ MethodName: "GetWorkspace",
+ Handler: _OpenShell_GetWorkspace_Handler,
+ },
+ {
+ MethodName: "ListWorkspaces",
+ Handler: _OpenShell_ListWorkspaces_Handler,
+ },
+ {
+ MethodName: "DeleteWorkspace",
+ Handler: _OpenShell_DeleteWorkspace_Handler,
+ },
+ {
+ MethodName: "AddWorkspaceMember",
+ Handler: _OpenShell_AddWorkspaceMember_Handler,
+ },
+ {
+ MethodName: "RemoveWorkspaceMember",
+ Handler: _OpenShell_RemoveWorkspaceMember_Handler,
+ },
+ {
+ MethodName: "ListWorkspaceMembers",
+ Handler: _OpenShell_ListWorkspaceMembers_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{
+ {
+ StreamName: "ExecSandbox",
+ Handler: _OpenShell_ExecSandbox_Handler,
+ ServerStreams: true,
+ },
+ {
+ StreamName: "ForwardTcp",
+ Handler: _OpenShell_ForwardTcp_Handler,
+ ServerStreams: true,
+ ClientStreams: true,
+ },
+ {
+ StreamName: "ExecSandboxInteractive",
+ Handler: _OpenShell_ExecSandboxInteractive_Handler,
+ ServerStreams: true,
+ ClientStreams: true,
+ },
+ {
+ StreamName: "PushSandboxLogs",
+ Handler: _OpenShell_PushSandboxLogs_Handler,
+ ClientStreams: true,
+ },
+ {
+ StreamName: "ConnectSupervisor",
+ Handler: _OpenShell_ConnectSupervisor_Handler,
+ ServerStreams: true,
+ ClientStreams: true,
+ },
+ {
+ StreamName: "RelayStream",
+ Handler: _OpenShell_RelayStream_Handler,
+ ServerStreams: true,
+ ClientStreams: true,
+ },
+ {
+ StreamName: "WatchSandbox",
+ Handler: _OpenShell_WatchSandbox_Handler,
+ ServerStreams: true,
+ },
+ },
+ Metadata: "openshell.proto",
+}
diff --git a/sdk/go/proto/optionsv1/options.pb.go b/sdk/go/proto/optionsv1/options.pb.go
new file mode 100644
index 000000000..3219a94b1
--- /dev/null
+++ b/sdk/go/proto/optionsv1/options.pb.go
@@ -0,0 +1,204 @@
+// 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 (unknown)
+// source: options.proto
+
+package optionsv1
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ descriptorpb "google.golang.org/protobuf/types/descriptorpb"
+ 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)
+)
+
+// Per-method authorization rule. Consumed at runtime by the gateway's
+// descriptor-pool-based auth table to enforce auth mode, role, and scope.
+type AuthorizationRule struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Authentication mode: "bearer", "sandbox", "dual", or "unauthenticated".
+ AuthMode string `protobuf:"bytes,1,opt,name=auth_mode,json=authMode,proto3" json:"auth_mode,omitempty"`
+ // Minimum workspace-level role required (checked by handler via
+ // authorize_workspace): "user" or "admin". Mutually exclusive with
+ // global_role.
+ WorkspaceRole string `protobuf:"bytes,2,opt,name=workspace_role,json=workspaceRole,proto3" json:"workspace_role,omitempty"`
+ // Global role required (checked by middleware via OIDC claims):
+ // "platform_admin". Mutually exclusive with workspace_role.
+ GlobalRole string `protobuf:"bytes,3,opt,name=global_role,json=globalRole,proto3" json:"global_role,omitempty"`
+ // Required OIDC scope on the bearer path (e.g. "sandbox:read").
+ Scope string `protobuf:"bytes,4,opt,name=scope,proto3" json:"scope,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *AuthorizationRule) Reset() {
+ *x = AuthorizationRule{}
+ mi := &file_options_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *AuthorizationRule) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AuthorizationRule) ProtoMessage() {}
+
+func (x *AuthorizationRule) ProtoReflect() protoreflect.Message {
+ mi := &file_options_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 AuthorizationRule.ProtoReflect.Descriptor instead.
+func (*AuthorizationRule) Descriptor() ([]byte, []int) {
+ return file_options_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *AuthorizationRule) GetAuthMode() string {
+ if x != nil {
+ return x.AuthMode
+ }
+ return ""
+}
+
+func (x *AuthorizationRule) GetWorkspaceRole() string {
+ if x != nil {
+ return x.WorkspaceRole
+ }
+ return ""
+}
+
+func (x *AuthorizationRule) GetGlobalRole() string {
+ if x != nil {
+ return x.GlobalRole
+ }
+ return ""
+}
+
+func (x *AuthorizationRule) GetScope() string {
+ if x != nil {
+ return x.Scope
+ }
+ return ""
+}
+
+var file_options_proto_extTypes = []protoimpl.ExtensionInfo{
+ {
+ ExtendedType: (*descriptorpb.MethodOptions)(nil),
+ ExtensionType: (*AuthorizationRule)(nil),
+ Field: 50000,
+ Name: "openshell.options.v1.authorization",
+ Tag: "bytes,50000,opt,name=authorization",
+ Filename: "options.proto",
+ },
+ {
+ ExtendedType: (*descriptorpb.FieldOptions)(nil),
+ ExtensionType: (*bool)(nil),
+ Field: 50001,
+ Name: "openshell.options.v1.secret",
+ Tag: "varint,50001,opt,name=secret",
+ Filename: "options.proto",
+ },
+}
+
+// Extension fields to descriptorpb.MethodOptions.
+var (
+ // Authorization metadata for a gRPC method.
+ //
+ // optional openshell.options.v1.AuthorizationRule authorization = 50000;
+ E_Authorization = &file_options_proto_extTypes[0]
+)
+
+// Extension fields to descriptorpb.FieldOptions.
+var (
+ // optional bool secret = 50001;
+ E_Secret = &file_options_proto_extTypes[1]
+)
+
+var File_options_proto protoreflect.FileDescriptor
+
+const file_options_proto_rawDesc = "" +
+ "\n" +
+ "\roptions.proto\x12\x14openshell.options.v1\x1a google/protobuf/descriptor.proto\"\x8e\x01\n" +
+ "\x11AuthorizationRule\x12\x1b\n" +
+ "\tauth_mode\x18\x01 \x01(\tR\bauthMode\x12%\n" +
+ "\x0eworkspace_role\x18\x02 \x01(\tR\rworkspaceRole\x12\x1f\n" +
+ "\vglobal_role\x18\x03 \x01(\tR\n" +
+ "globalRole\x12\x14\n" +
+ "\x05scope\x18\x04 \x01(\tR\x05scope:o\n" +
+ "\rauthorization\x12\x1e.google.protobuf.MethodOptions\x18І\x03 \x01(\v2'.openshell.options.v1.AuthorizationRuleR\rauthorization:7\n" +
+ "\x06secret\x12\x1d.google.protobuf.FieldOptions\x18ц\x03 \x01(\bR\x06secretb\x06proto3"
+
+var (
+ file_options_proto_rawDescOnce sync.Once
+ file_options_proto_rawDescData []byte
+)
+
+func file_options_proto_rawDescGZIP() []byte {
+ file_options_proto_rawDescOnce.Do(func() {
+ file_options_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_options_proto_rawDesc), len(file_options_proto_rawDesc)))
+ })
+ return file_options_proto_rawDescData
+}
+
+var file_options_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_options_proto_goTypes = []any{
+ (*AuthorizationRule)(nil), // 0: openshell.options.v1.AuthorizationRule
+ (*descriptorpb.MethodOptions)(nil), // 1: google.protobuf.MethodOptions
+ (*descriptorpb.FieldOptions)(nil), // 2: google.protobuf.FieldOptions
+}
+var file_options_proto_depIdxs = []int32{
+ 1, // 0: openshell.options.v1.authorization:extendee -> google.protobuf.MethodOptions
+ 2, // 1: openshell.options.v1.secret:extendee -> google.protobuf.FieldOptions
+ 0, // 2: openshell.options.v1.authorization:type_name -> openshell.options.v1.AuthorizationRule
+ 3, // [3:3] is the sub-list for method output_type
+ 3, // [3:3] is the sub-list for method input_type
+ 2, // [2:3] is the sub-list for extension type_name
+ 0, // [0:2] is the sub-list for extension extendee
+ 0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_options_proto_init() }
+func file_options_proto_init() {
+ if File_options_proto != nil {
+ return
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_options_proto_rawDesc), len(file_options_proto_rawDesc)),
+ NumEnums: 0,
+ NumMessages: 1,
+ NumExtensions: 2,
+ NumServices: 0,
+ },
+ GoTypes: file_options_proto_goTypes,
+ DependencyIndexes: file_options_proto_depIdxs,
+ MessageInfos: file_options_proto_msgTypes,
+ ExtensionInfos: file_options_proto_extTypes,
+ }.Build()
+ File_options_proto = out.File
+ file_options_proto_goTypes = nil
+ file_options_proto_depIdxs = nil
+}
diff --git a/sdk/go/proto/sandboxv1/sandbox.pb.go b/sdk/go/proto/sandboxv1/sandbox.pb.go
new file mode 100644
index 000000000..6ed4cf2ec
--- /dev/null
+++ b/sdk/go/proto/sandboxv1/sandbox.pb.go
@@ -0,0 +1,2234 @@
+// 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 (unknown)
+// source: sandbox.proto
+
+package sandboxv1
+
+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)
+)
+
+// Scope that currently controls a setting.
+type SettingScope int32
+
+const (
+ SettingScope_SETTING_SCOPE_UNSPECIFIED SettingScope = 0
+ SettingScope_SETTING_SCOPE_SANDBOX SettingScope = 1
+ SettingScope_SETTING_SCOPE_GLOBAL SettingScope = 2
+)
+
+// Enum value maps for SettingScope.
+var (
+ SettingScope_name = map[int32]string{
+ 0: "SETTING_SCOPE_UNSPECIFIED",
+ 1: "SETTING_SCOPE_SANDBOX",
+ 2: "SETTING_SCOPE_GLOBAL",
+ }
+ SettingScope_value = map[string]int32{
+ "SETTING_SCOPE_UNSPECIFIED": 0,
+ "SETTING_SCOPE_SANDBOX": 1,
+ "SETTING_SCOPE_GLOBAL": 2,
+ }
+)
+
+func (x SettingScope) Enum() *SettingScope {
+ p := new(SettingScope)
+ *p = x
+ return p
+}
+
+func (x SettingScope) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (SettingScope) Descriptor() protoreflect.EnumDescriptor {
+ return file_sandbox_proto_enumTypes[0].Descriptor()
+}
+
+func (SettingScope) Type() protoreflect.EnumType {
+ return &file_sandbox_proto_enumTypes[0]
+}
+
+func (x SettingScope) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use SettingScope.Descriptor instead.
+func (SettingScope) EnumDescriptor() ([]byte, []int) {
+ return file_sandbox_proto_rawDescGZIP(), []int{0}
+}
+
+// Source used for the policy payload in GetSandboxConfigResponse.
+type PolicySource int32
+
+const (
+ PolicySource_POLICY_SOURCE_UNSPECIFIED PolicySource = 0
+ PolicySource_POLICY_SOURCE_SANDBOX PolicySource = 1
+ PolicySource_POLICY_SOURCE_GLOBAL PolicySource = 2
+)
+
+// Enum value maps for PolicySource.
+var (
+ PolicySource_name = map[int32]string{
+ 0: "POLICY_SOURCE_UNSPECIFIED",
+ 1: "POLICY_SOURCE_SANDBOX",
+ 2: "POLICY_SOURCE_GLOBAL",
+ }
+ PolicySource_value = map[string]int32{
+ "POLICY_SOURCE_UNSPECIFIED": 0,
+ "POLICY_SOURCE_SANDBOX": 1,
+ "POLICY_SOURCE_GLOBAL": 2,
+ }
+)
+
+func (x PolicySource) Enum() *PolicySource {
+ p := new(PolicySource)
+ *p = x
+ return p
+}
+
+func (x PolicySource) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (PolicySource) Descriptor() protoreflect.EnumDescriptor {
+ return file_sandbox_proto_enumTypes[1].Descriptor()
+}
+
+func (PolicySource) Type() protoreflect.EnumType {
+ return &file_sandbox_proto_enumTypes[1]
+}
+
+func (x PolicySource) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use PolicySource.Descriptor instead.
+func (PolicySource) EnumDescriptor() ([]byte, []int) {
+ return file_sandbox_proto_rawDescGZIP(), []int{1}
+}
+
+// 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"`
+ // Reusable supervisor middleware configs for network egress, keyed by their
+ // policy-local names. At most 10 configs are accepted, and at most 10 stages
+ // can be selected per request.
+ NetworkMiddlewares map[string]*NetworkMiddlewareConfig `protobuf:"bytes,6,rep,name=network_middlewares,json=networkMiddlewares,proto3" json:"network_middlewares,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
+}
+
+func (x *SandboxPolicy) GetNetworkMiddlewares() map[string]*NetworkMiddlewareConfig {
+ if x != nil {
+ return x.NetworkMiddlewares
+ }
+ 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 reusable middleware config selected for admitted egress by host.
+type NetworkMiddlewareConfig struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Human-readable name for this middleware config.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // Built-in middleware name or operator-owned registration name.
+ Middleware string `protobuf:"bytes,2,opt,name=middleware,proto3" json:"middleware,omitempty"`
+ // Service-specific configuration.
+ Config *structpb.Struct `protobuf:"bytes,3,opt,name=config,proto3" json:"config,omitempty"`
+ // Failure behavior: "fail_closed" (default) or "fail_open".
+ OnError string `protobuf:"bytes,4,opt,name=on_error,json=onError,proto3" json:"on_error,omitempty"`
+ // Host selector controlling which admitted destinations use this config.
+ Endpoints *MiddlewareEndpointSelector `protobuf:"bytes,5,opt,name=endpoints,proto3" json:"endpoints,omitempty"`
+ // Execution order. Values must be unique within a policy; lower values run first.
+ Order int32 `protobuf:"varint,6,opt,name=order,proto3" json:"order,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *NetworkMiddlewareConfig) Reset() {
+ *x = NetworkMiddlewareConfig{}
+ mi := &file_sandbox_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *NetworkMiddlewareConfig) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*NetworkMiddlewareConfig) ProtoMessage() {}
+
+func (x *NetworkMiddlewareConfig) 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 NetworkMiddlewareConfig.ProtoReflect.Descriptor instead.
+func (*NetworkMiddlewareConfig) Descriptor() ([]byte, []int) {
+ return file_sandbox_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *NetworkMiddlewareConfig) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *NetworkMiddlewareConfig) GetMiddleware() string {
+ if x != nil {
+ return x.Middleware
+ }
+ return ""
+}
+
+func (x *NetworkMiddlewareConfig) GetConfig() *structpb.Struct {
+ if x != nil {
+ return x.Config
+ }
+ return nil
+}
+
+func (x *NetworkMiddlewareConfig) GetOnError() string {
+ if x != nil {
+ return x.OnError
+ }
+ return ""
+}
+
+func (x *NetworkMiddlewareConfig) GetEndpoints() *MiddlewareEndpointSelector {
+ if x != nil {
+ return x.Endpoints
+ }
+ return nil
+}
+
+func (x *NetworkMiddlewareConfig) GetOrder() int32 {
+ if x != nil {
+ return x.Order
+ }
+ return 0
+}
+
+// Host selector controlling which admitted destinations use a middleware config.
+type MiddlewareEndpointSelector struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Exact host or DNS glob patterns included in the selection. Include and
+ // exclude accept at most 32 combined patterns.
+ Include []string `protobuf:"bytes,1,rep,name=include,proto3" json:"include,omitempty"`
+ // Exact host or DNS glob patterns removed from the selection.
+ // Exclusions take precedence over inclusions.
+ Exclude []string `protobuf:"bytes,2,rep,name=exclude,proto3" json:"exclude,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *MiddlewareEndpointSelector) Reset() {
+ *x = MiddlewareEndpointSelector{}
+ mi := &file_sandbox_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *MiddlewareEndpointSelector) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MiddlewareEndpointSelector) ProtoMessage() {}
+
+func (x *MiddlewareEndpointSelector) 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 MiddlewareEndpointSelector.ProtoReflect.Descriptor instead.
+func (*MiddlewareEndpointSelector) Descriptor() ([]byte, []int) {
+ return file_sandbox_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *MiddlewareEndpointSelector) GetInclude() []string {
+ if x != nil {
+ return x.Include
+ }
+ return nil
+}
+
+func (x *MiddlewareEndpointSelector) GetExclude() []string {
+ if x != nil {
+ return x.Exclude
+ }
+ 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", "websocket", "graphql", "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"`
+ // Explicit L7 deny rules. When present, requests matching any deny rule
+ // are blocked even if they match an allow rule or access preset.
+ // Deny rules take precedence over allow rules.
+ DenyRules []*L7DenyRule `protobuf:"bytes,10,rep,name=deny_rules,json=denyRules,proto3" json:"deny_rules,omitempty"`
+ // When true, percent-encoded '/' (%2F) is preserved in path segments
+ // rather than rejected by the L7 path canonicalizer. Required for
+ // upstreams like GitLab that embed %2F in namespaced resource paths.
+ // Defaults to false (strict).
+ AllowEncodedSlash bool `protobuf:"varint,11,opt,name=allow_encoded_slash,json=allowEncodedSlash,proto3" json:"allow_encoded_slash,omitempty"`
+ // GraphQL persisted-query behavior for hash-only/saved-query requests:
+ // "deny" (default) or "allow_registered".
+ PersistedQueries string `protobuf:"bytes,12,opt,name=persisted_queries,json=persistedQueries,proto3" json:"persisted_queries,omitempty"`
+ // Trusted GraphQL persisted-query registry keyed by hash or service-specific ID.
+ // Only used when persisted_queries is "allow_registered".
+ GraphqlPersistedQueries map[string]*GraphqlOperation `protobuf:"bytes,13,rep,name=graphql_persisted_queries,json=graphqlPersistedQueries,proto3" json:"graphql_persisted_queries,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ // Maximum GraphQL request body bytes to buffer for inspection.
+ // Defaults to 65536 when unset.
+ GraphqlMaxBodyBytes uint32 `protobuf:"varint,14,opt,name=graphql_max_body_bytes,json=graphqlMaxBodyBytes,proto3" json:"graphql_max_body_bytes,omitempty"`
+ // Optional HTTP path glob that scopes this L7 endpoint on shared host:port APIs.
+ // Example: use path "/graphql" for protocol "graphql" and "/repos/**" for
+ // protocol "rest" when both surfaces live under api.example.com:443.
+ // Empty means all paths.
+ Path string `protobuf:"bytes,15,opt,name=path,proto3" json:"path,omitempty"`
+ // When true on a "rest" endpoint, OpenShell rewrites credential placeholders
+ // inside client-to-server WebSocket text messages after an allowed HTTP 101
+ // upgrade. Defaults to false.
+ WebsocketCredentialRewrite bool `protobuf:"varint,16,opt,name=websocket_credential_rewrite,json=websocketCredentialRewrite,proto3" json:"websocket_credential_rewrite,omitempty"`
+ // When true on a "rest" endpoint, OpenShell rewrites credential placeholders
+ // inside supported textual HTTP request bodies before forwarding upstream.
+ // Defaults to false.
+ RequestBodyCredentialRewrite bool `protobuf:"varint,17,opt,name=request_body_credential_rewrite,json=requestBodyCredentialRewrite,proto3" json:"request_body_credential_rewrite,omitempty"`
+ // Internal provenance marker for policy-advisor generated endpoints.
+ // Advisor-proposed endpoints must not satisfy exact-host SSRF trust unless
+ // they are converted through an explicit user-authored policy path.
+ AdvisorProposed bool `protobuf:"varint,18,opt,name=advisor_proposed,json=advisorProposed,proto3" json:"advisor_proposed,omitempty"`
+ // Proxy-side credential signing mode: "sigv4" for AWS SigV4 re-signing.
+ // When set, the proxy strips the client's Authorization header and computes
+ // a fresh SigV4 signature using real credentials from the provider.
+ CredentialSigning string `protobuf:"bytes,19,opt,name=credential_signing,json=credentialSigning,proto3" json:"credential_signing,omitempty"`
+ // AWS signing service name override. Required when credential_signing is
+ // "sigv4" — e.g. "bedrock" for bedrock-runtime endpoints.
+ SigningService string `protobuf:"bytes,20,opt,name=signing_service,json=signingService,proto3" json:"signing_service,omitempty"`
+ // AWS region override for SigV4 signing. When set, takes precedence over
+ // hostname-based region extraction. Required for non-standard endpoints.
+ SigningRegion string `protobuf:"bytes,21,opt,name=signing_region,json=signingRegion,proto3" json:"signing_region,omitempty"`
+ // Maximum JSON-RPC-over-HTTP request body bytes to buffer for inspection.
+ // Defaults to 65536 when unset.
+ JsonRpcMaxBodyBytes uint32 `protobuf:"varint,22,opt,name=json_rpc_max_body_bytes,json=jsonRpcMaxBodyBytes,proto3" json:"json_rpc_max_body_bytes,omitempty"`
+ // MCP-only policy and inspection options. Only used when protocol is "mcp".
+ Mcp *McpOptions `protobuf:"bytes,23,opt,name=mcp,proto3" json:"mcp,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *NetworkEndpoint) Reset() {
+ *x = NetworkEndpoint{}
+ mi := &file_sandbox_proto_msgTypes[7]
+ 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[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 NetworkEndpoint.ProtoReflect.Descriptor instead.
+func (*NetworkEndpoint) Descriptor() ([]byte, []int) {
+ return file_sandbox_proto_rawDescGZIP(), []int{7}
+}
+
+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
+}
+
+func (x *NetworkEndpoint) GetDenyRules() []*L7DenyRule {
+ if x != nil {
+ return x.DenyRules
+ }
+ return nil
+}
+
+func (x *NetworkEndpoint) GetAllowEncodedSlash() bool {
+ if x != nil {
+ return x.AllowEncodedSlash
+ }
+ return false
+}
+
+func (x *NetworkEndpoint) GetPersistedQueries() string {
+ if x != nil {
+ return x.PersistedQueries
+ }
+ return ""
+}
+
+func (x *NetworkEndpoint) GetGraphqlPersistedQueries() map[string]*GraphqlOperation {
+ if x != nil {
+ return x.GraphqlPersistedQueries
+ }
+ return nil
+}
+
+func (x *NetworkEndpoint) GetGraphqlMaxBodyBytes() uint32 {
+ if x != nil {
+ return x.GraphqlMaxBodyBytes
+ }
+ return 0
+}
+
+func (x *NetworkEndpoint) GetPath() string {
+ if x != nil {
+ return x.Path
+ }
+ return ""
+}
+
+func (x *NetworkEndpoint) GetWebsocketCredentialRewrite() bool {
+ if x != nil {
+ return x.WebsocketCredentialRewrite
+ }
+ return false
+}
+
+func (x *NetworkEndpoint) GetRequestBodyCredentialRewrite() bool {
+ if x != nil {
+ return x.RequestBodyCredentialRewrite
+ }
+ return false
+}
+
+func (x *NetworkEndpoint) GetAdvisorProposed() bool {
+ if x != nil {
+ return x.AdvisorProposed
+ }
+ return false
+}
+
+func (x *NetworkEndpoint) GetCredentialSigning() string {
+ if x != nil {
+ return x.CredentialSigning
+ }
+ return ""
+}
+
+func (x *NetworkEndpoint) GetSigningService() string {
+ if x != nil {
+ return x.SigningService
+ }
+ return ""
+}
+
+func (x *NetworkEndpoint) GetSigningRegion() string {
+ if x != nil {
+ return x.SigningRegion
+ }
+ return ""
+}
+
+func (x *NetworkEndpoint) GetJsonRpcMaxBodyBytes() uint32 {
+ if x != nil {
+ return x.JsonRpcMaxBodyBytes
+ }
+ return 0
+}
+
+func (x *NetworkEndpoint) GetMcp() *McpOptions {
+ if x != nil {
+ return x.Mcp
+ }
+ return nil
+}
+
+// MCP options are grouped so MCP-specific policy can grow without adding more
+// top-level NetworkEndpoint fields. Current enforcement targets the active
+// 2025-11-25 Streamable HTTP/tools behavior, while preserving space for
+// version-profile policy if OpenShell adopts 2026-07-28 draft behavior later.
+//
+// Planned policy extensions should use OpenShell-owned static definitions for
+// MCP method/version profiles rather than treating dependency enums as the
+// policy contract. Candidate profile checks include request metadata/header
+// validation, response/SSE introspection, trusted annotation handling,
+// resultType/cache metadata validation, x-mcp-header tool-definition checks,
+// and subscriptions/listen handling.
+//
+// Sources:
+// - https://modelcontextprotocol.io/specification/2025-11-25/server/tools
+// - https://modelcontextprotocol.io/specification/draft/changelog
+// - https://modelcontextprotocol.io/specification/draft/basic/transports/streamable-http
+// - https://modelcontextprotocol.io/specification/draft/server/tools
+type McpOptions struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Hardening boundary for tools/call params.name. When unset or true, the
+ // supervisor enforces the MCP recommended tool-name syntax
+ // ^[A-Za-z0-9_.-]{1,128}$ before policy evaluation. Set false only for
+ // compatibility with servers that intentionally use non-recommended names.
+ //
+ // Source:
+ // - https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool-names
+ StrictToolNames *bool `protobuf:"varint,1,opt,name=strict_tool_names,json=strictToolNames,proto3,oneof" json:"strict_tool_names,omitempty"`
+ // Method-layer default for MCP endpoints. When true, OpenShell allows parsed
+ // MCP-family methods at the method layer unless a tool-name policy narrows
+ // tools/call. When unset or false, explicit method rules are required.
+ AllowAllKnownMcpMethods *bool `protobuf:"varint,2,opt,name=allow_all_known_mcp_methods,json=allowAllKnownMcpMethods,proto3,oneof" json:"allow_all_known_mcp_methods,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *McpOptions) Reset() {
+ *x = McpOptions{}
+ mi := &file_sandbox_proto_msgTypes[8]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *McpOptions) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*McpOptions) ProtoMessage() {}
+
+func (x *McpOptions) 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 McpOptions.ProtoReflect.Descriptor instead.
+func (*McpOptions) Descriptor() ([]byte, []int) {
+ return file_sandbox_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *McpOptions) GetStrictToolNames() bool {
+ if x != nil && x.StrictToolNames != nil {
+ return *x.StrictToolNames
+ }
+ return false
+}
+
+func (x *McpOptions) GetAllowAllKnownMcpMethods() bool {
+ if x != nil && x.AllowAllKnownMcpMethods != nil {
+ return *x.AllowAllKnownMcpMethods
+ }
+ return false
+}
+
+// Trusted GraphQL operation classification.
+type GraphqlOperation struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Operation type: "query", "mutation", or "subscription".
+ OperationType string `protobuf:"bytes,1,opt,name=operation_type,json=operationType,proto3" json:"operation_type,omitempty"`
+ // Operation name, if known.
+ OperationName string `protobuf:"bytes,2,opt,name=operation_name,json=operationName,proto3" json:"operation_name,omitempty"`
+ // Root field names selected by the operation.
+ Fields []string `protobuf:"bytes,3,rep,name=fields,proto3" json:"fields,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GraphqlOperation) Reset() {
+ *x = GraphqlOperation{}
+ mi := &file_sandbox_proto_msgTypes[9]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GraphqlOperation) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GraphqlOperation) ProtoMessage() {}
+
+func (x *GraphqlOperation) 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 GraphqlOperation.ProtoReflect.Descriptor instead.
+func (*GraphqlOperation) Descriptor() ([]byte, []int) {
+ return file_sandbox_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *GraphqlOperation) GetOperationType() string {
+ if x != nil {
+ return x.OperationType
+ }
+ return ""
+}
+
+func (x *GraphqlOperation) GetOperationName() string {
+ if x != nil {
+ return x.OperationName
+ }
+ return ""
+}
+
+func (x *GraphqlOperation) GetFields() []string {
+ if x != nil {
+ return x.Fields
+ }
+ return nil
+}
+
+// An L7 deny rule that blocks specific requests.
+// Mirrors L7Allow — same fields, same matching semantics, inverted effect.
+// Deny rules are evaluated after allow rules and take precedence.
+type L7DenyRule struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Protocol method: HTTP method (REST/WebSocket), JSON-RPC method name, or
+ // "*" for any when supported by the protocol.
+ Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"`
+ // URL path glob pattern (REST): "/repos/*/pulls/*/reviews", "**" 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"`
+ // Query parameter matcher map (REST).
+ // Same semantics as L7Allow.query.
+ Query map[string]*L7QueryMatcher `protobuf:"bytes,4,rep,name=query,proto3" json:"query,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ // GraphQL operation type: "query", "mutation", "subscription", or "*" for any.
+ OperationType string `protobuf:"bytes,5,opt,name=operation_type,json=operationType,proto3" json:"operation_type,omitempty"`
+ // GraphQL operation name glob. "*" matches any operation name.
+ OperationName string `protobuf:"bytes,6,opt,name=operation_name,json=operationName,proto3" json:"operation_name,omitempty"`
+ // GraphQL root field globs. Deny rules match when any selected root field
+ // matches any configured glob.
+ Fields []string `protobuf:"bytes,7,rep,name=fields,proto3" json:"fields,omitempty"`
+ // MCP params matcher map. Currently only params.name is supported for
+ // tools/call filtering. Generic protocol "json-rpc" rejects params matchers.
+ Params map[string]*L7QueryMatcher `protobuf:"bytes,9,rep,name=params,proto3" json:"params,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *L7DenyRule) Reset() {
+ *x = L7DenyRule{}
+ mi := &file_sandbox_proto_msgTypes[10]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *L7DenyRule) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*L7DenyRule) ProtoMessage() {}
+
+func (x *L7DenyRule) 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 L7DenyRule.ProtoReflect.Descriptor instead.
+func (*L7DenyRule) Descriptor() ([]byte, []int) {
+ return file_sandbox_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *L7DenyRule) GetMethod() string {
+ if x != nil {
+ return x.Method
+ }
+ return ""
+}
+
+func (x *L7DenyRule) GetPath() string {
+ if x != nil {
+ return x.Path
+ }
+ return ""
+}
+
+func (x *L7DenyRule) GetCommand() string {
+ if x != nil {
+ return x.Command
+ }
+ return ""
+}
+
+func (x *L7DenyRule) GetQuery() map[string]*L7QueryMatcher {
+ if x != nil {
+ return x.Query
+ }
+ return nil
+}
+
+func (x *L7DenyRule) GetOperationType() string {
+ if x != nil {
+ return x.OperationType
+ }
+ return ""
+}
+
+func (x *L7DenyRule) GetOperationName() string {
+ if x != nil {
+ return x.OperationName
+ }
+ return ""
+}
+
+func (x *L7DenyRule) GetFields() []string {
+ if x != nil {
+ return x.Fields
+ }
+ return nil
+}
+
+func (x *L7DenyRule) GetParams() map[string]*L7QueryMatcher {
+ if x != nil {
+ return x.Params
+ }
+ 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[11]
+ 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[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 L7Rule.ProtoReflect.Descriptor instead.
+func (*L7Rule) Descriptor() ([]byte, []int) {
+ return file_sandbox_proto_rawDescGZIP(), []int{11}
+}
+
+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"`
+ // Protocol method: HTTP method (REST/WebSocket), JSON-RPC method name, or
+ // "*" for any when supported by the protocol.
+ 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"`
+ // Query parameter matcher map (REST).
+ // Key is the decoded query parameter name (case-sensitive).
+ // Value supports either a single glob (`glob`) or a list (`any`).
+ Query map[string]*L7QueryMatcher `protobuf:"bytes,4,rep,name=query,proto3" json:"query,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ // GraphQL operation type: "query", "mutation", "subscription", or "*" for any.
+ OperationType string `protobuf:"bytes,5,opt,name=operation_type,json=operationType,proto3" json:"operation_type,omitempty"`
+ // GraphQL operation name glob. "*" matches any operation name.
+ OperationName string `protobuf:"bytes,6,opt,name=operation_name,json=operationName,proto3" json:"operation_name,omitempty"`
+ // GraphQL root field globs. Allow rules match only when every selected root
+ // field matches one of the configured globs. Omit to match all fields.
+ Fields []string `protobuf:"bytes,7,rep,name=fields,proto3" json:"fields,omitempty"`
+ // MCP params matcher map. Currently only params.name is supported for
+ // tools/call filtering. Generic protocol "json-rpc" rejects params matchers.
+ Params map[string]*L7QueryMatcher `protobuf:"bytes,9,rep,name=params,proto3" json:"params,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *L7Allow) Reset() {
+ *x = L7Allow{}
+ mi := &file_sandbox_proto_msgTypes[12]
+ 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[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 L7Allow.ProtoReflect.Descriptor instead.
+func (*L7Allow) Descriptor() ([]byte, []int) {
+ return file_sandbox_proto_rawDescGZIP(), []int{12}
+}
+
+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 ""
+}
+
+func (x *L7Allow) GetQuery() map[string]*L7QueryMatcher {
+ if x != nil {
+ return x.Query
+ }
+ return nil
+}
+
+func (x *L7Allow) GetOperationType() string {
+ if x != nil {
+ return x.OperationType
+ }
+ return ""
+}
+
+func (x *L7Allow) GetOperationName() string {
+ if x != nil {
+ return x.OperationName
+ }
+ return ""
+}
+
+func (x *L7Allow) GetFields() []string {
+ if x != nil {
+ return x.Fields
+ }
+ return nil
+}
+
+func (x *L7Allow) GetParams() map[string]*L7QueryMatcher {
+ if x != nil {
+ return x.Params
+ }
+ return nil
+}
+
+// Query value matcher for one query parameter key.
+type L7QueryMatcher struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Single glob pattern.
+ Glob string `protobuf:"bytes,1,opt,name=glob,proto3" json:"glob,omitempty"`
+ // Any-of glob patterns.
+ Any []string `protobuf:"bytes,2,rep,name=any,proto3" json:"any,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *L7QueryMatcher) Reset() {
+ *x = L7QueryMatcher{}
+ mi := &file_sandbox_proto_msgTypes[13]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *L7QueryMatcher) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*L7QueryMatcher) ProtoMessage() {}
+
+func (x *L7QueryMatcher) ProtoReflect() protoreflect.Message {
+ mi := &file_sandbox_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 L7QueryMatcher.ProtoReflect.Descriptor instead.
+func (*L7QueryMatcher) Descriptor() ([]byte, []int) {
+ return file_sandbox_proto_rawDescGZIP(), []int{13}
+}
+
+func (x *L7QueryMatcher) GetGlob() string {
+ if x != nil {
+ return x.Glob
+ }
+ return ""
+}
+
+func (x *L7QueryMatcher) GetAny() []string {
+ if x != nil {
+ return x.Any
+ }
+ return nil
+}
+
+// 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[14]
+ 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[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 NetworkBinary.ProtoReflect.Descriptor instead.
+func (*NetworkBinary) Descriptor() ([]byte, []int) {
+ return file_sandbox_proto_rawDescGZIP(), []int{14}
+}
+
+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 settings by sandbox ID.
+type GetSandboxConfigRequest 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 *GetSandboxConfigRequest) Reset() {
+ *x = GetSandboxConfigRequest{}
+ mi := &file_sandbox_proto_msgTypes[15]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetSandboxConfigRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetSandboxConfigRequest) ProtoMessage() {}
+
+func (x *GetSandboxConfigRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_sandbox_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 GetSandboxConfigRequest.ProtoReflect.Descriptor instead.
+func (*GetSandboxConfigRequest) Descriptor() ([]byte, []int) {
+ return file_sandbox_proto_rawDescGZIP(), []int{15}
+}
+
+func (x *GetSandboxConfigRequest) GetSandboxId() string {
+ if x != nil {
+ return x.SandboxId
+ }
+ return ""
+}
+
+// Request to get gateway-global settings.
+type GetGatewayConfigRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetGatewayConfigRequest) Reset() {
+ *x = GetGatewayConfigRequest{}
+ mi := &file_sandbox_proto_msgTypes[16]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetGatewayConfigRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetGatewayConfigRequest) ProtoMessage() {}
+
+func (x *GetGatewayConfigRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_sandbox_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 GetGatewayConfigRequest.ProtoReflect.Descriptor instead.
+func (*GetGatewayConfigRequest) Descriptor() ([]byte, []int) {
+ return file_sandbox_proto_rawDescGZIP(), []int{16}
+}
+
+// Response containing gateway-global settings.
+type GetGatewayConfigResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Gateway-global settings map excluding the reserved policy key.
+ // Registered keys without a configured value are returned with an empty SettingValue.
+ Settings map[string]*SettingValue `protobuf:"bytes,1,rep,name=settings,proto3" json:"settings,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ // Monotonically increasing revision for gateway-global settings.
+ SettingsRevision uint64 `protobuf:"varint,2,opt,name=settings_revision,json=settingsRevision,proto3" json:"settings_revision,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetGatewayConfigResponse) Reset() {
+ *x = GetGatewayConfigResponse{}
+ mi := &file_sandbox_proto_msgTypes[17]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetGatewayConfigResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetGatewayConfigResponse) ProtoMessage() {}
+
+func (x *GetGatewayConfigResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_sandbox_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 GetGatewayConfigResponse.ProtoReflect.Descriptor instead.
+func (*GetGatewayConfigResponse) Descriptor() ([]byte, []int) {
+ return file_sandbox_proto_rawDescGZIP(), []int{17}
+}
+
+func (x *GetGatewayConfigResponse) GetSettings() map[string]*SettingValue {
+ if x != nil {
+ return x.Settings
+ }
+ return nil
+}
+
+func (x *GetGatewayConfigResponse) GetSettingsRevision() uint64 {
+ if x != nil {
+ return x.SettingsRevision
+ }
+ return 0
+}
+
+// Type-aware setting value for sandbox/gateway settings.
+type SettingValue struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Types that are valid to be assigned to Value:
+ //
+ // *SettingValue_StringValue
+ // *SettingValue_BoolValue
+ // *SettingValue_IntValue
+ // *SettingValue_BytesValue
+ Value isSettingValue_Value `protobuf_oneof:"value"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SettingValue) Reset() {
+ *x = SettingValue{}
+ mi := &file_sandbox_proto_msgTypes[18]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SettingValue) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SettingValue) ProtoMessage() {}
+
+func (x *SettingValue) ProtoReflect() protoreflect.Message {
+ mi := &file_sandbox_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 SettingValue.ProtoReflect.Descriptor instead.
+func (*SettingValue) Descriptor() ([]byte, []int) {
+ return file_sandbox_proto_rawDescGZIP(), []int{18}
+}
+
+func (x *SettingValue) GetValue() isSettingValue_Value {
+ if x != nil {
+ return x.Value
+ }
+ return nil
+}
+
+func (x *SettingValue) GetStringValue() string {
+ if x != nil {
+ if x, ok := x.Value.(*SettingValue_StringValue); ok {
+ return x.StringValue
+ }
+ }
+ return ""
+}
+
+func (x *SettingValue) GetBoolValue() bool {
+ if x != nil {
+ if x, ok := x.Value.(*SettingValue_BoolValue); ok {
+ return x.BoolValue
+ }
+ }
+ return false
+}
+
+func (x *SettingValue) GetIntValue() int64 {
+ if x != nil {
+ if x, ok := x.Value.(*SettingValue_IntValue); ok {
+ return x.IntValue
+ }
+ }
+ return 0
+}
+
+func (x *SettingValue) GetBytesValue() []byte {
+ if x != nil {
+ if x, ok := x.Value.(*SettingValue_BytesValue); ok {
+ return x.BytesValue
+ }
+ }
+ return nil
+}
+
+type isSettingValue_Value interface {
+ isSettingValue_Value()
+}
+
+type SettingValue_StringValue struct {
+ StringValue string `protobuf:"bytes,1,opt,name=string_value,json=stringValue,proto3,oneof"`
+}
+
+type SettingValue_BoolValue struct {
+ BoolValue bool `protobuf:"varint,2,opt,name=bool_value,json=boolValue,proto3,oneof"`
+}
+
+type SettingValue_IntValue struct {
+ IntValue int64 `protobuf:"varint,3,opt,name=int_value,json=intValue,proto3,oneof"`
+}
+
+type SettingValue_BytesValue struct {
+ BytesValue []byte `protobuf:"bytes,4,opt,name=bytes_value,json=bytesValue,proto3,oneof"`
+}
+
+func (*SettingValue_StringValue) isSettingValue_Value() {}
+
+func (*SettingValue_BoolValue) isSettingValue_Value() {}
+
+func (*SettingValue_IntValue) isSettingValue_Value() {}
+
+func (*SettingValue_BytesValue) isSettingValue_Value() {}
+
+// Effective setting value and the scope it was resolved from.
+type EffectiveSetting struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Value *SettingValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
+ Scope SettingScope `protobuf:"varint,2,opt,name=scope,proto3,enum=openshell.sandbox.v1.SettingScope" json:"scope,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *EffectiveSetting) Reset() {
+ *x = EffectiveSetting{}
+ mi := &file_sandbox_proto_msgTypes[19]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *EffectiveSetting) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EffectiveSetting) ProtoMessage() {}
+
+func (x *EffectiveSetting) ProtoReflect() protoreflect.Message {
+ mi := &file_sandbox_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 EffectiveSetting.ProtoReflect.Descriptor instead.
+func (*EffectiveSetting) Descriptor() ([]byte, []int) {
+ return file_sandbox_proto_rawDescGZIP(), []int{19}
+}
+
+func (x *EffectiveSetting) GetValue() *SettingValue {
+ if x != nil {
+ return x.Value
+ }
+ return nil
+}
+
+func (x *EffectiveSetting) GetScope() SettingScope {
+ if x != nil {
+ return x.Scope
+ }
+ return SettingScope_SETTING_SCOPE_UNSPECIFIED
+}
+
+// Response containing effective sandbox settings and policy.
+type GetSandboxConfigResponse 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"`
+ // Effective settings resolved for this sandbox, excluding the reserved policy key.
+ // Registered keys without a configured value are returned with an empty EffectiveSetting.value.
+ Settings map[string]*EffectiveSetting `protobuf:"bytes,4,rep,name=settings,proto3" json:"settings,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ // Fingerprint for effective config (policy + settings). Changes when any effective input changes.
+ ConfigRevision uint64 `protobuf:"varint,5,opt,name=config_revision,json=configRevision,proto3" json:"config_revision,omitempty"`
+ // Source of the policy payload for this response.
+ PolicySource PolicySource `protobuf:"varint,6,opt,name=policy_source,json=policySource,proto3,enum=openshell.sandbox.v1.PolicySource" json:"policy_source,omitempty"`
+ // When policy_source is GLOBAL, the version of the global policy revision.
+ // Zero when no global policy is active or when policy_source is SANDBOX.
+ GlobalPolicyVersion uint32 `protobuf:"varint,7,opt,name=global_policy_version,json=globalPolicyVersion,proto3" json:"global_policy_version,omitempty"`
+ // Fingerprint for provider credential inputs attached to this sandbox.
+ // Changes when attached provider names or attached provider records change.
+ ProviderEnvRevision uint64 `protobuf:"varint,8,opt,name=provider_env_revision,json=providerEnvRevision,proto3" json:"provider_env_revision,omitempty"`
+ // Operator-registered supervisor middleware services required by the
+ // effective policy. Built-in middleware is not included.
+ SupervisorMiddlewareServices []*SupervisorMiddlewareService `protobuf:"bytes,9,rep,name=supervisor_middleware_services,json=supervisorMiddlewareServices,proto3" json:"supervisor_middleware_services,omitempty"`
+ // Workspace the sandbox belongs to. Allows the supervisor to learn its
+ // workspace context for subsequent workspace-scoped RPCs.
+ Workspace string `protobuf:"bytes,10,opt,name=workspace,proto3" json:"workspace,omitempty"`
+ // Gateway-configured posture for rejected policy generations. Valid values
+ // are "fail_closed" and "retain_last_valid". Unknown or empty values must
+ // be treated as fail_closed by the supervisor.
+ PolicyValidationFailureMode string `protobuf:"bytes,11,opt,name=policy_validation_failure_mode,json=policyValidationFailureMode,proto3" json:"policy_validation_failure_mode,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetSandboxConfigResponse) Reset() {
+ *x = GetSandboxConfigResponse{}
+ mi := &file_sandbox_proto_msgTypes[20]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetSandboxConfigResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetSandboxConfigResponse) ProtoMessage() {}
+
+func (x *GetSandboxConfigResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_sandbox_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 GetSandboxConfigResponse.ProtoReflect.Descriptor instead.
+func (*GetSandboxConfigResponse) Descriptor() ([]byte, []int) {
+ return file_sandbox_proto_rawDescGZIP(), []int{20}
+}
+
+func (x *GetSandboxConfigResponse) GetPolicy() *SandboxPolicy {
+ if x != nil {
+ return x.Policy
+ }
+ return nil
+}
+
+func (x *GetSandboxConfigResponse) GetVersion() uint32 {
+ if x != nil {
+ return x.Version
+ }
+ return 0
+}
+
+func (x *GetSandboxConfigResponse) GetPolicyHash() string {
+ if x != nil {
+ return x.PolicyHash
+ }
+ return ""
+}
+
+func (x *GetSandboxConfigResponse) GetSettings() map[string]*EffectiveSetting {
+ if x != nil {
+ return x.Settings
+ }
+ return nil
+}
+
+func (x *GetSandboxConfigResponse) GetConfigRevision() uint64 {
+ if x != nil {
+ return x.ConfigRevision
+ }
+ return 0
+}
+
+func (x *GetSandboxConfigResponse) GetPolicySource() PolicySource {
+ if x != nil {
+ return x.PolicySource
+ }
+ return PolicySource_POLICY_SOURCE_UNSPECIFIED
+}
+
+func (x *GetSandboxConfigResponse) GetGlobalPolicyVersion() uint32 {
+ if x != nil {
+ return x.GlobalPolicyVersion
+ }
+ return 0
+}
+
+func (x *GetSandboxConfigResponse) GetProviderEnvRevision() uint64 {
+ if x != nil {
+ return x.ProviderEnvRevision
+ }
+ return 0
+}
+
+func (x *GetSandboxConfigResponse) GetSupervisorMiddlewareServices() []*SupervisorMiddlewareService {
+ if x != nil {
+ return x.SupervisorMiddlewareServices
+ }
+ return nil
+}
+
+func (x *GetSandboxConfigResponse) GetWorkspace() string {
+ if x != nil {
+ return x.Workspace
+ }
+ return ""
+}
+
+func (x *GetSandboxConfigResponse) GetPolicyValidationFailureMode() string {
+ if x != nil {
+ return x.PolicyValidationFailureMode
+ }
+ return ""
+}
+
+// Connection details for one operator-registered supervisor middleware service.
+// V1 supports plaintext and server-authenticated TLS gRPC.
+type SupervisorMiddlewareService struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Operator-owned registration name used by policy attachments and diagnostics.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // gRPC endpoint reachable from the sandbox supervisor.
+ GrpcEndpoint string `protobuf:"bytes,2,opt,name=grpc_endpoint,json=grpcEndpoint,proto3" json:"grpc_endpoint,omitempty"`
+ // Operator-owned body limit applied to every binding exposed by the service.
+ MaxBodyBytes uint64 `protobuf:"varint,3,opt,name=max_body_bytes,json=maxBodyBytes,proto3" json:"max_body_bytes,omitempty"`
+ // Default RPC timeout for this service. Empty uses the platform default of
+ // 500ms. Values use an integer with an `ms` or `s` suffix and must be
+ // between 10ms and 30s.
+ Timeout string `protobuf:"bytes,4,opt,name=timeout,proto3" json:"timeout,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SupervisorMiddlewareService) Reset() {
+ *x = SupervisorMiddlewareService{}
+ mi := &file_sandbox_proto_msgTypes[21]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SupervisorMiddlewareService) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SupervisorMiddlewareService) ProtoMessage() {}
+
+func (x *SupervisorMiddlewareService) ProtoReflect() protoreflect.Message {
+ mi := &file_sandbox_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 SupervisorMiddlewareService.ProtoReflect.Descriptor instead.
+func (*SupervisorMiddlewareService) Descriptor() ([]byte, []int) {
+ return file_sandbox_proto_rawDescGZIP(), []int{21}
+}
+
+func (x *SupervisorMiddlewareService) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *SupervisorMiddlewareService) GetGrpcEndpoint() string {
+ if x != nil {
+ return x.GrpcEndpoint
+ }
+ return ""
+}
+
+func (x *SupervisorMiddlewareService) GetMaxBodyBytes() uint64 {
+ if x != nil {
+ return x.MaxBodyBytes
+ }
+ return 0
+}
+
+func (x *SupervisorMiddlewareService) GetTimeout() string {
+ if x != nil {
+ return x.Timeout
+ }
+ return ""
+}
+
+var File_sandbox_proto protoreflect.FileDescriptor
+
+const file_sandbox_proto_rawDesc = "" +
+ "\n" +
+ "\rsandbox.proto\x12\x14openshell.sandbox.v1\x1a\x1cgoogle/protobuf/struct.proto\"\xa8\x05\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\x12l\n" +
+ "\x13network_middlewares\x18\x06 \x03(\v2;.openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntryR\x12networkMiddlewares\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\x1at\n" +
+ "\x17NetworkMiddlewaresEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12C\n" +
+ "\x05value\x18\x02 \x01(\v2-.openshell.sandbox.v1.NetworkMiddlewareConfigR\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\"\xff\x01\n" +
+ "\x17NetworkMiddlewareConfig\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12\x1e\n" +
+ "\n" +
+ "middleware\x18\x02 \x01(\tR\n" +
+ "middleware\x12/\n" +
+ "\x06config\x18\x03 \x01(\v2\x17.google.protobuf.StructR\x06config\x12\x19\n" +
+ "\bon_error\x18\x04 \x01(\tR\aonError\x12N\n" +
+ "\tendpoints\x18\x05 \x01(\v20.openshell.sandbox.v1.MiddlewareEndpointSelectorR\tendpoints\x12\x14\n" +
+ "\x05order\x18\x06 \x01(\x05R\x05order\"P\n" +
+ "\x1aMiddlewareEndpointSelector\x12\x18\n" +
+ "\ainclude\x18\x01 \x03(\tR\ainclude\x12\x18\n" +
+ "\aexclude\x18\x02 \x03(\tR\aexclude\"\x84\t\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\x12?\n" +
+ "\n" +
+ "deny_rules\x18\n" +
+ " \x03(\v2 .openshell.sandbox.v1.L7DenyRuleR\tdenyRules\x12.\n" +
+ "\x13allow_encoded_slash\x18\v \x01(\bR\x11allowEncodedSlash\x12+\n" +
+ "\x11persisted_queries\x18\f \x01(\tR\x10persistedQueries\x12~\n" +
+ "\x19graphql_persisted_queries\x18\r \x03(\v2B.openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntryR\x17graphqlPersistedQueries\x123\n" +
+ "\x16graphql_max_body_bytes\x18\x0e \x01(\rR\x13graphqlMaxBodyBytes\x12\x12\n" +
+ "\x04path\x18\x0f \x01(\tR\x04path\x12@\n" +
+ "\x1cwebsocket_credential_rewrite\x18\x10 \x01(\bR\x1awebsocketCredentialRewrite\x12E\n" +
+ "\x1frequest_body_credential_rewrite\x18\x11 \x01(\bR\x1crequestBodyCredentialRewrite\x12)\n" +
+ "\x10advisor_proposed\x18\x12 \x01(\bR\x0fadvisorProposed\x12-\n" +
+ "\x12credential_signing\x18\x13 \x01(\tR\x11credentialSigning\x12'\n" +
+ "\x0fsigning_service\x18\x14 \x01(\tR\x0esigningService\x12%\n" +
+ "\x0esigning_region\x18\x15 \x01(\tR\rsigningRegion\x124\n" +
+ "\x17json_rpc_max_body_bytes\x18\x16 \x01(\rR\x13jsonRpcMaxBodyBytes\x122\n" +
+ "\x03mcp\x18\x17 \x01(\v2 .openshell.sandbox.v1.McpOptionsR\x03mcp\x1ar\n" +
+ "\x1cGraphqlPersistedQueriesEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12<\n" +
+ "\x05value\x18\x02 \x01(\v2&.openshell.sandbox.v1.GraphqlOperationR\x05value:\x028\x01\"\xb6\x01\n" +
+ "\n" +
+ "McpOptions\x12/\n" +
+ "\x11strict_tool_names\x18\x01 \x01(\bH\x00R\x0fstrictToolNames\x88\x01\x01\x12A\n" +
+ "\x1ballow_all_known_mcp_methods\x18\x02 \x01(\bH\x01R\x17allowAllKnownMcpMethods\x88\x01\x01B\x14\n" +
+ "\x12_strict_tool_namesB\x1e\n" +
+ "\x1c_allow_all_known_mcp_methods\"x\n" +
+ "\x10GraphqlOperation\x12%\n" +
+ "\x0eoperation_type\x18\x01 \x01(\tR\roperationType\x12%\n" +
+ "\x0eoperation_name\x18\x02 \x01(\tR\roperationName\x12\x16\n" +
+ "\x06fields\x18\x03 \x03(\tR\x06fields\"\x88\x04\n" +
+ "\n" +
+ "L7DenyRule\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\x12A\n" +
+ "\x05query\x18\x04 \x03(\v2+.openshell.sandbox.v1.L7DenyRule.QueryEntryR\x05query\x12%\n" +
+ "\x0eoperation_type\x18\x05 \x01(\tR\roperationType\x12%\n" +
+ "\x0eoperation_name\x18\x06 \x01(\tR\roperationName\x12\x16\n" +
+ "\x06fields\x18\a \x03(\tR\x06fields\x12D\n" +
+ "\x06params\x18\t \x03(\v2,.openshell.sandbox.v1.L7DenyRule.ParamsEntryR\x06params\x1a^\n" +
+ "\n" +
+ "QueryEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12:\n" +
+ "\x05value\x18\x02 \x01(\v2$.openshell.sandbox.v1.L7QueryMatcherR\x05value:\x028\x01\x1a_\n" +
+ "\vParamsEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12:\n" +
+ "\x05value\x18\x02 \x01(\v2$.openshell.sandbox.v1.L7QueryMatcherR\x05value:\x028\x01J\x04\b\b\x10\t\"=\n" +
+ "\x06L7Rule\x123\n" +
+ "\x05allow\x18\x01 \x01(\v2\x1d.openshell.sandbox.v1.L7AllowR\x05allow\"\xff\x03\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\x12>\n" +
+ "\x05query\x18\x04 \x03(\v2(.openshell.sandbox.v1.L7Allow.QueryEntryR\x05query\x12%\n" +
+ "\x0eoperation_type\x18\x05 \x01(\tR\roperationType\x12%\n" +
+ "\x0eoperation_name\x18\x06 \x01(\tR\roperationName\x12\x16\n" +
+ "\x06fields\x18\a \x03(\tR\x06fields\x12A\n" +
+ "\x06params\x18\t \x03(\v2).openshell.sandbox.v1.L7Allow.ParamsEntryR\x06params\x1a^\n" +
+ "\n" +
+ "QueryEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12:\n" +
+ "\x05value\x18\x02 \x01(\v2$.openshell.sandbox.v1.L7QueryMatcherR\x05value:\x028\x01\x1a_\n" +
+ "\vParamsEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12:\n" +
+ "\x05value\x18\x02 \x01(\v2$.openshell.sandbox.v1.L7QueryMatcherR\x05value:\x028\x01J\x04\b\b\x10\t\"6\n" +
+ "\x0eL7QueryMatcher\x12\x12\n" +
+ "\x04glob\x18\x01 \x01(\tR\x04glob\x12\x10\n" +
+ "\x03any\x18\x02 \x03(\tR\x03any\"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" +
+ "\x17GetSandboxConfigRequest\x12\x1d\n" +
+ "\n" +
+ "sandbox_id\x18\x01 \x01(\tR\tsandboxId\"\x19\n" +
+ "\x17GetGatewayConfigRequest\"\x82\x02\n" +
+ "\x18GetGatewayConfigResponse\x12X\n" +
+ "\bsettings\x18\x01 \x03(\v2<.openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntryR\bsettings\x12+\n" +
+ "\x11settings_revision\x18\x02 \x01(\x04R\x10settingsRevision\x1a_\n" +
+ "\rSettingsEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x128\n" +
+ "\x05value\x18\x02 \x01(\v2\".openshell.sandbox.v1.SettingValueR\x05value:\x028\x01\"\x9f\x01\n" +
+ "\fSettingValue\x12#\n" +
+ "\fstring_value\x18\x01 \x01(\tH\x00R\vstringValue\x12\x1f\n" +
+ "\n" +
+ "bool_value\x18\x02 \x01(\bH\x00R\tboolValue\x12\x1d\n" +
+ "\tint_value\x18\x03 \x01(\x03H\x00R\bintValue\x12!\n" +
+ "\vbytes_value\x18\x04 \x01(\fH\x00R\n" +
+ "bytesValueB\a\n" +
+ "\x05value\"\x86\x01\n" +
+ "\x10EffectiveSetting\x128\n" +
+ "\x05value\x18\x01 \x01(\v2\".openshell.sandbox.v1.SettingValueR\x05value\x128\n" +
+ "\x05scope\x18\x02 \x01(\x0e2\".openshell.sandbox.v1.SettingScopeR\x05scope\"\x87\x06\n" +
+ "\x18GetSandboxConfigResponse\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" +
+ "policyHash\x12X\n" +
+ "\bsettings\x18\x04 \x03(\v2<.openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntryR\bsettings\x12'\n" +
+ "\x0fconfig_revision\x18\x05 \x01(\x04R\x0econfigRevision\x12G\n" +
+ "\rpolicy_source\x18\x06 \x01(\x0e2\".openshell.sandbox.v1.PolicySourceR\fpolicySource\x122\n" +
+ "\x15global_policy_version\x18\a \x01(\rR\x13globalPolicyVersion\x122\n" +
+ "\x15provider_env_revision\x18\b \x01(\x04R\x13providerEnvRevision\x12w\n" +
+ "\x1esupervisor_middleware_services\x18\t \x03(\v21.openshell.sandbox.v1.SupervisorMiddlewareServiceR\x1csupervisorMiddlewareServices\x12\x1c\n" +
+ "\tworkspace\x18\n" +
+ " \x01(\tR\tworkspace\x12C\n" +
+ "\x1epolicy_validation_failure_mode\x18\v \x01(\tR\x1bpolicyValidationFailureMode\x1ac\n" +
+ "\rSettingsEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12<\n" +
+ "\x05value\x18\x02 \x01(\v2&.openshell.sandbox.v1.EffectiveSettingR\x05value:\x028\x01\"\x96\x01\n" +
+ "\x1bSupervisorMiddlewareService\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12#\n" +
+ "\rgrpc_endpoint\x18\x02 \x01(\tR\fgrpcEndpoint\x12$\n" +
+ "\x0emax_body_bytes\x18\x03 \x01(\x04R\fmaxBodyBytes\x12\x18\n" +
+ "\atimeout\x18\x04 \x01(\tR\atimeout*b\n" +
+ "\fSettingScope\x12\x1d\n" +
+ "\x19SETTING_SCOPE_UNSPECIFIED\x10\x00\x12\x19\n" +
+ "\x15SETTING_SCOPE_SANDBOX\x10\x01\x12\x18\n" +
+ "\x14SETTING_SCOPE_GLOBAL\x10\x02*b\n" +
+ "\fPolicySource\x12\x1d\n" +
+ "\x19POLICY_SOURCE_UNSPECIFIED\x10\x00\x12\x19\n" +
+ "\x15POLICY_SOURCE_SANDBOX\x10\x01\x12\x18\n" +
+ "\x14POLICY_SOURCE_GLOBAL\x10\x02b\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_enumTypes = make([]protoimpl.EnumInfo, 2)
+var file_sandbox_proto_msgTypes = make([]protoimpl.MessageInfo, 31)
+var file_sandbox_proto_goTypes = []any{
+ (SettingScope)(0), // 0: openshell.sandbox.v1.SettingScope
+ (PolicySource)(0), // 1: openshell.sandbox.v1.PolicySource
+ (*SandboxPolicy)(nil), // 2: openshell.sandbox.v1.SandboxPolicy
+ (*FilesystemPolicy)(nil), // 3: openshell.sandbox.v1.FilesystemPolicy
+ (*LandlockPolicy)(nil), // 4: openshell.sandbox.v1.LandlockPolicy
+ (*ProcessPolicy)(nil), // 5: openshell.sandbox.v1.ProcessPolicy
+ (*NetworkPolicyRule)(nil), // 6: openshell.sandbox.v1.NetworkPolicyRule
+ (*NetworkMiddlewareConfig)(nil), // 7: openshell.sandbox.v1.NetworkMiddlewareConfig
+ (*MiddlewareEndpointSelector)(nil), // 8: openshell.sandbox.v1.MiddlewareEndpointSelector
+ (*NetworkEndpoint)(nil), // 9: openshell.sandbox.v1.NetworkEndpoint
+ (*McpOptions)(nil), // 10: openshell.sandbox.v1.McpOptions
+ (*GraphqlOperation)(nil), // 11: openshell.sandbox.v1.GraphqlOperation
+ (*L7DenyRule)(nil), // 12: openshell.sandbox.v1.L7DenyRule
+ (*L7Rule)(nil), // 13: openshell.sandbox.v1.L7Rule
+ (*L7Allow)(nil), // 14: openshell.sandbox.v1.L7Allow
+ (*L7QueryMatcher)(nil), // 15: openshell.sandbox.v1.L7QueryMatcher
+ (*NetworkBinary)(nil), // 16: openshell.sandbox.v1.NetworkBinary
+ (*GetSandboxConfigRequest)(nil), // 17: openshell.sandbox.v1.GetSandboxConfigRequest
+ (*GetGatewayConfigRequest)(nil), // 18: openshell.sandbox.v1.GetGatewayConfigRequest
+ (*GetGatewayConfigResponse)(nil), // 19: openshell.sandbox.v1.GetGatewayConfigResponse
+ (*SettingValue)(nil), // 20: openshell.sandbox.v1.SettingValue
+ (*EffectiveSetting)(nil), // 21: openshell.sandbox.v1.EffectiveSetting
+ (*GetSandboxConfigResponse)(nil), // 22: openshell.sandbox.v1.GetSandboxConfigResponse
+ (*SupervisorMiddlewareService)(nil), // 23: openshell.sandbox.v1.SupervisorMiddlewareService
+ nil, // 24: openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry
+ nil, // 25: openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry
+ nil, // 26: openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry
+ nil, // 27: openshell.sandbox.v1.L7DenyRule.QueryEntry
+ nil, // 28: openshell.sandbox.v1.L7DenyRule.ParamsEntry
+ nil, // 29: openshell.sandbox.v1.L7Allow.QueryEntry
+ nil, // 30: openshell.sandbox.v1.L7Allow.ParamsEntry
+ nil, // 31: openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry
+ nil, // 32: openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry
+ (*structpb.Struct)(nil), // 33: google.protobuf.Struct
+}
+var file_sandbox_proto_depIdxs = []int32{
+ 3, // 0: openshell.sandbox.v1.SandboxPolicy.filesystem:type_name -> openshell.sandbox.v1.FilesystemPolicy
+ 4, // 1: openshell.sandbox.v1.SandboxPolicy.landlock:type_name -> openshell.sandbox.v1.LandlockPolicy
+ 5, // 2: openshell.sandbox.v1.SandboxPolicy.process:type_name -> openshell.sandbox.v1.ProcessPolicy
+ 24, // 3: openshell.sandbox.v1.SandboxPolicy.network_policies:type_name -> openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry
+ 25, // 4: openshell.sandbox.v1.SandboxPolicy.network_middlewares:type_name -> openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry
+ 9, // 5: openshell.sandbox.v1.NetworkPolicyRule.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint
+ 16, // 6: openshell.sandbox.v1.NetworkPolicyRule.binaries:type_name -> openshell.sandbox.v1.NetworkBinary
+ 33, // 7: openshell.sandbox.v1.NetworkMiddlewareConfig.config:type_name -> google.protobuf.Struct
+ 8, // 8: openshell.sandbox.v1.NetworkMiddlewareConfig.endpoints:type_name -> openshell.sandbox.v1.MiddlewareEndpointSelector
+ 13, // 9: openshell.sandbox.v1.NetworkEndpoint.rules:type_name -> openshell.sandbox.v1.L7Rule
+ 12, // 10: openshell.sandbox.v1.NetworkEndpoint.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule
+ 26, // 11: openshell.sandbox.v1.NetworkEndpoint.graphql_persisted_queries:type_name -> openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry
+ 10, // 12: openshell.sandbox.v1.NetworkEndpoint.mcp:type_name -> openshell.sandbox.v1.McpOptions
+ 27, // 13: openshell.sandbox.v1.L7DenyRule.query:type_name -> openshell.sandbox.v1.L7DenyRule.QueryEntry
+ 28, // 14: openshell.sandbox.v1.L7DenyRule.params:type_name -> openshell.sandbox.v1.L7DenyRule.ParamsEntry
+ 14, // 15: openshell.sandbox.v1.L7Rule.allow:type_name -> openshell.sandbox.v1.L7Allow
+ 29, // 16: openshell.sandbox.v1.L7Allow.query:type_name -> openshell.sandbox.v1.L7Allow.QueryEntry
+ 30, // 17: openshell.sandbox.v1.L7Allow.params:type_name -> openshell.sandbox.v1.L7Allow.ParamsEntry
+ 31, // 18: openshell.sandbox.v1.GetGatewayConfigResponse.settings:type_name -> openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry
+ 20, // 19: openshell.sandbox.v1.EffectiveSetting.value:type_name -> openshell.sandbox.v1.SettingValue
+ 0, // 20: openshell.sandbox.v1.EffectiveSetting.scope:type_name -> openshell.sandbox.v1.SettingScope
+ 2, // 21: openshell.sandbox.v1.GetSandboxConfigResponse.policy:type_name -> openshell.sandbox.v1.SandboxPolicy
+ 32, // 22: openshell.sandbox.v1.GetSandboxConfigResponse.settings:type_name -> openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry
+ 1, // 23: openshell.sandbox.v1.GetSandboxConfigResponse.policy_source:type_name -> openshell.sandbox.v1.PolicySource
+ 23, // 24: openshell.sandbox.v1.GetSandboxConfigResponse.supervisor_middleware_services:type_name -> openshell.sandbox.v1.SupervisorMiddlewareService
+ 6, // 25: openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry.value:type_name -> openshell.sandbox.v1.NetworkPolicyRule
+ 7, // 26: openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry.value:type_name -> openshell.sandbox.v1.NetworkMiddlewareConfig
+ 11, // 27: openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry.value:type_name -> openshell.sandbox.v1.GraphqlOperation
+ 15, // 28: openshell.sandbox.v1.L7DenyRule.QueryEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher
+ 15, // 29: openshell.sandbox.v1.L7DenyRule.ParamsEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher
+ 15, // 30: openshell.sandbox.v1.L7Allow.QueryEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher
+ 15, // 31: openshell.sandbox.v1.L7Allow.ParamsEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher
+ 20, // 32: openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry.value:type_name -> openshell.sandbox.v1.SettingValue
+ 21, // 33: openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry.value:type_name -> openshell.sandbox.v1.EffectiveSetting
+ 34, // [34:34] is the sub-list for method output_type
+ 34, // [34:34] is the sub-list for method input_type
+ 34, // [34:34] is the sub-list for extension type_name
+ 34, // [34:34] is the sub-list for extension extendee
+ 0, // [0:34] 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
+ }
+ file_sandbox_proto_msgTypes[8].OneofWrappers = []any{}
+ file_sandbox_proto_msgTypes[18].OneofWrappers = []any{
+ (*SettingValue_StringValue)(nil),
+ (*SettingValue_BoolValue)(nil),
+ (*SettingValue_IntValue)(nil),
+ (*SettingValue_BytesValue)(nil),
+ }
+ 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: 2,
+ NumMessages: 31,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_sandbox_proto_goTypes,
+ DependencyIndexes: file_sandbox_proto_depIdxs,
+ EnumInfos: file_sandbox_proto_enumTypes,
+ MessageInfos: file_sandbox_proto_msgTypes,
+ }.Build()
+ File_sandbox_proto = out.File
+ file_sandbox_proto_goTypes = nil
+ file_sandbox_proto_depIdxs = nil
+}
diff --git a/tasks/ci.toml b/tasks/ci.toml
index a3ed236ae..7294da9d0 100644
--- a/tasks/ci.toml
+++ b/tasks/ci.toml
@@ -56,7 +56,7 @@ hide = true
[ci]
description = "Run full checks (lint, compile/type checks, and tests)"
-depends = ["lint", "check", "test"]
+depends = ["lint", "check", "test", "go:ci"]
[all]
description = "Alias for ci"
diff --git a/tasks/go.toml b/tasks/go.toml
new file mode 100644
index 000000000..2a80b9a49
--- /dev/null
+++ b/tasks/go.toml
@@ -0,0 +1,163 @@
+# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0
+
+# Go SDK development, build, lint, and format tasks
+
+["go:test"]
+description = "Run Go SDK unit tests with coverage"
+dir = "sdk/go"
+run = "go test -coverprofile=coverage.out -coverpkg=./openshell/... -race ./..."
+hide = true
+
+["go:test:integration"]
+description = "Run Go SDK integration tests"
+dir = "sdk/go"
+run = "go test -tags=integration -race ./..."
+hide = true
+
+["go:lint"]
+description = "Run Go SDK linter"
+dir = "sdk/go"
+run = "golangci-lint run ./..."
+hide = true
+
+["go:fmt"]
+description = "Format Go SDK code"
+dir = "sdk/go"
+run = "goimports -w . && go fmt ./..."
+hide = true
+
+["go:build"]
+description = "Build Go SDK packages"
+dir = "sdk/go"
+run = "go build ./..."
+hide = true
+
+["go:format:check"]
+description = "Verify Go SDK code is gofmt-formatted"
+dir = "sdk/go"
+run = """
+#!/usr/bin/env bash
+set -euo pipefail
+UNFORMATTED=$(gofmt -l . 2>/dev/null || true)
+if [ -n "$UNFORMATTED" ]; then
+ echo "ERROR: The following files are not gofmt-formatted:"
+ echo "$UNFORMATTED"
+ exit 1
+fi
+"""
+hide = true
+
+["go:ci"]
+description = "Run Go SDK full CI pipeline"
+depends = ["go:format:check", "go:lint", "go:build", "go:test", "go:proto:check", "go:docs:check"]
+
+["go:docs:check"]
+description = "Verify every public Go SDK package has a docs page"
+dir = "sdk/go"
+run = """
+#!/usr/bin/env bash
+set -euo pipefail
+
+DOCS_DIR="docs/src/api"
+SUMMARY="docs/src/SUMMARY.md"
+MISSING=0
+
+# Find all public packages with a doc.go (excluding internal, proto, types)
+for docfile in openshell/v1/*/doc.go; do
+ pkg=$(basename "$(dirname "$docfile")")
+
+ # Skip internal packages and types (no user-facing docs needed)
+ case "$pkg" in
+ internal|types) continue ;;
+ esac
+
+ # Check for matching docs page
+ if [ ! -f "$DOCS_DIR/$pkg.md" ]; then
+ echo "MISSING: $DOCS_DIR/$pkg.md (package openshell/v1/$pkg has doc.go but no docs page)"
+ MISSING=$((MISSING + 1))
+ fi
+
+ # Check for SUMMARY.md entry
+ if ! grep -q "api/$pkg.md" "$SUMMARY" 2>/dev/null; then
+ echo "MISSING: SUMMARY.md entry for api/$pkg.md"
+ MISSING=$((MISSING + 1))
+ fi
+done
+
+if [ "$MISSING" -gt 0 ]; then
+ echo ""
+ echo "ERROR: $MISSING documentation gaps found."
+ echo "Every public package with doc.go needs a docs/src/api/.md page"
+ echo "and a SUMMARY.md entry. See Constitution XIII."
+ exit 1
+fi
+
+echo "Docs check passed: all public packages have documentation."
+"""
+hide = true
+
+["go:proto:gen"]
+description = "Generate Go bindings from proto files using buf"
+dir = "sdk/go"
+run = """
+#!/usr/bin/env bash
+set -euo pipefail
+
+for tool in buf protoc-gen-go protoc-gen-go-grpc; do
+ if ! command -v "$tool" &>/dev/null; then
+ echo "ERROR: $tool not found. Run 'mise install' to install it."
+ exit 1
+ fi
+done
+
+# Clean previous output before regeneration
+find proto -name '*.pb.go' -delete 2>/dev/null || true
+
+buf generate
+
+echo "Proto generation complete."
+echo "Generated packages:"
+for pkg in openshellv1 datamodelv1 sandboxv1 optionsv1; do
+ count=$(find "proto/$pkg" -name '*.go' 2>/dev/null | wc -l | tr -d ' ')
+ echo " proto/$pkg/: $count files"
+done
+"""
+hide = true
+
+["go:proto:check"]
+description = "Verify generated Go SDK proto files are up to date"
+dir = "sdk/go"
+run = """
+#!/usr/bin/env bash
+set -euo pipefail
+
+for tool in buf protoc-gen-go protoc-gen-go-grpc; do
+ if ! command -v "$tool" &>/dev/null; then
+ echo "ERROR: $tool not found. Run 'mise install' to install it."
+ exit 1
+ fi
+done
+
+WORK_DIR=$(mktemp -d)
+trap 'rm -rf "$WORK_DIR"' EXIT
+
+# Generate to temp directory with adjusted output path
+sed "s|out: \\.|out: $WORK_DIR|" buf.gen.yaml > "$WORK_DIR/buf.gen.yaml"
+buf generate --template "$WORK_DIR/buf.gen.yaml"
+
+DIFF_OUTPUT=$(diff -r "$WORK_DIR/proto" "proto" \
+ --exclude="*.proto" \
+ 2>&1) || true
+
+if [ -n "$DIFF_OUTPUT" ]; then
+ echo "ERROR: Generated proto files are out of date."
+ echo "Run 'mise run go:proto:gen' to regenerate."
+ echo ""
+ echo "$DIFF_OUTPUT"
+ exit 1
+fi
+
+echo "Proto check passed: generated files are up to date."
+"""
+hide = true