Skip to content

Release 1.0.13: OpenClaw enforcement on 2026.9.6+, daemon setup on Fedora/RHEL - #958

Open
chhhee10 wants to merge 15 commits into
mainfrom
release/1.0.13
Open

chhhee10 wants to merge 15 commits into
mainfrom
release/1.0.13

Conversation

@chhhee10

@chhhee10 chhhee10 commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

Release 1.0.13

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.
  • CHANGELOG.md opens ## 1.0.13 — 2026-10-28 with 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-published 1.0.13-beta.0 section) and the quoting fix. The 1.0.13-beta.* sections stay below it unchanged.
  • 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:

gh release create v1.0.13 --repo FailproofAI/failproofai --target main --title "1.0.13" --notes ""

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

🤖 Generated with Claude Code

Hermes review

Field Value
Status Approved
Reviewed commit 65c12498a5695d250e3d941d5eed1f0709ff15cd
Policy revision 1d8f31d926828f3bae215c58f5b35baa44acbff0
Model gpt-5.6-terra
Duration 350s
Updated 2026-10-28T11:58:46.851855179+00:00

Summary

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

  • Passed docker 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)
  • Passed docker run --rm --network=none ... bun -e '<OpenClaw fail-closed gate smoke>' — Verified unavailable daemon results block both tool calls and prompts. (1s)
  • Passed docker run --rm --network=none ... bun -e '<shellQuote smoke>' — Verified POSIX quoting preserves spaces, command substitutions, backticks, and literal quotes. (1s)
  • Skipped centrally 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.

chhhee10 and others added 15 commits October 27, 2026 17:57
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>
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>
1.0.13-beta.1 was published from another branch, and main's
1.0.13-beta.0 slot should stay free for main.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Thanks @chhhee10 for your contribution to Failproof AI! 🙌

We'd love to discuss your PR and welcome you to our community.

Discord: https://discord.befailproof.ai/
Reddit: https://www.reddit.com/r/failproofai/

@coderabbitai

coderabbitai Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

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.
Map verdicts to OpenClaw hook results
openclaw-plugin/hooks.js, openclaw-plugin/index.js, __tests__/hooks/openclaw-plugin.test.ts, CLAUDE.md, CHANGELOG.md, src/hooks/enforcement-capability.ts
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.

Priority: Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant OpenClawHooks
  participant DaemonClient
  participant FailproofaidDaemon
  OpenClawHooks->>DaemonClient: Send hook event and payload
  DaemonClient->>FailproofaidDaemon: Send framed protocol version 2 request
  FailproofaidDaemon-->>DaemonClient: Return verdict response
  DaemonClient-->>OpenClawHooks: Return validated verdict or failure
Loading

Possibly related PRs

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: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning 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 Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly identifies the stable 1.0.13 release and its two main changes: OpenClaw enforcement and Fedora/RHEL daemon setup.
Description check Passed 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 Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed 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.

❤️ Share

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.

@hermes-exosphere

Copy link
Copy Markdown
Contributor

Hermes

Status Reviewing
Verdict Not reviewed yet
Head 65c12498a569
Rounds 0 of 5

No summary yet.

What this changes

No component map for this revision.

Rounds

No review has finished on this pull request yet.

Findings

Nothing raised yet.


@hermes-exosphere help lists every command. This comment is maintained in place — I rewrite it after each review rather than posting a new one.

@hermes-exosphere

Copy link
Copy Markdown
Contributor

Hermes

Status Reviewed
Verdict Approved
Head 65c12498a569
Rounds 0 of 5

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.

What this changes

flowchart LR
    n0OpenClawplugin["~ OpenClaw plugin"]
    n1DaemonIPCprotocol["Daemon IPC protocol"]
    n2Policyevaluation["Policy evaluation"]
    n3Integrationregistry["~ Integration registry"]
    n4Daemonservicelifecycle["~ Daemon service lifecycle"]
    n5Uninstallcommand["~ Uninstall command"]
    n6Canaryprobesuite["~ Canary probe suite"]
    n7Releasepackaging["~ Release packaging"]
    n0OpenClawplugin -- "framed hook requests" --> n1DaemonIPCprotocol
    n1DaemonIPCprotocol -- "raw events and verdicts" --> n2Policyevaluation
    n3Integrationregistry -- "daemon-required installation" --> n0OpenClawplugin
    n4Daemonservicelifecycle -- "provides Unix socket" --> n1DaemonIPCprotocol
    n4Daemonservicelifecycle -- "system binary location" --> n5Uninstallcommand
    n6Canaryprobesuite -- "daemon-only CLI list" --> n3Integrationregistry
    n7Releasepackaging -- "ships plugin assets" --> n0OpenClawplugin
Loading

Rounds

Round Reviewed Commits in this round Verdict
0 65c12498a569 85caba6985d3 f7e8976d8752 3b506d790b8c aeffbd398746 d6fdce2bbcb7 8eeeb05a570d 9792937d7024 f93fa5c03132 42d3daf72ab7 c15b64e35bbc 1828b60f7fc5 d9c4b32949ba 8159fb208df6 899c12291351 65c12498a569 Approved

Findings

Open

  • F1 Uninstall skips staged system binaries when the unit is already absent (src/hooks/daemon-service.ts) — round 1

@hermes-exosphere help lists every command. This comment is maintained in place — I rewrite it after each review rather than posting a new one.

@hermes-exosphere hermes-exosphere left a comment

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.

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)

@hermes-exosphere hermes-exosphere left a comment

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.

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
  • node /out/kit/openclaw-ui.cjs dead; node /out/kit/openclaw-ui.cjs allow
  • node /kit/bin/shot.mjs http://127.0.0.1:8020/policies and /projects
  • Real installDaemonService invocation with space-containing paths; /out/kit/manual-recipe.json
  • node scripts/release-announcement.mjs --version 1.0.13 --check
  • npm view failproofai@1.0.13 version --json
  • uv lock --check --directory sdk/python
  • bun run validate:mdx
  • bash -n integration-suite/probe-cli.sh
  • bunx vitest run from integration-suite
  • git diff --check origin/main...HEAD; git status --short

Reviewed commit 65c1249 with gpt-6.1-sol. A person merges.

pr-autopilot · Codex in a locked-down container · traced by failproofai

// left pointing at a deleted file. The shared parent goes only if no
// other user's directory is in it.
const binRoot = systemBinaryRoot();
if (existsSync(binRoot)) {

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.

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.

@hermes-exosphere

Copy link
Copy Markdown
Contributor

pr-autopilot review

Verdict Changes requested
Head 65c1249
Round 1
Ran failproofai kit: the PR's stack booted in 1m 22s
Tests 17 passed · 1 failed · 2 could not run
Findings 1 open · 0 resolved

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
Loading
Result Test How Evidence
✅ pass Full unit suite tests /kit/bin/check unit: 426 files passed; 8,795 tests passed and 11 skipped.
✅ pass Repository end-to-end suite CLI /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.
✅ pass Python lockfile consistency other uv lock --check --directory sdk/python resolved 195 packages successfully.
✅ pass Documentation validation build 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 + 1828b60 d9c4b32 8159fb2 899c122 65c1249 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
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.

2 participants