Skip to content

fix(gateway): narrow plugin route runtime scopes#58167

Merged
vincentkoc merged 6 commits into
mainfrom
triage-mhgq-plugin-route-scope
Mar 31, 2026
Merged

fix(gateway): narrow plugin route runtime scopes#58167
vincentkoc merged 6 commits into
mainfrom
triage-mhgq-plugin-route-scope

Conversation

@vincentkoc

Copy link
Copy Markdown
Member

Summary

  • Problem: plugin-auth HTTP routes were running with write-capable runtime client scopes.
  • Why it matters: plugin-owned webhook handlers should not inherit write-capable runtime access unless the route itself requires gateway auth.
  • What changed: plugin route runtime clients now map auth: "plugin" routes to read scope, keep auth: "gateway" routes on write scope, and add regression coverage that proves write-helper access fails closed on plugin-auth routes.
  • What did NOT change (scope boundary): route matching, route admission, and gateway-auth enforcement behavior outside runtime scope selection.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #
  • Related #
  • This PR fixes a bug or regression

Root Cause / Regression History (if applicable)

  • Root cause: plugin HTTP route dispatch minted a synthetic runtime client with write scope for every matched route, regardless of whether the route used plugin auth or gateway auth.
  • Missing detection / guardrail: there was no regression test that exercised write-helper gating through plugin route runtime scope selection.
  • Prior context (git blame, prior PR, issue, or refactor if known): the current branch preserves the existing route-scope fix work and adds a tighter regression guardrail on top.
  • Why this regressed now: runtime scope selection was too coarse and treated all plugin routes as write-capable internal callers.
  • If unknown, what was ruled out: N/A.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/gateway/server/plugins-http.runtime-scopes.test.ts
  • Scenario the test should lock in: plugin-auth routes fail closed when a write-scoped runtime helper is checked, while gateway-auth routes keep write-capable runtime access.
  • Why this is the smallest reliable guardrail: it exercises the actual plugin route wrapper plus the shared gateway method scope authorizer without pulling in heavier gateway bootstrap mocks.
  • Existing test that already covers this (if any): none.
  • If no new test is added, why not: N/A.

User-visible / Behavior Changes

Plugin-owned HTTP routes that use plugin auth no longer get write-capable runtime helper access by default. Gateway-authenticated plugin routes keep the existing write-capable runtime behavior.

Diagram (if applicable)

Before:
[plugin-auth route] -> [synthetic write-scoped runtime client] -> [write helper allowed]

After:
[plugin-auth route] -> [synthetic read-scoped runtime client] -> [write helper denied]
[gateway-auth route] -> [synthetic write-scoped runtime client] -> [write helper allowed]

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (Yes)
  • If any Yes, explain risk + mitigation: plugin-auth HTTP routes now run with the narrower read scope, while gateway-auth routes keep write scope. Coverage locks the intended split in place.

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: local worktree
  • Model/provider: N/A
  • Integration/channel (if any): gateway plugin HTTP routes
  • Relevant config (redacted): N/A

Steps

  1. Register a plugin-auth HTTP route whose handler checks write-helper eligibility.
  2. Dispatch that route without gateway auth.
  3. Dispatch an equivalent gateway-auth route with gateway auth satisfied.

Expected

  • Plugin-auth route fails closed on write-helper access.
  • Gateway-auth route retains write-helper access.

Actual

  • Matches expected in the added regression coverage.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

  • Verified scenarios: reviewed the preserved fix, added a focused regression test for plugin-auth vs gateway-auth runtime scope behavior, attempted targeted tests, pnpm check, and pnpm build on the rebased tree.
  • Edge cases checked: plugin-auth routes still fail closed; gateway-auth routes keep write-helper eligibility.
  • What you did not verify: full local completion of the targeted Vitest lane, pnpm check, and pnpm build was blocked by host-level process contention during this session.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)
  • If yes, exact upgrade steps:

Risks and Mitigations

  • Risk: plugin-auth routes that were implicitly relying on write-capable runtime helpers will now fail closed.
    • Mitigation: gateway-auth routes keep write scope, and the changelog entry plus regression coverage document the intended split.

AI-assisted: yes. Testing: targeted regression coverage added; local verification attempted as noted above.

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: M maintainer Maintainer-authored PR labels Mar 31, 2026
@vincentkoc vincentkoc self-assigned this Mar 31, 2026
@greptile-apps

greptile-apps Bot commented Mar 31, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR narrows the runtime OAuth scope for plugin-owned HTTP routes from operator.write to operator.read when those routes use auth: \"plugin\", keeping operator.write only for routes that require gateway authentication. The one-line change in createPluginRouteRuntimeClient is correct and minimal.

Key changes:

  • plugins-http.ts: createPluginRouteRuntimeClient now accepts requiresGatewayAuth and selects READ_SCOPE vs WRITE_SCOPE accordingly.
  • plugins-http.runtime-scopes.test.ts (new): Behavioral regression test that verifies write-helper access throws inside plugin-auth routes and succeeds inside gateway-auth routes.
  • plugins-http.test.ts: Replaced a heavyweight integration mock (subagent runtime + gateway request mocks) with a lightweight scope-capture helper that directly asserts the assigned scopes — cleaner and more stable.
  • CHANGELOG.md: Entry added in the correct section.

