Skip to content

feat(policy): add OpenClaw install policy adapter - #35

Merged
jesse-merhi merged 31 commits into
mainfrom
jesse/openclaw-install-gate-plugin
Jul 31, 2026
Merged

feat(policy): add OpenClaw install policy adapter#35
jesse-merhi merged 31 commits into
mainfrom
jesse/openclaw-install-gate-plugin

Conversation

@jesse-merhi

@jesse-merhi jesse-merhi commented Jul 28, 2026

Copy link
Copy Markdown
Member

New behavior

OpenClaw operators can configure the trusted ClawScan binary directly as security.installPolicy.exec for both skill and plugin installs. The command reads OpenClaw's protocol-v1 request from stdin, scans the staged source with an operator-owned profile, and returns a bounded protocol-v1 allow, warn, or block response. Invalid requests, incomplete scanner evidence, scanner failures, unsafe dependency layouts, unsupported judge-backed profiles, and unknown gate results fail closed.

ClawScan gate Policy decision OpenClaw behavior
pass allow Install commit continues
warn warn with a non-empty reason Host pauses before commit and requires explicit user confirmation
block block with a non-empty reason Install is rejected and cannot be overridden

OpenClaw owns all prompting and acknowledgement UI. The policy process adds no prompts, approval tokens, capability negotiation, phase IDs, or other approval machinery. Optional findings are bounded and contain only ruleId, severity, message, and optional evidence.

  • The built-in openclaw-install-policy profile deterministically composes SkillSpector and clawscan-static; custom profiles remain operator-owned composition points.
  • Host-declared skill and plugin target kinds are preserved even when staged files do not contain a manifest.
  • The npm package exports a resolver for the absolute native binary path required by OpenClaw's trusted-command checks.
  • Native Windows visibly returns a warning after static-only scanning because Linux Docker cannot consume native Windows staging paths. Non-Windows Docker-unavailable degradation is deliberately outside this PR; those environments continue to fail closed until the separately tracked degraded-mode work defines and proves that security trade-off.

Important

This integration requires the coordinated OpenClaw host change that accepts protocol-v1 warn and performs confirmation before install commit. There is not yet a released OpenClaw version floor to name. Older allow/block-only hosts reject warn and fail closed. Do not deploy or enable this adapter until the matching host contract lands.

End-to-end operator flow

flowchart LR
  A["OpenClaw stages a skill or plugin"] --> B["Protocol-v1 request with sourcePath"]
  B --> C["Trusted security.installPolicy.exec process"]
  C --> D["clawscan-static in the policy process"]
  C --> E["SkillSpector in ClawScan's Docker sandbox"]
  D --> F["Combine scanner gate rules"]
  E --> F
  F --> G{"Policy decision"}
  G -- "allow" --> H["Commit install"]
  G -- "warn" --> I["OpenClaw requests explicit confirmation"]
  G -- "block" --> J["Reject install"]
Loading

OpenClaw first stages the candidate instead of mutating the installed location. It supplies the staged path and target metadata over JSON stdin; ClawScan returns exactly one protocol response over stdout. OpenClaw remains the owner of install commit and warning confirmation.

OpenClaw configuration

After resolving the package's real, non-symlink native executable path, configure the Gateway with that absolute path and its containing trusted directory:

{
  security: {
    installPolicy: {
      enabled: true,
      targets: ["skill", "plugin"],
      exec: {
        source: "exec",
        command: "/absolute/path/to/clawscan",
        args: ["openclaw-install-policy"],
        trustedDirs: ["/absolute/path/to"],
        passEnv: ["PATH", "DOCKER_HOST"],
        timeoutMs: 1200000,
        noOutputTimeoutMs: 1200000,
        maxOutputBytes: 1048576
      }
    }
  }
}

The command path and any interpreter script arguments must pass OpenClaw's ownership, permission, non-symlink, and trusted-directory checks. PATH lets ClawScan find Docker; DOCKER_HOST is needed only for non-default Docker setups. openclaw doctor --deep performs a synthetic policy probe after configuration.

Host contract required by ClawScan

ClawScan uses only the existing external install-policy request fields:

  • protocolVersion: 1
  • targetType: "skill" | "plugin" and targetName
  • staged sourcePath and sourcePathKind
  • source and origin metadata
  • request.kind, request.mode, and optional request.requestedSpecifier
  • existing skill/plugin metadata, including plugin contentType

It returns protocolVersion, decision, a required non-empty reason for warn and block, and optional bounded findings. No parallel hook contract or activation mechanism is introduced.

Sandbox and containerized Gateway behavior

security.installPolicy.exec runs as a trusted local child of the OpenClaw Gateway/install process; the normal agent tool sandbox does not isolate it. ClawScan then applies its own Docker sandbox to command-backed scanners such as SkillSpector. It automatically mounts the staged sourcePath read-only at the same absolute path and mounts its temporary scanner-result directory writable, so the default host installation needs no manual target --sandbox-mount.

A containerized Gateway using the host Docker socket must make both path classes visible to the Docker daemon. The supported nested-Docker setup uses one temporary root bind-mounted from the host into the Gateway at the same absolute path, sets the Gateway's TMPDIR to that root, and adds TMPDIR to exec.passEnv. This keeps OpenClaw staging paths and ClawScan result paths mountable by scanner containers. A container-only /tmp does not work in this topology.

The documented alternative is to treat an intentionally isolated, disposable Gateway container as the sandbox, install every selected scanner inside it, and configure --sandbox off. This removes ClawScan's inner Docker boundary and is not a workaround for an ordinary missing daemon or mismatched staging path.

npm install-stage behavior

One npm plugin install can invoke the policy more than once. Each call has a distinct purpose:

OpenClaw stage ClawScan behavior Observable result
Registry metadata preflight Identifies the plugin/npm file stage, then validates the complete immutable npm/file/package tuple before using clawscan-static without Docker Metadata provenance is checked; malformed tuples block instead of falling through, and an info finding states that this is not plugin-code coverage
Resolved package Runs the full selected profile against staged package code Normal three-way gate decision
Installed dependency tree Exposes installed packages in one bounded scan view without node_modules exclusions, omits only OpenClaw's host-validated peer symlink, then runs the full profile Transitive code reaches both default scanners; escaping links and copy-budget violations block, while safe in-tree links are copied as stable scanner-visible files
Empty dependency tree Validates the stage directory and records that no runtime dependency code exists Explicit allow/info response because the package was already scanned

A local plugin-file request never matches the metadata shortcut. Dependency materialization is capped by package count, filesystem entries, per-file bytes, and aggregate bytes before untrusted content can exhaust the temporary scan area.

Protocol proof

A successful scan returns:

{"protocolVersion":1,"decision":"allow"}

A warning returns control to the host for confirmation:

{
  "protocolVersion": 1,
  "decision": "warn",
  "reason": "ClawScan gate reported warnings for the staged installation",
  "findings": [
    {
      "ruleId": "clawscan-static/example",
      "severity": "warn",
      "message": "Review this finding before installing"
    }
  ]
}

A malformed request or failed required scanner returns a non-overridable fail-closed response:

{
  "protocolVersion": 1,
  "decision": "block",
  "reason": "ClawScan install policy failed closed: ..."
}

JSON responses are written to stdout; diagnostics stay on stderr. Reasons and finding text are length-bounded and control-character sanitized before OpenClaw logs or displays them.

How to verify

The focused multi-stage test creates valid and malformed metadata, package, transitive-dependency, and dependency-free payloads and checks the distinct protocol responses:

TMPDIR=/private/tmp go test -count=1 ./cmd/clawscan \
  -run TestRunOpenClawInstallPolicyHandlesNPMInstallStagesSeparately

The dependency tests additionally prove nested package code is visible outside normal node_modules exclusions, the exact host peer link is omitted, safe in-tree symlink targets are copied into the scan view, other escaping symlinks fail closed, and all copy budgets are enforced:

TMPDIR=/private/tmp go test -count=1 ./internal/installpolicy

Operator setup, executable trust checks, automatic target mounts, containerized-Gateway path sharing, custom-profile composition, request/response semantics, multi-call npm behavior, and scope boundaries are documented in docs/openclaw-install-policy.md.

Checks

  • TMPDIR=/private/tmp go test -count=1 ./...
  • TMPDIR=/private/tmp go vet ./...
  • node --test npm/clawscan/test/*.test.mjs scripts/build-npm-package.test.mjs (15 tests)
  • actionlint .github/workflows/npm-release.yml .github/workflows/release.yml
  • node scripts/build-npm-package.mjs --version v0.0.0 --pack --smoke
  • make release VERSION=v0.0.0-test
  • make docs-site (7 pages)
  • git diff --check
  • Repository pre-ship review — clean after fixing dependency symlink coverage, malformed npm preflight fallback, judge-profile handling, and npm promotion idempotency/tag verification.

Implementation notes

PR #34 is now merged; this branch is restacked directly on main so the net diff contains only the install-policy adapter. The policy command does not claim a singleton scanner: operators can select multiple ClawScan adapters or place ClawScan behind a broader policy wrapper and combine decisions deterministically. Judge-backed profiles fail closed until a canonical judge-to-policy mapping exists. Skill Workshop authoring and manual filesystem copies remain outside OpenClaw's supply-chain install boundary.

@socket-security

socket-security Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​@​openclaw/​clawscan@​0.0.0-devN/AN/AN/AN/AN/A

View full report

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. labels Jul 28, 2026
@clawsweeper

clawsweeper Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codex review: needs maintainer review before merge. Reviewed July 31, 2026, 12:27 AM ET / 04:27 UTC.

ClawSweeper review

What this changes

This PR adds a clawscan openclaw-install-policy command, built-in scanning profile, npm binary resolver, tests, docs, and release packaging support for OpenClaw’s staged skill and plugin installation-policy protocol.

Merge readiness

⚠️ Ready for maintainer review - 4 items remain

Keep this PR open for maintainer coordination rather than closing or mechanically repairing it. The adapter is coherent and its tests/docs describe the intended fail-closed behavior, but its useful warn path depends on a coordinated OpenClaw host contract that is not yet tied to a compatible released host version; as a MEMBER-authored PR, it also requires explicit maintainer judgment.

Priority: P2
Reviewed head: f91194ef348e18ef7f64a3c1c664209125fb6a0b
Owner decision: Required. See Decision needed.

Review scores

Measure Result What it means
Overall readiness 🐚 platinum hermit (4/6) The patch is a substantial, well-scoped implementation with focused tests and documentation, but merge readiness depends on a maintainer decision and coordinated host compatibility proof.
Proof confidence 🌊 off-meta tidepool Not applicable: The contributor is a repository MEMBER, so the external-contributor real-behavior-proof gate does not apply; the remaining required evidence is maintainer-visible host compatibility proof before rollout.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Not applicable Not applicable: The contributor is a repository MEMBER, so the external-contributor real-behavior-proof gate does not apply; the remaining required evidence is maintainer-visible host compatibility proof before rollout.
Evidence reviewed 4 items Documented host-version dependency: The new operator documentation says deployment requires an OpenClaw release whose protocol-v1 parser supports decision: "warn" and explicit confirmation; older allow/block-only hosts reject warn and fail closed, while no compatible release floor is available yet.
CLI integration is intentionally external-policy based: The command dispatches openclaw-install-policy through the public ClawScan CLI and routes its stdin/stdout protocol handling to the install-policy package rather than adding provider credentials or API-key flags.
Bounded fail-closed policy surface: The new policy package bounds request and finding sizes and defines typed protocol request/response structures; the staged-source helpers also impose dependency-copy budgets before scanner execution.
Findings None None.
Security None None.

How this fits together

OpenClaw stages a third-party skill or plugin and invokes a trusted external install-policy command before committing the install. This adapter feeds the staged path through ClawScan scanners and maps the resulting gate to an allow, warn, or block response that the OpenClaw host must interpret.

flowchart LR
  A[Staged skill or plugin] --> B[OpenClaw protocol request]
  B --> C[Trusted ClawScan policy command]
  C --> D[Built-in policy profile]
  D --> E[Static scanner and sandboxed scanners]
  E --> F[Gate aggregation]
  F --> G[Allow warn or block response]
  G --> H[OpenClaw install commit or confirmation]
Loading

Decision needed

Question Recommendation
Should ClawScan merge and expose this install-policy adapter before OpenClaw’s matching warn-and-confirm host contract has landed with a documented compatible version floor? Coordinate host support first: Wait for the compatible OpenClaw host contract, then land this adapter with an end-to-end compatibility proof and documented minimum host version.

Why: The branch deliberately introduces a protocol response that older released hosts reject; choosing whether to merge an intentionally non-deployable-by-default integration ahead of its host dependency is a product and release-coordination decision, not a mechanical code repair.

Before merge

  • Resolve merge risk (P1) - Existing OpenClaw hosts that only accept allow and block will reject this adapter’s warn response and fail closed if operators enable it before the matching host contract is available.
  • Resolve merge risk (P1) - The documented containerized-Gateway setup relies on Docker-visible staging and temporary-result paths, so compatibility needs an end-to-end host integration check rather than only unit-level policy tests.
  • Complete next step (P2) - Maintainers need to decide the release/rollout order for the cross-repository warn contract; there is no narrow mechanical repair to queue independently.
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Patch scope 27 files affected; 2,954 additions and 89 deletions The implementation spans CLI dispatch, policy parsing, scanner execution, profiles, npm packaging, release workflows, tests, and operator docs.
Protocol coverage 2 new install-policy test packages plus CLI coverage The branch includes focused tests for policy decoding, staged npm install variants, dependency materialization, and command responses, but they do not replace host integration proof.

Merge-risk options

Maintainer options:

  1. Prove the matching host contract before merge (recommended)
    Add or link an end-to-end run against an OpenClaw host that accepts warn, confirms it before commit, and documents the first compatible release.
  2. Accept deferred deployability
    Merge the adapter now only if maintainers explicitly accept that operators must not enable it until the coordinated host release is available.
  3. Pause for cross-repository coordination
    Keep this PR open until the OpenClaw host contract and release plan make the compatibility story reviewable.

Technical review

Best possible solution:

Coordinate and land the OpenClaw host support for protocol-v1 warning confirmation, then verify this adapter against that host on both ordinary and containerized Gateway deployments and document the minimum compatible host release before operator rollout.

Do we have a high-confidence way to reproduce the issue?

Not applicable: this PR proposes a new opt-in install-policy integration rather than reporting broken existing behavior. The branch supplies focused protocol and staging tests, while the remaining question is compatibility with the coordinating OpenClaw host.

Is this the best way to solve the issue?

Unclear: the adapter is a focused use of the existing external-policy boundary, but it is not yet the complete deployable solution until the host accepts warn, performs confirmation, and has a documented compatible version floor.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 13c6cb59b581.

Labels

Label justifications:

  • P2: This is a substantial but opt-in security-install integration whose unresolved work is cross-repository compatibility coordination rather than an active user regression.
  • merge-risk: 🚨 compatibility: The new warn protocol response is incompatible with released allow/block-only OpenClaw hosts and can cause enabled installations to fail closed.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🌊 off-meta tidepool and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Not applicable: The contributor is a repository MEMBER, so the external-contributor real-behavior-proof gate does not apply; the remaining required evidence is maintainer-visible host compatibility proof before rollout.

Evidence

What I checked:

  • Documented host-version dependency: The new operator documentation says deployment requires an OpenClaw release whose protocol-v1 parser supports decision: "warn" and explicit confirmation; older allow/block-only hosts reject warn and fail closed, while no compatible release floor is available yet. (docs/openclaw-install-policy.md:7, f91194ef348e)
  • CLI integration is intentionally external-policy based: The command dispatches openclaw-install-policy through the public ClawScan CLI and routes its stdin/stdout protocol handling to the install-policy package rather than adding provider credentials or API-key flags. (cmd/clawscan/main.go:52, f91194ef348e)
  • Bounded fail-closed policy surface: The new policy package bounds request and finding sizes and defines typed protocol request/response structures; the staged-source helpers also impose dependency-copy budgets before scanner execution. (internal/installpolicy/policy.go:1, f91194ef348e)
  • Merged prerequisite provenance: The related declarative gate-policy PR is merged into current main at 13c6cb59b58176b6ed23f0514d5bca095f715eda; this PR is explicitly restacked on that prerequisite, but the separate OpenClaw host support for warn/confirmation remains an external coordination dependency. (13c6cb59b581)

Likely related people:

  • jesse-merhi: Authored the current PR and the related declarative JSON gate-policy work that was merged into current main, making them the clearest history-connected routing candidate for the ClawScan policy/profile boundary. (role: recent merged policy contributor; confidence: high; commits: d8e57e37a403, 13c6cb59b581; files: internal/installpolicy/policy.go, internal/profiles/openclaw-install-policy/clawscan.yml, cmd/clawscan/main.go)

Rank-up moves

Optional improvements that raise the rating; they are not merge blockers.

  • Link or add an end-to-end run with an OpenClaw host that accepts warn and pauses before commit.
  • Document the first compatible OpenClaw release before telling operators to enable the command.

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (23 earlier review cycles; latest 8 shown)
  • reviewed 2026-07-30T12:19:52.230Z sha 5c5a000 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-30T12:23:54.019Z sha 5c5a000 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-30T15:06:12.875Z sha c2d2cd7 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-30T15:28:39.796Z sha 324dcff :: needs maintainer review before merge. :: none
  • reviewed 2026-07-30T15:36:17.643Z sha 324dcff :: needs maintainer review before merge. :: none
  • reviewed 2026-07-30T20:13:26.981Z sha 324dcff :: needs maintainer review before merge. :: none
  • reviewed 2026-07-30T23:04:03.697Z sha 324dcff :: needs maintainer review before merge. :: none
  • reviewed 2026-07-31T00:27:55.386Z sha 324dcff :: needs maintainer review before merge. :: none

@jesse-merhi
jesse-merhi force-pushed the jesse/openclaw-install-gate-plugin branch from f0a2669 to 735c244 Compare July 28, 2026 16:16
@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 29, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

@clawsweeper clawsweeper Bot removed the status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. label Jul 29, 2026
@jesse-merhi jesse-merhi changed the title feat(plugin): add OpenClaw install gate feat(policy): add OpenClaw install policy adapter Jul 30, 2026
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Jul 30, 2026
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Jul 30, 2026
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Jul 30, 2026
Base automatically changed from jesse/openclaw-native-gate-policy to main July 31, 2026 04:21
@jesse-merhi
jesse-merhi marked this pull request as ready for review July 31, 2026 04:22
Copilot AI review requested due to automatic review settings July 31, 2026 04:22

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@jesse-merhi

Copy link
Copy Markdown
Member Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 31, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

@clawsweeper

clawsweeper Bot commented Jul 31, 2026

Copy link
Copy Markdown

ClawSweeper status: review started.

I am starting a fresh review of this pull request: feat(policy): add OpenClaw install policy adapter This is item 1/1 in the current shard. Shard 0/1.

This placeholder means the worker is alive and reading the current context. I will edit this same comment with the actual review when the claws are done clicking.

Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted.

@jesse-merhi
jesse-merhi merged commit e63bacb into main Jul 31, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants