fix: comprehensive code review fixes across security, correctness, and robustness#131
Conversation
Code reviewFound 3 issues:
Lines 118 to 136 in 731fd38
Paths 1 (flag) and 2 (env var) in Lines 160 to 164 in 731fd38
Lines 51 to 53 in 731fd38 Generated by the |
…and distribution Phase 1 (Security): Redact token from debug logs, add HTTP timeouts, add 10MB response body limits, fix remediate_finding silent error bug. Phase 2 (MCP): Add unified abstract tools (search/get/triage/ticket/events/fix), ToolSet flag (default/all/minimal/findings/admin), 5 new prompts, 2 new resources. Phase 3 (UX): Move generated commands under `nullify api`, add new commands (scan, fix, open, repos, whoami, version), concurrent API calls via errgroup, output consistency with --output flag, --quiet/--no-color flags, help examples. Phase 4 (HTTP): User-Agent header, retry with exponential backoff, fix env var precedence, refreshing auth transport for MCP sessions, shared apierror package, distinct exit codes. Phase 5 (Distribution): Homebrew tap config, `nullify update` command, SARIF output format, enhanced `nullify version` with build metadata. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Buffer request body in retry transport to prevent empty bodies on retry - Clone request in RoundTrip to avoid mutating the original (both transports) - Fix generator template missing api. prefix logic for host - Strip api. prefix in open.go to navigate to dashboard, not API - Remove unnecessary mutex in findings.go (goroutines write to distinct indices) - Use DoPost instead of DoGet for mutation operations in fix.go - Fix Content-Type check in apierror to use HasPrefix for charset variants - Sort finding type names for deterministic MCP tool enum ordering - Parallelize ci report API calls with errgroup - Use structured exit codes (ExitAuthError) instead of bare os.Exit(1) - Remove misleading _ = token in mcp.go, validate auth inline Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…obustness Critical fixes: - Fix broken refresh token flow: send token as HTTP cookie instead of query param to match backend expectation (security-droid reads from cookie) - Fix GITHUB_ACTION_REPOSITORY → GITHUB_REPOSITORY (non-standard env var) - Add url.PathEscape for finding IDs in all URL path interpolations (MCP, CLI) - Replace bare http.Get with http.NewRequestWithContext for proper timeout/context - URL-encode GitHub token and owner in token exchange request Security & correctness: - Fix retry transport to respect context cancellation (select on ctx.Done) - Fix file handle leak in openapi.go (missing defer Close) - Fix openapi.go nil,nil return to return descriptive error - SanitizeNullifyHost now delegates to ParseCustomerDomain, accepting 'acme', 'acme.nullify.ai', and 'api.acme.nullify.ai' formats - Strip path/query from host input, validate hostname characters - Add severity-threshold validation in ci gate command - Mark pentest --spec-path as required flag Exit codes & UX: - Use ExitAuthError(2) for auth failures, ExitNetworkError(3) for API errors, ExitFindings(1) for gate failures across all commands - Fix ci report to use limit=1000 for accurate counts (was limit=1) - Fix "1 findings" → "1 finding" singular form in status output - Fix auth token command to print trailing newline - Add periodic "still waiting" message during login authentication - Improve auth config error message Architecture & deduplication: - Deduplicate buildQueryString in MCP package to use lib.BuildQueryString - Add ClientOption/WithHTTPClient to generated API client for retry support - Export NewRetryTransport and wire retry into generated API client - Remove unused --auth-config global flag - Parallelize status command scanner queries with errgroup - Add missing scanner types (pentest, bughunt, cspm) to MCP composite tools - Use promptResult helper consistently in MCP prompts - Fix wizard to use absolute paths via os.Getwd() - Handle output.Print errors with stderr fallback - Clear stale Token field on refreshing transport client - Log warning when NULLIFY_HOST env var is invalid Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The status command now directly imports errgroup from golang.org/x/sync. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…bugs - Move time.After(10min) outside for/select loop so it fires correctly - Sanitize config file host through SanitizeNullifyHost in resolveHost - Normalize credential keys to bare form (strip api. prefix) at save/lookup - Fix SanitizeNullifyHost to return bare host form consistently Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
731fd38 to
69d09ff
Compare
- Use cmd.Context() instead of context.Background() in update command - Accept context.Context param in setupLogger() so cobra commands pass their own context instead of always creating a new background context - Delete unused scan command that only printed help text - Add credential key migration in LoadCredentials() to normalize old "api." prefixed keys to bare form, preventing auth failures after host sanitization changes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Check io.Copy return value in local_scan.go to fix golangci-lint errcheck - Use auth.CredentialKey() for credential map lookups in all commands (chat, mcp, status, whoami, fix, ci, findings) to match the normalized key format used when saving credentials Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Addresses 34 issues identified in a senior-level code review of the CLI repository (5 critical, 6 high, 11 medium, 7 low, 5 nit). Key highlights:
Critical & Security Fixes
security-droid) expectationGITHUB_ACTION_REPOSITORY→GITHUB_REPOSITORY: The old env var name is non-standard and not set by GitHub Actionsurl.PathEscapefor finding IDs in all URL path interpolations across MCP tools and CLI commands, preventing path traversalhttp.Getwithhttp.NewRequestWithContextfor proper timeout and context cancellation in GitHub token exchangeselectonctx.Done()openapi.go(missingdefer Close)ci gateto reject invalid valuesCorrectness Fixes
SanitizeNullifyHostnow delegates toParseCustomerDomain, acceptingacme,acme.nullify.ai, andapi.acme.nullify.aiformats (strips path/query, validates hostname chars)openapi.gonil, nilreturn → descriptive errorci reportlimit from 1 → 1000 for accurate finding counts--spec-pathas required flag (removes manual check)get_findings_for_repoandget_critical_pathExit Codes & UX
ExitAuthError(2),ExitNetworkError(3),ExitFindings(1)— CI pipelines can now distinguish auth failures from findingsauth tokento print trailing newline (was breaking piping)auth configerror message when no config existsArchitecture & Code Quality
buildQueryStringin MCP package → delegates tolib.BuildQueryStringClientOption/WithHTTPClientto generated API client; wire retry transport into itNewRetryTransportfor reuse across client typesstatuscommand scanner queries witherrgrouppromptResulthelper consistently in all MCP promptsos.Getwd()instead of relative pathsoutput.Printerrors with stderr fallback--auth-configglobal flag (pentest-specific flag remains)Tokenfield on refreshing transport clientNULLIFY_HOSTenv var is invalidFiles Changed (25)
internal/auth/login.go,internal/lib/get_token.go,internal/lib/urls.go,internal/lib/openapi.go,internal/client/retry.go,internal/client/client.go,internal/client/refreshing_transport.go,internal/api/client.go,internal/mcp/server.go,internal/mcp/tools_unified.go,internal/mcp/tools_composite.go,internal/mcp/prompts.go,internal/wizard/steps.go,cmd/cli/cmd/root.go,cmd/cli/cmd/ci.go,cmd/cli/cmd/status.go,cmd/cli/cmd/findings.go,cmd/cli/cmd/fix.go,cmd/cli/cmd/auth.go,cmd/cli/cmd/chat.go,cmd/cli/cmd/mcp.go,cmd/cli/cmd/pentest.go,cmd/cli/cmd/repos.go,cmd/cli/cmd/status_test.go,scripts/generate/main.goTest plan
go build ./...— compiles cleanlygo vet ./...— no warningsgo test ./...— all tests pass (updated test expectations for singular form and new URL parsing behavior)nullify auth login --host acmeaccepts short-form hostnullify ci gate --severity-threshold invalidrejects with errornullify auth tokenoutputs trailing newline🤖 Generated with Claude Code