Confidence Score: 5/5

Safe to merge; the core change is a single-line scope selection with correct logic and two complementary test suites that lock in the intended behavior.

All remaining findings are P2. The logic change is minimal and correct: requiresGatewayAuth is already computed before the runtime client is created and correctly reflects whether any matched route requires gateway auth. The test rewrite removes fragile mocks and asserts directly on observable state. No P0 or P1 issues found.

No files require special attention.

Important Files Changed

Filename Overview
src/gateway/server/plugins-http.ts Core change: createPluginRouteRuntimeClient now accepts requiresGatewayAuth and maps plugin-auth routes to READ_SCOPE while gateway-auth routes keep WRITE_SCOPE. Logic is correct and minimal.
src/gateway/server/plugins-http.runtime-scopes.test.ts New regression test file. Correctly verifies the behavioral contract: plugin-auth routes fail closed when write-helper access is attempted, and gateway-auth routes retain write-helper access.
src/gateway/server/plugins-http.test.ts Heavy mock infrastructure replaced with a lightweight scope-capture helper. Tests now assert on actual scope values rather than downstream permission failure side-effects.
CHANGELOG.md Changelog entry added to the correct section, accurately describing the scope narrowing change.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/gateway/server/plugins-http.runtime-scopes.test.ts
Line: 48

Comment:
**Partial log stub bypasses type safety**

`{ warn: vi.fn() }` is cast with `as` to the full `SubsystemLogger` type, so any invocation of a non-stubbed method (e.g. `info`, `error`, `debug`) would throw at runtime and produce a confusing test failure rather than a clear type error. `plugins-http.test.ts` avoids this by using `as unknown as PluginHandlerLog`; a consistent pattern here would be safer.

```suggestion
    const log = { warn: vi.fn(), info: vi.fn(), error: vi.fn(), debug: vi.fn() } as Parameters<typeof createGatewayPluginRequestHandler>[0]["log"];
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "test(gateway): cover plugin route runtim..." | Re-trigger Greptile

Comment thread src/gateway/server/plugins-http.runtime-scopes.test.ts Outdated
@vincentkoc
vincentkoc force-pushed the triage-mhgq-plugin-route-scope branch from 363cd87 to 863ef68 Compare March 31, 2026 08:45
@vincentkoc
vincentkoc merged commit 2a1db0c into main Mar 31, 2026
9 checks passed
@vincentkoc
vincentkoc deleted the triage-mhgq-plugin-route-scope branch March 31, 2026 15:21

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 67b6068b40

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

function createPluginRouteRuntimeClient(
requiresGatewayAuth: boolean,
): GatewayRequestOptions["client"] {
const scopes = requiresGatewayAuth ? [WRITE_SCOPE] : [];

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.

P2 Badge Grant read scope for plugin-auth runtime clients

Using an empty scope array for non-gateway plugin routes removes all operator privileges, not just write access. In this codebase, read methods still require operator.read (see authorizeOperatorScopesForMethod), so plugin-auth webhook handlers that call read-only runtime helpers (for example, subagent paths that dispatch sessions.get) will now fail with missing scope: operator.read and return 500s. This change narrows more than intended; plugin-auth routes need a read scope rather than no scope.

Useful? React with 👍 / 👎.

steipete pushed a commit to Mlightsnow/openclaw that referenced this pull request Apr 1, 2026
* wip(gateway): preserve plugin route scope progress

* test(gateway): cover plugin route runtime scopes

* test(gateway): finish plugin route scope rebase

* fix(gateway): drop scopes from plugin-auth routes
EthanHunter1229 pushed a commit to EthanHunter1229/openclaw that referenced this pull request Apr 8, 2026
* wip(gateway): preserve plugin route scope progress

* test(gateway): cover plugin route runtime scopes

* test(gateway): finish plugin route scope rebase

* fix(gateway): drop scopes from plugin-auth routes
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
* wip(gateway): preserve plugin route scope progress

* test(gateway): cover plugin route runtime scopes

* test(gateway): finish plugin route scope rebase

* fix(gateway): drop scopes from plugin-auth routes
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
* wip(gateway): preserve plugin route scope progress

* test(gateway): cover plugin route runtime scopes

* test(gateway): finish plugin route scope rebase

* fix(gateway): drop scopes from plugin-auth routes
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
* wip(gateway): preserve plugin route scope progress

* test(gateway): cover plugin route runtime scopes

* test(gateway): finish plugin route scope rebase

* fix(gateway): drop scopes from plugin-auth routes
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
* wip(gateway): preserve plugin route scope progress

* test(gateway): cover plugin route runtime scopes

* test(gateway): finish plugin route scope rebase

* fix(gateway): drop scopes from plugin-auth routes
Nachx639 pushed a commit to Nachx639/clawdbot that referenced this pull request Jun 17, 2026
* wip(gateway): preserve plugin route scope progress

* test(gateway): cover plugin route runtime scopes

* test(gateway): finish plugin route scope rebase

* fix(gateway): drop scopes from plugin-auth routes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime maintainer Maintainer-authored PR size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant