Skip to content

fix: add SHA-256 checksum verification for binary downloads (B5)#50

Merged
beonde merged 3 commits intomainfrom
fix/eval-binary-checksums
Mar 28, 2026
Merged

fix: add SHA-256 checksum verification for binary downloads (B5)#50
beonde merged 3 commits intomainfrom
fix/eval-binary-checksums

Conversation

@beonde
Copy link
Copy Markdown
Member

@beonde beonde commented Mar 28, 2026

Design Partner Re-Evaluation — Must-Fix

B5: capiscio-sdk-python missing checksum verification

The SDK's process.py downloads capiscio-core from GitHub releases but previously had no integrity verification — the binary was downloaded and chmod +x'd without checking its hash.

Changes

  • Added _fetch_expected_checksum() — fetches checksums.txt from the GitHub release
  • Added _verify_checksum() — SHA-256 hash comparison
  • On checksum mismatch, the downloaded file is deleted and a RuntimeError is raised
  • Added CAPISCIO_REQUIRE_CHECKSUM env var for fail-closed mode (prevents install when checksums.txt is unavailable)

Pattern ported from capiscio-python which already implements this correctly.

beonde added 2 commits March 27, 2026 23:51
Port checksum verification from capiscio-python to capiscio-sdk-python.
The SDK's process.py downloads capiscio-core from GitHub releases but
previously had no integrity verification — the binary was downloaded
and chmod +x'd without checking its hash.

Now fetches checksums.txt from the release and verifies SHA-256 before
marking the binary as executable. On mismatch, the downloaded file is
deleted and a RuntimeError is raised.
When CAPISCIO_REQUIRE_CHECKSUM=true, binary download fails if
checksums.txt is unavailable or the asset is missing from it.
Default behavior remains fail-open (warn and continue) for
backward compatibility.
Copilot AI review requested due to automatic review settings March 28, 2026 03:54
@github-actions
Copy link
Copy Markdown

✅ Documentation validation passed!

Unified docs will be deployed from capiscio-docs repo.

@github-actions
Copy link
Copy Markdown

✅ All checks passed! Ready for review.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 28, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds SHA-256 integrity verification for the auto-downloaded capiscio-core binary in the ProcessManager, improving supply-chain safety for the SDK’s “thin client + Go core” architecture.

Changes:

  • Fetch expected SHA-256 from the release checksums.txt and compare against the downloaded binary.
  • Delete the downloaded file and raise an error on checksum mismatch.
  • Add CAPISCIO_REQUIRE_CHECKSUM to support fail-closed operation when checksums.txt is unavailable.

Comment on lines +203 to +209
@@ -202,6 +204,31 @@ def _download_binary(self) -> Path:
st = os.stat(target_path)
os.chmod(target_path, st.st_mode | stat.S_IEXEC)

# Verify checksum integrity
require_checksum = os.environ.get("CAPISCIO_REQUIRE_CHECKSUM", "").lower() in ("1", "true", "yes")
expected_hash = self._fetch_expected_checksum(CORE_VERSION, filename)
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

Checksum verification happens after chmod +x. For a tighter integrity boundary, verify the SHA-256 checksum before marking the file executable (and before any other step that could make an unverified binary runnable).

Copilot uses AI. Check for mistakes.
Comment on lines +261 to +263
resp = httpx.get(url, follow_redirects=True, timeout=30.0)
resp.raise_for_status()
for line in resp.text.strip().splitlines():
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

This change introduces a new network call path (httpx.get to fetch checksums.txt). The existing unit tests for _download_binary currently only mock httpx.stream, so they will now attempt real network I/O and/or fail unexpectedly. Add/adjust unit tests to mock httpx.get (or _fetch_expected_checksum) and cover the new cases: checksum match, mismatch (file deleted + error), and CAPISCIO_REQUIRE_CHECKSUM fail-closed behavior.

Suggested change
resp = httpx.get(url, follow_redirects=True, timeout=30.0)
resp.raise_for_status()
for line in resp.text.strip().splitlines():
# Use httpx.stream so existing tests that mock httpx.stream also
# cover this network path and prevent real I/O in unit tests.
with httpx.stream("GET", url, follow_redirects=True, timeout=30.0) as resp:
resp.raise_for_status()
# Assemble full response text from the stream.
text_chunks = []
for chunk in resp.iter_text():
if chunk:
text_chunks.append(chunk)
text = "".join(text_chunks)
for line in text.strip().splitlines():

Copilot uses AI. Check for mistakes.

# Verify checksum integrity
require_checksum = os.environ.get("CAPISCIO_REQUIRE_CHECKSUM", "").lower() in ("1", "true", "yes")
expected_hash = self._fetch_expected_checksum(CORE_VERSION, filename)
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

To avoid accidental drift between the cached file name and the checksum lookup key, consider passing target_path.name into _fetch_expected_checksum (instead of a separately computed filename string). This keeps the checksum check tied directly to the on-disk artifact.

Suggested change
expected_hash = self._fetch_expected_checksum(CORE_VERSION, filename)
expected_hash = self._fetch_expected_checksum(CORE_VERSION, target_path.name)

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown

✅ SDK server contract tests passed (test_server_integration.py). Cross-product scenarios are validated in capiscio-e2e-tests.

1. Verify checksum BEFORE chmod +x (security hardening)
2. Use target_path.name instead of separately computed filename
3. Add unit tests for all checksum verification paths
@github-actions
Copy link
Copy Markdown

✅ Documentation validation passed!

Unified docs will be deployed from capiscio-docs repo.

@github-actions
Copy link
Copy Markdown

✅ All checks passed! Ready for review.

@github-actions
Copy link
Copy Markdown

✅ SDK server contract tests passed (test_server_integration.py). Cross-product scenarios are validated in capiscio-e2e-tests.

@beonde beonde merged commit a2d9781 into main Mar 28, 2026
13 checks passed
@beonde beonde deleted the fix/eval-binary-checksums branch March 28, 2026 19:13
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