Skip to content

fix: CLI improvements — config show, completion install, enhanced doctor, Sigstore verification#465

Merged
Aureliolo merged 12 commits intomainfrom
fix/cli-improvements
Mar 15, 2026
Merged

fix: CLI improvements — config show, completion install, enhanced doctor, Sigstore verification#465
Aureliolo merged 12 commits intomainfrom
fix/cli-improvements

Conversation

@Aureliolo
Copy link
Copy Markdown
Owner

Summary

  • Self-update fix: Add release-assets.githubusercontent.com to allowed download hosts — GitHub started routing release assets through this domain, breaking synthorg update
  • synthorg config show: Displays current CLI configuration with masked JWT secret. Warns if not initialized
  • synthorg completion-install: Auto-detects shell (bash/zsh/fish/powershell) and installs tab-completion. Idempotent. Leaves Cobra's built-in completion command untouched
  • Enhanced synthorg doctor: Adds compose file validation, port conflict detection, Docker image availability checks, container detail parsing from compose ps JSON, Docker/Compose minimum version warnings
  • Native disk info: Replaces fsutil/df subprocess with Go syscalls (GetDiskFreeSpaceExW on Windows, Statfs on Unix) — fixes "unavailable" on non-admin Windows
  • Sigstore bundle verification: Self-update now downloads and verifies checksums.txt.sigstore.json against Sigstore's public good transparency log, checking that the signing identity matches the GitHub Actions OIDC issuer for this repo. Uses sigstore/sigstore-go (new dependency)
  • Review fixes: 15 findings from 5 review agents addressed — idiomatic iota, f.Close() error handling, function size splits, CLAUDE.md docs updates, PowerShell path validation, test cleanup

Closes #234

Test plan

  • cd cli && go vet ./... — clean
  • cd cli && golangci-lint run — 0 issues
  • cd cli && go test ./... — all pass
  • cd cli && go build -o synthorg ./main.go — builds
  • ./synthorg config show — displays config or "not initialized"
  • ./synthorg completion-install — detects shell, installs completions
  • ./synthorg completion-install (again) — reports "already installed"
  • ./synthorg doctor — shows compose file, images, disk info sections
  • ./synthorg completion bash — Cobra built-in still works

Review coverage

Pre-reviewed by 5 agents (go-reviewer, go-security-reviewer, go-conventions-enforcer, docs-consistency, issue-resolution-verifier). 15 findings addressed, 1 deferred (log secret redaction — user decision).

🤖 Generated with Claude Code

…hosts

GitHub started routing release asset downloads through this domain,
causing `synthorg update` to reject the redirect as an unexpected host.
Displays current CLI configuration with masked JWT secret.
Warns if not initialized and suggests running synthorg init.
Enhances diagnostics with five new checks:
- Compose file existence and validity
- Port conflict detection (skipped when containers are running)
- Local Docker image availability
- Container detail parsing from compose ps JSON
- Docker/Compose minimum version warnings
…etup

Detects the user's shell and installs tab-completion for synthorg.
Supports bash, zsh, fish, and powershell. Idempotent — safe to run
multiple times. Leaves Cobra's built-in completion command untouched.
Replaces fsutil/df subprocess calls with direct syscall usage:
- Windows: GetDiskFreeSpaceExW (no admin required)
- Unix: syscall.Statfs

Fixes disk info showing "unavailable" on non-admin Windows.
Pre-reviewed by 5 agents, 15 findings addressed:
- Fix non-idiomatic iota usage in ShellType constants
- Fix appendToFile to check f.Close() error
- Replace custom contains helper with strings.Contains
- Validate PowerShell profile path (absolute, clean, length)
- Fix StatePath called twice with potentially different inputs
- Split Collect and FormatText into sub-50-line functions
- Update CLAUDE.md: add completion/ package, config and
  completion-install commands, expand diagnostics description
- Add Sigstore bundle verification to self-update using sigstore-go
  (verifies checksums.txt signature against GitHub Actions OIDC identity
  via Sigstore public good transparency log)
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 15, 2026

Dependency Review

The following issues were found:

  • ✅ 0 vulnerable package(s)
  • ✅ 0 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ⚠️ 19 package(s) with unknown licenses.
  • ⚠️ 2 packages with OpenSSF Scorecard issues.

View full job summary

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 15, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds new CLI commands (config show, completion-install), a cross-shell completion installer, expanded diagnostics (compose/ports/images/container summaries, native disk usage), Sigstore bundle discovery & verification in self-update, corresponding tests, and go.mod dependency updates.

Changes

Cohort / File(s) Summary
CLI commands & wiring
cli/cmd/config.go, cli/cmd/completion_install.go, cli/cmd/update.go
Adds config show and completion-install commands; wires completion-install into root; update now forwards an optional Sigstore bundle URL to the selfupdate downloader.
CLI command tests
cli/cmd/config_test.go
Unit tests for secret masking, not-initialized behavior, and config output redaction.
Completion implementation & tests
cli/internal/completion/install.go, cli/internal/completion/install_test.go
New cross-shell completion installer (Bash, Zsh, Fish, PowerShell) with idempotency markers, profile path detection, file helpers, and tests verifying filesystem side effects.
Diagnostics expansion & tests
cli/internal/diagnostics/collect.go, cli/internal/diagnostics/collect_test.go
Extends Report with compose file validity, port conflicts, image status, container summary; adds compose ps parsing (JSON/NDJSON), port/image checks, formatting, and tests including a real port bind.
Disk usage platform support
cli/internal/diagnostics/disk_unix.go, cli/internal/diagnostics/disk_windows.go
Adds platform-specific diskUsage implementations for Unix (syscall.Statfs) and Windows (GetDiskFreeSpaceExW).
Self-update: sigstore plumbing & verification
cli/internal/selfupdate/updater.go, cli/internal/selfupdate/sigstore.go, cli/internal/selfupdate/updater_test.go
Propagates optional Sigstore bundle URL through asset discovery and Download; adds bundle parsing and signature verification; updates CheckResult and Download signatures and tests for bundle failure/invalid JSON.
Module manifest
cli/go.mod
Adds sigstore-related and other indirect dependencies required for bundle verification, protobufs, and related tooling.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as "CLI (self-update)"
  participant Releases as "GitHub Releases"
  participant Fetcher as "HTTP/TUF Fetcher"
  participant Verifier as "Sigstore Verifier"

  CLI->>Releases: request assetURL, checksumURL, optional bundleURL
  Releases-->>CLI: assetURL + checksumURL (+ bundleURL)
  CLI->>Fetcher: download checksum (checksumURL)
  Fetcher-->>CLI: checksumData
  alt bundleURL provided
    CLI->>Fetcher: download bundle (bundleURL)
    Fetcher-->>CLI: bundleData
    CLI->>Verifier: verify(bundleData, checksumData)
    Verifier-->>CLI: ok / error
  end
  alt verified or no bundle
    CLI->>Fetcher: download asset (assetURL)
    Fetcher-->>CLI: assetArchive
    CLI->>CLI: extract & replace binary
  end
  CLI-->>User: report success or failure
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: CLI improvements including config show, completion install, enhanced doctor, and Sigstore verification—all reflected in the code changes.
Description check ✅ Passed The description comprehensively explains each major change (self-update fix, config show, completion-install, enhanced doctor, native disk info, Sigstore verification) and matches the code modifications.
Linked Issues check ✅ Passed The PR fulfills issue #234 objectives by implementing a functional CLI wrapper with terminal-formatted output (config show, doctor), basic commands (start/stop via existing code, new config display), and proper CLI technology (Cobra framework).
Out of Scope Changes check ✅ Passed All code changes directly support the stated PR objectives: new config/completion subcommands, enhanced diagnostics, Sigstore verification, and disk info utilities are all within scope and aligned with issue #234's CLI implementation requirements.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/cli-improvements
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/cli-improvements
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

@socket-security
Copy link
Copy Markdown

socket-security bot commented Mar 15, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedgolang/​github.com/​sigstore/​protobuf-specs@​v0.5.098100100100100
Addedgolang/​github.com/​sigstore/​sigstore-go@​v1.1.49810010010080

View full report

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly upgrades the CLI by introducing new commands for configuration management and streamlined shell completion installation. It also dramatically improves the diagnostic capabilities of the doctor command, making it more comprehensive in identifying potential system and Docker-related issues. A major security enhancement is the integration of Sigstore verification into the self-update process, ensuring the authenticity and integrity of the CLI binary. These changes collectively aim to deliver a more robust, user-friendly, and secure command-line experience.

Highlights

  • Self-Update Fix: The self-update mechanism was updated to correctly handle GitHub release assets routed through release-assets.githubusercontent.com.
  • New config show Command: A new CLI command, synthorg config show, was introduced to display the current CLI configuration, with sensitive JWT secrets automatically masked.
  • New completion-install Command: A new command, synthorg completion-install, was added to automatically detect the user's shell and install tab-completion scripts for Bash, Zsh, Fish, and PowerShell.
  • Enhanced doctor Command: The synthorg doctor command received significant enhancements, including compose file validation, detection of port conflicts, checks for Docker image availability, parsing of container details from compose ps output, and warnings for minimum Docker/Compose versions.
  • Native Disk Information: External calls to fsutil (Windows) and df (Unix) for disk information were replaced with native Go syscalls, resolving issues on non-admin Windows installations.
  • Sigstore Verification for Self-Updates: The self-update process now includes Sigstore bundle verification for checksums.txt.sigstore.json, ensuring the integrity and authenticity of downloaded files by checking the signing identity against the GitHub Actions OIDC issuer.
  • Review Feedback Addressed: Fifteen findings from five different review agents were addressed, covering aspects like idiomatic Go usage, error handling (specifically f.Close()), function size, documentation updates, PowerShell path validation, and test cleanup.
Changelog
  • CLAUDE.md
    • Updated the description of the cmd/ directory to include new commands config and completion-install.
    • Expanded the description of the diagnostics/ directory to reflect new functionalities.
  • cli/cmd/completion_install.go
    • Added a new Cobra command completion-install to automatically set up shell completions.
  • cli/cmd/config.go
    • Added a new Cobra command config with a show subcommand to display the current CLI configuration, with JWT secrets masked.
  • cli/cmd/config_test.go
    • Added unit tests for the maskSecret function and the config show command, covering both initialized and uninitialized states.
  • cli/cmd/update.go
    • Modified the updateCLI function to pass the SigstoreBundURL to the selfupdate.Download function.
  • cli/go.mod
    • Added github.com/sigstore/sigstore-go as a new direct dependency.
    • Updated various indirect dependencies to newer versions.
  • cli/go.sum
    • Updated checksums for existing and newly added Go modules.
  • cli/internal/completion/install.go
    • Implemented shell detection and installation logic for Bash, Zsh, Fish, and PowerShell completions.
    • Added helper functions fileContains and appendToFile.
  • cli/internal/completion/install_test.go
    • Added unit tests for shell detection, file content checks, and idempotent installation for various shells.
  • cli/internal/diagnostics/collect.go
    • Refactored Collect function into smaller, focused helper functions (collectDocker, collectHealth, collectConfig, collectInfra).
    • Introduced new fields in Report for compose file status, port conflicts, image status, and container summary.
    • Added checkComposeFile, checkPorts, checkImages, parseContainerDetails, and hasRunningContainers functions for enhanced diagnostics.
    • Updated diskInfo to use native syscalls instead of external commands.
    • Modified FormatText to include new diagnostic sections.
  • cli/internal/diagnostics/collect_test.go
    • Added unit tests for parseContainerDetails, hasRunningContainers, checkPorts, and the new sections in FormatText.
  • cli/internal/diagnostics/disk_unix.go
    • Added Unix-specific implementation for diskUsage using syscall.Statfs_t.
  • cli/internal/diagnostics/disk_windows.go
    • Added Windows-specific implementation for diskUsage using GetDiskFreeSpaceExW via syscall.
  • cli/internal/selfupdate/sigstore.go
    • Added verifySigstoreBundle function to perform Sigstore verification of checksums.txt against a bundle, checking issuer and SAN regex.
    • Added loadBundleFromJSON helper.
  • cli/internal/selfupdate/updater.go
    • Updated CheckResult to include SigstoreBundURL.
    • Modified findAssets to locate checksums.txt.sigstore.json.
    • Updated Download to conditionally perform Sigstore verification if a bundle URL is provided.
    • Added release-assets.githubusercontent.com to AllowedDownloadHosts.
  • cli/internal/selfupdate/updater_test.go
    • Adjusted Download calls in tests to include the new bundleURL parameter (empty string for existing tests).
Activity
  • The pull request was pre-reviewed by 5 agents (go-reviewer, go-security-reviewer, go-conventions-enforcer, docs-consistency, issue-resolution-verifier).
  • 15 findings from these reviews were addressed.
  • 1 finding (log secret redaction) was deferred based on user decision.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces significant improvements to the CLI, including new config show and completion-install commands, an enhanced doctor command with more diagnostics, and importantly, Sigstore verification for self-updates. The code is well-structured and includes tests for most of the new functionality. My review focuses on improving robustness in error handling, ensuring code comments are accurate, and highlighting the need for testing on the new security-critical Sigstore verification feature.

Comment on lines +217 to +226
// Sigstore bundle verification (optional but recommended).
if bundleURL != "" {
bundleData, err := httpGetWithClient(ctx, client, bundleURL, maxAPIResponseBytes)
if err != nil {
return nil, fmt.Errorf("downloading sigstore bundle: %w", err)
}
if err := verifySigstoreBundle(checksumData, bundleData); err != nil {
return nil, fmt.Errorf("sigstore verification failed: %w", err)
}
}
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.

high

This new Sigstore verification logic is a critical security feature, but it doesn't appear to be covered by any tests. The related sigstore.go file also lacks tests. It's important to add unit and/or integration tests to verify the signature validation process, including success and failure scenarios (e.g., invalid signature, wrong issuer, mismatched artifact digest) to ensure its correctness and robustness.

Comment on lines +259 to +263
if _, err := f.WriteString(content); err != nil {
_ = f.Close()
return fmt.Errorf("writing to %s: %w", path, err)
}
return f.Close()
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.

medium

The error from f.Close() on line 260 is ignored when a write error occurs. While the write error is the primary one, it's more robust to handle the close error as well, as it might indicate that the write was not fully flushed to disk. The current implementation also returns the f.Close() error on the happy path without wrapping it, which could lose context. Consider refactoring to ensure both write and close errors are checked and properly wrapped.

_, writeErr := f.WriteString(content)
closeErr := f.Close()
if writeErr != nil {
	return fmt.Errorf("writing to %s: %w", path, writeErr)
}
if closeErr != nil {
	return fmt.Errorf("closing %s: %w", path, closeErr)
}
return nil

Comment on lines +320 to +321
// diskInfoNative returns disk usage for the given path using native Go syscalls.
// Platform-specific implementations are in disk_unix.go and disk_windows.go.
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.

medium

The comment on line 320 refers to the function as diskInfoNative, but the function is named diskInfo. This discrepancy could be confusing for future maintainers. Please update the comment to match the function name.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cli/cmd/config.go`:
- Around line 35-43: runConfigShow currently calls resolveDataDir() and probes
config.StatePath(dir) before validating the directory, which can misreport
invalid --data-dir as "Not initialized"; instead validate the resolved data-dir
using the same validation used by config.Load (e.g., call config.SecurePath or
the canonical validation function with resolveDataDir() and return any error),
then build statePath from the validated safeDir via config.StatePath(safeDir)
and proceed to os.Stat; update runConfigShow to return the validation error when
present and only check for state file after successful validation.

In `@cli/internal/completion/install.go`:
- Around line 127-129: The current installZsh and installFish functions treat an
existing completion file (compFile) as "already installed" and return early;
change this so the presence check only sets res.AlreadyInstalled = true but does
not return — always regenerate and overwrite the completion file contents (use
os.WriteFile or equivalent with correct permissions) so users get updated
commands on rerun; keep the shell-init idempotent logic that updates ~/.zshrc or
fish config (the fpath/stanza checks) but do not skip writing the generated
completion file when it already exists. Ensure error handling/logging remains
for the write operations in installZsh and installFish (and the analogous
branches referenced around the other checks).

In `@cli/internal/diagnostics/collect.go`:
- Around line 236-247: checkComposeFile currently only checks for "compose.yml"
so projects using other default Compose filenames are treated as missing; update
checkComposeFile to look for the full default set
["compose.yml","compose.yaml","docker-compose.yml","docker-compose.yaml"], pick
the first existing path (set composePath to that), and only if none exist return
(false,false). Then run docker.ComposeExec with the discovered composePath (or
ensure the command is invoked in dataDir but referencing the discovered
filename) and return (true, err==nil) from checkComposeFile.
- Around line 291-307: The parseContainerDetails function currently treats
psJSON as NDJSON and splits on newlines; instead, parse the entire psJSON string
as a single JSON array into []ContainerDetail (i.e.,
json.Unmarshal([]byte(psJSON), &details)). Update parseContainerDetails to
unmarshal into details directly and return it; optionally keep a fallback path
to handle legacy NDJSON by falling back to line-by-line unmarshalling only if
the array unmarshal fails, ensuring ContainerDetail and callers like
hasRunningContainers receive the populated slice.

In `@cli/internal/diagnostics/disk_windows.go`:
- Around line 12-13: The code currently creates kernel32 :=
syscall.NewLazyDLL("kernel32.dll") and getDiskFreeSpaceExW :=
kernel32.NewProc("GetDiskFreeSpaceExW") on each call; move those to
package-level variables (e.g., var kernel32 = syscall.NewLazyDLL("kernel32.dll")
and var getDiskFreeSpaceExW = kernel32.NewProc("GetDiskFreeSpaceExW")) or
initialize them once in an init() function, then update the function that
currently declares the local kernel32/getDiskFreeSpaceExW to use the
package-level symbols instead; ensure any existing error handling still works if
the proc is nil or fails to find the symbol.

In `@cli/internal/selfupdate/sigstore.go`:
- Around line 32-36: root.FetchTrustedRoot() blocks without timeout; replace the
direct call with a Sigstore/TUF fetch using tuf.Options.WithFetcher(...) that
supplies a custom HTTP fetcher backed by an http.Client with a timeout;
implement a fetcher function (used by tuf.Options.WithFetcher) that performs the
same retrieval as FetchTrustedRoot but via HTTP requests with a configured
Timeout (or context-aware requests), and use that fetcher when constructing the
trusted root so network calls are bounded.

In `@cli/internal/selfupdate/updater_test.go`:
- Line 545: Add tests in updater_test.go that cover the bundleURL != "" path of
Download by exercising error scenarios: create httptest servers that when
Download is called with a non-empty bundleURL simulate (1) a bundle download
failure (return HTTP 500 or close connection) to assert Download returns an
error, and (2) a malformed/invalid JSON bundle response so that
verifySigstoreBundle (called from Download) fails and Download returns that
error; use the existing test harness that calls Download(ctx, assetURL,
checksumsURL, bundleURL) and assert errors are propagated from
Download/verifySigstoreBundle.

In `@cli/internal/selfupdate/updater.go`:
- Around line 176-179: The branch handling the "checksums.txt.sigstore.json"
asset silently ignores a.BrowserDownloadURL when it doesn't start with
expectedURLPrefix; change this to emit a debug-level log entry (using the
updater's existing logger) that includes the actual a.BrowserDownloadURL and the
expectedURLPrefix so callers can diagnose why the Sigstore bundle URL was
skipped, while leaving bundleURL unchanged. Target the switch case that matches
"checksums.txt.sigstore.json" and add the log on the else path where
strings.HasPrefix(a.BrowserDownloadURL, expectedURLPrefix) is false.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2cd08054-40f5-4ac1-9d3a-e06dcf8a4e1d

📥 Commits

Reviewing files that changed from the base of the PR and between 5009da7 and 3652201.

⛔ Files ignored due to path filters (1)
  • cli/go.sum is excluded by !**/*.sum
📒 Files selected for processing (15)
  • CLAUDE.md
  • cli/cmd/completion_install.go
  • cli/cmd/config.go
  • cli/cmd/config_test.go
  • cli/cmd/update.go
  • cli/go.mod
  • cli/internal/completion/install.go
  • cli/internal/completion/install_test.go
  • cli/internal/diagnostics/collect.go
  • cli/internal/diagnostics/collect_test.go
  • cli/internal/diagnostics/disk_unix.go
  • cli/internal/diagnostics/disk_windows.go
  • cli/internal/selfupdate/sigstore.go
  • cli/internal/selfupdate/updater.go
  • cli/internal/selfupdate/updater_test.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: CLI Test (windows-latest)
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (3)
cli/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

cli/**/*.go: Use native Go fuzz testing: testing.F fuzz functions (Fuzz*). Fuzz targets are in testdata/.
Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
Note: Go commands require cd cli because the Go module is in cli/ (exception to the "never use cd" rule—Go tooling requires working directory to be the module root).

Files:

  • cli/internal/diagnostics/disk_windows.go
  • cli/cmd/config_test.go
  • cli/internal/selfupdate/updater_test.go
  • cli/cmd/completion_install.go
  • cli/internal/diagnostics/collect_test.go
  • cli/internal/diagnostics/disk_unix.go
  • cli/internal/selfupdate/sigstore.go
  • cli/internal/selfupdate/updater.go
  • cli/cmd/config.go
  • cli/internal/completion/install_test.go
  • cli/cmd/update.go
  • cli/internal/diagnostics/collect.go
  • cli/internal/completion/install.go
**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Always read the relevant docs/design/ page before implementing any feature or planning any issue. The design spec in docs/design/ is the starting point for architecture, data models, and behavior. When a spec topic is referenced, read the relevant docs/design/ page before coding.

Files:

  • CLAUDE.md
cli/go.mod

📄 CodeRabbit inference engine (CLAUDE.md)

Go CLI dependencies: Go 1.26+, Cobra (commands), charmbracelet/huh (interactive CLI), charmbracelet/lipgloss (styled output).

Files:

  • cli/go.mod
🧠 Learnings (8)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Dependabot: auto-updates Docker image digests and versions daily.
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.

Applied to files:

  • cli/cmd/config_test.go
  • CLAUDE.md
  • cli/internal/selfupdate/sigstore.go
  • cli/internal/selfupdate/updater.go
  • cli/cmd/update.go
  • cli/go.mod
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).

Applied to files:

  • CLAUDE.md
  • cli/cmd/update.go
  • cli/internal/completion/install.go
  • cli/go.mod
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.

Applied to files:

  • CLAUDE.md
  • cli/go.mod
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to cli/go.mod : Go CLI dependencies: Go 1.26+, Cobra (commands), charmbracelet/huh (interactive CLI), charmbracelet/lipgloss (styled output).

Applied to files:

  • CLAUDE.md
  • cli/internal/completion/install.go
  • cli/go.mod
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to cli/**/*.go : Note: Go commands require `cd cli` because the Go module is in `cli/` (exception to the "never use cd" rule—Go tooling requires working directory to be the module root).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Shell commands: for Go CLI work, cd cli is an exception because Go tooling requires working directory to be the module root. Go commands require `cd cli` for other work, never use `cd`.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to docker/** : All Docker files (Dockerfiles, compose, .env.example) are in docker/. Backend: 3-stage build (builder → setup → distroless), Chainguard Python, non-root UID 65532. Web: nginxinc/nginx-unprivileged, Vue 3 SPA, API/WebSocket proxy. Sandbox: Python 3.14 + Node.js + git, non-root UID 10001.

Applied to files:

  • CLAUDE.md
🧬 Code graph analysis (7)
cli/internal/selfupdate/updater_test.go (1)
cli/internal/selfupdate/updater.go (1)
  • Download (195-230)
cli/cmd/completion_install.go (1)
cli/internal/completion/install.go (3)
  • DetectShell (49-68)
  • Unknown (22-22)
  • Install (78-93)
cli/internal/diagnostics/collect_test.go (1)
cli/internal/diagnostics/collect.go (2)
  • ContainerDetail (23-28)
  • Report (31-52)
cli/cmd/config.go (3)
cli/internal/ui/ui.go (1)
  • NewUI (57-69)
cli/internal/config/state.go (2)
  • StatePath (40-42)
  • Load (46-84)
cli/internal/config/paths.go (1)
  • DataDir (18-31)
cli/internal/completion/install_test.go (1)
cli/internal/completion/install.go (8)
  • Unknown (22-22)
  • PowerShell (26-26)
  • ShellType (19-19)
  • Bash (23-23)
  • Zsh (24-24)
  • Fish (25-25)
  • DetectShell (49-68)
  • Install (78-93)
cli/cmd/update.go (1)
cli/internal/selfupdate/updater.go (1)
  • Download (195-230)
cli/internal/diagnostics/collect.go (2)
cli/internal/config/state.go (1)
  • State (14-23)
cli/internal/docker/client.go (6)
  • Info (22-29)
  • Detect (34-66)
  • CheckMinVersions (69-78)
  • ComposeExecOutput (100-107)
  • ComposeExec (91-97)
  • RunCmd (110-119)
🪛 GitHub Check: CodeQL
cli/cmd/config.go

[failure] 40-40: Uncontrolled data used in path expression
This path depends on a user-provided value.
This path depends on a user-provided value.
This path depends on a user-provided value.

cli/internal/diagnostics/collect.go

[failure] 238-238: Uncontrolled data used in path expression
This path depends on a user-provided value.
This path depends on a user-provided value.
This path depends on a user-provided value.
This path depends on a user-provided value.

cli/internal/completion/install.go

[failure] 127-127: Uncontrolled data used in path expression
This path depends on a user-provided value.


[failure] 132-132: Uncontrolled data used in path expression
This path depends on a user-provided value.


[failure] 140-140: Uncontrolled data used in path expression
This path depends on a user-provided value.


[failure] 171-171: Uncontrolled data used in path expression
This path depends on a user-provided value.


[failure] 176-176: Uncontrolled data used in path expression
This path depends on a user-provided value.


[failure] 184-184: Uncontrolled data used in path expression
This path depends on a user-provided value.


[failure] 239-239: Uncontrolled data used in path expression
This path depends on a user-provided value.
This path depends on a user-provided value.
This path depends on a user-provided value.


[failure] 252-252: Uncontrolled data used in path expression
This path depends on a user-provided value.
This path depends on a user-provided value.
This path depends on a user-provided value.


[failure] 255-255: Uncontrolled data used in path expression
This path depends on a user-provided value.
This path depends on a user-provided value.
This path depends on a user-provided value.

🔇 Additional comments (12)
cli/internal/diagnostics/disk_unix.go (1)

1-16: LGTM!

The Unix disk usage implementation is correct:

  • Uses Bavail (blocks available to unprivileged users) rather than Bfree, which is the appropriate choice for user-facing disk space reporting.
  • Proper build tag for non-Windows platforms.
  • Error handling is straightforward and correct.
cli/internal/diagnostics/disk_windows.go (1)

1-31: LGTM overall — Windows implementation is correct.

The implementation correctly:

  • Uses freeBytesAvailable which respects disk quotas (matching Bavail on Unix).
  • Properly checks the return value (non-zero = success).
  • Handles UTF-16 conversion for Windows paths.
cli/go.mod (2)

5-10: Direct dependencies align with project requirements.

The direct dependencies match the coding guidelines: Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output, and the new sigstore-go for Sigstore verification as described in the PR objectives.


8-8: sigstore-go v1.1.4 is current and secure.

v1.1.4 is the latest release (Dec 10, 2025) with no known vulnerabilities. The sole published CVE for sigstore-go (CVE-2024-45395) affects only versions ≤ 0.6.0 and is already patched in v0.6.1 and all later versions, including v1.1.4.

CLAUDE.md (1)

147-157: LGTM!

Documentation updates accurately reflect the new CLI features:

  • config and completion-install commands added to the cmd list
  • Diagnostics expanded to include compose validation, port conflicts, image checks, and native disk usage
  • New completion/ package for shell completion auto-install
cli/internal/selfupdate/sigstore.go (2)

13-18: LGTM — Identity constraints are appropriately scoped.

The expected issuer and SAN regex correctly constrain signing to:

  • GitHub Actions OIDC issuer only
  • Workflows from the Aureliolo/synthorg repository

The regex is anchored at the start (^) which allows any workflow path within the repo, which is appropriate for release workflows.


71-78: LGTM — Bundle parsing helper is correct.

The helper properly initializes the nested protobuf structure before unmarshaling.

cli/internal/selfupdate/updater.go (3)

217-226: LGTM — Sigstore verification is correctly positioned.

The verification flow is secure:

  1. Download and verify checksum first (integrity check)
  2. Then verify Sigstore bundle (authenticity/provenance check)
  3. Only extract binary after both pass

This ordering is correct — checksum verification is a prerequisite for Sigstore verification since the bundle signs the checksums file.


324-329: LGTM — AllowedDownloadHosts expansion is correct.

Adding release-assets.githubusercontent.com accommodates GitHub's CDN routing for release assets, as mentioned in the PR objectives.


56-63: LGTM — CheckResult struct update is well-documented.

The new SigstoreBundURL field is clearly marked as optional via the comment, maintaining backward compatibility.

cli/cmd/update.go (1)

74-74: LGTM!

The update command correctly passes the Sigstore bundle URL to the Download function, enabling optional cryptographic verification of release artifacts.

cli/internal/selfupdate/updater_test.go (1)

571-571: LGTM — Test signature updates are consistent.

All Download calls in tests have been updated to include the empty bundleURL parameter, maintaining test functionality for the checksum verification path.

Also applies to: 713-713

Comment on lines +176 to +179
case "checksums.txt.sigstore.json":
if strings.HasPrefix(a.BrowserDownloadURL, expectedURLPrefix) {
bundleURL = a.BrowserDownloadURL
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider logging when Sigstore bundle URL is skipped due to prefix mismatch.

When checksums.txt.sigstore.json exists but doesn't match the expected URL prefix, it's silently ignored. This differs from asset/checksum URL handling which returns an error on prefix mismatch.

While acceptable for optional verification, a debug log could help diagnose unexpected behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cli/internal/selfupdate/updater.go` around lines 176 - 179, The branch
handling the "checksums.txt.sigstore.json" asset silently ignores
a.BrowserDownloadURL when it doesn't start with expectedURLPrefix; change this
to emit a debug-level log entry (using the updater's existing logger) that
includes the actual a.BrowserDownloadURL and the expectedURLPrefix so callers
can diagnose why the Sigstore bundle URL was skipped, while leaving bundleURL
unchanged. Target the switch case that matches "checksums.txt.sigstore.json" and
add the log on the else path where strings.HasPrefix(a.BrowserDownloadURL,
expectedURLPrefix) is false.

GO-2026-4354 and GO-2026-4355 in rekor@v1.4.3 (transitive dependency
from sigstore-go) are fixed in rekor@v1.5.0.
- Validate data-dir via SecurePath before probing config file
- Always regenerate completion files on rerun (pick up new commands)
- Wrap f.Close() error with context in appendToFile
- Fix diskInfoNative → diskInfo comment mismatch
- Check all compose file variants (compose.yml/yaml, docker-compose.yml/yaml)
- Parse container details as JSON array first, NDJSON fallback
- Move Windows kernel32 DLL loading to package-level init
- Add TUF fetch timeout (30s) to Sigstore trusted root retrieval
- Add tests for Download with invalid/failing bundle URL
- Extract testArchive helper to reduce test duplication
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cli/cmd/config.go`:
- Around line 45-49: The os.Stat check around statePath only handles
os.ErrNotExist and otherwise lets other errors fall through; change the logic in
the block that calls os.Stat so that if err != nil you distinguish
errors.Is(err, os.ErrNotExist) (keep the out.Warn/out.Hint and return nil) and
for any other err immediately return that error (wrap with context if desired)
instead of continuing to config.Load; refer to the os.Stat call, statePath
variable, and the out.Warn/out.Hint calls to locate where to add the early
return for non-ErrNotExist errors.
- Around line 14-28: The config and config show commands currently accept
arbitrary positional args because Cobra's default Arg validator is
cobra.ArbitraryArgs; update the command definitions for configCmd and
configShowCmd to explicitly set Args: cobra.NoArgs so unexpected positional
arguments are rejected (keep RunE: runConfigShow unchanged) and ensure both
configCmd and configShowCmd include the Args field.

In `@cli/internal/completion/install.go`:
- Line 95: The installBash function signature includes an unused rootCmd
parameter; remove that parameter from installBash and update its signature to
just func installBash(res Result) (Result, error), then update any call sites
that currently pass rootCmd (e.g. where installBash is invoked alongside
installPowerShell) to call installBash(res) instead; ensure the function body is
adjusted to reference only res and that installPowerShell remains unchanged for
consistency.

In `@cli/internal/diagnostics/collect.go`:
- Around line 299-323: parseContainerDetails currently filters out entries with
empty Name only in the NDJSON fallback but returns the unmarshaled JSON array
as-is, which can pass empty-named ContainerDetail entries downstream; update
parseContainerDetails (function name) to enforce the same Name != "" filtering
for the JSON array branch (ContainerDetail entries) before returning so both
array and NDJSON paths produce only entries with non-empty Name (used later to
build ContainerSummary).

In `@cli/internal/selfupdate/sigstore.go`:
- Around line 20-23: The SAN regex defined by expectedSANRegex is too broad (it
only pins the repo) and thus accepts any workflow; update expectedSANRegex in
sigstore.go to tightly match the full GitHub Actions workflow identity including
the workflow file and refs segment (e.g. include
".github/workflows/cli.yml@refs/" and, if applicable, the specific tag pattern
like "refs/tags/v[0-9]+"), so the matcher only accepts signatures issued by the
intended workflow that publishes releases.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0c54938d-bca3-41e3-b6d9-c27543f36e3a

📥 Commits

Reviewing files that changed from the base of the PR and between 3652201 and 20e972b.

⛔ Files ignored due to path filters (1)
  • cli/go.sum is excluded by !**/*.sum
📒 Files selected for processing (7)
  • cli/cmd/config.go
  • cli/go.mod
  • cli/internal/completion/install.go
  • cli/internal/diagnostics/collect.go
  • cli/internal/diagnostics/disk_windows.go
  • cli/internal/selfupdate/sigstore.go
  • cli/internal/selfupdate/updater_test.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: CLI Test (windows-latest)
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (2)
cli/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

cli/**/*.go: Use native Go fuzz testing: testing.F fuzz functions (Fuzz*). Fuzz targets are in testdata/.
Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
Note: Go commands require cd cli because the Go module is in cli/ (exception to the "never use cd" rule—Go tooling requires working directory to be the module root).

Files:

  • cli/internal/selfupdate/updater_test.go
  • cli/cmd/config.go
  • cli/internal/completion/install.go
  • cli/internal/selfupdate/sigstore.go
  • cli/internal/diagnostics/disk_windows.go
  • cli/internal/diagnostics/collect.go
cli/go.mod

📄 CodeRabbit inference engine (CLAUDE.md)

Go CLI dependencies: Go 1.26+, Cobra (commands), charmbracelet/huh (interactive CLI), charmbracelet/lipgloss (styled output).

Files:

  • cli/go.mod
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Dependabot: auto-updates Docker image digests and versions daily.
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).

Applied to files:

  • cli/cmd/config.go
  • cli/internal/completion/install.go
  • cli/go.mod
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.

Applied to files:

  • cli/cmd/config.go
  • cli/internal/selfupdate/sigstore.go
  • cli/go.mod
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to cli/go.mod : Go CLI dependencies: Go 1.26+, Cobra (commands), charmbracelet/huh (interactive CLI), charmbracelet/lipgloss (styled output).

Applied to files:

  • cli/cmd/config.go
  • cli/internal/completion/install.go
  • cli/go.mod
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to cli/**/*.go : Note: Go commands require `cd cli` because the Go module is in `cli/` (exception to the "never use cd" rule—Go tooling requires working directory to be the module root).

Applied to files:

  • cli/cmd/config.go
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.

Applied to files:

  • cli/internal/selfupdate/sigstore.go
  • cli/go.mod
🧬 Code graph analysis (3)
cli/internal/selfupdate/updater_test.go (1)
cli/internal/selfupdate/updater.go (1)
  • Download (195-230)
cli/cmd/config.go (2)
cli/internal/config/paths.go (2)
  • SecurePath (58-64)
  • DataDir (18-31)
cli/internal/config/state.go (2)
  • StatePath (40-42)
  • Load (46-84)
cli/internal/diagnostics/collect.go (2)
cli/internal/config/state.go (1)
  • State (14-23)
cli/internal/docker/client.go (6)
  • Info (22-29)
  • Detect (34-66)
  • CheckMinVersions (69-78)
  • ComposeExecOutput (100-107)
  • ComposeExec (91-97)
  • RunCmd (110-119)
🪛 GitHub Check: CodeQL
cli/cmd/config.go

[failure] 45-45: Uncontrolled data used in path expression
This path depends on a user-provided value.
This path depends on a user-provided value.
This path depends on a user-provided value.

cli/internal/completion/install.go

[failure] 127-127: Uncontrolled data used in path expression
This path depends on a user-provided value.


[failure] 132-132: Uncontrolled data used in path expression
This path depends on a user-provided value.


[failure] 139-139: Uncontrolled data used in path expression
This path depends on a user-provided value.


[failure] 170-170: Uncontrolled data used in path expression
This path depends on a user-provided value.


[failure] 175-175: Uncontrolled data used in path expression
This path depends on a user-provided value.


[failure] 182-182: Uncontrolled data used in path expression
This path depends on a user-provided value.


[failure] 240-240: Uncontrolled data used in path expression
This path depends on a user-provided value.
This path depends on a user-provided value.
This path depends on a user-provided value.


[failure] 253-253: Uncontrolled data used in path expression
This path depends on a user-provided value.
This path depends on a user-provided value.
This path depends on a user-provided value.


[failure] 256-256: Uncontrolled data used in path expression
This path depends on a user-provided value.
This path depends on a user-provided value.
This path depends on a user-provided value.

cli/internal/diagnostics/collect.go

[failure] 245-245: Uncontrolled data used in path expression
This path depends on a user-provided value.
This path depends on a user-provided value.
This path depends on a user-provided value.
This path depends on a user-provided value.

🔇 Additional comments (19)
cli/internal/diagnostics/disk_windows.go (2)

10-13: LGTM! DLL loading now cached at package level.

The kernel32 DLL and GetDiskFreeSpaceExW proc are now initialized once at package level, eliminating the per-call overhead. This properly addresses the previous review feedback.


16-32: Implementation looks correct.

The syscall usage follows standard Windows API patterns—UTF-16 path conversion, pointer passing, and checking return value for success (non-zero).

cli/internal/diagnostics/collect.go (7)

22-51: LGTM! Well-structured diagnostic types.

The ContainerDetail type cleanly maps to compose ps JSON output, and the Report extensions (ComposeFileExists, PortConflicts, etc.) provide rich diagnostic data with appropriate omitempty tags for optional fields.


54-103: Clean refactoring with proper path validation.

The SecurePath validation at line 64 ensures safeDir is sanitized before being passed to downstream functions. The decomposition into collectDocker, collectHealth, collectConfig, and collectInfra helpers improves readability.


105-127: LGTM with minor observation.

The LimitReader at line 121 properly bounds memory usage. Discarding the resp.Body.Close() error is acceptable here since response body close failures are non-actionable in this context.


335-362: LGTM! Clean disk info formatting.

The unused ctx parameter is correctly named _ to indicate it's intentionally ignored (common pattern for interface compatibility). The humanBytes function correctly implements binary prefix formatting (KiB, MiB, GiB...).


257-276: LGTM! Port conflict detection is well-implemented.

Using DialContext with a 1-second timeout to detect bound ports is a reasonable approach. The structured iteration over port configurations keeps the code clean.


278-297: LGTM! Image availability check is straightforward.

Using docker image inspect to verify local image presence is the correct approach. The conditional sandbox image check aligns with the broader CLI design.


241-255: Compose file variants properly addressed; CodeQL warning is a false positive.

The function now correctly searches all default compose filenames (compose.yaml, compose.yml, docker-compose.yaml, docker-compose.yml), addressing the previous review feedback.

The CodeQL warning at line 244 is a false positive. dataDir is guaranteed to be an absolute, cleaned path (from config.SecurePath), and name comes from a hardcoded slice of safe filenames. The combination of an absolute cleaned path with hardcoded filenames is safe from path traversal—no user input reaches the path construction.

cli/internal/completion/install.go (7)

18-43: LGTM!

Clean idiomatic iota enum with exhaustive String() method covering all cases including a default fallback.


47-68: LGTM!

Shell detection logic is sound—correctly extracts the base name, handles PowerShell Core (pwsh) on Unix, and applies sensible defaults per platform.


116-158: Regeneration on rerun is now correctly implemented.

The previous review flagged that completion files weren't being regenerated on rerun. This is now fixed: lines 127-129 only set AlreadyInstalled = true but no longer return early—the completion file is always rewritten (lines 131-141), ensuring users get updated commands after CLI upgrades.

Regarding the CodeQL warnings on lines 127, 132, 139: These are false positives. The paths are constructed from os.UserHomeDir(), which returns an OS-provided value, not attacker-controlled input. Combined with filepath.Join for safe path construction, there is no path traversal vulnerability here.


160-186: LGTM!

Correctly follows the same regeneration-on-rerun pattern as zsh. The CodeQL warnings (lines 170, 175, 182) are false positives for the same reason—paths are derived from os.UserHomeDir(), not user-controlled input.


208-224: PowerShell profile path validation is reasonable but consider documenting threat model.

The path comes from executing $PROFILE in PowerShell (line 212), which is external process output. The current validation (lines 215-221) provides reasonable defense:

  • Rejects empty or excessively long (>2048) paths
  • Requires an absolute path via filepath.IsAbs()
  • Normalizes with filepath.Clean()

The CodeQL warning here has some validity since this is external data, but the practical risk is low: if an attacker can manipulate PowerShell's $PROFILE output, they already have code execution on the system. The filepath.IsAbs() check prevents relative path exploits.

No changes required, but consider adding a brief comment noting that $PROFILE is trusted because compromising it implies existing system access.


237-248: LGTM!

Clean helper with well-documented behavior for non-existent files. The CodeQL warning (line 240) is a false positive—all callers pass paths derived from os.UserHomeDir() or validated PowerShell profile paths.


250-269: LGTM!

Solid helper with proper error handling:

  • Defensively creates parent directories
  • Correctly handles both write and close errors separately (avoiding the common mistake of ignoring f.Close() errors)
  • Uses appropriate file permissions (0o644)

The CodeQL warnings (lines 253, 256) are false positives for the same reasons as above.

cli/cmd/config.go (2)

39-42: Good fix: data-dir is validated before path-based file checks.

config.SecurePath before config.StatePath/os.Stat closes the earlier unsafe path flow and aligns behavior with config.Load.


71-76: Secret masking behavior is correct and safe.

Returning (not set) for empty and a constant mask for non-empty values avoids leaking secret length/content.

cli/internal/selfupdate/updater_test.go (1)

758-824: Good bundle-path error coverage.

These two cases exercise the new non-empty bundleURL branches without depending on live Sigstore infrastructure, which makes regressions in the self-update flow much easier to catch.

- Handle non-ErrNotExist os.Stat errors in config show
- Add cobra.NoArgs to config and config show commands
- Remove unused rootCmd param from installBash
- Filter empty-name containers in JSON array parse path
- Tighten Sigstore SAN regex to cli.yml workflow on tag refs only
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cli/internal/completion/install.go`:
- Around line 53-62: The shell-detection switch uses the variable base and only
checks for "pwsh" before returning PowerShell, so add an additional match for
"powershell" (e.g., change the pwsh case to check strings.Contains(base, "pwsh")
|| strings.Contains(base, "powershell")) so systems reporting "powershell" are
detected; modify the case that returns PowerShell (symbols: base, PowerShell)
accordingly and keep the other cases for Bash, Zsh, and Fish unchanged.

In `@cli/internal/diagnostics/collect.go`:
- Around line 242-255: The checkComposeFile function currently returns a boolean
validity that is incorrect when validation is skipped and hides non-ErrNotExist
os.Stat errors; change the validity return to a tri-state (e.g. change signature
to func checkComposeFile(ctx context.Context, info docker.Info, dataDir string)
(exists bool, valid *bool) so nil = unknown), and update callers accordingly;
inside checkComposeFile, treat os.Stat errors: if os.IsNotExist(err) continue,
otherwise return true, nil (existence uncertain/permission error) so the error
isn't swallowed; when a compose file is found and info.DockerPath == "" return
true, nil (unknown) instead of true,false; when running docker.ComposeExec, set
valid = pointerToBool(err == nil); apply the same tri-state and os.Stat error
handling to the analogous function referenced at lines 178-186.

In `@cli/internal/selfupdate/sigstore.go`:
- Line 22: Update the expectedSANRegex variable in sigstore.go to require a
full-string match and enforce a semver tag instead of a loose numeric token;
specifically replace the current pattern (expectedSANRegex) so it adds an end
anchor ($) and a semver constraint like
v[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)? to ensure the
SAN exactly matches the workflow ref string and prevents suffix injection.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 644f0c04-599e-4a17-b68c-69595136034f

📥 Commits

Reviewing files that changed from the base of the PR and between 20e972b and 506cc20.

📒 Files selected for processing (4)
  • cli/cmd/config.go
  • cli/internal/completion/install.go
  • cli/internal/diagnostics/collect.go
  • cli/internal/selfupdate/sigstore.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: CLI Test (windows-latest)
🧰 Additional context used
📓 Path-based instructions (1)
cli/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

cli/**/*.go: Use native Go fuzz testing: testing.F fuzz functions (Fuzz*). Fuzz targets are in testdata/.
Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
Note: Go commands require cd cli because the Go module is in cli/ (exception to the "never use cd" rule—Go tooling requires working directory to be the module root).

Files:

  • cli/cmd/config.go
  • cli/internal/diagnostics/collect.go
  • cli/internal/selfupdate/sigstore.go
  • cli/internal/completion/install.go
🧠 Learnings (8)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).

Applied to files:

  • cli/cmd/config.go
  • cli/internal/completion/install.go
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.

Applied to files:

  • cli/internal/selfupdate/sigstore.go
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.

Applied to files:

  • cli/internal/selfupdate/sigstore.go
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to .github/workflows/docker.yml : Docker workflow: builds backend + web + sandbox images, pushes to GHCR, signs with cosign. SLSA L3 provenance attestations via actions/attest-build-provenance. Scans: Trivy (CRITICAL = hard fail, HIGH = warn) + Grype (critical cutoff) + CIS Docker Benchmark v1.6.0 compliance (informational). CVE triage via .github/.trivyignore.yaml and .github/.grype.yaml. Images only pushed after scans pass. Triggers on push to main and version tags (v*).

Applied to files:

  • cli/internal/selfupdate/sigstore.go
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to .github/cla-signatures.json : CLA signatures stored in .github/cla-signatures.json on the cla-signatures branch (unprotected, so the action can commit directly). CLA check via contributor-assistant/github-action on pull_request_target and issue_comment. Skips Dependabot.

Applied to files:

  • cli/internal/selfupdate/sigstore.go
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to .github/workflows/finalize-release.yml : Finalize Release workflow: publishes draft releases created by Release Please. Triggers on workflow_run completion of Docker and CLI workflows. Verifies both workflows succeeded for the associated tag before publishing. Extracts CLI checksums, cosign verification, and container verification data from HTML comments, assembles into combined Verification section. Guards against PR-triggered runs. Handles TOCTOU races. Immutable releases enabled—once published, release assets and body cannot be modified.

Applied to files:

  • cli/internal/selfupdate/sigstore.go
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to cli/go.mod : Go CLI dependencies: Go 1.26+, Cobra (commands), charmbracelet/huh (interactive CLI), charmbracelet/lipgloss (styled output).

Applied to files:

  • cli/internal/completion/install.go
🧬 Code graph analysis (1)
cli/cmd/config.go (2)
cli/internal/config/paths.go (2)
  • SecurePath (58-64)
  • DataDir (18-31)
cli/internal/config/state.go (2)
  • StatePath (40-42)
  • Load (46-84)
🪛 GitHub Check: CodeQL
cli/cmd/config.go

[failure] 47-47: Uncontrolled data used in path expression
This path depends on a user-provided value.
This path depends on a user-provided value.
This path depends on a user-provided value.

🔇 Additional comments (16)
cli/cmd/config.go (6)

1-12: LGTM!

Imports are clean and all are used within the file.


14-30: LGTM!

Both commands correctly specify Args: cobra.NoArgs to reject unexpected positional arguments, and sharing the same RunE handler for the parent command provides intuitive default behavior.


32-35: LGTM!

Standard Cobra command registration pattern.


37-54: Path validation is appropriate for CLI context.

The CodeQL warning about "uncontrolled data used in path expression" (line 47) is mitigated here:

  1. SecurePath on line 41 cleans and validates the path is absolute before any filesystem operations
  2. This is a CLI tool where users inherently control their own system—specifying arbitrary paths is expected behavior (similar to cat <path>)

The validation ensures consistent behavior (absolute paths only, no .. components) without artificially restricting legitimate use cases. The past review suggestion to validate with SecurePath before os.Stat has been correctly implemented.


61-74: LGTM!

Clean structured output with:

  • Appropriate use of strconv for type conversions
  • JWT secret properly masked for security
  • Docker socket conditionally displayed only when relevant (sandbox enabled)

76-81: LGTM!

Good secret masking approach—uses a fixed mask length regardless of actual secret length, preventing information leakage while distinguishing between "not set" and "configured."

cli/internal/completion/install.go (8)

1-16: LGTM!

Package declaration and imports are clean. Standard library imports are appropriate for file I/O, path manipulation, and subprocess execution. Cobra dependency aligns with the project's CLI framework choice.


18-43: LGTM!

Idiomatic use of iota for the shell type enum with Unknown as the zero value. The String() method provides complete coverage including the default case.


77-93: LGTM!

Clean dispatcher pattern with appropriate error handling for unsupported shells. The selective propagation of ctx and rootCmd to only the installers that need them is reasonable given the quick local I/O operations.


95-114: LGTM!

The runtime eval approach ensures bash completions are always current without needing static file regeneration. Marker-based idempotency is correctly implemented. The previous review finding about unused rootCmd parameter has been addressed.


116-158: LGTM!

The completion file is now always regenerated (line 131 comment), addressing the prior review finding about stale completions. The AlreadyInstalled flag correctly serves as an informational indicator without blocking regeneration. The .zshrc modification remains idempotent via the fpathLine check.


160-186: LGTM!

Clean implementation that leverages Fish's auto-discovery of completion files. The regeneration behavior mirrors the zsh installer, ensuring updated commands are picked up. No profile modification needed since Fish automatically loads completions from ~/.config/fish/completions/.


188-235: LGTM!

Good security practices in powershellProfilePath: the validation on lines 215-221 ensures the path from the external process is non-empty, within reasonable length bounds, cleaned, and absolute before use. The context is properly propagated for subprocess cancellation. Fallback paths provide reasonable defaults when the subprocess approach fails.


237-269: LGTM!

Well-implemented helpers with robust error handling. fileContains correctly treats non-existent files as "does not contain" rather than an error. appendToFile properly captures both write and close errors separately, ensuring close failures aren't silently ignored.

cli/internal/selfupdate/sigstore.go (1)

39-44: Good reliability hardening on trusted-root fetch timeout.

Line 42’s bounded HTTP client timeout is a solid safeguard against hanging network calls during TUF root retrieval.

cli/internal/diagnostics/collect.go (1)

299-329: Robust container parsing fallback looks good.

JSON-array-first with NDJSON fallback and Name != "" filtering is solid and avoids the prior empty-summary failure mode.

…r SAN regex

- Detect "powershell" in addition to "pwsh" in shell detection
- Surface permission errors from compose file stat in Errors slice
- Anchor SAN regex with $ and enforce full semver tag pattern
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
cli/internal/diagnostics/collect.go (1)

48-50: ⚠️ Potential issue | 🟠 Major

Compose validity is modeled as binary, so “not checked” is reported as “invalid”.

Line 50 and Line 181 force a yes/no state even when validation is skipped (e.g., compose command unavailable), and Line 248-250 can record stat errors while still ending up with a misleading “Not found/Valid: no” report.

🔧 Proposed fix
 type Report struct {
 	ComposeFileExists bool              `json:"compose_file_exists"`
-	ComposeFileValid  bool              `json:"compose_file_valid,omitempty"`
+	ComposeFileValid  *bool             `json:"compose_file_valid,omitempty"`
 	PortConflicts     []string          `json:"port_conflicts,omitempty"`
 	ImageStatus       []string          `json:"image_status,omitempty"`
 	ContainerSummary  []ContainerDetail `json:"container_summary,omitempty"`
 }
