Skip to content

fix: add exact command allowlist matching#652

Open
jason-allen-oneal wants to merge 7 commits into
openclaw:mainfrom
jason-allen-oneal:fix/exact-command-allowlist
Open

fix: add exact command allowlist matching#652
jason-allen-oneal wants to merge 7 commits into
openclaw:mainfrom
jason-allen-oneal:fix/exact-command-allowlist

Conversation

@jason-allen-oneal
Copy link
Copy Markdown

@jason-allen-oneal jason-allen-oneal commented May 29, 2026

Summary

Adds --enable-commands-exact for strict command allowlisting.

The existing --enable-commands behavior remains unchanged and continues to allow command-prefix matches. This preserves compatibility for users who intentionally allow whole command families such as gmail or drive.

The new exact allowlist mode lets agent and CI callers permit only specific command paths, such as gmail.search, without also enabling sibling commands such as gmail.send.

Security impact

Before this change, command allowlist matching was prefix-based. A broad allowlist entry such as gmail enabled the full Gmail command family. That is useful for humans, but risky for agent deployments because the Gmail family includes read, write, and settings/admin-style commands.

This change provides a non-breaking strict alternative:

  • --enable-commands gmail keeps the existing prefix behavior.
  • --enable-commands-exact gmail.search allows only gmail search.
  • --enable-commands-exact gmail.search blocks sibling Gmail commands.
  • GOG_ENABLE_COMMANDS_EXACT=gmail.search configures the same exact allowlist through the env/default path.

Review follow-up

Addressed review feedback:

  • Added default:"${enabled_commands_exact}" to the new root flag.
  • Wired enabled_commands_exact to GOG_ENABLE_COMMANDS_EXACT in newParser.
  • Added focused end-to-end tests for enforceEnabledCommands covering prefix-only allow, exact-only allow, combined allowlists, blocked sibling commands, neither allowlist matching, and env/default wiring.
  • Added README coverage for --enable-commands-exact and GOG_ENABLE_COMMANDS_EXACT.
  • Added docs/spec.md environment coverage for GOG_ENABLE_COMMANDS_EXACT.

Observed behavior proof

Proof was run locally on Kali from branch fix/exact-command-allowlist.

Observed output:

ok      github.com/steipete/gogcli/internal/cmd 0.403s
command "gmail send" is not enabled (set --enable-commands or --enable-commands-exact to allow it)
command "gmail send" is not enabled (set --enable-commands or --enable-commands-exact to allow it)
[allowed gmail search path reached normal OAuth/Gmail API handling and failed later at token exchange]

Interpretation:

  • Unit tests pass for matcher behavior, enforcement behavior, and env/default wiring.
  • The CLI exact allowlist blocks sibling Gmail command execution before auth/API handling.
  • The env/default exact allowlist also blocks sibling Gmail command execution, proving GOG_ENABLE_COMMANDS_EXACT is wired into the same gate.
  • The allowed gmail.search path is not blocked by the exact allowlist gate. It proceeds to normal auth/API handling, which proves the intended command path passed the gate.

Docs proof

Docs-only follow-up was run locally after commit cb5b071.

Observed output:

ok      github.com/steipete/gogcli/internal/cmd 0.387s
README.md:386:- `--enable-commands-exact <csv>`: allow only exact command paths. Parent paths do not allow children, so `gmail.search` allows `gog gmail search` without allowing sibling commands like `gog gmail send`.
README.md:394:  --enable-commands-exact gmail.search,gmail.get,drive.ls,docs.cat \
README.md:401:For environment-configured agents or CI, set `GOG_ENABLE_COMMANDS_EXACT` to the
README.md:405:GOG_ENABLE_COMMANDS_EXACT=gmail.search,gmail.get,drive.ls,docs.cat \
docs/spec.md:156:- `GOG_ENABLE_COMMANDS_EXACT=calendar.events,gmail.search` (optional exact allowlist; dot paths allowed; parent paths do not allow children)

Compatibility

This is non-breaking. Existing --enable-commands prefix behavior is unchanged.

Note

This branch was prepared through the GitHub API, so it contains several small mechanical commits. The final diff is limited to internal/cmd/enabled_commands.go, internal/cmd/enabled_commands_test.go, internal/cmd/root.go, README.md, and docs/spec.md, and can be squash-merged into one commit.

Copilot AI review requested due to automatic review settings May 29, 2026 16:04
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds support for enabling only specific commands (exact matches) in the CLI command allowlist logic.

Changes:

  • Introduces --enable-commands-exact flag alongside existing --enable-commands.
  • Updates enable-command enforcement to allow either prefix-based matches or exact matches.
  • Adds unit tests for exact-match command path logic.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
internal/cmd/root.go Adds the new root flag and wires it into enforcement + arg parsing for value-taking flags.
internal/cmd/enabled_commands.go Extends enable-command enforcement to support exact allow rules.
internal/cmd/enabled_commands_test.go Adds tests for commandPathMatchesExact.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/cmd/root.go Outdated
Comment on lines +36 to +37
EnableCommands string `help:"Comma-separated list of enabled command prefixes; dot paths allowed (restricts CLI)" default:"${enabled_commands}"`
EnableCommandsExact string `name:"enable-commands-exact" help:"Comma-separated list of exact enabled commands; dot paths allowed and parent commands do not enable children"`
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in the latest branch update. EnableCommandsExact now has default:"${enabled_commands_exact}", and newParser wires enabled_commands_exact from GOG_ENABLE_COMMANDS_EXACT. I also added TestEnableCommandsExactEnvDefault to cover the env/default path.

Comment on lines +9 to 34
func enforceEnabledCommands(kctx *kong.Context, enabled string, enabledExact string) error {
enabled = strings.TrimSpace(enabled)
if enabled == "" {
enabledExact = strings.TrimSpace(enabledExact)
if enabled == "" && enabledExact == "" {
return nil
}

allow := parseEnabledCommands(enabled)
if len(allow) == 0 {
exactAllow := parseEnabledCommands(enabledExact)
if len(allow) == 0 && len(exactAllow) == 0 {
return nil
}
if allow["*"] || allow["all"] {
if allow["*"] || allow["all"] || exactAllow["*"] || exactAllow["all"] {
return nil
}

path := commandPath(kctx.Command())
if len(path) == 0 {
return nil
}
if !commandPathMatches(allow, path) {
return usagef("command %q is not enabled (set --enable-commands to allow it)", strings.Join(path, " "))
if commandPathMatches(allow, path) || commandPathMatchesExact(exactAllow, path) {
return nil
}
return nil

return usagef("command %q is not enabled (set --enable-commands or --enable-commands-exact to allow it)", strings.Join(path, " "))
}
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in the latest branch update. Added focused enforceEnabledCommands coverage for prefix-only allow, exact-only allow, combined allowlists, exact allow blocking a sibling command, and neither allowlist matching returning the usage error. Also added env/default coverage for GOG_ENABLE_COMMANDS_EXACT.

@clawsweeper
Copy link
Copy Markdown

clawsweeper Bot commented May 29, 2026

Codex review: needs changes before merge. Reviewed May 29, 2026, 12:53 PM ET / 16:53 UTC.

Summary
The PR adds --enable-commands-exact and GOG_ENABLE_COMMANDS_EXACT, updates command enforcement to accept either prefix or exact allowlist matches, and adds tests plus README/spec coverage.

Reproducibility: not applicable. This PR adds a new strict allowlist mode rather than reporting a broken existing behavior. Source inspection and the PR body’s terminal output are enough to review the intended behavior.

Review metrics: 3 noteworthy metrics.

  • Changed surface: 5 files, +210/-41. The patch touches command enforcement, root flag/env wiring, tests, and two hand-written docs surfaces.
  • Generated docs surface: 572 generated command pages. A new root flag is part of the global command schema, so the generated command reference is a large mechanical docs surface.
  • New config surface: 1 CLI flag and 1 environment variable added. Maintainers should notice and approve new safety-boundary configuration before merge.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Regenerate the generated command reference so --enable-commands-exact appears in per-command docs.

Risk before merge

  • [P1] This PR changes a command execution safety boundary: if a deployment configures both a broad prefix allowlist and the new exact allowlist, the broad prefix still wins because matching is additive, so maintainers should explicitly accept that non-breaking behavior.
  • [P1] The generated command reference is not refreshed, so users reading per-command generated docs would not see the new global flag until make docs-commands output is committed.

Maintainer options:

  1. Regenerate command reference docs (recommended)
    Run the generated docs refresh so the new global flag appears in the command reference before the security-boundary change lands.
  2. Accept additive allowlist semantics
    Maintainers may approve the current OR behavior where prefix allowlists, exact allowlists, and wildcard/all entries in either list are all permissive.
  3. Pause for stricter semantics
    If exact allowlists should override broad prefix entries, pause this PR and ask for a product/security decision before changing the gate behavior.
Copy recommended automerge instruction
@clawsweeper automerge

Special instructions:
Regenerate the command reference after the new root flag/env support: run `make docs-commands`, include only generated command-reference documentation updates, and do not change Go behavior or CHANGELOG.md.

Next step before merge

  • [P2] A narrow mechanical docs-generation repair remains; the code path itself is otherwise ready for maintainer security-boundary review.

Security
Cleared: No concrete security or supply-chain regression was found; the diff adds an opt-in stricter command gate and does not change dependencies, secrets handling, or release automation.

Review findings

  • [P3] Regenerate the command reference for the new flag — internal/cmd/root.go:37
Review details

Best possible solution:

Land the additive exact allowlist with regenerated command reference docs after maintainers confirm the prefix-or-exact matching model is the intended compatibility tradeoff.

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

Not applicable: this PR adds a new strict allowlist mode rather than reporting a broken existing behavior. Source inspection and the PR body’s terminal output are enough to review the intended behavior.

Is this the best way to solve the issue?

Mostly yes: an additive exact allowlist preserves existing prefix behavior while giving agents a stricter option. The remaining improvement is to regenerate the command reference and have maintainers explicitly accept the additive matching semantics.

Full review comments:

  • [P3] Regenerate the command reference for the new flag — internal/cmd/root.go:37
    The checked-in generated command reference says to run make docs-commands after changing flags, but this patch adds the global --enable-commands-exact flag without updating docs/commands.generated.md or docs/commands/*.md. Regenerate those docs so the new safety flag is visible anywhere users look up command flags.
    Confidence: 0.9

Overall correctness: patch is correct
Overall confidence: 0.86

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 929e26b4a999.

Label changes

Label justifications:

  • P2: This is a normal-priority security/ergonomics improvement for command allowlisting with limited blast radius.
  • merge-risk: 🚨 security-boundary: The diff changes the command execution allowlist boundary and introduces new exact-vs-prefix safety semantics.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body includes after-change local test output and copied CLI output showing blocked sibling commands and the allowed exact path reaching normal auth/API handling.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-change local test output and copied CLI output showing blocked sibling commands and the allowed exact path reaching normal auth/API handling.
Evidence reviewed

Acceptance criteria:

  • [P1] make docs-commands.
  • [P1] rg -n "enable-commands-exact|GOG_ENABLE_COMMANDS_EXACT" README.md docs/spec.md docs/commands.generated.md docs/commands/gog-gmail-send.md.
  • [P1] go test ./internal/cmd.

What I checked:

  • Current main only has prefix allowlisting: enforceEnabledCommands on current main accepts one allowlist string, calls commandPathMatches, and reports only --enable-commands in the failure message. (internal/cmd/enabled_commands.go:9, 929e26b4a999)
  • Current main has no exact root flag or env default: RootFlags only defines EnableCommands, and newParser only wires GOG_ENABLE_COMMANDS; there is no EnableCommandsExact or GOG_ENABLE_COMMANDS_EXACT on main. (internal/cmd/root.go:36, 929e26b4a999)
  • PR diff adds the exact allowlist implementation: The PR diff adds EnableCommandsExact, passes it into enforceEnabledCommands, adds commandPathMatchesExact, wires enabled_commands_exact, and updates README/spec docs. (internal/cmd/root.go:37, cb5b071f92f2)
  • PR proof covers the changed behavior: The PR body includes local go test ./internal/cmd output plus observed CLI output showing exact allowlisting blocks gmail send and lets gmail search pass the gate. (cb5b071f92f2)
  • Generated command docs require refresh after flag changes: The generated command reference says to run make docs-commands after changing command flags, and current generated command pages still list only --enable-commands/--disable-commands. (docs/commands/README.md:3, 929e26b4a999)

Likely related people:

  • Peter Steinberger: git blame and git log -S'enforceEnabledCommands' show the existing allow/deny command gating and root flag wiring came in with the v0.19.0 release commit; local history is compacted to that release commit, so deeper provenance is limited. (role: introduced current command gating surface; confidence: medium; commits: b25a3c029b37; files: internal/cmd/enabled_commands.go, internal/cmd/root.go, internal/cmd/root_more_test.go)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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.

How this review workflow works
  • 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.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. 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: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. labels May 29, 2026
@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. 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. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels May 29, 2026
Copy link
Copy Markdown
Author

@jason-allen-oneal jason-allen-oneal left a comment

Choose a reason for hiding this comment

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

Follow-up docs request addressed in cb5b071.

Added README coverage for --enable-commands-exact and GOG_ENABLE_COMMANDS_EXACT, and added docs/spec.md environment coverage for GOG_ENABLE_COMMANDS_EXACT while keeping the compatibility-preserving prefix behavior documented for --enable-commands.

Local proof from the docs follow-up:

ok      github.com/steipete/gogcli/internal/cmd 0.387s
README.md:386:- `--enable-commands-exact <csv>`: allow only exact command paths. Parent paths do not allow children, so `gmail.search` allows `gog gmail search` without allowing sibling commands like `gog gmail send`.
README.md:394:  --enable-commands-exact gmail.search,gmail.get,drive.ls,docs.cat \
README.md:401:For environment-configured agents or CI, set `GOG_ENABLE_COMMANDS_EXACT` to the
README.md:405:GOG_ENABLE_COMMANDS_EXACT=gmail.search,gmail.get,drive.ls,docs.cat \
docs/spec.md:156:- `GOG_ENABLE_COMMANDS_EXACT=calendar.events,gmail.search` (optional exact allowlist; dot paths allowed; parent paths do not allow children)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. P2 Normal priority bug or improvement with limited blast radius. proof: sufficient Contributor real behavior proof is sufficient. 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