Permission strategies - #79
Conversation
…port Introduce durable token enrollment, HTTPS mailbox and sidecar transport, and hardened Docker/Kubernetes deployment with address preflight and lifecycle controls. Persist remote task history and expose sandbox catalogs, credential publishing, deployment management, and runtime inspection through the API and web UI. BREAKING CHANGE: replace single-use git-agent join-token APIs and replay semantics with durable captain tokens; callers must use AdmitToken and context-aware enrollment.
…ions Add opt-in mirroring for Claude and Codex subscription logins with refresh-token redaction and expiry tracking. Publish credentials atomically to host directories or Kubernetes Secrets, refresh them from `serve`, and expose local-only status and sync controls. Wire acquired logins through sandbox isolation while centralizing token-provider selection and resolving model credentials from the Captain vault.
…n access Protect off-host API and git-agent requests with durable, revocable bearer tokens while preserving loopback access for the local UI and CLI. Add TLS certificate management and local-only command registration to prevent host-administering commands from being exposed through the REST executor. Persist hashed credentials with scoped, bound or pooled identities, expiry, revocation, and usage tracking. BREAKING CHANGE: Non-loopback requests to /api/v1 and /git now require a valid scoped Captain bearer token provisioned with `captain token create`.
Allow non-streaming workflow providers to satisfy the runner's event contract via buffered execution instead of failing. Add coverage for completed text and result events.
Every other configurable axis — model, effort, cliArgs, sandbox — is declared in the registry, served to clients, and guarded server-side. Permissions had none of that: any posture or per-tool policy could be written for any backend, and the mismatch surfaced only when a provider built argv, minutes into a run. Declare what each backend actually does with a permissions block: which postures it honours (native, approximated, or not at all, plus the argv or sandbox/approval pair each compiles to), which per-tool policies it can enforce, and which resources it can switch. Project it through RuntimeModeEntry and backends[] so clients read it from the static catalog rather than from a TTL-d probe, where an unprobed backend would appear to support nothing. Tool-policy capability is keyed by provenance, not by backend alone, because where a tool came from decides what is enforceable. Captain builds the caller-tool list itself and omits a denied tool, so deny is honoured on codex-agent — which has no tool filter of its own — while deny on a codex built-in is not. Resources are keyed by the value requested as well as the kind: MCP is only switchable off and skills only on, so one cell per kind would report "supported" for a request that is accepted and dropped. The table states what the code does today, warts included, and the tests prove it against CodexSafety, the three CLI arg builders, the cmux command builder and the claude-agent initialize params, so a mapper and its declaration cannot drift apart in silence. Claude-Session-Id: c3c29851-27f6-4cce-831d-ca61a67461d4
Tools and MCP carry every field as json:"-" behind hand-written marshalers, so
reflection reported {} for both — the two fields that decide what an agent may
do validated anything at all and told a client nothing. The permission enums
are plain string types, so they reflected to a bare string with no values,
which is why the editor grew its own hardcoded copies that then went stale.
Add invopop describers for PermissionMode, ToolPolicy, ResourceMode, Preset,
Tools, MCP and ResourcePolicies. ResourcePolicies also declares the legacy
string-array form it has always decoded, so a document using it no longer
fails validation against captain's own schema.
pkg/api hosts both invopop and clicky describer signatures and a type given
the wrong one is silently ignored; the rule is the consumer, so anything
reachable from api.Spec uses invopop.
Claude-Session-Id: c3c29851-27f6-4cce-831d-ca61a67461d4
Print the declared capability table so a silent drop is visible before a run is spent on it. Settings x backends, grouped one table per agent family: eleven backend names do not fit a terminal, and truncating them collapses claude-cli and claude-cmux into the same ambiguous header. Grouping also matches the question people actually ask — I picked claude, which transport honours this? Approximated cells get their own mark rather than rounding to yes or no; that conflation is what let dontAsk read as supported on codex, where it resolves to the read-only default. --notes prints the reason attached to every cell that is not honoured exactly. A separate namespace from sandbox presets, which already owns that word for container presets. Deliberately not excluded from REST/MCP auto-exposure: it reads a compile-time table and touches no host state. local_only_test pins POST /api/v1/permissions/matrix as the group's only route so a future mutating command cannot slip in beside it. The gavel fixture is the second pinning mechanism: 44 cases over the printed grid and the JSON, so a change to what captain does with a permissions block has to arrive as a reviewable diff to the declared truth. Claude-Session-Id: c3c29851-27f6-4cce-831d-ca61a67461d4
Claude-Session-Id: a317c3d6-1ab9-47ea-8118-4897be0ec96c
Runs that only touch git-ignored paths (scratch dirs) no longer fail over the caller's unrelated dirty files. committable() filters ignored paths; the refusal error lists only committable paths, improving diagnostic accuracy.
…ad of field access
…ations Carry the clicky RPCOperation whole on ToolInfo/ToolDefinition instead of flattening entity, verb, scope, method and path into a clicky/* annotation map that three call sites parsed back into typed fields. The key names no longer live twice, once as constants here and once as literals in clicky. Add PermissionStrategy with HTTPVerbStrategy and MCPHintStrategy — the first implementation of the ordered policy in #61. Authority resolves weakest to strongest: what a tool's own facts imply, what its author registered, then an operator's rules. At every layer 'auto' defers to the layer below rather than overriding it, so a rule can hand a tool back to its hints instead of being ignored. serve_chat's isReadOnlyCaptainTool becomes captainReadOnlyStrategy, declared in the chain where captain hands its command tree over, and ResolveOptions.Strategies threads it through the chat service.
|
Important Review skippedToo many files! This PR contains 273 files, which is 173 over the limit of 100. To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to a paid plan to raise the limit. This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (4)
📒 Files selected for processing (273)
You can disable this status message by setting the Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Gavel summary
Totals: 0 passed · 0 failed · 0 skipped · - |
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
Gavel summary
Totals: 3649 passed · 3 failed · 11 skipped · 2m42s Failing testsginkgo Timeout'/home/runner/work/captain/captain/.ginkgo/ginkgo-report-.-pkg-cli-1787499075454719582.json' not found gitagent_e2e_test.go:347: serve exited before listening (exit status 1): |
No description provided.