Skip to content

feat(rpc): impl pledge/set + pledge/clear (#228)#289

Merged
Destynova2 merged 1 commit intomainfrom
feat/rpc-pledge-228
Apr 26, 2026
Merged

feat(rpc): impl pledge/set + pledge/clear (#228)#289
Destynova2 merged 1 commit intomainfrom
feat/rpc-pledge-228

Conversation

@Destynova2
Copy link
Copy Markdown
Contributor

Summary

Replaces the TODO(#228) stubs in server::rpc::pledge_ns::set and clear with working in-memory mutations of config.pledge. Follows the P1 (config) / P2 (tools) pattern.

Behaviour

  • set(profile, source):
    • When source is Some, upserts a PledgeRule { source, profile } (replaces any rule with the same source).
    • When source is None, replaces config.pledge.default_profile.
    • Always flips config.pledge.enabled = true.
  • clear() drops all rules and resets default_profile to full.
  • Profile names validated against the built-in catalogue (read_only, execute, full, none).
  • Disk persistence out of scope per Runtime config mutation for RPC namespaces (7 TODOs) #228.

Mutation logic split into pure sync helpers (apply_set, apply_clear, is_known_profile) for unit testability without an AppState.

Tests — 11/11 passing

set_default_profile_with_no_source, set_per_source_appends_rule, set_per_source_upserts_existing, set_rejects_unknown_profile, set_rejects_empty_profile, set_rejects_empty_source, clear_drops_rules_and_resets_default, require_role_denies_observer_for_admin_methods + 3 pre-existing PledgeProfileInfo tests.

Test plan

  • cargo nextest run -E 'test(pledge_ns)' --features mcp — 11/11
  • cargo fmt --all -- --check clean
  • cargo clippy --all-features -- -D warnings clean
  • CI: full suite

Implements P3 of the cli-forge-chef brigade plan for #228. P4 (hit) follows.

🤖 Generated with Claude Code

Replaces the `TODO(#228)` stubs in `server::rpc::pledge_ns::set` and
`clear` with working in-memory mutations of `config.pledge`. Follows
the P1/P2 pattern (atomic state swap, no disk persistence).

Behaviour:
- `set(profile, source)`: upserts a per-source rule, or replaces the
  default profile when source is None. Always flips
  `config.pledge.enabled = true`.
- `clear()` drops all rules and resets `default_profile` to `full`.
- Profile names validated against the built-in catalogue
  (read_only, execute, full, none).
- Disk persistence out of scope per #228.

Mutation logic split into pure sync helpers `apply_set` / `apply_clear`
+ `is_known_profile` for unit testability without an `AppState`.

# Errors

- `ERR_FORBIDDEN` when the caller is below `Admin`.
- `INVALID_PARAMS_CODE` for empty profile, unknown profile, empty source.
- `ERR_INTERNAL` when the registry rebuild or atomic swap fails.

Tests: 11/11 passing.

Implements P3 of the cli-forge-chef brigade plan for #228.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Destynova2 Destynova2 enabled auto-merge April 26, 2026 16:38
@Destynova2 Destynova2 merged commit f825752 into main Apr 26, 2026
42 checks passed
@Destynova2 Destynova2 deleted the feat/rpc-pledge-228 branch April 26, 2026 16:50
Destynova2 pushed a commit that referenced this pull request Apr 26, 2026
…228)

Replaces the two `TODO(#228)` stubs in `server::rpc::hit_ns::set_policy`
and `resolve` with working implementations. Closes the last of the four
RPC namespaces tracked by issue #228.

set_policy(name, policy_json):
- Deserializes the JSON payload into `PolicyConfig`.
- The `name` argument always wins over `policy.name` (path-vs-payload).
- Upserts in `config.policies` (replace if same name, append otherwise).
- Compiles a fresh `PolicyMatcher` BEFORE the swap so a malformed glob
  is rejected without dirtying the running registry.
- Atomic-swaps the ReloadableState; the matcher is rebuilt by
  `ReloadableState::new`, so the new policy is live before the RPC
  returns.

resolve(context):
- Builds a `RequestContext` field-by-field from a JSON object (the type
  has no Deserialize derive — it is constructed imperatively in the
  dispatch path; we keep parity here).
- Missing fields fall back to permissive defaults so a partial probe
  ("just match on model") still works.
- Calls `PolicyMatcher::evaluate` and projects the merged
  `ResolvedPolicy` to JSON for transport.

Both functions are gated on `#[cfg(feature = "policies")]` with a
graceful no-op fallback when the feature is off.

# Errors

- `ERR_FORBIDDEN` when the caller is below `Admin` (set_policy) or
  `Operator` (resolve).
- `INVALID_PARAMS_CODE` for empty name, malformed policy JSON,
  malformed glob in match_rules, non-object context.
- `ERR_INTERNAL` when the registry rebuild or atomic swap fails.

Tests: 10/10 passing.

Implements P4 of the cli-forge-chef brigade plan for #228.
With #286 (P1), #287 (P2), #289 (P3), #228 closes when this lands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant