You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Release 1.0.13: OpenClaw enforcement on 2026.9.6+, daemon setup on Fedora/RHEL - #958
Combines #956 and #957 into one branch and prepares it for the stable 1.0.13 release. Supersedes both: they can be closed once this merges.
What ships
#956: OpenClaw enforcement works again on OpenClaw 2026.9.6 and later. Those releases load plugins from a captured copy that holds only the plugin's own directory, so the plugin's relative path to the CLI pointed at nothing and every tool call was silently allowed. The plugin now asks failproofaid over its Unix socket, as the Hermes plugin does, sending the same hook request the CLI's --hook path sends. It is daemon-only, like Hermes: install refuses without a daemon, and a missing or malformed verdict blocks tool calls and prompts instead of allowing them. Shipped as 1.0.13-beta.1. It was checked on 13 OpenClaw releases from 2026.7.1 to 2026.10.10-beta.4 (table in #956), and the beta was run end to end on a real machine: clean uninstall, install, allow, the always-on guard block, an enabled-policy block, dashboard activity, fail-closed with the daemon stopped, and the OpenClaw chat UI. All passed.
#957: failproofai config works on Fedora, RHEL, Rocky and Alma. SELinux does not let systemd execute a binary in a home directory, so the unit now runs a root-owned copy staged under /opt/failproofai/<user>/bin.
New here: the manual root recipes quote every path. When sudo is not available, config and uninstall print commands to run by hand. Since the /opt change those carried unquoted paths. A home directory with a space split sudo install -m 0755 <binary> <target> into extra words, failing the &&-joined recipe before the unit was written, and the removal recipe's sudo rm -rf <dir> could be pointed at another path. The existing shellQuote() moves to src/hooks/shell-quote.ts, and every path in both recipes goes through it. This was raised by the Hermes (Medium/High) and CodeRabbit reviews of #957.
Release preparation
package.json, the Cargo workspace version, the workspace crates in Cargo.lock and hermes-plugin/plugin.yaml are all 1.0.13, moved together as publish.yml's bump does.
scripts/release-announcement.mjs --version 1.0.13 --check passes from the changelog alone: 1.0.13 has release notes (11 entries). That is the preflight check a stable release runs, so the release can be published without hand-written notes.
failproofai@1.0.13 is not on npm yet.
Publishing after merge
A stable release is cut by publishing a GitHub Release on main, and only the logins in STABLE_RELEASE_ACTORS (publish.yml) can authorize one:
publish.yml then builds the four daemon binaries, attaches them, publishes at latest, announces, and bumps main to 1.0.14-beta.0. With an empty release body the notes come from the 1.0.13 changelog section; passing --notes-file <file> publishes hand-written notes instead.
Testing
Unit: bun run test:run, 426 files and 8,795 tests passed (11 skipped). E2E: bun run test:e2e, 364 passed (1 skipped). tsc --noEmit is clean, and eslint has 0 errors (5 warnings that already exist on main).
New tests: __tests__/hooks/shell-quote.test.ts checks the helper against a real sh, including $(), backticks, ; and a literal '. A daemon-service test drives the real install path under a home directory with a space and fails on the unquoted recipe. The uninstall-cli recipe expectation is updated to the quoted form.
The merges themselves were clean: only the two version bumps and the changelog conflicted, and the release commit replaces both.
Left for follow-ups
CodeRabbit (Minor, fix(daemon): run the systemd unit from /opt so setup works on Fedora/RHEL #957): remove a staged /opt binary when writing the unit fails afterwards. Not done here. The staged file is versioned and may be exactly the one a running unit uses, so deleting it on a failed write risks taking out a live daemon's binary. Today the leftover is a stray root-owned file that the next successful install prunes.
CodeRabbit (fix(openclaw): get verdicts from the daemon socket instead of spawning the CLI #956): report a refused daemon-only install as INCONCLUSIVE in the canary. Declined. That path only runs on the live-daemon leg, where a refusal means users could not enable enforcement, so a red FAIL is the right signal. The reason is printed next to the verdicts.
Reviewed the complete PR. OpenClaw now fails closed through the daemon socket and Linux service installation stages a system-owned binary. One low-severity uninstall cleanup gap remains.
Changes
Replaced the OpenClaw plugin's CLI spawning with framed Unix-socket hook requests and fail-closed gate behavior.
Stages Linux daemon binaries under per-user /opt paths for SELinux-compatible systemd execution.
Quotes manual privileged cleanup/install paths and prepares the 1.0.13 release.
Validation
Passeddocker run --rm --network=none ... bun -e '<OpenClaw daemon socket smoke>' — Verified framed OpenClaw hook request construction and deny-verdict parsing against a Unix-socket test daemon. (1s)
Passeddocker run --rm --network=none ... bun -e '<OpenClaw fail-closed gate smoke>' — Verified unavailable daemon results block both tool calls and prompts. (1s)
Passeddocker run --rm --network=none ... bun -e '<shellQuote smoke>' — Verified POSIX quoting preserves spaces, command substitutions, backticks, and literal quotes. (1s)
Skippedcentrally configured validation commands — None were configured in the authoritative policy. (0s)
Findings
No blocking findings.
1 advisory finding
Low/High Uninstall skips staged system binaries when the unit is already absent — uninstallDaemonService() returns immediately when the systemd unit path is absent (src/hooks/daemon-service.ts:1826), before reaching the newly added /opt/failproofai/<user> removal at lines 1841-1848. The CLI also calls this routine only when that unit exists (src/hooks/uninstall-cli.ts:337). Thus a failed install after stageSystemBinary() or a manually removed unit leaves the root-owned staged binary behind, including after uninstall --purge. (src/hooks/daemon-service.ts:1826)
Open questions
None.
Policy overrides
None.
Summary by CodeRabbit
New Features
OpenClaw now uses the local daemon to evaluate tool calls and prompts, blocking them when required verdicts are unavailable.
Linux daemon installation now supports Fedora-family systems with SELinux-compatible staging.
Bug Fixes
Restored OpenClaw enforcement for version 2026.9.6 and later.
Improved safety of manual installation and removal commands for paths containing spaces.
Documentation
Added guidance for installing and using the OpenClaw integration.
On Fedora, RHEL, Rocky and Alma, SELinux labels files under /home
user_home_t and gives systemd (init_t) no execute permission on that
type, so a unit whose ExecStart pointed at
~/.failproofai/bin/failproofaid-<version> failed 203/EXEC and
`failproofai config` aborted at its last step.
On Linux the install now copies the binary as root to
/opt/failproofai/<user>/bin/failproofaid-<version> (bin_t under the
policy's generic /opt/(.*/)?bin rule; restorecon re-applies it, since a
new file inherits its directory's usr_t) and points ExecStart there.
The daemon then runs as unconfined_service_t, which may run the worker's
node from ~/.nvm and accept hooks on the socket. The home copy stays for
the version checks; install prunes the /opt copy to current + one, and
uninstall removes it. macOS is unchanged.
Verified against the shipped policies (matchpathcon/sesearch on Fedora
41 and Rocky 9) and end to end on real systemd: the real daemon + worker
installed by a sudo user on Fedora 41 answers the hook and policy
probes; the root-only lifecycle suite passes on Fedora 41 and Ubuntu
24.04.
…he CLI
OpenClaw 2026.9.6 and later import plugins from a copy under
~/.openclaw/tmp/plugin-captures/ that holds only the plugin's own directory.
The plugin located the CLI relative to its own file (../dist/cli.mjs, then
bun ../bin/failproofai.mjs), so inside the copy it spawned a file that does
not exist and read the failure as an allow: every OpenClaw tool call ran
unchecked and no hook activity was recorded, while session telemetry kept
flowing. Verified live on 2026.10.5 by an A/B with the always-on guard.
The plugin now sends failproofaid the same `hook` request the CLI's --hook
path sends (raw event, cli "openclaw", payload as stdin, the gateway
profile's openclaw.json as agentSettingsPath) over the owner-only Unix
socket, as the Hermes plugin does, and reads the same flat verdict back, so
policies and verdict mapping are unchanged. Every module in openclaw-plugin/
imports only node built-ins and its siblings.
Like Hermes it is daemon-only: install requires a healthy daemon
(requiresHealthyDaemon), and when no verdict comes back before_tool_call and
before_agent_run fail closed with the reason logged through api.logger;
before_agent_finalize does not force a revise, which would only loop the turn.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…m as allow
A hookResult frame missing stdout was read as an empty stdout, which is the
allow, and any string permission was accepted, so {"permission":"unknown"}
passed both gates (they block only on deny). Require the complete hookResult
the daemon always serializes (integer exitCode, string stdout and stderr),
accept only allow/deny/instruct, and type-check the optional reason,
policyName and policyNames; anything else is an invalid reply, so the tool
and prompt gates block. Adds regression tests for each shape, plus the two
reported cases end to end through the real daemon client. (SEC-001)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
OpenClaw now requires a healthy daemon to install, as Hermes already did, but
probe-cli.sh installed hooks before its first daemon_cycle and discarded the
installer's output. On the live daemon leg (the canary box's stable leg) the
install refused, the gateway started without the plugin, and both probes went
INCONCLUSIVE instead of testing enforcement — the same state Hermes was in.
- Live daemon leg: start a setup daemon before install_hooks/wire for the
daemon-only CLIs (DAEMON_ONLY_CLIS="hermes openclaw"); each probe still
cycles a fresh daemon into its own oracle dir.
- Keep the installer's refusal and print it with the verdicts instead of
sending it to /dev/null.
- Any other leg (in-process beta, the dead-daemon leg): those CLIs cannot be
hooked at all, and driving them unhooked would score the benign side effect
as a silent-allow FAIL, so report INCONCLUSIVE with the reason and stop.
Tripwires: the shell list matches the integrations flagged
requiresHealthyDaemon, the setup daemon precedes install_hooks, the skip
happens before anything is installed or driven, and the refusal is reported.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A branch beta under its own number rather than main's unpublished
1.0.13-beta.0, which main keeps for its own next cut: a dispatch publishes
whatever package.json carries, and a machine caches failproofaid per version,
so a shared number could also hand a later install the wrong daemon. Moves
package.json, the Cargo workspace version, Cargo.lock's workspace crates and
hermes-plugin/plugin.yaml together, as publish.yml's bump does, and gives the
release its own CHANGELOG section with this PR's entry.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Published 2026-10-28 (CVSS 8.6) against nltk 3.10.3, which sdk/python/uv.lock
pulls in through llama-index-core; the dev/test lockfile only, since the SDK
ships zero runtime dependencies. It turned OSV-Scanner red on every pull
request. Only the nltk entry moves: resolved with the uv CI uses (0.13.6, the
lockfile's revision 5) and checked with `uv lock --check`; osv-scanner with
the repo's config now reports no issues.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he envelope
The plugin capped the whole socket envelope at 1 MiB, but the envelope
carries the payload as an escaped JSON string plus routing fields, while the
CLI accepts up to 1 MiB of raw stdin (handler.ts, read-stdin.ts). A valid
payload near that limit was refused before connecting, and the gates then
blocked the call as a missing verdict. The payload is now bounded at the
CLI's 1 MiB and the envelope only by the daemon's 16 MiB frame limit; a
payload over 1 MiB is evaluated as empty, exactly as the CLI discards an
oversized stdin, and the plugin logs it rather than doing so silently.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When sudo is not available, `config` prints the commands to install the
service by hand and `uninstall` the commands to remove it. Since the /opt
staging change those recipes carried unquoted paths: a home directory with a
space split `sudo install -m 0755 <binary> <target>` into extra words, failing
the `&&`-joined recipe before the unit was written, and the removal recipe's
`sudo rm -rf <dir>` could be pointed at another path.
The existing POSIX `shellQuote()` moves to its own module so both files use
it (uninstall-cli's tests replace daemon-service wholesale, so it cannot be
imported from there), and every path in both recipes goes through it. A test
drives the real install path under a home with a space; it fails on the
unquoted recipe. The helper itself is checked against a real `sh`.
Raised by the Hermes and CodeRabbit reviews of #957.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stable release of OpenClaw enforcement on OpenClaw 2026.9.6 and later (#956,
shipped as 1.0.13-beta.1) and of daemon setup on Fedora/RHEL/Rocky/Alma
(#957). Moves package.json, the Cargo workspace version, Cargo.lock's
workspace crates and hermes-plugin/plugin.yaml to 1.0.13 together, and opens
the 1.0.13 CHANGELOG section that the release's announcement step reads:
#957's entry moves out of the never-published 1.0.13-beta.0 section into it,
beside the recipe-quoting fix; the 1.0.13-beta.* sections stay as they are.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No actionable comments were generated in the recent review.
Recent review info
Run configuration
Source mode: Auto
Repository: Unavailable
Branch: Unavailable
File: No configuration file from this repository applied
Commit: Unavailable
Layers: Organization UI
Review profile: CHILL
Plan: Advanced
Run ID: bfd92d89-96d4-4f24-b55d-fbb54c13bf02
Commits
Reviewing files that changed from the base of the PR and between cc0ecee and 65c1249.
Files ignored due to path filters: 2
Cargo.lock is excluded by !**/*.lock
sdk/python/uv.lock is excluded by !**/*.lock
Files selected for processing: 21
CHANGELOG.md
CLAUDE.md
Cargo.toml
__tests__/hooks/daemon-service.test.ts
__tests__/hooks/integrations.test.ts
__tests__/hooks/openclaw-plugin.test.ts
__tests__/hooks/shell-quote.test.ts
__tests__/hooks/uninstall-cli.test.ts
__tests__/integration-suite/local-runner.test.ts
docs/reference/harnesses.mdx
hermes-plugin/plugin.yaml
integration-suite/probe-cli.sh
openclaw-plugin/daemon-client.js
openclaw-plugin/hooks.js
openclaw-plugin/index.js
package.json
src/hooks/daemon-service.ts
src/hooks/enforcement-capability.ts
src/hooks/integrations.ts
src/hooks/shell-quote.ts
src/hooks/uninstall-cli.ts
Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 6 remain after this review.
Walkthrough
This release stages managed Linux daemon binaries under /opt/failproofai/<user>/bin and updates OpenClaw to request verdicts through the daemon socket. It also updates daemon-only integration checks, release versions, documentation, and tests.
Changes: Linux daemon binary staging
Layer / File(s)
Summary
Stage and run managed daemon binaries src/hooks/daemon-service.ts, src/hooks/shell-quote.ts, __tests__/hooks/daemon-service.test.ts, __tests__/hooks/shell-quote.test.ts, CLAUDE.md, CHANGELOG.md
Linux service installation stages managed binaries in a per-user system directory, uses the staged path for systemd, attempts SELinux relabeling, and prunes older copies. Shell commands use shellQuote; tests and guidance cover these changes.
Remove staged binaries and quote commands src/hooks/daemon-service.ts, src/hooks/uninstall-cli.ts, __tests__/hooks/daemon-service.test.ts, __tests__/hooks/uninstall-cli.test.ts
Linux uninstall removes the per-user staged-binary directory and attempts to remove its shared parent. Manual removal instructions quote service paths and include staged-binary cleanup.
OpenClaw daemon enforcement
Layer / File(s)
Summary
Send and validate daemon hook requests openclaw-plugin/daemon-client.js, __tests__/hooks/openclaw-plugin.test.ts
The daemon client resolves socket and settings paths, sends framed protocol-v2 requests, applies payload and timeout limits, and validates responses. Tests cover path resolution, framing, verdicts, and failures.
The plugin registers hooks and maps verdicts or evaluation failures to hook results. The entry point delegates registration to the hook module; guidance describes the daemon-based behavior.
Require a live daemon for OpenClaw src/hooks/integrations.ts, integration-suite/probe-cli.sh, __tests__/integration-suite/local-runner.test.ts, __tests__/hooks/integrations.test.ts, docs/reference/harnesses.mdx
OpenClaw is marked as requiring a healthy daemon. The probe script starts the daemon before installation, skips daemon-only probes without a live daemon, and reports installation failures. Tests and documentation cover these behaviors.
Stable release metadata
Layer / File(s)
Summary
Set release versions and notes Cargo.toml, package.json, hermes-plugin/plugin.yaml, CHANGELOG.md
Workspace, package, and Hermes plugin versions change to 1.0.13. The changelog adds the stable release heading and records the NLTK development/test lockfile update.
FailproofAI/failproofai#933: Includes the daemon protocol v2 and agent-settings-path contract used by the OpenClaw client.
FailproofAI/failproofai#957: Implements the Linux daemon staging and SELinux behavior included in this release.
Suggested reviewers:niveditjain, hermes-exosphere
Merge Risk: Minimal · up to 65c12
This release moves OpenClaw enforcement to the daemon socket and stages the daemon binary for SELinux systems. No concrete merge-blocking defect was identified in the supplied changes, and the version bumps are consistent across the Cargo, npm and Hermes plugin manifests.
Pre-merge checks: 4 · 1
Failed checks: 1 warning
Check name
Status
Explanation
Resolution
Docstring Coverage
Docstring coverage is 78.95% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documenta…
Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed checks: 4 passed
Check name
Status
Explanation
Title check
The title clearly identifies the stable 1.0.13 release and its two main changes: OpenClaw enforcement and Fedora/RHEL daemon setup.
Description check
The description is comprehensive and covers the purpose, changes, testing, release preparation, and follow-ups. It does not use the template's exact Description, Type of Change, or Checklist headings,…
Linked Issues check
Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check
Check skipped because no linked issues were found for this pull request.
Full details: Description check
Explanation
The description is comprehensive and covers the purpose, changes, testing, release preparation, and follow-ups. It does not use the template's exact Description, Type of Change, or Checklist headings, but it provides equivalent substantive information, including reported test results.
Full details: Docstring Coverage
Explanation
Docstring coverage is 78.95% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 19 functions across 15 files. (6 skipped: 6 unsupported.)
Resolution
Write docstrings for the functions missing them to satisfy the coverage threshold.
Finishing Touches: 💡 1
📝 Generate docstrings: 💡
Commit to this branch
Create a new PR
Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Warning
Some tools did not complete. Review the errors below.
ESLint
If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.
__tests__/hooks/daemon-service.test.ts
ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.
__tests__/hooks/integrations.test.ts
ESLint skipped: the matched ESLint configuration already failed (missing-dependency).
__tests__/hooks/openclaw-plugin.test.ts
ESLint skipped: the matched ESLint configuration already failed (missing-dependency).
13 others
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.
A rabbit taps the socket door, A verdict hops across the floor. Linux bins wear labels neat, Quoted paths keep every beat. The stable tag is fresh and bright, Then bunny bounds into the night.
Comment @coderabbitai help to get the list of available commands.
Reviewed the complete PR. OpenClaw now fails closed through the daemon socket and Linux service installation stages a system-owned binary. One low-severity uninstall cleanup gap remains.
The reason will be displayed to describe this comment to others. Learn more.
Hermes found no blocking issues in this revision.
1 advisory finding
Low/High Uninstall skips staged system binaries when the unit is already absent — uninstallDaemonService() returns immediately when the systemd unit path is absent (src/hooks/daemon-service.ts:1826), before reaching the newly added /opt/failproofai/<user> removal at lines 1841-1848. The CLI also calls this routine only when that unit exists (src/hooks/uninstall-cli.ts:337). Thus a failed install after stageSystemBinary() or a manually removed unit leaves the root-owned staged binary behind, including after uninstall --purge. (src/hooks/daemon-service.ts:1826)
The reason will be displayed to describe this comment to others. Learn more.
Approve with one known cleanup advisory. Real OpenClaw gateway enforcement and chat fail-closed behavior pass; privileged SELinux lifecycle remains untested.
What the PR says it does
Claim
Evidence
verified
OpenClaw enforcement works when the gateway captures only the plugin directory.
OpenClaw 2026.10.8 loaded the packed plugin into plugin-captures. A benign command created its marker; guard and block-sudo requests produced daemon-recorded denies and created no markers.
verified
OpenClaw installation requires a healthy daemon and unavailable or malformed verdicts block tool calls and prompts.
Installation without a daemon refused before creating plugin configuration. Stopping the real daemon blocked a gateway prompt in 173 ms and displayed the block in chat. Missing-socket callbacks and malformed-reply tests also blocked both gates.
verified
Existing event mapping, instructions, Stop revisions, and activity recording are preserved.
The copied packed plugin exercised all eight callbacks against the real daemon: allow, policy deny, prompt deny, Stop revise, instruction retry, session cleanup, and observers passed. The native gateway recorded 31 OpenClaw activity rows.
untested
Linux setup works on Fedora-family systems using root-owned, SELinux-compatible staged binaries.
Target-path tests passed, but the 11 privileged lifecycle tests were skipped. This container has no systemctl, sudo, Docker, or enforcing SELinux environment.
verified
New manual recovery paths are safely quoted.
The real install refusal quoted source and staging paths containing spaces. Shell quoting and manual removal expectations passed in the unit suite; evidence is in /out/kit/manual-recipe.json.
untested
The canary starts a daemon before daemon-only installation and skips unsuitable legs.
Shell syntax and 108 local-runner contract tests passed. The Docker canary could not be driven because Docker is unavailable.
verified
Release metadata is synchronized at 1.0.13, automatic release notes pass, and npm has not published this version.
CLI and daemon report 1.0.13; version-consistency tests passed. Release-note preflight reported 11 entries, and npm returned E404 for failproofai@1.0.13.
verified
The Python development lockfile upgrades NLTK to 3.10.4.
The changed lockfile records 3.10.4; uv lock --check resolved 195 packages successfully.
Notes
No blocking defect found. The reproduced staged-file cleanup gap remains an advisory follow-up.
OpenClaw was exercised on 2026.10.8. Fedora SELinux/systemd behavior, macOS service behavior, and the Docker canary remain untested.
Evidence is saved under /out/kit and /out/screenshots. The checkout remains unchanged.
What was run
. /kit/bin/kit-env.sh before PR runtime checks
/kit/bin/check unit
/kit/bin/check e2e
/kit/bin/check cargo-test
/kit/bin/check tsc
/kit/bin/check lint
/kit/bin/hook-check
/kit/bin/drive-codex --daemon --keep --timeout 90
node /out/kit/openclaw-live.mjs
OpenClaw 2026.10.8 onboard, gateway run, and agent turns; logs under /out/kit/openclaw-*.log
The reason will be displayed to describe this comment to others. Learn more.
warning This cleanup is skipped when the unit is already absent: the earlier return and the CLI's serviceInstalled check prevent reaching it. With redirected system paths, uninstall --yes --purge exited 0 but retained the staged binary. Please make uninstall consider staged files independently of unit existence, while preserving the safeguard against deleting a binary referenced by a live unit.
Approve with one known cleanup advisory. Real OpenClaw gateway enforcement and chat fail-closed behavior pass; privileged SELinux lifecycle remains untested.
What this changes
Replaces OpenClaw CLI spawning with daemon socket requests.
Requires a healthy daemon for OpenClaw installation and blocks unavailable or malformed verdicts.
Stages Linux daemon binaries under per-user /opt directories.
Quotes paths in manual installation and removal recipes.
Prepares version 1.0.13, release notes, and the NLTK lockfile update.
What was run against this PR
pie showData title Round 1 tests
"passed" : 17
"failed" : 1
"could not run" : 2
/kit/bin/check e2e: 358 tests passed and 7 skipped across the hook and CLI suites.
✅ pass
Rust workspace tests
tests
/kit/bin/check cargo-test completed with exit 0; all workspace tests passed.
✅ pass
Type check
build
/kit/bin/check tsc exited 0.
✅ pass
Lint
other
/kit/bin/check lint reported zero errors and five existing warnings.
✅ pass
Packed hook routing regression check
CLI
/kit/bin/hook-check printed HOOK-CHECK-OK after allow/deny checks in process, through the daemon, and with the daemon unavailable.
✅ pass
Real Codex daemon enforcement
CLI
drive-codex --daemon --keep --timeout 90 recorded four hook events and EXPECTED_DENY block-failproofai-commands SEEN.
✅ pass
Copied OpenClaw plugin round trips
API
node /out/kit/openclaw-live.mjs exercised the copied packed plugin against the real daemon and worker. All eight callbacks, instruction retries, fail-closed handling, install refusal, and plugin uninstall passed.
✅ pass
Real OpenClaw capture loading and enforcement
CLI
OpenClaw 2026.10.8 gateway turns using a local model stub created REVIEW_ALLOWED.txt. Guard and block-sudo turns created no markers and recorded the expected policy denies.
✅ pass
Real OpenClaw daemon outage
CLI
After stopping failproofaid, a real gateway turn returned status error and 'blocked by failproofai' in 173 ms. REVIEW_DEAD.txt was absent; gateway logs named the unreachable daemon.
✅ pass
OpenClaw chat block and recovery
UI
Playwright sent chat prompts with the daemon stopped and restarted. The UI displayed the block, then successfully created an allowed marker after recovery. Screenshots: openclaw-chat-dead.png and openclaw-chat-allow.png.
✅ pass
Dashboard smoke
UI
Dashboard /policies and /projects returned HTTP 200 with no console errors. Screenshots are saved; navigation-close ERR_ABORTED requests matched the kit's documented behavior.
✅ pass
Manual recipe path quoting
CLI
Calling the real install path without elevation produced quoted source and staging paths containing spaces; /out/kit/manual-recipe.json captures the output.
❌ fail
Staged-file cleanup without a unit
CLI
With redirected system paths and no unit, the packed CLI's uninstall --yes --purge exited 0 while retaining the staged-path file. This confirms the existing advisory.
✅ pass
Release readiness checks
CLI
Release-note preflight reported '1.0.13 has release notes (11 entries)'; both runtime versions matched. npm view failproofai@1.0.13 returned the expected E404.
bun run validate:mdx parsed 1,063 pages successfully.
✅ pass
Shell syntax and diff validation
other
bash -n integration-suite/probe-cli.sh and git diff --check origin/main...HEAD both passed.
⏸️ could not run
Kit's standalone integration-suite test recipe
tests
Running Vitest inside integration-suite found no test files. Its applicable tests live in the root suite, where all 108 local-runner tests passed.
⏸️ could not run
Privileged service lifecycle and Docker canary
CLI
Privileged installation and Docker canary execution were unavailable: uid 501, no sudo/systemctl/Docker, and no enforcing SELinux environment.
What the PR says it does
pie showData title Claims
"verified" : 6
"untested" : 2
Loading
Claim
Evidence
verified
OpenClaw enforcement works when the gateway captures only the plugin directory.
OpenClaw 2026.10.8 loaded the packed plugin into plugin-captures. A benign command created its marker; guard and block-sudo requests produced daemon-recorded denies and created no markers.
verified
OpenClaw installation requires a healthy daemon and unavailable or malformed verdicts block tool calls and prompts.
Installation without a daemon refused before creating plugin configuration. Stopping the real daemon blocked a gateway prompt in 173 ms and displayed the block in chat. Missing-socket callbacks and malformed-reply tests also blocked both gates.
verified
Existing event mapping, instructions, Stop revisions, and activity recording are preserved.
The copied packed plugin exercised all eight callbacks against the real daemon: allow, policy deny, prompt deny, Stop revise, instruction retry, session cleanup, and observers passed. The native gateway recorded 31 OpenClaw activity rows.
untested
Linux setup works on Fedora-family systems using root-owned, SELinux-compatible staged binaries.
Target-path tests passed, but the 11 privileged lifecycle tests were skipped. This container has no systemctl, sudo, Docker, or enforcing SELinux environment.
verified
New manual recovery paths are safely quoted.
The real install refusal quoted source and staging paths containing spaces. Shell quoting and manual removal expectations passed in the unit suite; evidence is in /out/kit/manual-recipe.json.
untested
The canary starts a daemon before daemon-only installation and skips unsuitable legs.
Shell syntax and 108 local-runner contract tests passed. The Docker canary could not be driven because Docker is unavailable.
verified
Release metadata is synchronized at 1.0.13, automatic release notes pass, and npm has not published this version.
CLI and daemon report 1.0.13; version-consistency tests passed. Release-note preflight reported 11 entries, and npm returned E404 for failproofai@1.0.13.
verified
The Python development lockfile upgrades NLTK to 3.10.4.
The changed lockfile records 3.10.4; uv lock --check resolved 195 packages successfully.
Findings
Open
Severity
Finding
Where
Since
F1
warning
This cleanup is skipped when the unit is already absent: the earlier return and the CLI's service...
src/hooks/daemon-service.ts:1842
round 1
Rounds
Round
Reviewed
Commits in this round
Verdict
1
65c1249
10 earlier + 1828b60d9c4b328159fb2899c12265c1249
Changes requested — F1
Rewritten after every review, not posted again. Reviewed 65c1249 with gpt-6.1-sol. A person merges.
pr-autopilot · Codex in a locked-down container · traced by failproofai
This branch has not been deployed
No deployments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release 1.0.13
Combines #956 and #957 into one branch and prepares it for the stable
1.0.13release. Supersedes both: they can be closed once this merges.What ships
#956: OpenClaw enforcement works again on OpenClaw 2026.9.6 and later. Those releases load plugins from a captured copy that holds only the plugin's own directory, so the plugin's relative path to the CLI pointed at nothing and every tool call was silently allowed. The plugin now asks
failproofaidover its Unix socket, as the Hermes plugin does, sending the samehookrequest the CLI's--hookpath sends. It is daemon-only, like Hermes: install refuses without a daemon, and a missing or malformed verdict blocks tool calls and prompts instead of allowing them. Shipped as1.0.13-beta.1. It was checked on 13 OpenClaw releases from 2026.7.1 to 2026.10.10-beta.4 (table in #956), and the beta was run end to end on a real machine: clean uninstall, install, allow, the always-on guard block, an enabled-policy block, dashboard activity, fail-closed with the daemon stopped, and the OpenClaw chat UI. All passed.#957:
failproofai configworks on Fedora, RHEL, Rocky and Alma. SELinux does not let systemd execute a binary in a home directory, so the unit now runs a root-owned copy staged under/opt/failproofai/<user>/bin.New here: the manual root recipes quote every path. When sudo is not available,
configanduninstallprint commands to run by hand. Since the/optchange those carried unquoted paths. A home directory with a space splitsudo install -m 0755 <binary> <target>into extra words, failing the&&-joined recipe before the unit was written, and the removal recipe'ssudo rm -rf <dir>could be pointed at another path. The existingshellQuote()moves tosrc/hooks/shell-quote.ts, and every path in both recipes goes through it. This was raised by the Hermes (Medium/High) and CodeRabbit reviews of #957.Release preparation
package.json, the Cargo workspace version, the workspace crates inCargo.lockandhermes-plugin/plugin.yamlare all1.0.13, moved together aspublish.yml's bump does.CHANGELOG.mdopens## 1.0.13 — 2026-10-28with a summary line, fix(daemon): run the systemd unit from /opt so setup works on Fedora/RHEL #957's entry (moved out of the never-published1.0.13-beta.0section) and the quoting fix. The1.0.13-beta.*sections stay below it unchanged.scripts/release-announcement.mjs --version 1.0.13 --checkpasses from the changelog alone:1.0.13 has release notes (11 entries). That is the preflight check a stable release runs, so the release can be published without hand-written notes.failproofai@1.0.13is not on npm yet.Publishing after merge
A stable release is cut by publishing a GitHub Release on
main, and only the logins inSTABLE_RELEASE_ACTORS(publish.yml) can authorize one:publish.ymlthen builds the four daemon binaries, attaches them, publishes atlatest, announces, and bumpsmainto1.0.14-beta.0. With an empty release body the notes come from the1.0.13changelog section; passing--notes-file <file>publishes hand-written notes instead.Testing
bun run test:run, 426 files and 8,795 tests passed (11 skipped). E2E:bun run test:e2e, 364 passed (1 skipped).tsc --noEmitis clean, and eslint has 0 errors (5 warnings that already exist onmain).__tests__/hooks/shell-quote.test.tschecks the helper against a realsh, including$(), backticks,;and a literal'. Adaemon-servicetest drives the real install path under a home directory with a space and fails on the unquoted recipe. Theuninstall-clirecipe expectation is updated to the quoted form.Left for follow-ups
/optbinary when writing the unit fails afterwards. Not done here. The staged file is versioned and may be exactly the one a running unit uses, so deleting it on a failed write risks taking out a live daemon's binary. Today the leftover is a stray root-owned file that the next successful install prunes.🤖 Generated with Claude Code
Hermes review
65c12498a5695d250e3d941d5eed1f0709ff15cd1d8f31d926828f3bae215c58f5b35baa44acbff0gpt-5.6-terraSummary
Reviewed the complete PR. OpenClaw now fails closed through the daemon socket and Linux service installation stages a system-owned binary. One low-severity uninstall cleanup gap remains.
Changes
Validation
Passeddocker run --rm --network=none ... bun -e '<OpenClaw daemon socket smoke>'— Verified framed OpenClaw hook request construction and deny-verdict parsing against a Unix-socket test daemon. (1s)Passeddocker run --rm --network=none ... bun -e '<OpenClaw fail-closed gate smoke>'— Verified unavailable daemon results block both tool calls and prompts. (1s)Passeddocker run --rm --network=none ... bun -e '<shellQuote smoke>'— Verified POSIX quoting preserves spaces, command substitutions, backticks, and literal quotes. (1s)Skippedcentrally configured validation commands— None were configured in the authoritative policy. (0s)Findings
No blocking findings.
1 advisory finding
uninstallDaemonService()returns immediately when the systemd unit path is absent (src/hooks/daemon-service.ts:1826), before reaching the newly added/opt/failproofai/<user>removal at lines 1841-1848. The CLI also calls this routine only when that unit exists (src/hooks/uninstall-cli.ts:337). Thus a failed install afterstageSystemBinary()or a manually removed unit leaves the root-owned staged binary behind, including afteruninstall --purge. (src/hooks/daemon-service.ts:1826)Open questions
None.
Policy overrides
None.
Summary by CodeRabbit