Skip to content

feat(gong): verify SHA256 checksum of downloaded binary before installation#2001

Open
MusaMisto wants to merge 5 commits into
bruin-data:mainfrom
MusaMisto:feat/gong-checksum-verification
Open

feat(gong): verify SHA256 checksum of downloaded binary before installation#2001
MusaMisto wants to merge 5 commits into
bruin-data:mainfrom
MusaMisto:feat/gong-checksum-verification

Conversation

@MusaMisto

Copy link
Copy Markdown

What

Adds SHA256 checksum verification to the gong helper binary download flow.

Before: binary was downloaded and installed with no integrity check.
After: download binary → download checksums.txt → verify SHA256 → install only if valid.
On any failure the temp file is discarded and the final path is never written.

Changes

  • pkg/gong/checksum.go — three stdlib-only helpers: parseChecksumManifest,
    verifySHA256, isValidSHA256. No new dependencies — crypto/sha256 is already
    in the Go standard library.

  • pkg/gong/gong.go — wires verification into downloadGong between
    tmpFile.Close() and os.Chmod/os.Rename. This placement is deliberate:
    the file must be fully written before its hash can be read, and chmod/rename
    must never run on an unverified file. The existing defer os.Remove(tmpPath)
    handles cleanup on any failure path automatically — the final path is never
    created on a bad checksum.
    Adds baseURL/installDir as private zero-value fields rather than constructor
    parameters so the public API is completely unchanged; existing callers using
    &Checker{} see no behavior difference.

  • .goreleaser.yaml — adds checksum: name_template: "checksums.txt" / algorithm: sha256. The filename must match the hardcoded path in
    buildChecksumURL (/releases/{version}/checksums.txt) — making it explicit
    in the release config prevents any future divergence.

  • SECURITY.md — documents the new Binary Integrity behavior for users and
    maintainers. Supply-chain integrity policy belongs in SECURITY.md, not README
    or docs/, so it is independently linkable and not buried in installation steps.

Tests

  • 20 unit tests covering all helper functions and every error path (parse, verify,
    edge cases including uppercase hash, missing file, invalid expected value)
  • 4 integration-style tests using httptest.Server: valid checksum installs,
    wrong checksum blocks, missing entry blocks, server failure blocks.
    The "binary does not exist at final path" assertion in the failure cases is the
    key safety proof — it confirms os.Rename never ran.

Testing

  • go test ./pkg/gong/...: passed (32/32)
  • Full pkg/... suite: passed for all packages unrelated to pre-existing CGO
    build failures that reproduce identically on main (no C compiler on this
    Windows dev machine; race detector requires GCC)

@greptile-apps

greptile-apps Bot commented May 5, 2026

Copy link
Copy Markdown
Contributor
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
pkg/gong/gong.go:333
**Artifact name missing OS component may cause checksum lookup to always fail**

`artifactName` is built as `"gong_" + getArchName()` (e.g. `gong_amd64`), but the binary URL embeds the OS in the *path* (`releases/{version}/linux/gong_amd64`), not the filename. A single `checksums.txt` covering all platforms must distinguish linux/darwin/windows binaries of the same architecture. If the manifest uses `gong_linux_amd64` / `gong_darwin_amd64` (standard GoReleaser convention) or path-prefixed entries like `linux/gong_amd64`, then `parseChecksumManifest` will always return `"checksum entry not found for gong_amd64"` and every install will fail. Even if the current manifest uses bare `gong_amd64` entries, those entries are ambiguous when two platforms produce different binaries — `parseChecksumManifest` returns the first match regardless of the running OS, potentially accepting a hash intended for the wrong platform's binary.

### Issue 2 of 2
pkg/gong/gong.go:246-249
**No size cap on checksum manifest response**

`io.ReadAll` will buffer the entire response body without any size limit. A misbehaving or compromised server could return a very large body and exhaust memory. A modest cap (e.g. 1 MiB) is more than enough for a text checksum manifest.

```suggestion
	data, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20)) // 1 MiB cap
	if err != nil {
		return nil, fmt.Errorf("failed to read checksum file: %w", err)
	}
```

Reviews (1): Last reviewed commit: "feat(gong): verify SHA256 checksum of do..." | Re-trigger Greptile

Comment thread pkg/gong/gong.go Outdated
Comment thread pkg/gong/gong.go Outdated

@karakanb karakanb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can you please fix all the extra spaces in the code?

Comment thread pkg/gong/checksum.go Outdated
Comment thread pkg/gong/checksum.go Outdated
@MusaMisto MusaMisto force-pushed the feat/gong-checksum-verification branch 2 times, most recently from d7c4b61 to 5eafa72 Compare May 5, 2026 15:23
…lation

- Add checksum.go with parseChecksumManifest, verifySHA256, isValidSHA256
- Wire verification into downloadGong between write and chmod/rename
- Add baseURL/installDir test-hook fields on Checker (zero value = no behavior change)
- Add 20 unit tests and 4 httptest integration tests (32 total)
- Add checksum block to .goreleaser.yaml (name_template: checksums.txt, algorithm: sha256)
- Document Binary Integrity in SECURITY.md
@MusaMisto MusaMisto force-pushed the feat/gong-checksum-verification branch from 5eafa72 to 03e1daa Compare May 5, 2026 15:30
Musa Misto and others added 4 commits May 5, 2026 18:35
…test.go

Co-authored-by: Copilot <copilot@github.com>
…t.go, gong_install_test.go, and checksum_test.go

Co-authored-by: Copilot <copilot@github.com>
@MusaMisto MusaMisto requested a review from karakanb May 5, 2026 16:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants