You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(039): never call keyring.Set from scanner configure on macOS (F-03 follow-up)
The previous fix in this branch removed the IsAvailable probe that was
popping the "Keychain Not Found" system modal, but the modal continued to
appear on the user's machine during every `mcpproxy security configure`
call with the real scanner_<id>_<env> key (screenshotted).
Root cause: my runWithTimeout helper wrapped keyring.Set in a goroutine
and returned ErrKeyringTimeout after 3s if the goroutine didn't finish.
That protects the server process from blocking but does NOT cancel the
goroutine — Go has no goroutine cancellation, and the underlying
Security.framework call continues running in the background. While it
runs, macOS keeps the modal on the user's screen. Worse: each subsequent
Store call spawns another zombie goroutine.
Fix: eliminate the keyring.Set call from the scanner configure path
entirely.
1. internal/security/scanner/service.go — ConfigureScanner now stores
scanner env values directly in the scanner's ConfiguredEnv map in
BBolt. No SecretStore call. Scanner env vars end up in the scanner
container's /proc/environ at scan time anyway, so keyring storage adds
no meaningful confidentiality. Users who want keyring-backed storage
for a specific secret can still pass a `${keyring:my-name}` reference
as the env value — the resolver expands it via a read-only Get at
scan time, which is safe.
2. internal/secret/keyring_provider.go — KeyringProvider.Store now
refuses to call keyring.Set on darwin by default. The opt-in is
MCPPROXY_KEYRING_WRITE=1 (env) or SetWritesEnabled(true) (programmatic,
for tests). On Linux/Windows the default is unchanged. The previous
three-layer guard (known-unavailable cache, first-time probe, failure
cache) still applies behind the macOS gate for the opt-in case.
3. internal/secret/keyring_provider_test.go — new regression test
TestKeyringProvider_Store_MacOSDefaultRefuses pins the exact user
scenario (configure mcp-scan SNYK_TOKEN on macOS) and asserts that
keyring.Set is NOT called. Other Store tests updated to explicitly
opt in via SetWritesEnabled(true) so they exercise the three-layer
guard path regardless of runtime.GOOS.
Verified on arm64 macOS: `time mcpproxy security configure mcp-scan --env
SNYK_TOKEN=...` returns in 0.041s (was 3s, before that 60s+), emits zero
keyring log lines, and does NOT pop the macOS modal. Subsequent scan of
the "everything" server runs mcp-scan successfully using the token
pulled from ConfiguredEnv.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
0 commit comments