Skip to content

Add runtime policy, revocation, and audit correlation for generated tools#2547

Open
vaddisrinivas wants to merge 1 commit into
tinyhumansai:mainfrom
vaddisrinivas:codex/oh-2543-generated-tool-runtime-policy
Open

Add runtime policy, revocation, and audit correlation for generated tools#2547
vaddisrinivas wants to merge 1 commit into
tinyhumansai:mainfrom
vaddisrinivas:codex/oh-2543-generated-tool-runtime-policy

Conversation

@vaddisrinivas
Copy link
Copy Markdown
Contributor

@vaddisrinivas vaddisrinivas commented May 23, 2026

Summary

  • Add generated-tool runtime context to tool-policy requests.
  • Add a generic runtime policy that can allow, require approval, or deny by provider, capability, or risk.
  • Add generated-tool audit correlation fields for provider, capability, policy decision, and approval ID.

Problem

  • Generated capability tools need runtime enforcement after admission, including revocation and audit correlation, without hard-coding any one external provider or package format.
  • Existing policy decisions only modeled allow/deny, so callers could not express a policy-mandated approval state.

Solution

  • Extend ToolPolicyRequest with optional GeneratedToolRuntimeContext.
  • Add ToolPolicyDecision::RequireApproval and a shared blocking_reason helper so the existing session runner blocks non-allow decisions.
  • Add GeneratedToolRuntimePolicy and structured generated-tool audit helpers while preserving the default allow-all policy.

Submission Checklist

  • Tests added or updated (happy path + at least one failure / edge case) per Testing Strategy: disabled policy allow path, revoked provider, revoked capability, risk approval, and audit correlation fields.
  • Diff coverage ≥ 80% — local full coverage not run; focused Rust tests cover the changed modules and CI coverage gate will enforce final diff coverage.
  • Coverage matrix updated — N/A: generic policy/audit infrastructure, no existing feature row added/removed/renamed.
  • All affected feature IDs from the matrix are listed in the PR description under ## Related: N/A, no coverage-matrix feature ID applies.
  • No new external network dependencies introduced (mock backend used per Testing Strategy): no network dependency added.
  • Manual smoke checklist updated if this touches release-cut surfaces (docs/RELEASE-MANUAL-SMOKE.md): N/A, no release-cut UI/runtime smoke surface changed.
  • Linked issue closed via Closes #NNN in the ## Related section.

Impact

  • Runtime/platform impact: policy-aware callers can pass generated-tool context and enforce revocations before execution.
  • Security impact: enables runtime provider/capability/risk policy gates and audit correlation for generated capability tools.
  • Compatibility: default policy and requests without generated-tool context retain existing behavior.

Related


AI Authored PR Metadata (required for Codex/Linear PRs)

Linear Issue

Commit & Branch

  • Branch: codex/oh-2543-generated-tool-runtime-policy
  • Commit SHA: 4b144df2e542c25190a4853a18a650d0c97fdd8b

Validation Run

  • pnpm --filter openhuman-app format:check: N/A, Rust-only backend policy/audit change.
  • pnpm typecheck: N/A, Rust-only backend policy/audit change.
  • Focused tests: cargo test --manifest-path Cargo.toml generated_runtime_policy --lib; cargo test --manifest-path Cargo.toml audit_log_generated_tool --lib
  • Rust fmt/check (if changed): cargo fmt --manifest-path Cargo.toml --all --check; git diff --check
  • Tauri fmt/check (if changed): N/A, no Tauri code changed.
  • PR checklist: node scripts/check-pr-checklist.mjs /tmp/openhuman-pr-body-2543.md

Validation Blocked

  • command: N/A
  • error: N/A
  • impact: N/A

Behavior Changes

  • Intended behavior change: callers can model generated-tool runtime policy outcomes including approval-required decisions.
  • User-visible effect: None by default; allow-all policy remains unchanged unless callers install the stricter policy and context.

Parity Contract

  • Legacy behavior preserved: yes, requests without generated-tool context and the default allow-all policy behave as before.
  • Guard/fallback/dispatch parity checks: non-allow decisions are blocked before tool execution, matching existing denial placement.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): None found for vaddisrinivas:codex/oh-2543-generated-tool-runtime-policy.
  • Canonical PR: this PR.
  • Resolution (closed/superseded/updated): N/A.

Summary by CodeRabbit

  • New Features
    • Added generated tool runtime policy system with configurable risk-based decision making and revocation controls.
    • Introduced approval workflow support for tool execution with dedicated tracking and metadata capture.
    • Enhanced audit logging to record provider, capability, risk level, and approval details for tool execution events.

Review Change Stack

@vaddisrinivas vaddisrinivas requested a review from a team May 23, 2026 15:46
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 23, 2026

📝 Walkthrough

Walkthrough

This PR implements runtime policy enforcement and audit correlation for generated tools. It adds configurable provider/capability revocation, risk-based action mappings, and decision variants (Allow, RequireApproval, Deny) in the policy layer; refactors tool execution to extract denial/approval reasons; and extends audit logging to correlate policy decisions and approval IDs with tool execution events.

Changes

Generated Tool Policy and Audit

