Skip to content

Commit 505d293

Browse files
committed
fix(server): make GetDraftPolicy dual-auth so /wait works under OIDC
policy.local calls GetDraftPolicy from inside the sandbox supervisor via the sandbox gRPC client, which authenticates with the shared x-sandbox-secret. GetDraftPolicy was listed only in the Bearer-auth scope table (config:read) and was not in SANDBOX_SECRET_METHODS or DUAL_AUTH_METHODS, so OIDC-enabled gateways rejected those calls and the /wait long-poll surfaced gateway_lookup_failed. Local/no-OIDC setups happened to work because the auth check is short-circuited. Add GetDraftPolicy to DUAL_AUTH_METHODS, matching the existing GetSandboxConfig pattern (called by both CLI reviewer surfaces with Bearer and the sandbox supervisor with x-sandbox-secret). Dual-auth short-circuits the scope check for sandbox-secret callers, so the config:read entry in authz.rs continues to gate Bearer-only flows. Mirror the openshell_get_sandbox_config_is_dual_auth assertion for GetDraftPolicy. Note: ssh_handshake_secret is server-wide, not per-sandbox, so a sandbox-secret caller can today name any sandbox in a SubmitPolicyAnalysis request — and now in a GetDraftPolicy request. The exposure is symmetric with the existing SANDBOX_SECRET_METHODS pattern. Filed as a follow-up: per-sandbox secret binding, tracked separately. Signed-off-by: Alexander Watson <zredlined@gmail.com>
1 parent 574c806 commit 505d293

1 file changed

Lines changed: 19 additions & 0 deletions

File tree

  • crates/openshell-server/src/auth

crates/openshell-server/src/auth/oidc.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,13 @@ const SANDBOX_SECRET_METHODS: &[&str] = &[
5656
/// (policy/settings mutations) and the sandbox supervisor (policy sync on
5757
/// startup). `OpenShell/GetSandboxConfig` serves CLI settings reads while
5858
/// remaining compatible with sandbox-secret-authenticated callers.
59+
/// `GetDraftPolicy` serves CLI reviewer surfaces (`openshell rule get`,
60+
/// TUI inbox) AND the sandbox-side `policy.local /wait` long-poll that
61+
/// blocks on the agent's proposal until the developer decides.
5962
const DUAL_AUTH_METHODS: &[&str] = &[
6063
"/openshell.v1.OpenShell/UpdateConfig",
6164
"/openshell.v1.OpenShell/GetSandboxConfig",
65+
"/openshell.v1.OpenShell/GetDraftPolicy",
6266
];
6367

6468
/// Returns `true` if the method accepts either Bearer or sandbox-secret auth.
@@ -495,6 +499,21 @@ mod tests {
495499
));
496500
}
497501

502+
#[test]
503+
fn openshell_get_draft_policy_is_dual_auth() {
504+
// policy.local calls GetDraftPolicy with x-sandbox-secret (from
505+
// inside the sandbox supervisor), and the CLI/TUI reviewer
506+
// surfaces call it with an OIDC Bearer. Sandbox-secret-only
507+
// would lock CLI out; Bearer-only would 401 the /wait long-poll
508+
// in OIDC-enabled deployments.
509+
assert!(!is_sandbox_secret_method(
510+
"/openshell.v1.OpenShell/GetDraftPolicy"
511+
));
512+
assert!(is_dual_auth_method(
513+
"/openshell.v1.OpenShell/GetDraftPolicy"
514+
));
515+
}
516+
498517
#[test]
499518
fn sandbox_secret_validation() {
500519
let mut headers = http::HeaderMap::new();

0 commit comments

Comments
 (0)