@@
 func (r Report) formatComposeSection(b *strings.Builder) {
 	b.WriteString("--- Compose File ---\n")
 	if r.ComposeFileExists {
-		valid := "yes"
-		if !r.ComposeFileValid {
-			valid = "no"
+		valid := "unknown"
+		if r.ComposeFileValid != nil {
+			if *r.ComposeFileValid {
+				valid = "yes"
+			} else {
+				valid = "no"
+			}
 		}
 		fmt.Fprintf(b, "Exists: yes  Valid: %s\n\n", valid)
 	} else {
 		b.WriteString("Not found\n\n")
 	}
 }
@@
 func checkComposeFile(ctx context.Context, r *Report, info docker.Info, dataDir string) {
 	for _, name := range composeFileNames {
 		composePath := filepath.Join(dataDir, name)
 		if _, err := os.Stat(composePath); err != nil {
 			if errors.Is(err, os.ErrNotExist) {
 				continue
 			}
+			r.ComposeFileExists = true
 			r.Errors = append(r.Errors, fmt.Sprintf("compose: %s: %v", composePath, err))
-			continue
+			return
 		}
 		r.ComposeFileExists = true
-		if info.DockerPath != "" {
-			r.ComposeFileValid = docker.ComposeExec(ctx, info, dataDir, "config", "--quiet") == nil
+		if len(info.ComposeCmd) > 0 {
+			ok := docker.ComposeExec(ctx, info, dataDir, "config", "--quiet") == nil
+			r.ComposeFileValid = &ok
 		}
 		return
 	}
 }

Also applies to: 177-184, 241-255

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cli/internal/diagnostics/collect.go` around lines 48 - 50, The
ComposeFileValid field is currently a bool so skipped/unchecked states are
reported as "invalid"; change ComposeFileValid from bool to *bool in the
diagnostics struct (keep `json:"compose_file_valid,omitempty"`), update all code
paths that set ComposeFileValid (places around the existing compose-check logic
referenced by ComposeFileExists and the compose validation code paths) to assign
a pointer to true/false only when validation actually ran, and leave it nil when
validation was skipped or a stat/error prevented checking so the field is
omitted from JSON; also ensure any code that reads ComposeFileValid dereferences
safely (nil means "not checked").
cli/internal/completion/install.go (1)

214-223: ⚠️ Potential issue | 🟠 Major

Constrain PowerShell profile path to trusted locations before writing.

This is still an uncontrolled path sink pattern: an absolute path from external command output is later used in appendToFile (Line 251+). Clean + IsAbs is not enough; enforce that the path is under the current user’s home and matches expected profile filename(s).

Proposed hardening
 func powershellProfilePath(ctx context.Context) (string, error) {
+	home, homeErr := os.UserHomeDir()
+	if homeErr != nil {
+		return "", fmt.Errorf("cannot determine home directory: %w", homeErr)
+	}
+
 	// Try pwsh (PowerShell Core) first, then powershell (Windows PowerShell).
 	for _, shell := range []string{"pwsh", "powershell"} {
 		out, err := exec.CommandContext(ctx, shell, "-NoProfile", "-Command", "echo $PROFILE").Output()
 		if err == nil {
 			p := strings.TrimSpace(string(out))
 			if p == "" || len(p) > 2048 {
 				continue
 			}
 			p = filepath.Clean(p)
 			if !filepath.IsAbs(p) {
 				continue
 			}
+			rel, relErr := filepath.Rel(home, p)
+			if relErr != nil || rel == ".." || strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
+				continue
+			}
+			base := strings.ToLower(filepath.Base(p))
+			if base != "microsoft.powershell_profile.ps1" && base != "profile.ps1" {
+				continue
+			}
 			return p, nil
 		}
 	}
 
 	// Fallback: construct the default path.
-	home, err := os.UserHomeDir()
-	if err != nil {
-		return "", fmt.Errorf("cannot determine home directory: %w", err)
-	}
 	if runtime.GOOS == "windows" {
 		return filepath.Join(home, "Documents", "PowerShell", "Microsoft.PowerShell_profile.ps1"), nil
 	}
 	return filepath.Join(home, ".config", "powershell", "Microsoft.PowerShell_profile.ps1"), nil
 }

Also applies to: 251-257

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cli/internal/completion/install.go` around lines 214 - 223, The returned
PowerShell profile path (variable p) is currently only cleaned and checked for
absoluteness before being used by appendToFile; tighten this by validating p is
inside the current user's home directory and has an expected profile filename.
Update the code around the filepath.Clean/IsAbs checks in the function that
returns p to: resolve the current user home (os.UserHomeDir or equivalent),
ensure p has the home directory as a path prefix (use filepath.Rel or
strings.HasPrefix after evaluating symlinks if relevant), and verify
filepath.Base(p) matches an allowlist of acceptable names (e.g., expected
PowerShell profile filenames). Only return p if all checks pass; otherwise
continue the loop so appendToFile never writes to an untrusted location.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cli/internal/completion/install.go`:
- Around line 81-87: Guard against a nil rootCmd in the exported Install
function before calling the zsh/fish installers: if shell is Zsh or Fish and
rootCmd is nil, return a typed error instead of dispatching to installZsh or
installFish; ensure installZsh and installFish still call
rootCmd.GenZshCompletion() / rootCmd.GenFishCompletion() only when rootCmd is
non-nil. Reference Install, installZsh, installFish, GenZshCompletion and
GenFishCompletion in your change.

In `@cli/internal/diagnostics/collect.go`:
- Around line 82-87: The docker.Detect call in collectDocker can return a
partial docker.Info on error, causing later logic that only checks
info.DockerPath (e.g., the checkImages call at/around lines 150-152) to run and
produce false negatives; change collectDocker so that when docker.Detect returns
an error you append the error to r.Errors and return a zeroed/empty docker.Info
(not the partial info) to signal detection failure (or explicitly clear
info.DockerPath / set a detection flag) so downstream checks like checkImages
will be skipped; update collectDocker (and its return behavior) to ensure
callers rely on a clear "not detected" state rather than partial data.

---

Duplicate comments:
In `@cli/internal/completion/install.go`:
- Around line 214-223: The returned PowerShell profile path (variable p) is
currently only cleaned and checked for absoluteness before being used by
appendToFile; tighten this by validating p is inside the current user's home
directory and has an expected profile filename. Update the code around the
filepath.Clean/IsAbs checks in the function that returns p to: resolve the
current user home (os.UserHomeDir or equivalent), ensure p has the home
directory as a path prefix (use filepath.Rel or strings.HasPrefix after
evaluating symlinks if relevant), and verify filepath.Base(p) matches an
allowlist of acceptable names (e.g., expected PowerShell profile filenames).
Only return p if all checks pass; otherwise continue the loop so appendToFile
never writes to an untrusted location.

In `@cli/internal/diagnostics/collect.go`:
- Around line 48-50: The ComposeFileValid field is currently a bool so
skipped/unchecked states are reported as "invalid"; change ComposeFileValid from
bool to *bool in the diagnostics struct (keep
`json:"compose_file_valid,omitempty"`), update all code paths that set
ComposeFileValid (places around the existing compose-check logic referenced by
ComposeFileExists and the compose validation code paths) to assign a pointer to
true/false only when validation actually ran, and leave it nil when validation
was skipped or a stat/error prevented checking so the field is omitted from
JSON; also ensure any code that reads ComposeFileValid dereferences safely (nil
means "not checked").
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: bc92a65a-16bd-489f-904a-08fb463f9a36

📥 Commits

Reviewing files that changed from the base of the PR and between 506cc20 and d929f6d.

📒 Files selected for processing (3)
  • cli/internal/completion/install.go
  • cli/internal/diagnostics/collect.go
  • cli/internal/selfupdate/sigstore.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: CLI Test (windows-latest)
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (1)
cli/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

cli/**/*.go: Use native Go fuzz testing: testing.F fuzz functions (Fuzz*). Fuzz targets are in testdata/.
Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
Note: Go commands require cd cli because the Go module is in cli/ (exception to the "never use cd" rule—Go tooling requires working directory to be the module root).

Files:

  • cli/internal/diagnostics/collect.go
  • cli/internal/selfupdate/sigstore.go
  • cli/internal/completion/install.go
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to .github/workflows/*.yml : Dependabot: daily updates for uv + github-actions + npm + pre-commit + docker + gomod, grouped minor/patch, no auto-merge. Use `/review-dep-pr` to review Dependabot PRs before merging.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to cli/go.mod : Go CLI dependencies: Go 1.26+, Cobra (commands), charmbracelet/huh (interactive CLI), charmbracelet/lipgloss (styled output).
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.

Applied to files:

  • cli/internal/diagnostics/collect.go
  • cli/internal/selfupdate/sigstore.go
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.

Applied to files:

  • cli/internal/selfupdate/sigstore.go
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to .github/workflows/docker.yml : Docker workflow: builds backend + web + sandbox images, pushes to GHCR, signs with cosign. SLSA L3 provenance attestations via actions/attest-build-provenance. Scans: Trivy (CRITICAL = hard fail, HIGH = warn) + Grype (critical cutoff) + CIS Docker Benchmark v1.6.0 compliance (informational). CVE triage via .github/.trivyignore.yaml and .github/.grype.yaml. Images only pushed after scans pass. Triggers on push to main and version tags (v*).

Applied to files:

  • cli/internal/selfupdate/sigstore.go
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to .github/cla-signatures.json : CLA signatures stored in .github/cla-signatures.json on the cla-signatures branch (unprotected, so the action can commit directly). CLA check via contributor-assistant/github-action on pull_request_target and issue_comment. Skips Dependabot.

Applied to files:

  • cli/internal/selfupdate/sigstore.go
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to .github/workflows/finalize-release.yml : Finalize Release workflow: publishes draft releases created by Release Please. Triggers on workflow_run completion of Docker and CLI workflows. Verifies both workflows succeeded for the associated tag before publishing. Extracts CLI checksums, cosign verification, and container verification data from HTML comments, assembles into combined Verification section. Guards against PR-triggered runs. Handles TOCTOU races. Immutable releases enabled—once published, release assets and body cannot be modified.

Applied to files:

  • cli/internal/selfupdate/sigstore.go
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to .github/workflows/docker.yml : CI Docker: build → scan → push to GHCR + cosign sign + SLSA L3 provenance via attest-build-provenance (images only pushed after Trivy/Grype scans pass).

Applied to files:

  • cli/internal/selfupdate/sigstore.go
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to .github/workflows/*.yml : Dependabot: daily updates for uv + github-actions + npm + pre-commit + docker + gomod, grouped minor/patch, no auto-merge. Use `/review-dep-pr` to review Dependabot PRs before merging.

Applied to files:

  • cli/internal/selfupdate/sigstore.go
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).

Applied to files:

  • cli/internal/completion/install.go
📚 Learning: 2026-03-15T19:54:39.887Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:54:39.887Z
Learning: Applies to cli/go.mod : Go CLI dependencies: Go 1.26+, Cobra (commands), charmbracelet/huh (interactive CLI), charmbracelet/lipgloss (styled output).

Applied to files:

  • cli/internal/completion/install.go
🧬 Code graph analysis (1)
cli/internal/diagnostics/collect.go (2)
cli/internal/config/state.go (1)
  • State (14-23)
cli/internal/docker/client.go (6)
  • Info (22-29)
  • Detect (34-66)
  • CheckMinVersions (69-78)
  • ComposeExecOutput (100-107)
  • ComposeExec (91-97)
  • RunCmd (110-119)
🪛 GitHub Check: CodeQL
cli/internal/diagnostics/collect.go

[failure] 244-244: Uncontrolled data used in path expression
This path depends on a user-provided value.
This path depends on a user-provided value.
This path depends on a user-provided value.
This path depends on a user-provided value.

🔇 Additional comments (4)
cli/internal/selfupdate/sigstore.go (3)

17-25: Signer identity and tag scoping look correctly hardened.

The SAN regex is fully anchored and scoped to cli.yml on semver tags, and the trusted-root fetch has an explicit timeout bound.


33-80: Verification path is robust and correctly layered.

Good sequence: bundle parse → trusted root fetch → verifier with SCT/tlog requirements → certificate identity policy → artifact digest verification.


83-89: loadBundleFromJSON is clean and purpose-specific.

The helper is concise and returns errors to the caller without swallowing context.

cli/internal/completion/install.go (1)

131-141: Good fix: completion files are always regenerated on rerun.

This correctly prevents stale zsh/fish completions after upgrades while keeping install idempotent.

Also applies to: 174-184

…e tri-state

- Guard against nil rootCmd in Install for zsh/fish shells
- Return zero docker.Info on Detect failure to prevent false negatives
- Validate PowerShell profile path is inside user's home directory
- Change ComposeFileValid to *bool: nil = not checked, true/false = result
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (1)
cli/internal/completion/install.go (1)

227-235: ⚠️ Potential issue | 🟠 Major

Harden path containment before writing profile files.

At Lines 227-235, the current check is lexical (Rel + prefix). A symlinked path inside home can still resolve outside home and be written by appendToFile. Resolve symlinks (or reject symlink targets) before accepting the final write path.

♻️ Proposed fix
 func powershellProfilePath(ctx context.Context) (string, error) {
 	home, err := os.UserHomeDir()
 	if err != nil {
 		return "", fmt.Errorf("cannot determine home directory: %w", err)
 	}
+	resolvedHome, err := filepath.EvalSymlinks(home)
+	if err != nil {
+		return "", fmt.Errorf("resolving home directory: %w", err)
+	}
@@
 			p = filepath.Clean(p)
 			if !filepath.IsAbs(p) {
 				continue
 			}
-			// Ensure path is inside the user's home directory.
-			if rel, relErr := filepath.Rel(home, p); relErr != nil || strings.HasPrefix(rel, "..") {
+			resolvedParent, relErr := filepath.EvalSymlinks(filepath.Dir(p))
+			if relErr != nil {
+				continue
+			}
+			candidate := filepath.Join(resolvedParent, filepath.Base(p))
+			// Ensure resolved path is inside the user's home directory.
+			rel, relErr := filepath.Rel(resolvedHome, candidate)
+			if relErr != nil || rel == ".." || strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
 				continue
 			}
-			return p, nil
+			return candidate, nil
 		}
 	}
@@
 func appendToFile(path, content string) error {
+	if fi, err := os.Lstat(path); err == nil && (fi.Mode()&os.ModeSymlink) != 0 {
+		return fmt.Errorf("refusing to write via symlink: %s", path)
+	}
 	dir := filepath.Dir(path)

Also applies to: 259-278

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cli/internal/completion/install.go` around lines 227 - 235, The lexical
containment check using filepath.Rel can be bypassed by symlinks; update the
path validation in install.go (the block that calls filepath.Clean,
filepath.IsAbs, filepath.Rel and returns p) to resolve and validate symlinks
before accepting the path: call filepath.EvalSymlinks on both the candidate path
and the user's home directory (or use os.Lstat to detect and reject symlinked
targets), then verify the evaluated absolute path is inside the evaluated home
directory and reject (continue) on EvalSymlinks errors or when the evaluated
path escapes home; mirror the same fix for the similar block around lines
259-278 so appendToFile only ever writes to resolved paths inside the home.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cli/internal/completion/install.go`:
- Around line 220-237: The PowerShell probing loop uses exec.CommandContext(ctx,
...) but ctx has no deadline so a hanging shell can block; wrap each
exec.CommandContext call in a short per-command context with a timeout (e.g.,
context.WithTimeout(ctx, 3-5s)), defer the cancel, and use that timed context
for exec.CommandContext in the loop that iterates over {"pwsh","powershell"}
(the block that calls exec.CommandContext, trims output, cleans path and
validates it) so each probe will be bounded and won't hang indefinitely.

In `@cli/internal/diagnostics/collect_test.go`:
- Around line 200-206: The test TestCheckPortsNoConflict makes a misleading
comment about port 0; update the comment near TestCheckPortsNoConflict to
clarify that we use port 0 because attempting to dial 127.0.0.1:0 will fail (you
can't connect to port 0) rather than implying port 0 is never bound; leave the
test invoking checkPorts(context.Background(), 0, 0) unchanged but replace the
comment with a precise explanation referencing TestCheckPortsNoConflict and
checkPorts.
- Around line 105-133: Add a test case to TestParseContainerDetails exercising
the JSON array format path in parseContainerDetails: create a new table entry
(e.g., name "json_array") whose input is a JSON array string like
`[{"Name":"app","State":"running","Status":"Up"},{"Name":"db","State":"exited","Status":"Exited
(1)"}]` and set want to 2, then run the same t.Run assertion so both NDJSON and
JSON-array parsing branches of parseContainerDetails are validated.

In `@cli/internal/diagnostics/collect.go`:
- Around line 364-375: The humanBytes function can panic if exp exceeds the
length of the suffix string "KMGTPE"; update humanBytes to defensively handle
extremely large values by bounding exp before indexing: compute exp as now, then
if exp >= len(suffixes) set exp = len(suffixes)-1 (or choose an extended suffix
string) so indexing into the suffix string (referenced in humanBytes) is always
safe; keep the rest of the formatting logic unchanged.

---

Duplicate comments:
In `@cli/internal/completion/install.go`:
- Around line 227-235: The lexical containment check using filepath.Rel can be
bypassed by symlinks; update the path validation in install.go (the block that
calls filepath.Clean, filepath.IsAbs, filepath.Rel and returns p) to resolve and
validate symlinks before accepting the path: call filepath.EvalSymlinks on both
the candidate path and the user's home directory (or use os.Lstat to detect and
reject symlinked targets), then verify the evaluated absolute path is inside the
evaluated home directory and reject (continue) on EvalSymlinks errors or when
the evaluated path escapes home; mirror the same fix for the similar block
around lines 259-278 so appendToFile only ever writes to resolved paths inside
the home.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 701cf309-5710-495a-952c-cee39bd41259

📥 Commits

Reviewing files that changed from the base of the PR and between d929f6d and 41e16ea.

📒 Files selected for processing (3)
  • cli/internal/completion/install.go
  • cli/internal/diagnostics/collect.go
  • cli/internal/diagnostics/collect_test.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: CLI Test (windows-latest)
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (2)
cli/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

cli/**/*.go: Use native testing.F fuzz functions (Fuzz*) for fuzz testing in Go.
Use Cobra for CLI commands in the Go CLI binary.
Use charmbracelet/huh for interactive CLI prompts.
Use charmbracelet/lipgloss for styled CLI output.

Files:

  • cli/internal/diagnostics/collect_test.go
  • cli/internal/completion/install.go
  • cli/internal/diagnostics/collect.go
cli/**/*test.go

📄 CodeRabbit inference engine (CLAUDE.md)

Run Go tests with race detector and coverage: go test -race -coverprofile.

Files:

  • cli/internal/diagnostics/collect_test.go
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).
📚 Learning: 2026-03-15T21:30:26.325Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:30:26.325Z
Learning: Applies to cli/**/*test.go : Run Go tests with race detector and coverage: `go test -race -coverprofile`.

Applied to files:

  • cli/internal/diagnostics/collect_test.go
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).

Applied to files:

  • cli/internal/completion/install.go
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Fix everything valid — never skip when review agents find valid issues (including pre-existing issues in surrounding code, suggestions, and findings adjacent to the PR's changes). No deferring, no 'out of scope' skipping.

Applied to files:

  • cli/internal/diagnostics/collect.go
🧬 Code graph analysis (2)
cli/internal/diagnostics/collect_test.go (1)
cli/internal/diagnostics/collect.go (2)
  • ContainerDetail (24-29)
  • Report (32-53)
cli/internal/diagnostics/collect.go (1)
cli/internal/docker/client.go (6)
  • Info (22-29)
  • Detect (34-66)
  • CheckMinVersions (69-78)
  • ComposeExecOutput (100-107)
  • ComposeExec (91-97)
  • RunCmd (110-119)
🔇 Additional comments (14)
cli/internal/diagnostics/collect.go (8)

23-29: LGTM!

The ContainerDetail struct is well-designed with appropriate JSON tags matching Docker Compose's output format. The omitempty on Health correctly handles containers without health checks.


47-52: LGTM!

The Report struct extensions are appropriate:

  • ComposeFileValid as *bool correctly implements tri-state (nil = not checked, true/false = result) as indicated in the commit messages.
  • New fields use omitempty appropriately for optional data.

82-104: LGTM!

The refactored collectDocker correctly returns a zero-value docker.Info{} on detection failure (line 86), which addresses the previous review feedback about false negatives from partial state. Downstream checks like checkImages will be properly skipped since info.DockerPath will be empty.


106-128: LGTM!

The function properly limits response body reads to 64KB using io.LimitReader, propagates context correctly, and handles errors appropriately.


244-262: LGTM!

The checkComposeFile function now correctly:

  1. Uses tri-state *bool for validity (nil = not checked, true/false = result)
  2. Properly distinguishes os.ErrNotExist from other errors using errors.Is
  3. Logs non-existence errors to r.Errors instead of swallowing them

This addresses the previous review feedback about misreported validation status and swallowed stat errors.


264-283: LGTM!

The port conflict detection uses a reasonable approach with proper timeout and connection cleanup. The logic correctly identifies ports already bound by attempting a TCP connection.


285-304: LGTM!

The image availability check is straightforward and correctly uses docker image inspect to verify local presence. The conditional sandbox image check respects the configuration.


306-336: LGTM!

The function correctly handles both JSON array (newer Compose) and NDJSON (legacy) formats, addressing previous review feedback. The consistent Name != "" filtering in both paths ensures ContainerSummary never receives empty-named entries.

cli/internal/diagnostics/collect_test.go (5)

105-133: LGTM!

The TestParseContainerDetails uses idiomatic table-driven tests covering key scenarios: single object, multiple NDJSON lines, empty input, invalid JSON, and blank lines. Good coverage of the parsing logic.


135-151: LGTM!

TestParseContainerDetailsFields validates that individual fields are correctly extracted from JSON, complementing the count-based tests with field-level assertions.


153-171: LGTM!

TestHasRunningContainers covers the key states: empty slice, running, exited, and mixed containers. The test correctly verifies the "running" state detection logic.


208-238: LGTM!

TestFormatTextNewSections comprehensively validates that all new report sections (Compose File, Container Summary, Port Conflicts, Docker Images) are correctly rendered in the text output. The test properly uses ptrBool helper for the tri-state ComposeFileValid field.


240-240: LGTM!

The ptrBool helper is a clean, minimal utility for creating *bool values in tests. Idiomatic Go approach.

cli/internal/completion/install.go (1)

81-83: Good defensive nil guard for generator-backed shells.

The check prevents panic paths before GenZshCompletion / GenFishCompletion are reached.

…coverage

- Add 5s timeout per PowerShell probe to prevent hanging
- Resolve symlinks before home-directory containment check
- Bound humanBytes exp index to prevent panic on exabyte+ values
- Fix misleading port 0 test comment
- Add JSON array test case for parseContainerDetails
@Aureliolo Aureliolo merged commit 9e08cec into main Mar 15, 2026
38 checks passed
@Aureliolo Aureliolo deleted the fix/cli-improvements branch March 15, 2026 21:56
Aureliolo added a commit that referenced this pull request Mar 15, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.2.6](v0.2.5...v0.2.6)
(2026-03-15)


### Features

* add intra-loop stagnation detector
([#415](#415))
([#458](#458))
([8e9f34f](8e9f34f))
* add RFC 9457 structured error responses (Phase 1)
([#457](#457))
([6612a99](6612a99)),
closes [#419](#419)
* implement AgentStateRepository for runtime state persistence
([#459](#459))
([5009da7](5009da7))
* **site:** add SEO essentials, contact form, early-access banner
([#467](#467))
([11b645e](11b645e)),
closes [#466](#466)


### Bug Fixes

* CLI improvements — config show, completion install, enhanced doctor,
Sigstore verification
([#465](#465))
([9e08cec](9e08cec))
* **site:** add reCAPTCHA v3, main landmark, and docs sitemap
([#469](#469))
([fa6d35c](fa6d35c))
* use force-tag-creation instead of manual tag creation hack
([#462](#462))
([2338004](2338004))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
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.

feat: implement CLI tool

2 participants