Layer / File(s) Summary
Policy types and generated-tool enforcement logic
src/openhuman/agent/tool_policy.rs
ToolPolicyRequest carries optional GeneratedToolRuntimeContext (provider/capability/risk/approval identifiers). ToolPolicyDecision gains RequireApproval { reason } variant and blocking_reason() extraction helper. GeneratedToolRuntimePolicy implements revocation lists by provider/capability and action mappings by provider/capability/risk, with precedence: revoked first, then mappings, else allow. Tests cover disabled allow, revoked provider/capability denial, and risk-based approval.
Policy decision extraction in tool execution
src/openhuman/agent/harness/session/turn.rs
Agent::execute_tool_call calls policy_decision.blocking_reason() instead of matching Deny enum variant to detect and report denials uniformly. Imports simplified to remove ToolPolicyDecision.
Audit metadata and generated-tool event logging
src/openhuman/security/audit.rs
Action audit struct gains optional provider_id, capability_id, policy_decision, approval_id fields (serialized only when set). GeneratedToolExecutionLog<'a> struct carries generated-tool correlation metadata. AuditEvent::with_generated_tool_action builder and AuditLogger::log_generated_tool_event method populate and log generated-tool events with full correlation. Test verifies serialization includes all metadata.

Sequence Diagram

sequenceDiagram
    participant Agent as Agent::execute_tool_call
    participant Policy as GeneratedToolRuntimePolicy
    participant Decision as ToolPolicyDecision
    participant Audit as AuditLogger
    Agent->>Policy: check(request + generated_tool context)
    Policy->>Decision: Allow / RequireApproval / Deny
    Decision->>Agent: decision with optional reason
    Agent->>Agent: blocking_reason() → check denial/approval
    alt blocked or requires approval
        Agent->>Audit: log_generated_tool_event(provider, capability, policy_decision, approval_id)
    else allowed
        Agent->>Agent: proceed with execution
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • tinyhumansai/openhuman#2334: Both PRs modify ToolPolicyRequest in tool_policy.rs and update policy handling in session/turn.rs to thread context through tool-policy checks.
  • tinyhumansai/openhuman#2137: Both PRs enhance ToolPolicyDecision and its extraction in Agent::execute_tool_call, building on the middleware-style policy enforcement introduced there.

Suggested labels

agent, feature, rust-core

Suggested reviewers

  • graycyrus
  • senamakel

Poem

🐰 A rabbit hops through policy gates,
Checking who calls, what they create.
Approvals logged in audit's glow,
Each tool's trust now laid bare for all to know!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: adding runtime policy, revocation, and audit correlation for generated tools, matching the core objectives across all three modified files.
Linked Issues check ✅ Passed The PR implements all key objectives from #2543: runtime policy with allow/deny/approval outcomes, provider/capability revocation, audit correlation fields, structured reasons, backward compatibility, and focused tests.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the linked issue #2543: tool policy enhancements, audit field additions, and agent integration—no unrelated modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 88.89% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. agent Built-in agents, prompts, orchestration, and agent runtime in src/openhuman/agent/. labels May 23, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/openhuman/agent/tool_policy.rs (1)

236-310: ⚡ Quick win

Add branch-level debug tracing for runtime policy decisions.

At Lines 236-310, generated-tool policy evaluation has multiple enforcement branches (revoked provider/capability, provider/capability/risk mappings, default allow) but emits no local debug/trace diagnostics, which makes runtime policy outcomes hard to audit during incidents.

♻️ Suggested patch
 impl GeneratedToolRuntimePolicy {
@@
     fn action_for(
         &self,
         tool_name: &str,
         context: &GeneratedToolRuntimeContext,
     ) -> (RuntimeToolPolicyAction, String) {
@@
-        if let Some(action) = self.config.risk_actions.get(&context.risk) {
+        if let Some(action) = self.config.risk_actions.get(&context.risk) {
             return (
                 *action,
                 format!("risk `{:?}` matched runtime policy", context.risk),
             );
         }
         (
             RuntimeToolPolicyAction::Allow,
             format!("tool `{tool_name}` allowed"),
         )
     }
 }
@@
     async fn check(&self, request: &ToolPolicyRequest) -> ToolPolicyDecision {
         if !self.config.enabled {
+            tracing::trace!(
+                policy = self.name(),
+                tool = request.tool_name.as_str(),
+                "[rpc] generated tool runtime policy disabled; allowing"
+            );
             return ToolPolicyDecision::Allow;
         }
         let Some(context) = request.generated_tool.as_ref() else {
+            tracing::trace!(
+                policy = self.name(),
+                tool = request.tool_name.as_str(),
+                "[rpc] generated tool context missing; allowing"
+            );
             return ToolPolicyDecision::Allow;
         };
         let (action, reason) = self.action_for(&request.tool_name, context);
+        tracing::debug!(
+            policy = self.name(),
+            tool = request.tool_name.as_str(),
+            provider_id = context.provider_id.as_str(),
+            capability_id = context.capability_id.as_str(),
+            risk = ?context.risk,
+            action = ?action,
+            reason = reason.as_str(),
+            "[rpc] generated tool runtime policy decision"
+        );
         match action {
             RuntimeToolPolicyAction::Allow => ToolPolicyDecision::Allow,
             RuntimeToolPolicyAction::RequireApproval => {
                 ToolPolicyDecision::require_approval(reason)
             }
             RuntimeToolPolicyAction::Deny => ToolPolicyDecision::deny(reason),
         }
     }
 }

As per coding guidelines: "Use log / tracing at debug or trace level on ... state transitions, and any branch that is hard to infer from tests alone."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/openhuman/agent/tool_policy.rs` around lines 236 - 310, The
action_for/check flow in GeneratedToolRuntimePolicy lacks branch-level debug
tracing; add debug or trace logs inside GeneratedToolRuntimePolicy::action_for
for each branch (revoked provider, revoked capability, capability_actions hit,
provider_actions hit, risk_actions hit, and default allow) emitting the chosen
RuntimeToolPolicyAction, the formatted reason, tool_name, context.provider_id,
context.capability_id, and context.risk as appropriate, and also log the final
decision in GeneratedToolRuntimePolicy::check right before returning the
ToolPolicyDecision (use ToolPolicyDecision::require_approval / deny / Allow
paths); reference the action_for function, the RuntimeToolPolicyAction enum, and
the check method to locate insertion points.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/openhuman/agent/harness/session/turn.rs`:
- Around line 1202-1205: The policy check is using ToolPolicyRequest::new which
leaves generated_tool as None so generated-tool runtime policy rules never run;
before calling self.tool_policy.check(&policy_request).await, populate the
request's generated_tool context (e.g., via the request builder/constructor that
accepts generated tool metadata or by setting the generated_tool field on the
ToolPolicyRequest you created) so the generated-tool runtime policy (revoked
provider/capability/risk action mappings) is available to the check; update the
code path around ToolPolicyRequest::new and the call site of
self.tool_policy.check to pass the generated tool context into the request.

---

Nitpick comments:
In `@src/openhuman/agent/tool_policy.rs`:
- Around line 236-310: The action_for/check flow in GeneratedToolRuntimePolicy
lacks branch-level debug tracing; add debug or trace logs inside
GeneratedToolRuntimePolicy::action_for for each branch (revoked provider,
revoked capability, capability_actions hit, provider_actions hit, risk_actions
hit, and default allow) emitting the chosen RuntimeToolPolicyAction, the
formatted reason, tool_name, context.provider_id, context.capability_id, and
context.risk as appropriate, and also log the final decision in
GeneratedToolRuntimePolicy::check right before returning the ToolPolicyDecision
(use ToolPolicyDecision::require_approval / deny / Allow paths); reference the
action_for function, the RuntimeToolPolicyAction enum, and the check method to
locate insertion points.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e9224089-8318-4a32-ba09-0fbac4e981b7

📥 Commits

Reviewing files that changed from the base of the PR and between f8c9698 and 4b144df.

📒 Files selected for processing (3)
  • src/openhuman/agent/harness/session/turn.rs
  • src/openhuman/agent/tool_policy.rs
  • src/openhuman/security/audit.rs

Comment on lines 1202 to +1205
let policy_request =
ToolPolicyRequest::new(call.name.clone(), call.arguments.clone(), context);
if let ToolPolicyDecision::Deny { reason } =
self.tool_policy.check(&policy_request).await
{
let policy_decision = self.tool_policy.check(&policy_request).await;
if let Some(reason) = policy_decision.blocking_reason() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Generated-tool runtime policy context is not wired into this policy check.

At Line 1203, ToolPolicyRequest::new(...) is used without attaching generated-tool context before self.tool_policy.check(...). Since ToolPolicyRequest::new initializes generated_tool to None, generated runtime policy rules (revoked provider/capability/risk action mapping) cannot execute on this path.

🐛 Suggested direction
-                let policy_request =
-                    ToolPolicyRequest::new(call.name.clone(), call.arguments.clone(), context);
+                let mut policy_request =
+                    ToolPolicyRequest::new(call.name.clone(), call.arguments.clone(), context);
+                // Populate from parsed generated-tool metadata when available.
+                if let Some(generated_ctx) = /* extract GeneratedToolRuntimeContext from call/tool metadata */ {
+                    policy_request = policy_request.with_generated_tool_context(generated_ctx);
+                }
                 let policy_decision = self.tool_policy.check(&policy_request).await;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/openhuman/agent/harness/session/turn.rs` around lines 1202 - 1205, The
policy check is using ToolPolicyRequest::new which leaves generated_tool as None
so generated-tool runtime policy rules never run; before calling
self.tool_policy.check(&policy_request).await, populate the request's
generated_tool context (e.g., via the request builder/constructor that accepts
generated tool metadata or by setting the generated_tool field on the
ToolPolicyRequest you created) so the generated-tool runtime policy (revoked
provider/capability/risk action mappings) is available to the check; update the
code path around ToolPolicyRequest::new and the call site of
self.tool_policy.check to pass the generated tool context into the request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent Built-in agents, prompts, orchestration, and agent runtime in src/openhuman/agent/. feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add runtime policy, revocation, and audit correlation for generated tools

1 participant