Skip to content

Conversation

@nader-ziada
Copy link
Contributor

@nader-ziada nader-ziada commented Nov 19, 2025

What type of PR is this?

/kind feature

What this PR does / why we need it:

Replace embedded server binaries with on-demand downloads from GitHub releases, reducing CLI size from ~100MB to ~78MB. Downloaded binaries are cryptographically verified using Sigstore and cached locally for reuse.

Which issue(s) this PR fixes:

Fixes #174

Proposed Changes

  • Add binary download system with automatic version resolution
  • Implement version-platform cache with automatic cleanup (keeps last 3 versions)
  • Add --server-version flag to specify server binary version
  • Support offline builds with cached binary fallback
  • Remove embedded binaries and build-server-binaries make target
  • Dev builds automatically use latest stable server binaries
  • Release builds download matching server version by default

Release note:

- `genmcp build` now downloads server binaries from GitHub releases, significantly reducing CLI binary size
- Server binaries are cached locally (in user cache directory) and reused across builds

Summary by CodeRabbit

  • New Features

    • Binary download and per-platform caching with automatic "latest" resolution for development builds, a --server-version flag, verbose mode, and automatic cache cleanup
    • Sigstore-based verification of downloaded binaries with offline fallback to cached artifacts
  • Changed

    • Binaries are now downloaded, versioned, and managed via a dynamic provider; CLI prints chosen server-version diagnostics and exposes version retrieval
    • Reduced CLI binary size due to removal of embedded assets
  • Removed

    • Embedded binaries and the --use-embedded-binaries flag
  • Documentation

    • Expanded build docs with examples, cache locations, requirements, multi-arch notes, and cleanup guidance
  • Tests

    • Added tests covering downloader/provider and cache behavior

✏️ Tip: You can customize this high-level summary in your review settings.

@nader-ziada nader-ziada requested a review from a team as a code owner November 19, 2025 18:05
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 19, 2025

Walkthrough

Replaces embedded server binaries with a download-and-cache system: build resolves a server version (flag or auto-resolve "latest" for dev), downloads GitHub release ZIPs, verifies binaries with Sigstore bundles, caches per-version/platform binaries with SHA256, supports offline fallback, and integrates with the ImageBuilder constructor.

Changes

