Skip to content

Warn in the provider editor when a custom command isn't runner-allowlisted - #4245

Merged
atomantic merged 1 commit into
mainfrom
claim/issue-4143
Aug 15, 2026
Merged

Warn in the provider editor when a custom command isn't runner-allowlisted#4245
atomantic merged 1 commit into
mainfrom
claim/issue-4143

Conversation

@atomantic

Copy link
Copy Markdown
Owner

Summary

A custom provider whose command isn't on the CoS Agent Runner's allowlist saves fine today and only fails later, at spawn time. This surfaces that up front, in the AI Providers editor, without rejecting the save.

  • GET /api/providers now also returns runnerAllowedCommands — the runner's exec allowlist, read-only.
  • The provider card shows a NO AGENT RUNNER badge (with a tooltip) for a CLI/TUI provider whose command is off the list.
  • The create/edit form shows an inline warning banner under the Command field as you type, naming the allowlisted commands.

Informational, never a rejection. Direct (non-runner) spawn doesn't consult this allowlist at all, so an off-list command is a legitimate config — blocking the save would break it. Save stays enabled and the copy says so.

The allowlist is not mirrored client-side. It's the runner's exec boundary and stays hand-curated in server/cos-runner/allowedCommands.js, never derived from the user-writable data/providers.json — so the client receives it from the server instead of carrying a second hand-maintained copy that could drift. What the client does mirror is the normalization isAllowedCommand applies before its membership test (strip directory prefix, strip trailing .exe), and a new parity test pins that against the server implementation over a table of path shapes.

Sentinel, not falsy. isRunnerAllowedCommand returns null for "list not fetched / field blank" and only false for "fetched, and definitely off the list" — so an older server that omits the field, or a failed fetch, renders no warning rather than accusing every command.

Published as a list rather than a per-provider runnerAllowed flag because the editor has to warn about the command being typed, which has no persisted provider to decorate.

Files

  • server/routes/providers.js — publish RUNNER_ALLOWED_COMMANDS on GET /
  • client/src/utils/providers.jsisRunnerAllowedCommand(command, allowedCommands) + the normalization mirror
  • client/src/pages/AIProviders.jsx — badge on the card, Banner in the editor
  • server/cos-runner/allowedCommands.parity.test.js — new parity pin
  • docs/API.md, client/src/utils/README.md — catalog rows

Test plan

  • cd server && NODE_ENV=test npx vitest run cos-runner routes/providers — 9 files / 138 tests pass (includes the new parity suite: shared normalization table, every shipped allowlist entry, the null sentinel cases, and the documented POSIX-backslash divergence).
  • cd client && npx vitest run src/utils src/pages/AIProviders.test.jsx — 51 files / 994 tests pass, including 4 new cases: badge appears for an off-list command, stays absent for an on-list one (/usr/local/bin/claude), stays absent when the server omits runnerAllowedCommands, and the editor banner appears on typing without disabling Save.
  • cd client && npx biome lint --error-on-warnings on the changed files — clean.

Closes #4143

…sted (#4143)

GET /api/providers now publishes the CoS Agent Runner's exec allowlist as
read-only `runnerAllowedCommands`, so the AI Providers editor can tell the
user a custom CLI/TUI command will never spawn via /spawn or /spawn-tui.

It stays informational, never a save-time rejection: direct (non-runner)
spawn does not consult the allowlist at all, so an off-list command is a
legitimate config and blocking the save would break it.

The allowlist itself is NOT mirrored client-side — it is the runner's exec
boundary and must stay hand-curated in cos-runner/allowedCommands.js rather
than derived from the user-writable data/providers.json. The client mirrors
only the basename/.exe normalization, pinned by a new parity test. An
allowlist the client couldn't fetch reads as "can't tell" (null), never as
"nothing is allowed", so an older server renders no warning at all.
@atomantic
atomantic merged commit 287d83f into main Aug 15, 2026
7 checks passed
@atomantic
atomantic deleted the claim/issue-4143 branch August 15, 2026 03:26
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.

Warn in provider editor when a custom command isn't runner-allowlisted

1 participant