Files
OpenShell/proto/gateway_interceptor.proto
Seth Jennings 2493d415c2 feat(extensions)!: normalize protocol negotiation (#3352)
* feat(extensions)!: normalize protocol negotiation

Closes #3057

Introduce a shared extension handshake, enforce protocol and capability compatibility across extension families, and expose immutable negotiated snapshots through gateway info and the Go SDK.

Signed-off-by: Seth Jennings <sjenning@redhat.com>

* fix(credentials): fail fast on negotiation errors

Signed-off-by: Seth Jennings <sjenning@redhat.com>

* fix(extensions): validate gateway handshake metadata

Signed-off-by: Seth Jennings <sjenning@redhat.com>

* fix(go-sdk): re-export extension kind constants

Signed-off-by: Seth Jennings <sjenning@redhat.com>

* fix(extensions): fail fast on credential handshake rejection

Signed-off-by: Seth Jennings <sjenning@redhat.com>

---------

Signed-off-by: Seth Jennings <sjenning@redhat.com>
2026-09-21 13:19:39 -07:00

152 lines
5.5 KiB
Protocol Buffer

// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
syntax = "proto3";
package openshell.gateway_interceptor.v1;
import "google/protobuf/struct.proto";
import "extension.proto";
import "openshell.proto";
// GatewayInterceptor lets an external governance service evaluate gateway
// control-plane operations after OpenShell admission and before or after the
// gateway applies the operation.
service GatewayInterceptor {
// Describe returns the interceptor manifest and declared bindings.
rpc Describe(DescribeRequest) returns (InterceptorManifest);
// SnapshotProviderProfiles returns the interceptor's current provider
// profile snapshot when the manifest advertises provider_profiles = true.
rpc SnapshotProviderProfiles(ProviderProfileSnapshotRequest)
returns (ProviderProfileSnapshot);
// Evaluate returns an allow, deny, or mutation decision for one operation
// phase.
rpc Evaluate(InterceptorEvaluation) returns (InterceptorResult);
}
message DescribeRequest {
// Gateway protocol metadata. Interceptors must reject unmet requirements.
openshell.extension.v1.PeerMetadata gateway = 1;
}
message ProviderProfileSnapshotRequest {}
enum GatewayInterceptorPhase {
GATEWAY_INTERCEPTOR_PHASE_UNSPECIFIED = 0;
GATEWAY_INTERCEPTOR_PHASE_MODIFY_OPERATION = 2;
GATEWAY_INTERCEPTOR_PHASE_VALIDATE = 3;
GATEWAY_INTERCEPTOR_PHASE_POST_COMMIT = 4;
}
message InterceptorEvaluation {
// Configured interceptor instance name.
string interceptor_name = 1;
// Manifest binding id selected for this evaluation.
string binding_id = 2;
// Public gRPC service name, e.g. "openshell.v1.OpenShell".
string service = 3;
// Public gRPC method name, e.g. "CreateSandbox".
string method = 4;
// Caller identity summary. Values are intentionally non-secret.
map<string, string> principal = 5;
// Exactly one phase payload is set for each evaluation.
oneof phase {
// Evaluation that may modify the prepared gateway operation.
ModifyOperationEvaluation modify_operation = 6;
// Evaluation that may reject, but not mutate, the prepared operation.
ValidateEvaluation validate = 7;
// Evaluation after the gateway operation has completed successfully.
PostCommitEvaluation post_commit = 8;
}
}
message ModifyOperationEvaluation {
// Gateway-prepared operation the gateway proposes to execute.
google.protobuf.Struct proposed_operation = 1;
}
message ValidateEvaluation {
// Gateway-prepared operation after earlier interceptor modifications.
google.protobuf.Struct proposed_operation = 1;
// Optional read-only gateway state loaded before applying the operation.
google.protobuf.Struct current_state = 2;
}
message PostCommitEvaluation {
// Protobuf JSON-shaped response returned by the committed gateway operation.
google.protobuf.Struct committed_response = 1;
}
message InterceptorResult {
// False denies the operation before side effects for modify_operation and
// validate. Post-commit denial is invalid.
bool allowed = 1;
// Human-readable reason for logs and denied gRPC status messages.
string reason = 2;
// Optional gRPC status code name for denials, e.g. "PERMISSION_DENIED".
string status_code = 3;
// RFC 6902 JSON patches. Only valid during modify_operation.
repeated JsonPatch patches = 4;
// Non-secret annotations included in gateway logs.
map<string, string> log_annotations = 5;
}
message InterceptorManifest {
// Human-readable interceptor name declared by the service.
string name = 1;
// Bindings declared by the interceptor service.
repeated InterceptorBinding bindings = 2;
// Optional default failure policy for bindings without their own policy.
// Supported values are "fail_closed" and "fail_open".
string failure_policy = 3;
// True when this interceptor implements SnapshotProviderProfiles.
bool provider_profiles = 4;
// Exact JWT audience this service verifies on inbound OpenShell calls.
// After authenticated Describe succeeds, the gateway refuses to start unless
// this matches the operator-configured audience. A strict verifier may reject
// an incorrect audience before returning this manifest. Empty skips this
// post-authentication consistency check.
string expected_audience = 5;
// Gateway-interceptor protocol metadata. Required for negotiation.
openshell.extension.v1.PeerMetadata extension = 6;
}
message ProviderProfileSnapshot {
// Opaque source revision used for cache freshness and sandbox reload checks.
string revision = 1;
// Complete profile snapshot vended by this source.
repeated openshell.v1.ProviderProfile profiles = 2;
}
message InterceptorBinding {
// Stable binding id used for config overrides and audit logs.
string id = 1;
// RPC selector. Selectors are intentionally tied to the public API shape.
InterceptorSelector selector = 2;
// Phases this binding wants to evaluate.
repeated GatewayInterceptorPhase phases = 3;
// Optional binding-specific failure policy.
// Supported values are "fail_closed" and "fail_open".
// Bindings that include post_commit must resolve to "fail_open" because the
// gateway operation has already committed before that phase runs.
string failure_policy = 4;
}
message InterceptorSelector {
// Full selector form: "openshell.v1.OpenShell/CreateSandbox".
string rpc = 1;
// Structured service/method form. If rpc is set, it takes precedence.
string service = 2;
string method = 3;
}
message JsonPatch {
string op = 1;
string path = 2;
google.protobuf.Value value = 3;
string from = 4;
}