Cohort / File(s) Summary
Changelog & docs
CHANGELOG.md, README.md, docs/commands.md
Add Unreleased notes and detailed docs for binary downloads, Sigstore verification, --server-version, version matching, cache locations/behavior, offline fallback, cleanup, and examples.
Go modules
go.mod, hack/jsonschemagen/go.mod
Add github.com/sigstore/sigstore-go and update/pin numerous direct/indirect dependencies (including mailru/easyjson, go.uber.org/multierr, google.golang.org/*, k8s.io/*, etc.).
Builder refactor
pkg/builder/builder.go
Remove embedded binary provider and embed usage; change constructor to New(saveToRegistry bool, version string, verbose bool) (*ImageBuilder, error) and initialize a download-based binary provider.
Download provider
pkg/builder/download_binary_provider.go, pkg/builder/download_binary_provider_test.go
Add DownloadBinaryProvider with NewDownloadBinaryProvider(version, verbose) and ExtractServerBinary(platform). Tests for explicit and "latest" versions; network/Sigstore fetch failures cause test skips.
Binary cache
pkg/cli/utils/binary_cache.go, pkg/cli/utils/binary_cache_test.go
New BinaryCache with binaries-index.json, Add/Get with SHA256 verification, GetLatestCached, Clean retention logic, persistence; tests for add/get, corruption, and persistence.
Downloader orchestration
pkg/cli/utils/binary_downloader.go, pkg/cli/utils/binary_downloader_test.go
New BinaryDownloader: resolves versions (including "latest"), checks cache, downloads release ZIPs and Sigstore bundles, verifies via SigstoreVerifier, extracts platform binary, updates cache, supports offline fallback, verbose logging and cleanup; tests for verbose/silent behavior.
Sigstore verification
pkg/cli/utils/sigstore_verifier.go
New SigstoreVerifier using sigstore-go/TUF to verify blobs against bundles; adds verification policy, identity constants, and VerifyBlob logic.
CLI integration
pkg/cli/build.go, pkg/cli/root.go
Add --server-version and -v/--verbose flags, version-resolution (dev → "latest") logic; call builder.New(push, version, verbose) and expose GetVersion() helper.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI as genmcp CLI
    participant Resolver as VersionResolver
    participant Downloader as BinaryDownloader
    participant Cache as BinaryCache
    participant GitHub as GitHubReleases
    participant Sigstore as SigstoreVerifier
    participant Builder as ImageBuilder

    User->>CLI: Run `genmcp build` [--server-version X]
    CLI->>Resolver: Resolve server version (flag | CLI version | "latest" for dev)
    Resolver-->>CLI: server_version

    CLI->>Downloader: GetBinary(server_version, os, arch)
    Downloader->>Cache: Get(server_version, platform)
    alt Cache hit
        Cache-->>Downloader: cached_path
    else Cache miss
        Downloader->>GitHub: Download release ZIP + sigstore bundle
        GitHub-->>Downloader: zip_path, bundle_path
        Downloader->>Downloader: extract platform binary from ZIP
        Downloader->>Sigstore: VerifyBlob(binary_path, bundle_path)
        alt Verified
            Sigstore-->>Downloader: ok
            Downloader->>Cache: Add(version, platform, binary_path)
            Cache-->>Downloader: cached_path
        else Verification failed
            Sigstore-->>Downloader: verification_error
            Downloader->>Cache: GetLatestCached(platform)
            alt Fallback found
                Cache-->>Downloader: fallback_path
            else
                Downloader-->>CLI: error
            end
        end
    end
    Downloader-->>CLI: binary_path

    CLI->>Builder: New(push, server_version, verbose)
    Builder->>Downloader: ExtractServerBinary(platform)
    Builder->>Builder: Build image using binary
    Builder-->>CLI: success
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Focus review on:
    • Sigstore verification policy, certificate identity regex, and TUF/bootstrap usage (pkg/cli/utils/sigstore_verifier.go)
    • Download/extract/verify/fallback flows, temp-file lifecycle, error wrapping, and logging (pkg/cli/utils/binary_downloader.go)
    • Cache index persistence, checksum verification, atomic updates, and Clean semantics (pkg/cli/utils/binary_cache.go)
    • Builder constructor signature change and all call sites (pkg/builder/builder.go, pkg/cli/build.go)
    • go.mod additions and transitive dependency implications

Possibly related PRs

Suggested reviewers

  • Cali0707
  • aliok
  • matzew

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.82% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'feat: add binary download and caching system with sigstore verification' clearly and concisely summarizes the main change: introducing a binary download and caching system with Sigstore verification.
Description check ✅ Passed The PR description includes all required template sections: type (/kind feature), clear explanation of changes and reasoning, linked issue (#174), proposed changes, and release notes.
Linked Issues check ✅ Passed All objectives from issue #174 are met: binaries downloaded from GitHub releases [build.go], version-platform caching implemented [binary_cache.go], Sigstore validation added [sigstore_verifier.go], and utilities in pkg/cli/utils support version-platform mapping.
Out of Scope Changes check ✅ Passed All changes are scoped to the stated objectives: documentation updates reflect new features, dependency updates support Sigstore verification, and embedded binaries are removed as required.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Contributor

@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

🧹 Nitpick comments (6)
pkg/builder/download_binary_provider_test.go (1)

35-53: Consider expanding test coverage.

The test creates a mock binary file but doesn't actually exercise ExtractServerBinary. While avoiding network calls in unit tests is appropriate, consider adding tests with a mock BinaryDownloader to verify the provider's logic independently of network operations.

pkg/cli/utils/binary_cache_test.go (1)

14-14: Explicitly handle the cleanup error.

The deferred os.RemoveAll error should be explicitly ignored or checked. In test cleanup contexts, it's acceptable to ignore the error, but make it explicit.

Apply this diff:

-	defer os.RemoveAll(tmpDir)
+	defer func() { _ = os.RemoveAll(tmpDir) }()
pkg/cli/utils/binary_downloader.go (2)

76-89: Explicitly handle cleanup error.

The deferred os.RemoveAll(tempDir) should explicitly ignore or check the error return value.

Apply this diff:

-	defer os.RemoveAll(tempDir) // Clean up after caching
+	defer func() { _ = os.RemoveAll(tempDir) }() // Clean up after caching

154-192: Handle deferred close errors.

The deferred Close() calls on lines 159 and 175 should explicitly handle or ignore their error returns.

Apply this diff:

 	r, err := zip.OpenReader(zipPath)
 	if err != nil {
 		return "", err
 	}
-	defer r.Close()
+	defer func() { _ = r.Close() }()
 
 	expectedName := fmt.Sprintf("genmcp-server-%s-%s", goos, goarch)
 	if goos == "windows" {
@@ -172,7 +172,7 @@
 		rc, err := f.Open()
 		if err != nil {
 			return "", err
 		}
-		defer rc.Close()
+		defer func() { _ = rc.Close() }()

Otherwise, the extraction logic is solid: it correctly handles platform-specific binary names (including .exe for Windows) and preserves file permissions.

pkg/cli/utils/binary_cache.go (2)

155-182: Handle deferred close error.

The checksum calculation logic is correct, but the deferred f.Close() should explicitly handle or ignore the error return.

Apply this diff:

 	f, err := os.Open(path)
 	if err != nil {
 		return "", err
 	}
-	defer f.Close()
+	defer func() { _ = f.Close() }()

Otherwise, the SHA-256 checksum logic is sound and the verification properly detects mismatches.


185-208: Handle deferred close errors.

The file copy logic correctly preserves permissions, but the deferred Close() calls should explicitly handle or ignore error returns.

Apply this diff:

 	source, err := os.Open(src)
 	if err != nil {
 		return err
 	}
-	defer source.Close()
+	defer func() { _ = source.Close() }()
 
 	destination, err := os.Create(dst)
 	if err != nil {
 		return err
 	}
-	defer destination.Close()
+	defer func() { _ = destination.Close() }()

Otherwise, the copy implementation is solid with proper permission preservation.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3be991 and 61897ff.

⛔ Files ignored due to path filters (2)
  • go.sum is excluded by !**/*.sum
  • hack/jsonschemagen/go.sum is excluded by !**/*.sum
📒 Files selected for processing (14)
  • CHANGELOG.md (1 hunks)
  • README.md (2 hunks)
  • docs/commands.md (2 hunks)
  • go.mod (5 hunks)
  • hack/jsonschemagen/go.mod (1 hunks)
  • pkg/builder/builder.go (1 hunks)
  • pkg/builder/download_binary_provider.go (1 hunks)
  • pkg/builder/download_binary_provider_test.go (1 hunks)
  • pkg/cli/build.go (4 hunks)
  • pkg/cli/root.go (1 hunks)
  • pkg/cli/utils/binary_cache.go (1 hunks)
  • pkg/cli/utils/binary_cache_test.go (1 hunks)
  • pkg/cli/utils/binary_downloader.go (1 hunks)
  • pkg/cli/utils/sigstore_verifier.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Use the server-only logger for any logs containing sensitive information; choose between the MCPServer-embedded logger (via logging.BaseFromContext(ctx)) and the shared server/client logger appropriately

Files:

  • pkg/cli/root.go
  • pkg/builder/download_binary_provider_test.go
  • pkg/builder/download_binary_provider.go
  • pkg/builder/builder.go
  • pkg/cli/utils/sigstore_verifier.go
  • pkg/cli/utils/binary_cache_test.go
  • pkg/cli/build.go
  • pkg/cli/utils/binary_cache.go
  • pkg/cli/utils/binary_downloader.go

⚙️ CodeRabbit configuration file

**/*.go: Review Go code for:

  • Proper error handling
  • Resource cleanup (defer statements)
  • Potential race conditions
  • Performance implications

Files:

  • pkg/cli/root.go
  • pkg/builder/download_binary_provider_test.go
  • pkg/builder/download_binary_provider.go
  • pkg/builder/builder.go
  • pkg/cli/utils/sigstore_verifier.go
  • pkg/cli/utils/binary_cache_test.go
  • pkg/cli/build.go
  • pkg/cli/utils/binary_cache.go
  • pkg/cli/utils/binary_downloader.go
pkg/**/*.go

⚙️ CodeRabbit configuration file

pkg/**/*.go: This is library code that may affect users.

CHANGELOG requirement:

  • If this PR changes public APIs, server behavior, or user-visible functionality, verify that CHANGELOG.md has been updated
  • Breaking API changes must be marked with BREAKING prefix in CHANGELOG.md
  • Internal implementation changes with no user impact do not require CHANGELOG updates
  • If unclear whether the change is user-visible, ask the PR author to clarify
  • If CHANGELOG.md is not modified for a user-visible change, REQUEST that it be updated

Referenced Documentation Contents

CHANGELOG.md:
Documented added binary download/caching system, Sigstore verification, version-platform cache, --server-version flag, latest/dev-version resolution, offline fallback, and cache cleanup (keep last 3 versions). Also notes removal of embedded binaries and related flag.

Files:

  • pkg/cli/root.go
  • pkg/builder/download_binary_provider_test.go
  • pkg/builder/download_binary_provider.go
  • pkg/builder/builder.go
  • pkg/cli/utils/sigstore_verifier.go
  • pkg/cli/utils/binary_cache_test.go
  • pkg/cli/build.go
  • pkg/cli/utils/binary_cache.go
  • pkg/cli/utils/binary_downloader.go
**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

When writing unit tests, follow the table-driven test convention used throughout the codebase

Files:

  • pkg/builder/download_binary_provider_test.go
  • pkg/cli/utils/binary_cache_test.go
docs/**

⚙️ CodeRabbit configuration file

docs/**: Documentation changes generally do not require CHANGELOG updates unless:

  • They document a new feature (in which case the feature itself should be in CHANGELOG)
  • They correct significant user-facing documentation errors

Files:

  • docs/commands.md
CHANGELOG.md

📄 CodeRabbit inference engine (AGENTS.md)

Before opening a PR with user-visible changes, update CHANGELOG.md with a short summary of the changes

Files:

  • CHANGELOG.md
**/CHANGELOG.md

⚙️ CodeRabbit configuration file

**/CHANGELOG.md: Verify that changelog entries:

  • Follow Keep a Changelog format (Added, Changed, Fixed, Removed, etc.)
  • Are user-focused (describe impact, not implementation details)
  • Include PR references (#XXX)
  • Breaking changes are marked with BREAKING prefix
  • Are in the correct section under the unreleased/current version

Referenced Documentation Contents

CHANGELOG.md:
Documented added binary download/caching system, Sigstore verification, version-platform cache, --server-version flag, latest/dev-version resolution, offline fallback, and cache cleanup (keep last 3 versions). Also notes removal of embedded binaries and related flag.

Files:

  • CHANGELOG.md
🧠 Learnings (6)
📚 Learning: 2025-11-05T00:59:13.052Z
Learnt from: Cali0707
Repo: genmcp/gen-mcp PR: 199
File: pkg/invocation/http/config.go:30-41
Timestamp: 2025-11-05T00:59:13.052Z
Learning: For the genmcp/gen-mcp repository, breaking changes are defined by changes to the YAML/JSON configuration file schema, not internal Go struct field names. If the JSON tags and serialization format remain unchanged, it is considered internal refactoring and does not require a CHANGELOG entry for breaking changes.

Applied to files:

  • docs/commands.md
  • CHANGELOG.md
  • hack/jsonschemagen/go.mod
📚 Learning: 2025-09-30T13:36:23.973Z
Learnt from: matzew
Repo: genmcp/gen-mcp PR: 130
File: hack/lib/common.sh:16-16
Timestamp: 2025-09-30T13:36:23.973Z
Learning: In the genmcp/gen-mcp repository, for the CONTAINER_ENGINE variable in hack/lib/common.sh, the maintainer prefers a simple approach without preflight validation checks for the container engine binary, favoring simplicity over early error detection.

Applied to files:

  • docs/commands.md
  • README.md
📚 Learning: 2025-10-07T17:29:19.445Z
Learnt from: Cali0707
Repo: genmcp/gen-mcp PR: 155
File: hack/jsonschemagen/go.mod:3-8
Timestamp: 2025-10-07T17:29:19.445Z
Learning: The gen-mcp project targets Go 1.24+ and does not require backward compatibility with Go 1.21.

Applied to files:

  • docs/commands.md
  • CHANGELOG.md
  • README.md
  • hack/jsonschemagen/go.mod
📚 Learning: 2025-10-20T06:48:47.678Z
Learnt from: CR
Repo: genmcp/gen-mcp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-20T06:48:47.678Z
Learning: Applies to CHANGELOG.md : Before opening a PR with user-visible changes, update CHANGELOG.md with a short summary of the changes

Applied to files:

  • CHANGELOG.md
  • README.md
📚 Learning: 2025-11-06T22:50:14.022Z
Learnt from: Cali0707
Repo: genmcp/gen-mcp PR: 203
File: pkg/mcpfile/parser.go:79-0
Timestamp: 2025-11-06T22:50:14.022Z
Learning: In the genmcp/gen-mcp repository, MCP file parsing (via ParseMCPFile in pkg/mcpfile/parser.go) happens only once at startup, so concerns about stale global state from multiple sequential parses do not apply.

Applied to files:

  • README.md
  • hack/jsonschemagen/go.mod
📚 Learning: 2025-10-08T21:13:36.046Z
Learnt from: aliok
Repo: genmcp/gen-mcp PR: 155
File: pkg/cli/utils/schema.go:9-16
Timestamp: 2025-10-08T21:13:36.046Z
Learning: In pkg/cli/utils/schema.go, the schema URL intentionally uses refs/heads/main instead of versioned tags, so that all mcpfiles validate against the latest schema on the main branch.

Applied to files:

  • hack/jsonschemagen/go.mod
🧬 Code graph analysis (7)
pkg/builder/download_binary_provider_test.go (1)
pkg/builder/download_binary_provider.go (1)
  • NewDownloadBinaryProvider (19-29)
pkg/builder/download_binary_provider.go (1)
pkg/cli/utils/binary_downloader.go (2)
  • BinaryDownloader (21-25)
  • NewBinaryDownloader (28-44)
pkg/builder/builder.go (1)
pkg/builder/download_binary_provider.go (1)
  • NewDownloadBinaryProvider (19-29)
pkg/cli/utils/binary_cache_test.go (1)
pkg/cli/utils/binary_cache.go (1)
  • NewBinaryCacheWithDir (40-59)
pkg/cli/build.go (2)
pkg/cli/root.go (1)
  • GetVersion (64-66)
pkg/builder/builder.go (1)
  • New (214-233)
pkg/cli/utils/binary_cache.go (1)
pkg/cli/utils/cache_file.go (1)
  • GetCacheDir (9-23)
pkg/cli/utils/binary_downloader.go (2)
pkg/cli/utils/binary_cache.go (2)
  • BinaryCache (24-28)
  • NewBinaryCache (31-37)
pkg/cli/utils/sigstore_verifier.go (2)
  • SigstoreVerifier (20-23)
  • NewSigstoreVerifier (26-49)
🪛 GitHub Actions: golangci-lint
pkg/builder/download_binary_provider_test.go

[error] 16-16: golangci-lint: Error return value of os.RemoveAll is not checked (errcheck).

🪛 GitHub Check: lint
pkg/builder/download_binary_provider_test.go

[failure] 16-16:
Error return value of os.RemoveAll is not checked (errcheck)

pkg/cli/utils/binary_cache_test.go

[failure] 14-14:
Error return value of os.RemoveAll is not checked (errcheck)

pkg/cli/utils/binary_cache.go

[failure] 196-196:
Error return value of destination.Close is not checked (errcheck)


[failure] 190-190:
Error return value of source.Close is not checked (errcheck)


[failure] 160-160:
Error return value of f.Close is not checked (errcheck)

pkg/cli/utils/binary_downloader.go

[failure] 175-175:
Error return value of rc.Close is not checked (errcheck)


[failure] 159-159:
Error return value of r.Close is not checked (errcheck)


[failure] 144-144:
Error return value of out.Close is not checked (errcheck)


[failure] 134-134:
Error return value of resp.Body.Close is not checked (errcheck)


[failure] 79-79:
Error return value of os.RemoveAll is not checked (errcheck)

🪛 markdownlint-cli2 (0.18.1)
README.md

163-163: Heading levels should only increment by one level at a time
Expected: h3; Actual: h4

(MD001, heading-increment)

🔇 Additional comments (29)
README.md (1)

153-226: LGTM!

The documentation comprehensively covers the new binary download and caching system, including:

  • Sigstore verification details
  • Version matching behavior for release/dev builds
  • Offline support and cache fallback
  • OS-specific cache locations
  • Multi-architecture build behavior

The content is clear, user-focused, and well-organized.

docs/commands.md (1)

305-344: LGTM!

The command documentation accurately describes:

  • The new --server-version flag with clear default behavior
  • Binary download and caching mechanism
  • Sigstore verification (built-in)
  • OS-specific cache locations
  • Version matching rules

The documentation is consistent with README.md and provides clear examples.

CHANGELOG.md (1)

17-34: LGTM!

The CHANGELOG entries are well-structured and user-focused:

  • Follows Keep a Changelog format correctly
  • Describes user-visible impact clearly
  • Includes PR references
  • Covers all major changes (binary downloads, caching, verification, flags)

The removal of --use-embedded-binaries is documented appropriately. Since the new behavior is automatic and doesn't require user action, the lack of a BREAKING prefix is acceptable.

Based on coding guidelines

pkg/builder/builder.go (1)

213-233: All callers correctly handle the new error return and version parameter.

The single caller at pkg/cli/build.go:63 properly:

  • Passes the version parameter to builder.New(push, version)
  • Handles the error return with if err != nil and exits gracefully
  • Provides meaningful error context

The CHANGELOG.md is updated with the feature documentation under PR #151, including binary download system, caching, and version specification. The API signature change to support this feature has been properly integrated throughout the codebase.

go.mod (1)

17-17: sigstore-go v1.1.3 is the latest stable version with no active vulnerabilities.

Verification confirms v1.1.3 (released Sep 26, 2025) is the latest stable release. A LOW severity advisory exists for sigstore-go but affects only versions ≤ 0.6.0, with the fix available in v0.6.1. Since v1.1.3 is far beyond the patched version, it is not vulnerable.

pkg/cli/root.go (1)

63-66: Initialization order is correct; this review comment is inaccurate.

The execution flow guarantees that GetVersion() is only called after cliVersion is initialized:

  1. cmd/genmcp/main.go calls cli.Execute(version)
  2. Execute() sets cliVersion (lines 20–22) before calling rootCmd.Execute()
  3. rootCmd.Execute() processes subcommands and only invokes their handlers after the function has set up
  4. GetVersion() is called exclusively from Cobra command handlers (executeBuildCmd at line 49, version command handler), which run after rootCmd.Execute() is invoked

There is no code path where GetVersion() can be invoked before Execute() completes initialization.

Likely an incorrect or invalid review comment.

hack/jsonschemagen/go.mod (1)

7-7: I need to gather more information about the remaining dependency. Let me search for details on the google/jsonschema-go version and any potential breaking changes in easyjson.

Let me search more specifically for the easyjson v0.9.0 release notes and google/jsonschema-go v0.3.0 stability:

Run tests to verify easyjson and google/jsonschema-go compatibility after the update.

Based on verification:

  • google/jsonschema-go implements JSON Schema specification with support for creating schemas, validating JSON values, and inferring schemas from Go structs, but specific v0.3.0 release stability information was unavailable in public sources.

  • easyjson v0.9.0 included "up go version and bugfixes", and later patch releases (v0.9.1 included fixes for unmarshal null handling to existing values and non-pointer fields), indicating behavioral changes. Since the project is still at 0.x, breaking changes between v0.7.7 and v0.9.0 are possible per Go semver conventions.

  • go.uber.org/multierr v1.10.0 → v1.11.0 is safe; the package is stable under the v1.x line.

Action: Run the project's test suite after upgrading, particularly focusing on JSON unmarshaling edge cases to ensure compatibility.

pkg/cli/build.go (4)

20-20: LGTM! Verify CHANGELOG entry.

The new --server-version flag is well-documented and provides valuable flexibility for users.

Per the coding guidelines, verify that CHANGELOG.md documents this user-visible CLI flag addition. Based on the coding guidelines summary, it appears the CHANGELOG has been updated, but please confirm it mentions the new flag explicitly.


46-60: LGTM! Version resolution logic is clear and well-structured.

The version selection logic properly handles three scenarios:

  • User-specified version via flag
  • Development CLI → latest server binaries
  • Release CLI → matching server version

The diagnostic print statements provide good visibility into which server version is being used.


63-67: LGTM! Proper error handling for builder initialization.

The error handling correctly checks the builder constructor's error return and provides a clear error message before exiting.


169-172: LGTM! Simple and effective version detection.

The isDevelopmentVersion helper correctly identifies development builds using a prefix match. This aligns well with the version resolution logic in executeBuildCmd.

pkg/builder/download_binary_provider.go (2)

19-29: LGTM! Clean constructor with proper error handling.

The constructor correctly initializes the binary downloader and wraps any errors appropriately.


32-49: LGTM! Proper error handling and context.

The method correctly:

  • Delegates binary retrieval to the downloader
  • Reads the binary data from the cached path
  • Collects file metadata
  • Wraps all errors with platform-specific context for better debugging
pkg/cli/utils/sigstore_verifier.go (4)

14-17: Certificate identity configuration looks correct.

The OIDC issuer and SAN regex pattern correctly target GitHub Actions-signed artifacts for this repository. The regex pattern allows any path under the repository, which is appropriate for release artifacts.


52-91: LGTM! Comprehensive blob verification implementation.

The verification flow correctly:

  • Loads the sigstore bundle
  • Reads and hashes the artifact (SHA-256)
  • Constructs certificate identity with OIDC issuer and SAN regex
  • Creates verification policy with artifact digest and certificate requirements
  • Executes verification and returns detailed errors

94-98: LGTM! Correct SHA-256 digest implementation.

The helper function correctly computes and returns a hex-encoded SHA-256 digest.


26-49: Pass context with timeout to FetchTrustedRoot() to prevent indefinite hangs.

The current code calls root.FetchTrustedRoot() without a context parameter. Based on sigstore-go's API, this call should pass a context with timeout configured (e.g., context.WithTimeout()). Consider updating NewSigstoreVerifier to accept a context parameter and pass it to FetchTrustedRoot(ctx) with an appropriate deadline.

Verify the exact function signature in your sigstore-go version and ensure the fix is applied at line 29 in pkg/cli/utils/sigstore_verifier.go.

pkg/cli/utils/binary_downloader.go (6)

14-25: LGTM! Well-defined constants and structure.

The GitHub release URLs and cache retention count (3 versions) align with the PR objectives.


48-74: LGTM! Smart cache fallback logic.

The method properly:

  • Resolves "latest" to an actual version tag
  • Checks cache before downloading
  • Falls back to any cached version if download fails (good offline support)
  • Provides clear warning messages to users

This aligns well with the PR objective of supporting offline builds.


95-124: LGTM! Proper download and verification flow.

The method correctly:

  • Creates temporary directory for downloads (caller handles cleanup as documented)
  • Downloads both the binary archive and signature bundle
  • Performs Sigstore verification before extraction
  • Returns extracted binary path with proper error wrapping

195-197: LGTM! Convenient wrapper for current platform.

Simple delegation to GetBinary with the current runtime's OS and architecture.


200-224: LGTM! Proper version resolution from GitHub API.

The method correctly:

  • Calls the GitHub releases API
  • Checks HTTP status
  • Parses JSON response
  • Validates tag_name presence
  • Returns the version string

Note: The HTTP timeout issue mentioned in the earlier comment for downloadFile applies here too, but the fix location is in NewBinaryDownloader.


227-229: LGTM! Clean delegation to cache cleanup.

Properly delegates cache maintenance to the BinaryCache implementation.

pkg/cli/utils/binary_cache.go (6)

14-28: LGTM! Well-designed cache structures.

The cache entry includes all necessary metadata:

  • Version and platform for identification
  • Path to cached binary
  • SHA-256 checksum for integrity verification
  • Timestamp for cleanup/retention logic

The in-memory map with composite key ("version-platform") provides efficient lookups.


31-59: LGTM! Proper cache initialization.

The constructors correctly:

  • Create the cache directory structure
  • Define the index path
  • Load existing index or gracefully handle missing index
  • Wrap errors appropriately

62-82: LGTM! Robust cache retrieval with integrity checks.

The Get method properly:

  • Checks if the file exists on disk (handles external deletion)
  • Verifies the SHA-256 checksum (detects corruption)
  • Automatically removes invalid entries from the index
  • Returns not found for missing or corrupted entries

This defensive approach ensures cache reliability.


85-117: LGTM! Complete cache addition workflow.

The Add method correctly:

  • Computes SHA-256 before caching
  • Generates descriptive filenames with version and platform
  • Preserves file extensions (important for Windows .exe)
  • Creates a complete cache entry with timestamp
  • Persists the index to disk
  • Returns the cached path

120-152: LGTM! Straightforward index persistence.

The index serialization correctly:

  • Uses JSON for human-readable storage
  • Converts between array (JSON) and map (in-memory) representations
  • Provides indentation for easier debugging
  • Sets appropriate file permissions (0644)

211-227: LGTM! Simple and effective latest version lookup.

The method correctly finds the most recently downloaded binary for a platform by:

  • Filtering entries by platform
  • Comparing RFC3339 timestamps (lexicographically sortable)
  • Returning the version and path, or empty strings if not found

For the expected cache size (3 versions per platform), the linear search is appropriate.

Copy link
Contributor

@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: 0

♻️ Duplicate comments (4)
pkg/cli/utils/binary_cache.go (1)

230-256: Confirmed: Sorting issue has been resolved.

The previous review comment about sorting before removal has been addressed. The Clean method now correctly sorts entries by timestamp (lines 241-244) before removing old versions.

pkg/cli/utils/binary_downloader.go (2)

28-47: Confirmed: HTTP timeout has been added.

The previous review comment about adding an HTTP timeout has been addressed. The client now has a 5-minute timeout (line 43), which is appropriate for binary downloads.


127-152: Confirmed: Defer error handling has been fixed.

The previous review comment about handling close errors has been addressed. Both resp.Body.Close() (line 135) and out.Close() (line 145) now properly handle errors in deferred functions.

pkg/builder/download_binary_provider_test.go (1)

11-16: Confirmed: Defer error handling has been fixed.

The previous review comment about unchecked error in defer statement has been addressed. Line 16 now properly handles the cleanup error with defer func() { _ = os.RemoveAll(tmpDir) }().

🧹 Nitpick comments (3)
pkg/cli/utils/binary_downloader.go (2)

49-92: Consider using structured logging for user messages.

The fallback warnings (lines 70-71) are printed directly to stdout. While this provides user feedback, consider using a structured logger for consistency, especially since the coding guidelines mention logger usage for Go code.

However, for CLI user-facing messages, stdout may be appropriate. If this is intentional, this comment can be disregarded.


200-225: Consider validating tag_name format.

The fetchLatestVersion method correctly fetches and parses the GitHub API response. However, it doesn't validate the format of tag_name (e.g., ensuring it matches a version pattern like vX.Y.Z).

While the current implementation will fail gracefully at download time with a 404 if the tag is malformed, adding format validation here could provide earlier, more descriptive error messages.

pkg/builder/download_binary_provider_test.go (1)

35-53: Test doesn't exercise ExtractServerBinary method.

The test name suggests it tests ExtractServerBinary, but it only validates platform initialization without actually calling the method. While the comment at line 52 acknowledges this limitation, consider either:

  1. Renaming the test to reflect what it actually validates (e.g., "Platform initialization"), or
  2. Adding a mock-based test that actually exercises the ExtractServerBinary interface.

This would improve test coverage and clarity.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 61897ff and bead826.

📒 Files selected for processing (4)
  • pkg/builder/download_binary_provider_test.go (1 hunks)
  • pkg/cli/utils/binary_cache.go (1 hunks)
  • pkg/cli/utils/binary_cache_test.go (1 hunks)
  • pkg/cli/utils/binary_downloader.go (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • pkg/cli/utils/binary_cache_test.go
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Use the server-only logger for any logs containing sensitive information; choose between the MCPServer-embedded logger (via logging.BaseFromContext(ctx)) and the shared server/client logger appropriately

Files:

  • pkg/builder/download_binary_provider_test.go
  • pkg/cli/utils/binary_cache.go
  • pkg/cli/utils/binary_downloader.go

⚙️ CodeRabbit configuration file

**/*.go: Review Go code for:

  • Proper error handling
  • Resource cleanup (defer statements)
  • Potential race conditions
  • Performance implications

Files:

  • pkg/builder/download_binary_provider_test.go
  • pkg/cli/utils/binary_cache.go
  • pkg/cli/utils/binary_downloader.go
**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

When writing unit tests, follow the table-driven test convention used throughout the codebase

Files:

  • pkg/builder/download_binary_provider_test.go
pkg/**/*.go

⚙️ CodeRabbit configuration file

pkg/**/*.go: This is library code that may affect users.

CHANGELOG requirement:

  • If this PR changes public APIs, server behavior, or user-visible functionality, verify that CHANGELOG.md has been updated
  • Breaking API changes must be marked with BREAKING prefix in CHANGELOG.md
  • Internal implementation changes with no user impact do not require CHANGELOG updates
  • If unclear whether the change is user-visible, ask the PR author to clarify
  • If CHANGELOG.md is not modified for a user-visible change, REQUEST that it be updated

Files:

  • pkg/builder/download_binary_provider_test.go
  • pkg/cli/utils/binary_cache.go
  • pkg/cli/utils/binary_downloader.go
🧬 Code graph analysis (3)
pkg/builder/download_binary_provider_test.go (1)
pkg/builder/download_binary_provider.go (1)
  • NewDownloadBinaryProvider (19-29)
pkg/cli/utils/binary_cache.go (1)
pkg/cli/utils/cache_file.go (1)
  • GetCacheDir (9-23)
pkg/cli/utils/binary_downloader.go (2)
pkg/cli/utils/binary_cache.go (2)
  • BinaryCache (25-29)
  • NewBinaryCache (32-38)
pkg/cli/utils/sigstore_verifier.go (2)
  • SigstoreVerifier (20-23)
  • NewSigstoreVerifier (26-49)
⏰ 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: lint
  • GitHub Check: Unit Tests
🔇 Additional comments (15)
pkg/cli/utils/binary_cache.go (8)

15-29: LGTM!

The type definitions are well-structured with appropriate fields for caching and tracking binary metadata.


31-60: LGTM!

The constructors properly initialize the cache directory and handle the case where the index file doesn't exist yet.


62-83: LGTM!

The Get method properly validates both file existence and checksum, removing invalid entries as needed. Ignoring saveIndex errors during cleanup is acceptable for this read-heavy operation.


85-118: LGTM!

The Add method properly calculates checksums, preserves file permissions, and maintains the cache index.


120-153: LGTM!

The index persistence logic correctly serializes and deserializes the cache entries.


155-183: LGTM!

The checksum calculation and verification logic is correct with proper resource handling.


185-209: LGTM!

The copyFile method correctly copies file content and preserves permissions with proper resource cleanup.


211-228: LGTM!

The GetLatestCached method correctly identifies the most recently downloaded binary for a platform using RFC3339 timestamp comparison.

pkg/cli/utils/binary_downloader.go (6)

15-19: LGTM!

The constants are appropriately defined with reasonable defaults.


21-26: LGTM!

The BinaryDownloader type properly encapsulates its dependencies.


94-125: LGTM!

The download and verification flow is correct. Sigstore verification occurs before extraction, which is the proper security practice. The temp directory cleanup is appropriately delegated to the caller (as noted in the comment at line 95).


154-193: LGTM!

The extractBinary method correctly extracts the platform-specific binary from the ZIP archive. The defer statements inside the loop (lines 176, 183) are safe because the loop continues on name mismatch (line 169) and returns immediately on match (line 189), ensuring only one file's resources are managed.


195-198: LGTM!

The GetCurrentBinary convenience method correctly uses the current runtime platform.


227-230: LGTM!

The CleanOldBinaries method correctly delegates to the cache's Clean method.

pkg/builder/download_binary_provider_test.go (1)

18-33: LGTM!

The test appropriately handles potential initialization failures (which may occur in unit test environments without network access) and validates the provider's version field.

Copy link
Contributor

@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: 1

🧹 Nitpick comments (1)
pkg/builder/download_binary_provider_test.go (1)

7-44: Optional: collapse duplicate subtest logic into a table‑driven test

The two subtests share almost identical setup and assertions, differing only by the version string and expected value. To follow the project’s table‑driven convention and reduce duplication, you could refactor to a single table‑driven test:

-func TestNewDownloadBinaryProvider(t *testing.T) {
-	t.Run("creates provider with specified version", func(t *testing.T) {
-		provider, err := NewDownloadBinaryProvider("v0.1.0")
-		...
-	})
-
-	t.Run("creates provider with latest version", func(t *testing.T) {
-		provider, err := NewDownloadBinaryProvider("latest")
-		...
-	})
-}
+func TestNewDownloadBinaryProvider(t *testing.T) {
+	tests := []struct {
+		name    string
+		version string
+	}{
+		{name: "creates provider with specified version", version: "v0.1.0"},
+		{name: "creates provider with latest version", version: "latest"},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			provider, err := NewDownloadBinaryProvider(tt.version)
+			if err != nil {
+				t.Fatalf("unexpected error creating download provider for %q: %v", tt.version, err)
+			}
+
+			if provider == nil {
+				t.Fatal("expected provider to be created")
+			}
+			if provider.version != tt.version {
+				t.Errorf("expected version %s, got %s", tt.version, provider.version)
+			}
+			if provider.downloader == nil {
+				t.Error("expected downloader to be initialized")
+			}
+		})
+	}
+}

This keeps the behavior the same while aligning with the table‑driven test style.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bead826 and 2b94a66.

📒 Files selected for processing (1)
  • pkg/builder/download_binary_provider_test.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Use the server-only logger for any logs containing sensitive information; choose between the MCPServer-embedded logger (via logging.BaseFromContext(ctx)) and the shared server/client logger appropriately

Files:

  • pkg/builder/download_binary_provider_test.go

⚙️ CodeRabbit configuration file

**/*.go: Review Go code for:

  • Proper error handling
  • Resource cleanup (defer statements)
  • Potential race conditions
  • Performance implications

Files:

  • pkg/builder/download_binary_provider_test.go
**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

When writing unit tests, follow the table-driven test convention used throughout the codebase

Files:

  • pkg/builder/download_binary_provider_test.go
pkg/**/*.go

⚙️ CodeRabbit configuration file

pkg/**/*.go: This is library code that may affect users.

CHANGELOG requirement:

  • If this PR changes public APIs, server behavior, or user-visible functionality, verify that CHANGELOG.md has been updated
  • Breaking API changes must be marked with BREAKING prefix in CHANGELOG.md
  • Internal implementation changes with no user impact do not require CHANGELOG updates
  • If unclear whether the change is user-visible, ask the PR author to clarify
  • If CHANGELOG.md is not modified for a user-visible change, REQUEST that it be updated

Referenced Documentation Contents

CHANGELOG.md:
Notes Unreleased entries for PR 151: add binary download/caching with Sigstore verification, version-platform cache, --server-version flag, offline fallback, and 3-version retention. Highlights removal of embedded binaries and --use-embedded-binaries flag. Emphasizes no public API changes beyond changelog statements.

README.md:
Documentation sections describing binary downloads with Sigstore verification, version matching (Release/Development/Custom server version), offline support, and cache management per OS. Includes usage examples for --server-version and multi-arch handling; reiterates cache location and retention behavior.

docs/commands.md:
New Build command guidance: --server-version flag, binary management section detailing source (GitHub releases), cache, Sigstore verification, per-OS cache paths, version matching rules, and network requirements. Examples show building with --server-version and derivations for development/releases.

Files:

  • pkg/builder/download_binary_provider_test.go
🧬 Code graph analysis (1)
pkg/builder/download_binary_provider_test.go (1)
pkg/builder/download_binary_provider.go (1)
  • NewDownloadBinaryProvider (19-29)
⏰ 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: Unit Tests
  • GitHub Check: lint

Copy link
Contributor

@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: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2b94a66 and de8f61b.

📒 Files selected for processing (1)
  • pkg/builder/download_binary_provider_test.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Use the server-only logger for any logs containing sensitive information; choose between the MCPServer-embedded logger (via logging.BaseFromContext(ctx)) and the shared server/client logger appropriately

Files:

  • pkg/builder/download_binary_provider_test.go

⚙️ CodeRabbit configuration file

**/*.go: Review Go code for:

  • Proper error handling
  • Resource cleanup (defer statements)
  • Potential race conditions
  • Performance implications

Files:

  • pkg/builder/download_binary_provider_test.go
**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

When writing unit tests, follow the table-driven test convention used throughout the codebase

Files:

  • pkg/builder/download_binary_provider_test.go
pkg/**/*.go

⚙️ CodeRabbit configuration file

pkg/**/*.go: This is library code that may affect users.

CHANGELOG requirement:

  • If this PR changes public APIs, server behavior, or user-visible functionality, verify that CHANGELOG.md has been updated
  • Breaking API changes must be marked with BREAKING prefix in CHANGELOG.md
  • Internal implementation changes with no user impact do not require CHANGELOG updates
  • If unclear whether the change is user-visible, ask the PR author to clarify
  • If CHANGELOG.md is not modified for a user-visible change, REQUEST that it be updated

Referenced Documentation Contents

CHANGELOG.md:
Notes Unreleased changes for PR #151: binary download/caching system, Sigstore verification, version-platform cache with last 3 retained, --server-version flag, offline fallback, and cache cleanup. Also notes removal of embedded binaries and --use-embedded-binaries flag.

Files:

  • pkg/builder/download_binary_provider_test.go
🧬 Code graph analysis (1)
pkg/builder/download_binary_provider_test.go (1)
pkg/builder/download_binary_provider.go (1)
  • NewDownloadBinaryProvider (19-29)
⏰ 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: lint
  • GitHub Check: Unit Tests

Replace embedded server binaries with on-demand downloads from GitHub releases, reducing CLI size from ~100MB to ~78MB.
Downloaded binaries are cryptographically verified using Sigstore and cached locally for reuse.

- Add binary download system with automatic version resolution
- Implement version-platform cache with automatic cleanup (keeps last 3 versions)
- Add --server-version flag to specify server binary version
- Support offline builds with cached binary fallback
- Remove embedded binaries and build-server-binaries make target
- Dev builds automatically use latest stable server binaries
- Release builds download matching server version by default

Signed-off-by: Nader Ziada <[email protected]>
Signed-off-by: Nader Ziada <[email protected]>
Copy link
Contributor

@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: 1

🧹 Nitpick comments (1)
go.mod (1)

36-208: Large expansion of indirect dependencies warrants documentation.

The indirect dependency tree has expanded significantly (~70+ transitive dependencies added/updated), primarily from sigstore-go's ecosystem integration (Google Cloud, OpenTelemetry, Sigstore modules, Kubernetes, security libraries). While this is expected given the Sigstore verification requirement, it increases supply chain complexity and build artifact footprint.

Consider documenting in PR notes or architecture decisions:

  • Rationale for accepting the transitive dependency expansion
  • Any steps taken to audit high-risk transitive dependencies (e.g., cryptographic libs)
  • Whether the net binary size reduction (100MB → 78MB) justifies the dependency scope increase

Do you want me to generate a shell script to identify the most high-risk transitive dependencies (cryptography, networking, serialization) for targeted audit, or check for any duplicate/conflicting versions across the tree?

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 84539eb and c58ab54.

⛔ Files ignored due to path filters (2)
  • go.sum is excluded by !**/*.sum
  • hack/jsonschemagen/go.sum is excluded by !**/*.sum
📒 Files selected for processing (14)
  • CHANGELOG.md (1 hunks)
  • README.md (2 hunks)
  • docs/commands.md (2 hunks)
  • go.mod (5 hunks)
  • hack/jsonschemagen/go.mod (1 hunks)
  • pkg/builder/builder.go (1 hunks)
  • pkg/builder/download_binary_provider.go (1 hunks)
  • pkg/builder/download_binary_provider_test.go (1 hunks)
  • pkg/cli/build.go (4 hunks)
  • pkg/cli/root.go (1 hunks)
  • pkg/cli/utils/binary_cache.go (1 hunks)
  • pkg/cli/utils/binary_cache_test.go (1 hunks)
  • pkg/cli/utils/binary_downloader.go (1 hunks)
  • pkg/cli/utils/sigstore_verifier.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • hack/jsonschemagen/go.mod
  • pkg/builder/download_binary_provider.go
  • pkg/cli/utils/binary_cache_test.go
  • docs/commands.md
  • pkg/builder/download_binary_provider_test.go
  • pkg/cli/root.go
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Check whether you are using the server-only logger (embedded in the MCPServer type, and accessed from invocation contexts with logging.BaseFromContext(ctx)) or the server and client logger. Ensure that any logs with sensitive info use the server-only logger

Files:

  • pkg/builder/builder.go
  • pkg/cli/utils/sigstore_verifier.go
  • pkg/cli/build.go
  • pkg/cli/utils/binary_downloader.go
  • pkg/cli/utils/binary_cache.go

⚙️ CodeRabbit configuration file

**/*.go: Review Go code for:

  • Proper error handling
  • Resource cleanup (defer statements)
  • Potential race conditions
  • Performance implications

Files:

  • pkg/builder/builder.go
  • pkg/cli/utils/sigstore_verifier.go
  • pkg/cli/build.go
  • pkg/cli/utils/binary_downloader.go
  • pkg/cli/utils/binary_cache.go
pkg/**/*.go

⚙️ CodeRabbit configuration file

pkg/**/*.go: This is library code that may affect users.

CHANGELOG requirement:

  • If this PR changes public APIs, server behavior, or user-visible functionality, verify that CHANGELOG.md has been updated
  • Breaking API changes must be marked with BREAKING prefix in CHANGELOG.md
  • Internal implementation changes with no user impact do not require CHANGELOG updates
  • If unclear whether the change is user-visible, ask the PR author to clarify
  • If CHANGELOG.md is not modified for a user-visible change, REQUEST that it be updated

Files:

  • pkg/builder/builder.go
  • pkg/cli/utils/sigstore_verifier.go
  • pkg/cli/build.go
  • pkg/cli/utils/binary_downloader.go
  • pkg/cli/utils/binary_cache.go
**/CHANGELOG.md

⚙️ CodeRabbit configuration file

**/CHANGELOG.md: Verify that changelog entries:

  • Follow Keep a Changelog format (Added, Changed, Fixed, Removed, etc.)
  • Are user-focused (describe impact, not implementation details)
  • Include PR references (#XXX)
  • Breaking changes are marked with BREAKING prefix
  • Are in the correct section under the unreleased/current version

Files:

  • CHANGELOG.md
🧠 Learnings (5)
📚 Learning: 2025-09-30T13:36:23.973Z
Learnt from: matzew
Repo: genmcp/gen-mcp PR: 130
File: hack/lib/common.sh:16-16
Timestamp: 2025-09-30T13:36:23.973Z
Learning: In the genmcp/gen-mcp repository, for the CONTAINER_ENGINE variable in hack/lib/common.sh, the maintainer prefers a simple approach without preflight validation checks for the container engine binary, favoring simplicity over early error detection.

Applied to files:

  • README.md
📚 Learning: 2025-10-07T17:29:19.445Z
Learnt from: Cali0707
Repo: genmcp/gen-mcp PR: 155
File: hack/jsonschemagen/go.mod:3-8
Timestamp: 2025-10-07T17:29:19.445Z
Learning: The gen-mcp project targets Go 1.24+ and does not require backward compatibility with Go 1.21.

Applied to files:

  • README.md
  • CHANGELOG.md
📚 Learning: 2025-11-06T22:50:14.022Z
Learnt from: Cali0707
Repo: genmcp/gen-mcp PR: 203
File: pkg/mcpfile/parser.go:79-0
Timestamp: 2025-11-06T22:50:14.022Z
Learning: In the genmcp/gen-mcp repository, MCP file parsing (via ParseMCPFile in pkg/mcpfile/parser.go) happens only once at startup, so concerns about stale global state from multiple sequential parses do not apply.

Applied to files:

  • README.md
📚 Learning: 2025-11-05T00:59:13.052Z
Learnt from: Cali0707
Repo: genmcp/gen-mcp PR: 199
File: pkg/invocation/http/config.go:30-41
Timestamp: 2025-11-05T00:59:13.052Z
Learning: For the genmcp/gen-mcp repository, breaking changes are defined by changes to the YAML/JSON configuration file schema, not internal Go struct field names. If the JSON tags and serialization format remain unchanged, it is considered internal refactoring and does not require a CHANGELOG entry for breaking changes.

Applied to files:

  • CHANGELOG.md
📚 Learning: 2025-11-29T19:44:58.854Z
Learnt from: CR
Repo: genmcp/gen-mcp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-29T19:44:58.854Z
Learning: Update the `./CHANGELOG.md` file with relevant changes before opening a PR. Every PR with user-visible changes should update the `./CHANGELOG.md` with a short summary of the changes

Applied to files:

  • CHANGELOG.md
🧬 Code graph analysis (2)
pkg/builder/builder.go (1)
pkg/builder/download_binary_provider.go (1)
  • NewDownloadBinaryProvider (19-29)
pkg/cli/utils/binary_cache.go (1)
pkg/cli/utils/cache_file.go (1)
  • GetCacheDir (9-23)
⏰ 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: lint
  • GitHub Check: Unit Tests
🔇 Additional comments (13)
go.mod (2)

27-27: Minor version bump for easyjson is safe.

The update from v0.7.7 to v0.9.0 is a minor version bump and should be backward-compatible. No issues detected.


17-17: No action needed. sigstore-go v1.1.3 is a stable, officially released version (Sep 26, 2025, marked Latest) with no known CVEs affecting it. The dependency is appropriate for production use.

pkg/builder/builder.go (1)

213-233: Verify whether this public API change requires a BREAKING tag in CHANGELOG.

The New function signature has changed from New(saveToRegistry bool) *ImageBuilder to New(saveToRegistry bool, version string) (*ImageBuilder, error), which is a breaking change for any Go code that imports pkg/builder.

Since this is in pkg/builder, and the coding guidelines indicate that pkg/**/*.go is library code that may affect users, please clarify:

  • Is pkg/builder intended as a public API for external consumers, or is it internal-only?
  • If it's public, should this change be marked with BREAKING in the CHANGELOG?

Based on learnings, if pkg/builder is not intended for external use and only the CLI is the public interface, then the current CHANGELOG entry is appropriate. Otherwise, consider marking this as a breaking change.

pkg/cli/utils/binary_cache.go (1)

231-256: LGTM! Past sorting issue has been addressed.

The Clean method now correctly sorts entries by download timestamp (newest first) before removing old versions. This addresses the critical issue flagged in the previous review where entries were being removed without sorting.

The implementation properly:

  • Groups entries by platform
  • Sorts each platform's entries by timestamp (descending)
  • Keeps the first keepVersions entries (newest)
  • Removes older entries and cleans up their files
README.md (1)

155-228: Excellent documentation coverage.

The documentation comprehensively covers all aspects of the new binary download and caching system:

  • Binary downloads with Sigstore verification
  • Version matching strategies (release builds, development builds, custom versions)
  • Network requirements and offline support
  • Cache management and cleanup procedures
  • Platform-specific cache locations

The examples clearly demonstrate the new --server-version flag usage and align well with the implementation.

pkg/cli/build.go (2)

62-83: Well-implemented version resolution logic.

The version determination logic correctly implements the documented behavior:

  • Explicit --server-version takes precedence
  • Development CLI builds automatically use latest server binaries
  • Release CLI builds match server binary versions
  • Clear diagnostic messages inform users of the chosen version

The error handling for builder initialization is appropriate, providing clear feedback if setup fails.


255-258: Simple and effective development version detection.

The isDevelopmentVersion helper cleanly identifies development builds using the "development@" prefix convention.

pkg/cli/utils/sigstore_verifier.go (2)

25-49: Proper Sigstore verifier initialization.

The verifier correctly:

  • Fetches the trusted root from TUF (The Update Framework)
  • Requires SCT (Signed Certificate Timestamp)
  • Requires Rekor transparency log entry
  • Requires observer timestamps

This follows Sigstore best practices for secure verification.


51-91: Robust blob verification implementation.

The VerifyBlob method properly:

  • Loads the sigstore bundle
  • Computes the artifact's SHA256 digest
  • Constructs certificate identity with OIDC issuer and SAN regex matching GitHub Actions
  • Builds and applies verification policy
  • Returns detailed error messages on verification failure

The certificate identity regex https://github.com/genmcp/gen-mcp/.* appropriately matches GitHub Actions workflow runs from this repository.

pkg/cli/utils/binary_downloader.go (4)

40-46: Past review issue addressed: HTTP timeout configured.

The HTTP client now includes a 5-minute timeout, which prevents indefinite hangs on slow or stalled connections. This addresses the past review comment.


127-152: Past review issue addressed: Close errors handled properly.

All defer Close() calls now explicitly handle errors using _ = to acknowledge and ignore them where appropriate:

  • Line 135: resp.Body.Close()
  • Line 145: out.Close()

This addresses the errcheck linting issues flagged in the previous review.


49-92: Well-designed binary retrieval with offline fallback.

The GetBinary method implements a robust retrieval strategy:

  • Resolves "latest" to an actual version tag
  • Checks cache before downloading
  • Falls back to latest cached version on download failure
  • Provides clear warnings when using cached fallback
  • Automatically cleans old binaries to prevent cache bloat
  • Proper cleanup of temporary directories

This design ensures both reliability and good UX for offline scenarios.


154-193: Clean ZIP extraction with platform-specific handling.

The extractBinary method correctly:

  • Handles platform-specific binary naming (adds .exe for Windows)
  • Searches for the expected binary in the ZIP archive
  • Preserves file permissions from the archive
  • Returns a clear error if the binary is not found

Copy link
Collaborator

@Cali0707 Cali0707 left a comment

Choose a reason for hiding this comment

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

@nader-ziada this looks good! Left one comment about where we are verifying the binaries

Also, would it be possible to output when running genmcp build ... which files are being downloaded? Possibly behind a -v flag?

I realize this may involve changing the CLI logging architecture a bit as we may need to propagate something through to the builder package...

@nader-ziada
Copy link
Contributor Author

thanks for the review @Cali0707, will work on these changes

- also add verbose output to build command

Signed-off-by: Nader Ziada <[email protected]>
Copy link
Contributor

@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

🧹 Nitpick comments (5)
pkg/cli/utils/binary_downloader_test.go (1)

11-79: Consider refactoring to table-driven tests.

Both test functions share nearly identical structure (pipe setup, downloader creation, printf call, pipe teardown, output verification). This could be consolidated into a single table-driven test with verbose/silent as parameters, reducing duplication. However, the current approach is acceptable and readable.

pkg/builder/download_binary_provider.go (1)

31-49: Implementation is correct; consider nil-check for robustness.

The ExtractServerBinary method correctly orchestrates binary retrieval. One defensive improvement: if platform is nil, accessing platform.OS and platform.Architecture will panic.

 func (dp *DownloadBinaryProvider) ExtractServerBinary(platform *v1.Platform) ([]byte, fs.FileInfo, error) {
+	if platform == nil {
+		return nil, nil, fmt.Errorf("platform cannot be nil")
+	}
+
 	binaryPath, err := dp.downloader.GetBinary(dp.version, platform.OS, platform.Architecture)
pkg/cli/utils/binary_downloader.go (1)

230-241: Defers accumulate in loop iterations.

The defer statements for rc.Close() and dest.Close() on lines 234 and 241 are inside a loop. While this works correctly here because the function returns immediately after finding a match, it's generally better practice to use explicit close or wrap in a helper function for clarity.

Since the function returns on the first match (line 247), the current behavior is correct. However, if the loop logic changes in the future, this could cause resource leaks. Consider extracting the file extraction logic into a helper function for clearer resource management.

pkg/cli/utils/binary_cache.go (2)

62-83: Consider handling saveIndex errors when pruning invalid entries in Get

When cache entries are invalid (missing file or checksum mismatch), Get deletes them from bc.entries but ignores any error from bc.saveIndex(). If the index write fails, the on-disk index can still contain the bad entry, which may get reloaded in a new process and cause repeated verification failures.

If feasible, consider at least surfacing/logging the saveIndex error, or having a best-effort mechanism so repeated bad entries don’t persist across runs. This is not a blocker but would make cache corruption more self-healing.


1-256: Confirm CHANGELOG entry for this user-visible caching behavior

This cache is part of a larger change that alters how genmcp build locates and reuses server binaries (download-and-cache vs embedded). That’s clearly user-visible behavior for the CLI.

Per the repo guidelines, please ensure there is a corresponding entry in CHANGELOG.md describing the new binary download/caching behavior (and marking it as BREAKING if any existing workflows might be impacted). If you’ve already added it elsewhere in the PR, feel free to ignore this.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 208a5e6 and 54442f4.

📒 Files selected for processing (7)
  • pkg/builder/builder.go (1 hunks)
  • pkg/builder/download_binary_provider.go (1 hunks)
  • pkg/builder/download_binary_provider_test.go (1 hunks)
  • pkg/cli/build.go (4 hunks)
  • pkg/cli/utils/binary_cache.go (1 hunks)
  • pkg/cli/utils/binary_downloader.go (1 hunks)
  • pkg/cli/utils/binary_downloader_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/builder/download_binary_provider_test.go
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Check whether you are using the server-only logger (embedded in the MCPServer type, and accessed from invocation contexts with logging.BaseFromContext(ctx)) or the server and client logger. Ensure that any logs with sensitive info use the server-only logger

Files:

  • pkg/cli/utils/binary_downloader_test.go
  • pkg/builder/builder.go
  • pkg/cli/utils/binary_downloader.go
  • pkg/cli/utils/binary_cache.go
  • pkg/cli/build.go
  • pkg/builder/download_binary_provider.go

⚙️ CodeRabbit configuration file

**/*.go: Review Go code for:

  • Proper error handling
  • Resource cleanup (defer statements)
  • Potential race conditions
  • Performance implications

Files:

  • pkg/cli/utils/binary_downloader_test.go
  • pkg/builder/builder.go
  • pkg/cli/utils/binary_downloader.go
  • pkg/cli/utils/binary_cache.go
  • pkg/cli/build.go
  • pkg/builder/download_binary_provider.go
**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

Follow the table test convention used throughout the codebase when writing unit tests

Files:

  • pkg/cli/utils/binary_downloader_test.go
pkg/**/*.go

⚙️ CodeRabbit configuration file

pkg/**/*.go: This is library code that may affect users.

CHANGELOG requirement:

  • If this PR changes public APIs, server behavior, or user-visible functionality, verify that CHANGELOG.md has been updated
  • Breaking API changes must be marked with BREAKING prefix in CHANGELOG.md
  • Internal implementation changes with no user impact do not require CHANGELOG updates
  • If unclear whether the change is user-visible, ask the PR author to clarify
  • If CHANGELOG.md is not modified for a user-visible change, REQUEST that it be updated

Files:

  • pkg/cli/utils/binary_downloader_test.go
  • pkg/builder/builder.go
  • pkg/cli/utils/binary_downloader.go
  • pkg/cli/utils/binary_cache.go
  • pkg/cli/build.go
  • pkg/builder/download_binary_provider.go
🧬 Code graph analysis (4)
pkg/cli/utils/binary_downloader_test.go (1)
pkg/cli/utils/binary_downloader.go (1)
  • NewBinaryDownloader (30-49)
pkg/cli/utils/binary_cache.go (1)
pkg/cli/utils/cache_file.go (1)
  • GetCacheDir (9-23)
pkg/cli/build.go (2)
pkg/cli/root.go (1)
  • GetVersion (64-66)
pkg/builder/builder.go (1)
  • New (214-233)
pkg/builder/download_binary_provider.go (1)
pkg/cli/utils/binary_downloader.go (2)
  • BinaryDownloader (22-27)
  • NewBinaryDownloader (30-49)
⏰ 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: Unit Tests
  • GitHub Check: lint
🔇 Additional comments (7)
pkg/cli/build.go (3)

25-26: New CLI flags look good.

The --server-version and --verbose flags are well-documented with sensible defaults. The verbose flag defaulting to true provides good UX during binary downloads.


64-85: Version resolution logic is sound.

The logic correctly:

  • Uses "latest" for development builds
  • Matches CLI version for release builds
  • Allows explicit override via --server-version
  • Handles builder initialization errors appropriately

257-260: Verify CHANGELOG.md is updated for user-visible changes.

This PR introduces significant user-visible changes:

  • New --server-version and --verbose CLI flags
  • Changed build behavior (downloads binaries instead of using embedded ones)
  • Public API change: builder.New signature now includes version and verbose parameters and returns an error

As per coding guidelines for pkg/**/*.go, ensure CHANGELOG.md has been updated to document these changes. If CHANGELOG.md was modified, mark breaking API changes with a BREAKING prefix.

pkg/builder/builder.go (1)

213-233: Constructor changes are well-structured.

The updated New function:

  • Properly initializes the DownloadBinaryProvider with version and verbose settings
  • Correctly returns an error when provider creation fails
  • Maintains clean separation of concerns with dependency injection

The breaking API change (now returns error) is necessary to handle download/verification failures gracefully.

pkg/cli/utils/binary_downloader.go (2)

29-49: HTTP timeout and error handling look good.

The implementation correctly addresses previous review feedback:

  • HTTP client has a 5-minute timeout for binary downloads
  • All Close() calls use defer func() { _ = ... }() pattern to handle errors

74-82: Cached binary verification is properly implemented.

This addresses the previous review comment from Cali0707 requesting verification of cached binaries. The code now re-verifies cached binaries with verifyAndExtractZip and falls back to re-downloading if verification fails.

pkg/cli/utils/binary_cache.go (1)

211-228: Bug in GetLatestCached: pointer to range variable causes incorrect logic

The code takes the address of the range variable entry, which is reused across loop iterations in Go. This causes two problems:

  1. The comparison entry.DownloadedAt > latestEntry.DownloadedAt doesn't work as intended since both may reference the same memory location being updated.
  2. After the loop, latestEntry points to whatever value was assigned on the last iteration, not the entry with the latest DownloadedAt for the requested platform.

Fix by tracking the entry by value instead of pointer:

-func (bc *BinaryCache) GetLatestCached(platform string) (string, string) {
-	var latestEntry *BinaryCacheEntry
-
-	for _, entry := range bc.entries {
-		if entry.Platform == platform {
-			if latestEntry == nil || entry.DownloadedAt > latestEntry.DownloadedAt {
-				latestEntry = &entry
-			}
-		}
-	}
-
-	if latestEntry != nil {
-		return latestEntry.Version, latestEntry.ZipPath
-	}
-
-	return "", ""
-}
+func (bc *BinaryCache) GetLatestCached(platform string) (string, string) {
+	var latestEntry BinaryCacheEntry
+	found := false
+
+	for _, entry := range bc.entries {
+		if entry.Platform != platform {
+			continue
+		}
+		if !found || entry.DownloadedAt > latestEntry.DownloadedAt {
+			latestEntry = entry
+			found = true
+		}
+	}
+
+	if found {
+		return latestEntry.Version, latestEntry.ZipPath
+	}
+	return "", ""
+}

@nader-ziada
Copy link
Contributor Author

@Cali0707 add validation on getting file from cache and a verbose option for build

Copy link
Collaborator

@Cali0707 Cali0707 left a comment

Choose a reason for hiding this comment

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

LGTM, thanks @nader-ziada !

This is a great improvement to the build capabilities

@Cali0707 Cali0707 merged commit d5ad932 into genmcp:main Dec 4, 2025
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Download server binaries during genmcp build

2 participants