Skip to content

fix(cli): redact doctor credentials, honour global -c/-d, print errors once, explain locked set_profile (Spec fix-usertest-cli) - #1472

Merged
github-actions[bot] merged 9 commits into
mainfrom
fix-usertest-cli-security
Oct 2, 2026
Merged

github-actions[bot] merged 9 commits into
mainfrom
fix-usertest-cli-security

Conversation

@Dumbris

@Dumbris Dumbris commented Oct 2, 2026

Copy link
Copy Markdown
Member

Fixes four findings from the first-run user test (audit IDs F-01, F-06, F-09, F-11). Go CLI and MCP only; REST, the Web UI and the macOS app are unchanged. Refs #1396 (same family as F-06, different root cause).

What changes

  • F-01 (high): mcpproxy doctor no longer leaks the admin key. The ?apikey= URL in GET /api/v1/info was dumped verbatim into doctor -o json. Every doctor format now redacts credential query parameters (apikey, token, secret, and the other shared sensitive parameters) in any URL and scrubs the literal admin key wherever it would appear; both print as REDACTED. doctor -o yaml was silently empty and is now a real format (pretty, json, yaml); the global --json maps to json and an unknown format is an error instead of no output. status already masked the key and is covered by a regression test; status --show-key and --web-url stay the explicit opt-ins. GET /api/v1/info still returns the keyed URL to an authenticated administrator, as the tray needs it.
  • F-06: the global -c and -d are authoritative for every management command. The reported symptom reproduces with an empty value (-c "", for example an unset shell variable): it created $HOME/.mcpproxy/mcp_config.json and reported an empty list. An empty --config or --data-dir is now rejected at parse time on the root flags and on every command-local --config, with no help or --help-json change. A single resolver (command flag, then global -c, then <data-dir>/mcp_config.json when it exists, then legacy discovery) is used by upstream, doctor, auth, call, code, tools, token and registry/catalog loaders, so mcpproxy -d DIR upstream list reads DIR/mcp_config.json instead of fabricating a HOME default, and config-mode writes land in the file that was read. serve is unchanged.
  • F-09: a command error is printed once. Cobra and main() both printed Error: ..., so every unsilenced RunE error (including the connect binding-guard Fixes: list) appeared twice. A single executeRoot prints it once, keeps the unknown command help hint and the exit codes.
  • F-11: set_profile tells a client credential why a switch failed. A locked client got unknown profile 'work-full' for a profile that exists. Client credentials now get cannot switch to profile '<slug>': this client's profile is locked (locked) or cannot switch to profile '<slug>': it is not a profile this client may switch to (switchable). The text depends only on the credential's own mode, never on the slug, and never names the bound profile, so it stays non-enumerating; agent tokens, anonymous callers and administrators keep the Spec 105 text, and /mcp/p/<slug> keeps its 404. The Spec 057/105 suites are untouched and the frozen tools/list goldens are unchanged.

Spec and docs

Spec 108 contracts/refusals.md, contracts/mcp-tools.md, FR-018 and the user-story 4 scenario are updated; tasks.md gains Phase 17 (T153 to T156). New golden internal/profile/testdata/contract/set_profile_refusals.json. docs/cli-management-commands.md (doctor formats and redaction, global flags) and docs/features/profiles.md (set_profile texts) are updated.

Tests

TestDoctorOutput_*, TestStatusOutput_MasksKeyInEveryFormat, TestConfigFlagsRejectEmptyValue, TestLoadersHonorGlobalConfigFlag, TestLoadersPreferDataDirConfig, TestLoadCLIConfigDataDirWithoutFileCreatesNothingInHome, TestUpstreamConfigFilePathMatchesLoadPath, TestResolveCLIConfigPathPrecedence, TestExecuteRoot_*, TestSetProfileRefusalGolden, TestSetProfileV3_ClientRefusalTextMatchesGolden, plus the updated v3 set_profile expectations.

Follow-ups (not in this PR)

  • The /mcp/p/<slug> 404 for a locked client still says unknown profile (needs a Spec 105 contract decision).
  • serve -d DIR without -c still reads the cwd or HOME config.
  • status masks the URL key percent-encoded rather than as apikey=REDACTED.
  • Commands that print their own structured error and also return it may still double print.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Deploying mcpproxy-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 3405aae
Status: ✅  Deploy successful!
Preview URL: https://ecc6715c.mcpproxy-docs.pages.dev
Branch Preview URL: https://fix-usertest-cli-security.mcpproxy-docs.pages.dev

View logs

loadRegistryConfig (registry and catalog) now goes through loadCLIConfig so a --data-dir with no config file anywhere no longer creates HOME/.mcpproxy/mcp_config.json (O1).
@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

📦 Build Artifacts

Workflow Run: View Run
Branch: fix-usertest-cli-security

Available Artifacts

  • archive-darwin-amd64 (31 MB)
  • archive-darwin-arm64 (28 MB)
  • archive-linux-amd64 (19 MB)
  • archive-linux-arm64 (17 MB)
  • archive-windows-amd64 (31 MB)
  • archive-windows-arm64 (27 MB)
  • frontend-dist-pr (0 MB)
  • installer-dmg-darwin-amd64 (27 MB)
  • installer-dmg-darwin-arm64 (24 MB)
  • smart-mcp-proxymcpproxy-goOPRJCP.dockerbuild (0 MB)

How to Download

Option 1: GitHub Web UI (easiest)

  1. Go to the workflow run page linked above
  2. Scroll to the bottom "Artifacts" section
  3. Click on the artifact you want to download

Option 2: GitHub CLI

gh run download 37061695743 --repo smart-mcp-proxy/mcpproxy-go

Note: Artifacts expire in 14 days.

@codecov-commenter

codecov-commenter commented Oct 2, 2026 •

Copy link
Copy Markdown

@github-actions github-actions 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.

Approved (Model B): Paperclip review verdicts = ACCEPT and qa-gate green at this head SHA. Arming auto-merge; GitHub merges when all required checks pass.

@github-actions
github-actions Bot enabled auto-merge (squash) October 2, 2026 21:16
@github-actions
github-actions Bot merged commit a828c54 into main Oct 2, 2026
63 checks passed
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.

2 participants