feat(cli): add --read-only mode to block write operations#145
Merged
platinummonkey merged 3 commits intodatadog-labs:mainfrom Mar 3, 2026
Merged
feat(cli): add --read-only mode to block write operations#145platinummonkey merged 3 commits intodatadog-labs:mainfrom
platinummonkey merged 3 commits intodatadog-labs:mainfrom
Conversation
Extract inline is_write logic from build_command_schema() into a
standalone pub(crate) fn is_write_command_name() for reuse by the
upcoming read-only runtime guard.
- Added 5 missing write command names: move, link, unlink, configure, upgrade
- Tightened patch check: name.contains("patch") → name == "patch" || name.starts_with("patch-")
- Fixes agent schema JSON output where these commands were incorrectly marked read_only: true
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a --read-only flag, DD_READ_ONLY / DD_CLI_READ_ONLY env vars, and read_only config file option that blocks all write (CUD) operations at runtime, allowing only read operations. - Added read_only field to Config and FileConfig structs - Added --read-only global CLI flag to Cli struct - Refactored main_inner() to use ArgMatches for subcommand introspection - Added get_leaf_subcommand_name() and get_top_level_subcommand_name() helpers - Runtime guard fires before auth validation (fail-fast) - auth and alias commands exempted (local-only state) - Updated all 14 Config struct literals in test_commands.rs - Added 10 new tests covering write detection, read commands, nested commands, and auth/alias exemptions - Updated COMMANDS.md, ARCHITECTURE.md, and EXAMPLES.md docs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…x formatting Two test helpers (client.rs and formatter.rs) were missing the new `read_only: false` field added to `config::Config`, causing compile errors in CI. Also run cargo fmt to fix rustfmt violations in main.rs (is_write_command_name) and test_commands.rs (long array literal). Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Adds a
--read-onlyflag (+DD_READ_ONLY/DD_CLI_READ_ONLYenv vars +read_onlyconfig file option) that blocks all write (CUD) operations at runtime, allowing only read operations. Also fixes 5 missing write command names in the agent JSON schema as a preparatory commit.Motivation
My primary motivation for this was to derisk actions autonomous agents might take when using the
pupCLI. A flag that blocks all mutating actions is a stronger safeguard than updating my instructions to explicitly disallow creates/updates/deletes.Additional Notes
Design decisions:
auth/aliascommands are allowed - these only affect local state (credentials and config aliases), not Datadog resources.pup --read-only monitors create --file f.jsonfails fast even without credentials.bulk-export) are not flagged - these semantically are read operations. The guard thus checks the leaf subcommand name instead of the HTTP method.--no-read-onlyescape hatch in v1 - ifread_only: trueis in config, it cannot be overridden per-invocation. A safety feature should be hard to bypass especially by agents.patchcheck tightened - changedname.contains("patch")toname == "patch" || name.starts_with("patch-")since this logic is now a runtime blocker, not just schema metadata.Checklist
Related Issues
N/A