Skip to content

feat(extensions): add Sondera policy guardrails [AI-assisted]#8448

Closed
joshdevon wants to merge 26 commits intoopenclaw:mainfrom
sondera-ai:sondera-pr
Closed

feat(extensions): add Sondera policy guardrails [AI-assisted]#8448
joshdevon wants to merge 26 commits intoopenclaw:mainfrom
sondera-ai:sondera-pr

Conversation

@joshdevon
Copy link

@joshdevon joshdevon commented Feb 4, 2026

Summary

Adds Sondera, a Cedar-based policy guardrails extension that enforces deterministic security rules on tool calls before they execute.

  • 103 rules across 3 policy packs: Sondera Base (41), OpenClaw System (24), OWASP Agentic
    (38)
  • Blocks dangerous commands (rm -rf, sudo, reverse shells), credential access, and data exfiltration
  • Redacts secrets (API keys, tokens) from session transcripts
  • Fail-closed evaluation: only explicit permit rules allow actions
  • Optional lockdown mode: block all tools unless explicitly permitted
  • User-configurable custom Cedar rules via Settings UI

Built by Sondera, powered by Cedar (AWS's policy language).

Related Work

This extension depends on plugin hooks landing. Complementary to the ongoing security work:

AI Disclosure 🤖

  • AI-assisted
  • Lightly tested against local OpenClaw instance
  • Team reviewed and understands the code

Test Plan

  • Install extension: openclaw plugins install @openclaw/sondera
  • Verify blocking: run sudo whoami in a session → "Blocked by Sondera policy"
  • Toggle policy packs in Settings UI
  • Test lockdown mode with custom permit rules

Greptile Overview

Greptile Summary

This PR adds the new extensions/sondera plugin, which evaluates Cedar policies (via @cedar-policy/cedar-wasm) to block risky tool calls pre-execution and redact sensitive tool outputs when persisting results. It also wires tool-call enforcement into the embedded runner by wrapping tool execute() to run before_tool_call hooks and throw a dedicated ToolBlockedError on blocks.

The extension is integrated using the existing plugin hook system (before_tool_call, after_tool_call, tool_result_persist) and exposes configuration (policy packs, lockdown mode, custom rules/path) via openclaw.plugin.json schema/UI hints.

Main issues to address before merge are around Cedar policy parsing robustness (regex-based parsing can skip/truncate real policies), edge cases in lockdown mode policy construction, and a couple of logger calls that can throw when debug isn’t present.

Confidence Score: 2/5

  • This PR is not safe to merge as-is because policy parsing/initialization issues can silently disable intended guardrails.
  • The core security value of the PR depends on Cedar policies being parsed and evaluated correctly. The current regex-based policy extraction can skip/truncate real-world when { ... } blocks, and lockdown mode can feed comment-only text as a “policy,” both of which can lead to missing rules or inconsistent behavior. There are also a couple of runtime footguns (logger debug calls without optional chaining; tool wrapping assumes execute exists) that can break hooks/session runs.
  • extensions/sondera/evaluator.ts, extensions/sondera/index.ts, src/agents/pi-embedded-runner/run/attempt.ts

(2/5) Greptile learns from your feedback when you react with thumbs up/down!

@openclaw-barnacle openclaw-barnacle bot added the agents Agent runtime and tooling label Feb 4, 2026
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

3 files reviewed, 6 comments

Edit Code Review Agent Settings | Greptile

@joshdevon
Copy link
Author

Greptile Issues Addressed

Fixed in commits ead6622 and 96cb792:

Issue Fix
P0 Lockdown mode comment-only Use empty policy set (Cedar implicit deny) instead of invalid comment string
P1 Logger debug calls Added ?. optional chaining to all 6 api.logger.debug calls
P1 evaluatePostTool diagnostics Use isRedactionPolicy() with naming convention (sondera-redact-*, owasp-redact-*) instead of special-casing default-allow
P1 wrapToolForHooks Added typeof tool.execute !== "function" guard

Also replaced regex-based Cedar policy parsing with native cedar.policySetTextToParts() and cedar.policyToJson()

APIs to properly handle nested braces and complex expressions.

Adds the Sondera extension which provides deterministic Cedar policy
guardrails for OpenClaw agents. Evaluates policies before tool execution
(PRE_TOOL) and redacts sensitive output (POST_TOOL).

- 41-rule Sondera base pack (dangerous commands, RCE, sensitive files)
- 24-rule OpenClaw system protection pack
- 38-rule OWASP Agentic pack (opt-in)
- Lockdown mode for block-by-default operation
- Custom rules support via config UI or expert mode file
- Change evaluator to fail-closed: only explicit "allow" permits
- Handle lockdown mode with no policy packs (Cedar default-deny)
- Add debug logging for config initialization
- Fix syntax error in policy-sondera-base.cedar
Replace regex-based policy parsing with Cedar's native
policySetTextToParts() and policyToJson() APIs. The regex [^}]*
stops at the first } character, breaking policies with } in
string patterns (e.g., like "*}*").

- evaluator.ts: Use policySetTextToParts() for robust parsing
- validate-cedar.ts: Use checkParsePolicySet() for validation
- Add error handling for parse failures

Fixes Greptile P0: regex truncation issue
- Lockdown mode: use empty policy set (Cedar implicit deny) instead of comment
- Add optional chaining to all logger.debug calls
- Use naming convention to identify redaction policies (sondera-redact-*, owasp-redact-*)
- Guard wrapToolForHooks against tools without execute function
- Remove unused catch parameter `err` in index.ts (3 instances)
- Rename unused `ctx` parameters to `_ctx` in hook callbacks
- Add curly braces to single-line if statement in evaluator.ts
- Use proper TypeScript types instead of `any` in wrapToolForHooks
- Fix template literal with unknown error type
…errors

The previous change to use `unknown` types broke type compatibility with
AnyAgentTool and ToolDefinition. Using `any` with explicit oxlint-disable
comments is appropriate here since we're wrapping tools with varying signatures.
On Windows, `new URL(import.meta.url).pathname` returns `/C:/path/...`
with a leading slash. When used with path.resolve, this creates invalid
paths like `C:\C:\...`. Using fileURLToPath from the url module correctly
handles cross-platform path conversion.
Add Sondera fork installation instructions with PR openclaw#8448 reference.
Matches blog post and Sondera docs for consistent guidance until
hooks are merged into mainline OpenClaw.
Resolve merge conflicts in pnpm-lock.yaml and
src/agents/pi-embedded-runner/run/attempt.ts
- Remove duplicate hookRunner declaration in attempt.ts
- Cast EvaluationContext to Cedar's Context type in evaluator.ts
- Guard against AgentMessage variants without content in index.ts
The formal_conformance job fails on fork PRs because GitHub restricts
the GITHUB_TOKEN to read-only for pull_request events from forks.
Add continue-on-error to the comment step so the job succeeds
gracefully — the drift artifact is still uploaded regardless.
The inferred return type of getSlackSlashMocks references @vitest/spy
internals which are not portable under pnpm strict node_modules.
Add an explicit return type annotation to prevent the error.
@openclaw-barnacle openclaw-barnacle bot added the channel: slack Channel integration: slack label Feb 15, 2026
- exec-approvals: add stripUndefinedFields to send.shared mock
- discord actions: remove stale loadHandleDiscordMessageAction call
- web/media: pass explicit localRoots to avoid os.tmpdir() overlap
# Conflicts:
#	src/discord/monitor/exec-approvals.test.ts
#	src/slack/monitor/slash.test-harness.ts
@openclaw-barnacle openclaw-barnacle bot added channel: whatsapp-web Channel integration: whatsapp-web and removed channel: slack Channel integration: slack labels Feb 15, 2026
On CI (Linux), file writes within the same second share the same mtime.
The session store cache uses mtime to detect stale entries, so when a
previous test caches the empty store and this test writes new data in
the same second, loadSessionStore returns stale cached data.

Clear the cache in beforeEach to ensure each test reads fresh data.
@openclaw-barnacle openclaw-barnacle bot added the channel: discord Channel integration: discord label Feb 15, 2026
On Windows, path.resolve("/tmp/...") produces "C:\tmp\..." which
doesn't match hardcoded Unix paths. Use path.resolve() in the
expected values so the test passes on all platforms.
@openclaw-barnacle openclaw-barnacle bot removed the commands Command implementations label Feb 16, 2026
@joshdevon joshdevon changed the title feat(extensions): add Sondera Cedar policy guardrails [AI-assisted] feat(extensions): add Sondera policy guardrails [AI-assisted] Feb 20, 2026
@openclaw-barnacle
Copy link

Please make this as a third-party plugin that you maintain yourself in your own repo. Docs: https://docs.openclaw.ai/plugin. Feel free to open a PR after to add it to our community plugins page: https://docs.openclaw.ai/plugins/community

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

Labels

agents Agent runtime and tooling channel: discord Channel integration: discord channel: whatsapp-web Channel integration: whatsapp-web r: third-party-extension size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants