ci: fix smoke lint blockers, add E2E prove-verify workflow, Groth16 ceremony scaffold#773
Conversation
📝 WalkthroughWalkthroughAdds an E2E GitHub Actions workflow (INSERT→PROVE→VERIFY), a CLI tool to contribute to a Groth16 ceremony with tests, small parquet_writer refinements, an Olympus commit workflow check for API config, and related test updates and additions. ChangesE2E Testing Pipeline
Ceremony Contribution Tool
Parquet Writer Change
Olympus API Configuration Check
E2E Test Skip Wiring
Sequence Diagram(s)sequenceDiagram
participant GH as GitHub Actions Runner
participant DB as PostgreSQL Service (postgres:16)
participant Py as Python environment / pytest
participant Rust as Maturin / Rust extension build
GH->>DB: Start postgres:16 service & healthcheck
GH->>Py: Setup Python 3.12, install deps
GH->>Rust: maturin build --release
Rust-->>GH: wheel artifact
GH->>Py: Install wheel
Py->>Py: Run INSERT tests (pytest)
Py->>Py: Run PROVE tests (pytest)
Py->>Py: Run VERIFY tests (pytest)
Py-->>GH: Emit JUnit XML into test-results/
GH->>GH: Upload test-results/ artifact
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
…scaffold, annotate olympus-commit.yml Agent-Logs-Url: https://github.com/OlympusLedgerOrg/Olympus/sessions/03549d8a-92ee-45a1-af52-3d82a11db6af Co-authored-by: OlympusLedgerOrg <240737312+OlympusLedgerOrg@users.noreply.github.com>
…orkflow Agent-Logs-Url: https://github.com/OlympusLedgerOrg/Olympus/sessions/03549d8a-92ee-45a1-af52-3d82a11db6af Co-authored-by: OlympusLedgerOrg <240737312+OlympusLedgerOrg@users.noreply.github.com>
Agent-Logs-Url: https://github.com/OlympusLedgerOrg/Olympus/sessions/03549d8a-92ee-45a1-af52-3d82a11db6af Co-authored-by: OlympusLedgerOrg <240737312+OlympusLedgerOrg@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 10
🧹 Nitpick comments (1)
.github/workflows/e2e-prove-verify.yml (1)
20-22: ⚡ Quick winAdd a job timeout to prevent runaway E2E runs.
Set
timeout-minuteson the job so hangs don’t consume runner time for hours.⏱️ Suggested change
e2e-prove-verify: name: "insert → prove → verify (Postgres)" runs-on: ubuntu-latest + timeout-minutes: 45🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/e2e-prove-verify.yml around lines 20 - 22, The e2e-prove-verify job lacks a timeout and can hang indefinitely; add a timeout-minutes field to the job definition (the job named e2e-prove-verify / "insert → prove → verify (Postgres)") to limit run duration (e.g., timeout-minutes: 30) so the GitHub Actions runner will cancel long-running E2E runs; place the timeout-minutes key at the same indentation level as runs-on within that job block.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/e2e-prove-verify.yml:
- Line 51: Replace mutable action tags with pinned full commit SHAs for
third-party actions used in the workflow: change usages of actions/checkout,
actions/setup-python, and actions/upload-artifact (currently referenced with
tags like `@v4/`@vX) to their corresponding full-length commit SHAs; update each
step that references those action names so the action source is immutable (use
the commit SHA from the action's repository release/commit) and verify the SHAs
before committing.
In @.github/workflows/olympus-commit.yml:
- Around line 43-58: The api-check step incorrectly treats the API as
unconfigured only when both OLYMPUS_API_URL and OLYMPUS_API_KEY are empty;
change the condition in the api-check run block to mark configured=false when
either OLYMPUS_API_URL or OLYMPUS_API_KEY is missing (i.e., use a logical OR
test instead of AND), so the "Commit artifacts to Olympus" step (id: olympus,
if: steps.api-check.outputs.configured) is skipped when any required env var is
absent.
In `@protocol/parquet_writer.py`:
- Line 185: Replace the TypeError raised for unsupported inputs with a
ValueError: change the raise TypeError(...) that checks the parameter named data
to raise ValueError(...) instead, keeping the exact descriptive message (f"data
must be a pyarrow.Table or list[dict], got {type(data).__name__}") so callers
receive a ValueError for invalid input types.
In `@tests/test_ceremony_contribute.py`:
- Line 101: The helper function fake_run lacks type annotations; update its
signature for clarity and linting by annotating parameters and return type
(e.g., def fake_run(cmd: Sequence[str] | str, **kwargs: Any) ->
subprocess.CompletedProcess or -> Any) and add the necessary imports from typing
(Sequence, Any) and subprocess (CompletedProcess) or use a generic Any return if
mocking different shapes; ensure you update the fake_run declaration and imports
so the function parameters cmd and **kwargs and its return are fully typed.
- Around line 45-46: The test assertion in tests/test_ceremony_contribute.py
fails due to a case-sensitive regex: update the pytest.raises match to expect
the exact production error text (e.g., "Circuit not found" or include the full
pattern "Circuit not found:") or make the regex case-insensitive; locate the
test around the contrib call to contribute(...) and change the match from
"circuit" to a pattern that matches the actual FileNotFoundError message
produced by contribute (which uses "Circuit not found: {circuit_path}").
In `@tools/ceremony_contribute.py`:
- Around line 174-175: Add a clear docstring to the public function main()
describing its purpose (initializes logging and runs the CLI/entry logic), any
parameters (none) and what it returns (int exit code), and mention side effects
(configures logging). Place the docstring as the first statement in the main()
function (triple-quoted, following PEP 257) and include a short summary line, a
blank line, and an "Returns" section that specifies the integer exit code.
- Around line 111-143: Wrap the workflow that creates and uses initial_zkey in a
try/finally so the intermediate file is removed even on error: after assigning
initial_zkey and performing the subprocess.run calls (the snarkjs groth16 setup
and snarkjs zkey contribute invocations which produce setup_result and
contribute_result), move the subsequent error checks and contribution step into
the try block and in the finally block attempt to unlink/delete initial_zkey
(catching and logging any failure as a warning) so the DONOTCOMMIT zkey is
cleaned up by default while still surfacing original errors from
setup_result/contribute_result.
- Around line 114-118: Add a timeout to the long-running snarkjs subprocess
invocations: pass a timeout parameter to the subprocess.run call that creates
setup_result (the "npx snarkjs groth16 setup" call) and to the corresponding
"npx snarkjs zkey contribute" subprocess (e.g., contribute_result). Prefer
defining a single SNARKJS_TIMEOUT constant (e.g., 600 seconds) or reuse the
existing timeout pattern used for the version check, pass
timeout=SNARKJS_TIMEOUT to both subprocess.run calls, and add a try/except to
catch subprocess.TimeoutExpired around those runs to log the timeout and
exit/raise appropriately.
- Around line 151-159: Replace the non-canonical timestamp and JSON write: set
the metadata "timestamp" using protocol.timestamps.current_timestamp() instead
of datetime.now(...).isoformat(), and write the metadata JSON canonically by
serializing with json.dumps(metadata, sort_keys=True, separators=(",", ":"),
ensure_ascii=True) and writing it as UTF-8 (e.g., write bytes or open the file
with encoding="utf-8") instead of meta_path.write_text(json.dumps(metadata,
indent=2)); update the code around the metadata dict creation and the meta_path
write call (look for the metadata variable and meta_path.write_text usage in
ceremony_contribute.py).
- Around line 22-41: The _sha256_file function and its import should be replaced
to use the project's BLAKE3 helpers: remove the hashlib import and call into
protocol.hashes; inside _sha256_file (the function that reads the file in
chunks) accumulate file bytes (or read whole file) and pass them to
protocol.hashes.hash_bytes() (or directly use protocol.hashes.hash_hex() to
return a hex string) instead of hashlib.sha256(); ensure the function returns
the hex digest produced by protocol.hashes.hash_hex() (or by encoding the result
of hash_bytes()), and update imports to include protocol.hashes functions.
---
Nitpick comments:
In @.github/workflows/e2e-prove-verify.yml:
- Around line 20-22: The e2e-prove-verify job lacks a timeout and can hang
indefinitely; add a timeout-minutes field to the job definition (the job named
e2e-prove-verify / "insert → prove → verify (Postgres)") to limit run duration
(e.g., timeout-minutes: 30) so the GitHub Actions runner will cancel
long-running E2E runs; place the timeout-minutes key at the same indentation
level as runs-on within that job block.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: bfe0ccdb-b925-4e53-825e-e17682ce879a
📒 Files selected for processing (6)
.github/workflows/e2e-prove-verify.yml.github/workflows/olympus-commit.ymlprotocol/parquet_writer.pytests/test_ceremony_contribute.pytests/test_parquet_writer.pytools/ceremony_contribute.py
| - 5432:5432 | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
`What are the current full commit SHAs for:
- actions/checkout major version v4
- actions/setup-python major version v6
- actions/upload-artifact major version v4
that GitHub recommends pinning in workflow files?`
💡 Result:
I can’t reliably provide the “current full commit SHAs” that GitHub recommends pinning for these tag-major versions (actions/checkout@v4, actions/setup-python@v6, actions/upload-artifact@v4) with the sources I retrieved. The authoritative way to answer this is to resolve each floating major tag to its exact commit SHA at the present time (e.g., via git ls-remote --tags https://github.com/actions/checkout refs/tags/v4, and similarly for setup-python v6 and upload-artifact v4), but my web results did not include those specific SHA mappings. What I can cite from the sources is: (1) pinning to full-length commit SHAs is the recommended immutable-release approach, and (2) the way to look up the underlying SHA for a tag is to query the action repository/tag and use the referenced commit. If you want, tell me whether you’re OK with using an automated lookup command in your environment (recommended), or whether you need me to re-run the research until I can find sources that explicitly list the exact SHA for v4/v6/v4 today.
Citations:
- 1: https://stackoverflow.com/questions/78903499/how-do-i-pin-an-action-to-a-specific-sha
- 2: Pin GitHub Actions to commit SHAs esphome/home-assistant-voice-pe#572
- 3: Pin all GitHub Actions to immutable SHA commits for supply chain security github/gh-aw#5691
🏁 Script executed:
# Check file existence and content at specified lines
ls -la .github/workflows/e2e-prove-verify.yml
if [ -f .github/workflows/e2e-prove-verify.yml ]; then
echo "=== Line 51 ==="
sed -n '51p' .github/workflows/e2e-prove-verify.yml
echo "=== Line 54 ==="
sed -n '54p' .github/workflows/e2e-prove-verify.yml
echo "=== Line 103 ==="
sed -n '103p' .github/workflows/e2e-prove-verify.yml
echo "=== Full context around lines 45-60 ==="
sed -n '45,60p' .github/workflows/e2e-prove-verify.yml
fiRepository: OlympusLedgerOrg/Olympus
Length of output: 765
🌐 Web query:
GitHub official guidance on pinning GitHub Actions to commit SHAs vs major version tags security best practices 2025 2026
💡 Result:
GitHub official best practice (2025-2026) is to pin third-party GitHub Actions to a full-length commit SHA (immutable reference) rather than using major version tags, because tags can be moved and pinning to a commit SHA mitigates the risk of malicious changes being picked up automatically. 1) Pin to commit SHA vs major version tags: what GitHub says - GitHub Docs Security hardening guidance: “Pinning an action to a full-length commit SHA is currently the only way to use an action as an immutable release… Pinning to a particular SHA helps mitigate the risk of a bad actor adding a backdoor… When selecting a SHA, you should verify it is from the action’s repository and not a repository fork.” It also notes tags are more convenient but still risky because “a tag can be moved or deleted if a bad actor gains access.” 2) How “major version tags” fit into GitHub’s guidance - GitHub’s docs on action releases and tags explain that major/minor/patch version tags are pointers that can be updated by publishers (and that tags can be force-pushed). This means that “v1”/“v2” major tags are not inherently immutable, so they don’t provide the same immutability guarantee GitHub’s security guidance is targeting. 3) Enforcing SHA pinning (governance controls) in 2025-2026 - GitHub’s Enterprise/Org policy capabilities include enforcing “Require actions to be pinned to a full-length commit SHA”; this “includes actions authored by GitHub” and “reusable workflows can still be referenced by tag,” and the enforcement checks for a full commit SHA. - GitHub’s changelog (Aug 15, 2025) also states GitHub recommends pinning dependency versions to “a specific commit SHA” and that administrators can enforce SHA pinning via the allowed actions policy; workflows that attempt to use an action “that isn’t pinned will fail.” 4) Recommended practice for maintaining updates - GitHub’s guidance recommends pinned SHAs and describes using GitHub policies to require pinning. - For operational updates, GitHub Dependabot/GitHub tooling exists (and GitHub documentation elsewhere notes Dependabot security/alerts behavior differs based on whether an action is pinned to SHA). The practical pattern is: pin to a SHA for security, then use automation to open PRs when new versions are released. 5) Concrete “security best practice” summary (what you should do) - For each third-party (and ideally first-party) action used in workflow “uses:”: a) Prefer: actions/OWNER/REPO@<40-char commit SHA> (and optionally keep a comment mapping to the version tag). b) Avoid: actions/OWNER/REPO@v1 or @v2 (major version tags) as your primary security control. c) Verify the commit SHA belongs to the action’s official repository (not a fork). - At org/enterprise level, enable the policy that requires full commit SHA pinning so workflows fail closed when tags are used. Sources used (official GitHub documentation and GitHub announcements): - GitHub Docs: “Security hardening for GitHub Actions” (Secure use reference; pin to full-length commit SHA; tags risks) - GitHub Docs: “Using immutable releases and tags to manage your action’s releases” (how tags/force-push can move pointers) - GitHub Enterprise/Org docs: “Enforcing policies for GitHub Actions in your enterprise” (Require actions pinned to full-length commit SHA) - GitHub Changelog: “GitHub Actions policy now supports blocking and SHA pinning actions” (Aug 2025 enforcement + rationale)
Citations:
- 1: https://docs.github.com/en/actions/how-tos/security-for-github-actions/security-guides/security-hardening-for-github-actions
- 2: https://docs.github.com/actions/how-tos/create-and-publish-actions/using-immutable-releases-and-tags-to-manage-your-actions-releases
- 3: https://docs.github.com/en/enterprise-cloud@latest/admin/enforcing-policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-github-actions-in-your-enterprise
- 4: https://github.blog/changelog/2025-08-15-github-actions-policy-now-supports-blocking-and-sha-pinning-actions/
Pin third-party GitHub Actions to commit SHAs.
Using mutable tags (@v4, @v6) for actions/checkout, actions/setup-python, and actions/upload-artifact weakens supply-chain guarantees. Tags can be moved or force-pushed by maintainers or attackers. Pin to full-length commit SHAs to ensure immutability and mitigate the risk of malicious changes.
Example hardening
- - uses: actions/checkout@v4
+ - uses: actions/checkout@a5ac7e51b41094c7423c3a615bcc5b6c1658eaf5
- uses: actions/setup-python@v6
+ uses: actions/setup-python@82c7e631bb3cdc910f68e98d91b3e76923ad8be4
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f314592📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - uses: actions/checkout@v4 | |
| - uses: actions/checkout@a5ac7e51b41094c7423c3a615bcc5b6c1658eaf5 |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/e2e-prove-verify.yml at line 51, Replace mutable action
tags with pinned full commit SHAs for third-party actions used in the workflow:
change usages of actions/checkout, actions/setup-python, and
actions/upload-artifact (currently referenced with tags like `@v4/`@vX) to their
corresponding full-length commit SHAs; update each step that references those
action names so the action source is immutable (use the commit SHA from the
action's repository release/commit) and verify the SHAs before committing.
| - name: Check Olympus API is configured | ||
| id: api-check | ||
| run: | | ||
| if [ -z "${OLYMPUS_API_URL:-}" ] && [ -z "${OLYMPUS_API_KEY:-}" ]; then | ||
| echo "configured=false" >> "$GITHUB_OUTPUT" | ||
| echo "::notice::Olympus API not configured — skipping artifact anchoring" | ||
| else | ||
| echo "configured=true" >> "$GITHUB_OUTPUT" | ||
| fi | ||
| env: | ||
| OLYMPUS_API_URL: ${{ vars.OLYMPUS_API_URL }} | ||
| OLYMPUS_API_KEY: ${{ secrets.OLYMPUS_API_KEY }} | ||
|
|
||
| - name: Commit artifacts to Olympus | ||
| id: olympus | ||
| if: steps.api-check.outputs.configured == 'true' |
There was a problem hiding this comment.
Fix partial-config detection in API check.
At Line 46, && only marks unconfigured when both values are missing. If either OLYMPUS_API_URL or OLYMPUS_API_KEY is missing, Line 58 still allows the commit step to run and fail noisily instead of skipping cleanly.
Suggested fix
- if [ -z "${OLYMPUS_API_URL:-}" ] && [ -z "${OLYMPUS_API_KEY:-}" ]; then
+ if [ -z "${OLYMPUS_API_URL:-}" ] || [ -z "${OLYMPUS_API_KEY:-}" ]; then
echo "configured=false" >> "$GITHUB_OUTPUT"
- echo "::notice::Olympus API not configured — skipping artifact anchoring"
+ echo "::notice::Olympus API config incomplete — skipping artifact anchoring"
else
echo "configured=true" >> "$GITHUB_OUTPUT"
fi📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - name: Check Olympus API is configured | |
| id: api-check | |
| run: | | |
| if [ -z "${OLYMPUS_API_URL:-}" ] && [ -z "${OLYMPUS_API_KEY:-}" ]; then | |
| echo "configured=false" >> "$GITHUB_OUTPUT" | |
| echo "::notice::Olympus API not configured — skipping artifact anchoring" | |
| else | |
| echo "configured=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| env: | |
| OLYMPUS_API_URL: ${{ vars.OLYMPUS_API_URL }} | |
| OLYMPUS_API_KEY: ${{ secrets.OLYMPUS_API_KEY }} | |
| - name: Commit artifacts to Olympus | |
| id: olympus | |
| if: steps.api-check.outputs.configured == 'true' | |
| - name: Check Olympus API is configured | |
| id: api-check | |
| run: | | |
| if [ -z "${OLYMPUS_API_URL:-}" ] || [ -z "${OLYMPUS_API_KEY:-}" ]; then | |
| echo "configured=false" >> "$GITHUB_OUTPUT" | |
| echo "::notice::Olympus API config incomplete — skipping artifact anchoring" | |
| else | |
| echo "configured=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| env: | |
| OLYMPUS_API_URL: ${{ vars.OLYMPUS_API_URL }} | |
| OLYMPUS_API_KEY: ${{ secrets.OLYMPUS_API_KEY }} | |
| - name: Commit artifacts to Olympus | |
| id: olympus | |
| if: steps.api-check.outputs.configured == 'true' |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/olympus-commit.yml around lines 43 - 58, The api-check
step incorrectly treats the API as unconfigured only when both OLYMPUS_API_URL
and OLYMPUS_API_KEY are empty; change the condition in the api-check run block
to mark configured=false when either OLYMPUS_API_URL or OLYMPUS_API_KEY is
missing (i.e., use a logical OR test instead of AND), so the "Commit artifacts
to Olympus" step (id: olympus, if: steps.api-check.outputs.configured) is
skipped when any required env var is absent.
| raise TypeError( | ||
| f"data must be a pyarrow.Table or list[dict], got {type(data).__name__}" | ||
| ) | ||
| raise TypeError(f"data must be a pyarrow.Table or list[dict], got {type(data).__name__}") |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win
Use ValueError for unsupported data inputs.
This branch is rejecting caller input, so using ValueError keeps the API consistent with the repo’s Python error-handling convention.
Suggested fix
- raise TypeError(f"data must be a pyarrow.Table or list[dict], got {type(data).__name__}")
+ raise ValueError(f"data must be a pyarrow.Table or list[dict], got {type(data).__name__}")As per coding guidelines, "Raise ValueError for invalid inputs with descriptive messages in Python error handling".
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| raise TypeError(f"data must be a pyarrow.Table or list[dict], got {type(data).__name__}") | |
| raise ValueError(f"data must be a pyarrow.Table or list[dict], got {type(data).__name__}") |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@protocol/parquet_writer.py` at line 185, Replace the TypeError raised for
unsupported inputs with a ValueError: change the raise TypeError(...) that
checks the parameter named data to raise ValueError(...) instead, keeping the
exact descriptive message (f"data must be a pyarrow.Table or list[dict], got
{type(data).__name__}") so callers receive a ValueError for invalid input types.
| with pytest.raises(FileNotFoundError, match="circuit"): | ||
| contribute( |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "test_ceremony_contribute.py" -type fRepository: OlympusLedgerOrg/Olympus
Length of output: 104
🏁 Script executed:
find . -name "*ceremony*" -type f | grep -E "\.(py)$"Repository: OlympusLedgerOrg/Olympus
Length of output: 222
🏁 Script executed:
fd -type f "ceremony" | grep -E "\.py$"Repository: OlympusLedgerOrg/Olympus
Length of output: 239
🏁 Script executed:
cat -n tests/test_ceremony_contribute.py | sed -n '40,55p'Repository: OlympusLedgerOrg/Olympus
Length of output: 734
🏁 Script executed:
rg "FileNotFoundError|Circuit" tests/test_ceremony_contribute.py -A 2 -B 2Repository: OlympusLedgerOrg/Olympus
Length of output: 828
🏁 Script executed:
rg "Circuit not found|circuit" ceremony/ tools/ -A 2 -B 2Repository: OlympusLedgerOrg/Olympus
Length of output: 15018
Fix case-sensitive regex mismatch in test assertion
Line 45 uses match="circuit" but the production code raises FileNotFoundError(f"Circuit not found: {circuit_path}") with a capital "C". The regex pattern is case-sensitive and will not match the error message, causing the test to fail unexpectedly.
Suggested patch
- with pytest.raises(FileNotFoundError, match="circuit"):
+ with pytest.raises(FileNotFoundError, match="Circuit"):📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| with pytest.raises(FileNotFoundError, match="circuit"): | |
| contribute( | |
| with pytest.raises(FileNotFoundError, match="Circuit"): | |
| contribute( |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/test_ceremony_contribute.py` around lines 45 - 46, The test assertion
in tests/test_ceremony_contribute.py fails due to a case-sensitive regex: update
the pytest.raises match to expect the exact production error text (e.g.,
"Circuit not found" or include the full pattern "Circuit not found:") or make
the regex case-insensitive; locate the test around the contrib call to
contribute(...) and change the match from "circuit" to a pattern that matches
the actual FileNotFoundError message produced by contribute (which uses "Circuit
not found: {circuit_path}").
| r1cs.write_bytes(b"fake r1cs") | ||
| output = tmp_path / "contributions" / "test.zkey" | ||
|
|
||
| def fake_run(cmd, **kwargs): |
There was a problem hiding this comment.
Add type hints to fake_run
Line 101 defines fake_run without parameter/return type annotations.
Suggested patch
+from typing import Any
@@
- def fake_run(cmd, **kwargs):
+ def fake_run(cmd: list[str], **kwargs: Any) -> MagicMock:As per coding guidelines, "**/*.py: Always use type hints for function parameters and return values in Python".
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def fake_run(cmd, **kwargs): | |
| def fake_run(cmd: list[str], **kwargs: Any) -> MagicMock: |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/test_ceremony_contribute.py` at line 101, The helper function fake_run
lacks type annotations; update its signature for clarity and linting by
annotating parameters and return type (e.g., def fake_run(cmd: Sequence[str] |
str, **kwargs: Any) -> subprocess.CompletedProcess or -> Any) and add the
necessary imports from typing (Sequence, Any) and subprocess (CompletedProcess)
or use a generic Any return if mocking different shapes; ensure you update the
fake_run declaration and imports so the function parameters cmd and **kwargs and
its return are fully typed.
| import hashlib | ||
| import json | ||
| import logging | ||
| import secrets | ||
| import subprocess | ||
| import sys | ||
| from datetime import datetime, timezone | ||
| from pathlib import Path | ||
|
|
||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| def _sha256_file(path: Path) -> str: | ||
| """Compute SHA-256 of a file. Used to verify ceremony artifacts.""" | ||
| h = hashlib.sha256() | ||
| with path.open("rb") as fh: | ||
| while chunk := fh.read(1 << 20): | ||
| h.update(chunk) | ||
| return h.hexdigest() |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -type f -name "*.py" | grep -E "(ceremony|hashes)" | head -20Repository: OlympusLedgerOrg/Olympus
Length of output: 470
🏁 Script executed:
git ls-files | grep -E "(tools|protocol)" | head -30Repository: OlympusLedgerOrg/Olympus
Length of output: 958
🏁 Script executed:
wc -l ./tools/ceremony_contribute.pyRepository: OlympusLedgerOrg/Olympus
Length of output: 103
🏁 Script executed:
cat -n ./tools/ceremony_contribute.py | head -50Repository: OlympusLedgerOrg/Olympus
Length of output: 1708
🏁 Script executed:
cat -n ./protocol/hashes.pyRepository: OlympusLedgerOrg/Olympus
Length of output: 26302
🏁 Script executed:
grep -n "_sha256_file" ./tools/ceremony_contribute.pyRepository: OlympusLedgerOrg/Olympus
Length of output: 212
🏁 Script executed:
grep -rn "_sha256_file" . --include="*.py" | head -20Repository: OlympusLedgerOrg/Olympus
Length of output: 924
🏁 Script executed:
cat -n ./tools/ceremony_contribute.py | sed -n '44,120p'Repository: OlympusLedgerOrg/Olympus
Length of output: 3521
🏁 Script executed:
cat -n ./tools/ceremony_contribute.py | sed -n '120,160p'Repository: OlympusLedgerOrg/Olympus
Length of output: 1630
🏁 Script executed:
cat -n ./tools/ceremony_contribute.py | sed -n '140,170p'Repository: OlympusLedgerOrg/Olympus
Length of output: 1455
🏁 Script executed:
cat -n ./tests/test_ceremony_contribute.py | sed -n '135,160p'Repository: OlympusLedgerOrg/Olympus
Length of output: 1153
🏁 Script executed:
cat -n ./tools/ceremony_contribute.py | head -30Repository: OlympusLedgerOrg/Olympus
Length of output: 1052
🏁 Script executed:
grep -rn "BLAKE3\|blake3\|protocol.hashes" ./tools/ --include="*.py"Repository: OlympusLedgerOrg/Olympus
Length of output: 3044
🏁 Script executed:
cat -n ./protocol/__init__.pyRepository: OlympusLedgerOrg/Olympus
Length of output: 2487
🏁 Script executed:
cat -n ./tools/ceremony_contribute.py | sed -n '170,180p'Repository: OlympusLedgerOrg/Olympus
Length of output: 418
🏁 Script executed:
grep -n "def main" ./tools/ceremony_contribute.pyRepository: OlympusLedgerOrg/Olympus
Length of output: 91
Replace direct hashlib.sha256() with BLAKE3 from protocol.hashes
Lines 22 and 35–41 use hashlib.sha256() directly to hash ceremony artifacts, violating the project hash policy. Use protocol.hashes.hash_bytes() instead and remove the import hashlib statement.
Per coding guidelines: "**/*.py: Always use BLAKE3 via the hashes.py module for hash functions; use hash_bytes() for raw bytes, hash_string() for UTF-8 strings, and hash_hex() for hex-encoded output".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tools/ceremony_contribute.py` around lines 22 - 41, The _sha256_file function
and its import should be replaced to use the project's BLAKE3 helpers: remove
the hashlib import and call into protocol.hashes; inside _sha256_file (the
function that reads the file in chunks) accumulate file bytes (or read whole
file) and pass them to protocol.hashes.hash_bytes() (or directly use
protocol.hashes.hash_hex() to return a hex string) instead of hashlib.sha256();
ensure the function returns the hex digest produced by
protocol.hashes.hash_hex() (or by encoding the result of hash_bytes()), and
update imports to include protocol.hashes functions.
| initial_zkey = output_path.parent / "initial_DONOTCOMMIT.zkey" | ||
|
|
||
| # Step 1: Generate initial phase 2 key | ||
| setup_result = subprocess.run( | ||
| ["npx", "snarkjs", "groth16", "setup", str(r1cs_path), str(ptau_path), str(initial_zkey)], | ||
| capture_output=True, | ||
| text=True, | ||
| ) | ||
| if setup_result.returncode != 0: | ||
| raise RuntimeError( | ||
| f"snarkjs groth16 setup failed (exit {setup_result.returncode}):\n{setup_result.stderr}" | ||
| ) | ||
|
|
||
| # Step 2: Contribute | ||
| contribute_result = subprocess.run( | ||
| [ | ||
| "npx", | ||
| "snarkjs", | ||
| "zkey", | ||
| "contribute", | ||
| str(initial_zkey), | ||
| str(output_path), | ||
| f"--name={participant_name}", | ||
| f"-e={contribution_entropy}", | ||
| ], | ||
| capture_output=True, | ||
| text=True, | ||
| ) | ||
| if contribute_result.returncode != 0: | ||
| raise RuntimeError( | ||
| f"snarkjs zkey contribute failed (exit {contribute_result.returncode}):\n" | ||
| f"{contribute_result.stderr}" | ||
| ) |
There was a problem hiding this comment.
Best-effort cleanup for intermediate toxic-waste file should be automatic
initial_DONOTCOMMIT.zkey is created on Line 111, but failures after setup can leave it on disk. Add try/finally cleanup (with warning fallback) so sensitive intermediate artifacts are not retained by default.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tools/ceremony_contribute.py` around lines 111 - 143, Wrap the workflow that
creates and uses initial_zkey in a try/finally so the intermediate file is
removed even on error: after assigning initial_zkey and performing the
subprocess.run calls (the snarkjs groth16 setup and snarkjs zkey contribute
invocations which produce setup_result and contribute_result), move the
subsequent error checks and contribution step into the try block and in the
finally block attempt to unlink/delete initial_zkey (catching and logging any
failure as a warning) so the DONOTCOMMIT zkey is cleaned up by default while
still surfacing original errors from setup_result/contribute_result.
| setup_result = subprocess.run( | ||
| ["npx", "snarkjs", "groth16", "setup", str(r1cs_path), str(ptau_path), str(initial_zkey)], | ||
| capture_output=True, | ||
| text=True, | ||
| ) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, find the file and check if it exists
fd -t f "ceremony_contribute.py"Repository: OlympusLedgerOrg/Olympus
Length of output: 131
🏁 Script executed:
# Examine the file around the mentioned lines (114-118 and 125-138)
wc -l tools/ceremony_contribute.pyRepository: OlympusLedgerOrg/Olympus
Length of output: 101
🏁 Script executed:
# Read the specific sections mentioned in the review
sed -n '110,140p' tools/ceremony_contribute.pyRepository: OlympusLedgerOrg/Olympus
Length of output: 1074
🏁 Script executed:
# Search for all subprocess.run calls in the file to check for timeout patterns
rg "subprocess\.run" tools/ceremony_contribute.py -A 5Repository: OlympusLedgerOrg/Olympus
Length of output: 605
🏁 Script executed:
# Check if there are any existing timeout patterns in similar Python files
rg "timeout=" tools/ -A 2 -B 2Repository: OlympusLedgerOrg/Olympus
Length of output: 1510
Add timeouts to long-running snarkjs subprocess calls to prevent indefinite hangs
The subprocess.run() calls at lines 114 and 125 for snarkjs groth16 setup and snarkjs zkey contribute lack timeout controls. If snarkjs hangs, CI/jobs will block indefinitely. The same file already uses timeout=10 for the version check; long-running cryptographic operations should have comparable timeout protection.
Suggested patch
setup_result = subprocess.run(
["npx", "snarkjs", "groth16", "setup", str(r1cs_path), str(ptau_path), str(initial_zkey)],
capture_output=True,
text=True,
+ timeout=600,
)
@@
contribute_result = subprocess.run(
[
"npx",
"snarkjs",
"zkey",
"contribute",
str(initial_zkey),
str(output_path),
f"--name={participant_name}",
f"-e={contribution_entropy}",
],
capture_output=True,
text=True,
+ timeout=600,
)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tools/ceremony_contribute.py` around lines 114 - 118, Add a timeout to the
long-running snarkjs subprocess invocations: pass a timeout parameter to the
subprocess.run call that creates setup_result (the "npx snarkjs groth16 setup"
call) and to the corresponding "npx snarkjs zkey contribute" subprocess (e.g.,
contribute_result). Prefer defining a single SNARKJS_TIMEOUT constant (e.g., 600
seconds) or reuse the existing timeout pattern used for the version check, pass
timeout=SNARKJS_TIMEOUT to both subprocess.run calls, and add a try/except to
catch subprocess.TimeoutExpired around those runs to log the timeout and
exit/raise appropriately.
| "timestamp": datetime.now(timezone.utc).isoformat(), | ||
| "contribution_hash": contribution_hash, | ||
| "circuit_hash": circuit_hash, | ||
| "output_path": str(output_path), | ||
| } | ||
|
|
||
| # Write metadata alongside the zkey | ||
| meta_path = output_path.with_suffix(".json") | ||
| meta_path.write_text(json.dumps(metadata, indent=2)) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "ceremony_contribute.py" -type fRepository: OlympusLedgerOrg/Olympus
Length of output: 99
🏁 Script executed:
if [ -f "tools/ceremony_contribute.py" ]; then
wc -l tools/ceremony_contribute.py
fiRepository: OlympusLedgerOrg/Olympus
Length of output: 101
🏁 Script executed:
if [ -f "tools/ceremony_contribute.py" ]; then
sed -n '140,165p' tools/ceremony_contribute.py
fiRepository: OlympusLedgerOrg/Olympus
Length of output: 1065
🏁 Script executed:
find . -path "*protocol/timestamps*" -type fRepository: OlympusLedgerOrg/Olympus
Length of output: 93
🏁 Script executed:
if [ -f "protocol/timestamps.py" ] || [ -f "protocol/timestamps/__init__.py" ]; then
find . -path "*protocol/timestamps*" -type f | head -5
fiRepository: OlympusLedgerOrg/Olympus
Length of output: 93
🏁 Script executed:
cat -n protocol/timestamps.pyRepository: OlympusLedgerOrg/Olympus
Length of output: 1847
🏁 Script executed:
head -n 30 tools/ceremony_contribute.pyRepository: OlympusLedgerOrg/Olympus
Length of output: 842
Use canonical timestamp and canonical JSON serialization for metadata
Line 151 should use protocol.timestamps.current_timestamp() to generate RFC3339 timestamps with 'Z' suffix (not the stdlib datetime.now(timezone.utc).isoformat() which produces '+00:00'). Line 159 should serialize JSON canonically with sorted keys, compact separators, and ASCII-only output with explicit UTF-8 encoding.
Suggested patch
-from datetime import datetime, timezone
+from protocol.timestamps import current_timestamp
@@
metadata = {
"participant": participant_name,
- "timestamp": datetime.now(timezone.utc).isoformat(),
+ "timestamp": current_timestamp(),
"contribution_hash": contribution_hash,
"circuit_hash": circuit_hash,
"output_path": str(output_path),
}
@@
- meta_path.write_text(json.dumps(metadata, indent=2))
+ meta_path.write_text(
+ json.dumps(metadata, sort_keys=True, separators=(",", ":"), ensure_ascii=True),
+ encoding="utf-8",
+ )📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "timestamp": datetime.now(timezone.utc).isoformat(), | |
| "contribution_hash": contribution_hash, | |
| "circuit_hash": circuit_hash, | |
| "output_path": str(output_path), | |
| } | |
| # Write metadata alongside the zkey | |
| meta_path = output_path.with_suffix(".json") | |
| meta_path.write_text(json.dumps(metadata, indent=2)) | |
| "timestamp": current_timestamp(), | |
| "contribution_hash": contribution_hash, | |
| "circuit_hash": circuit_hash, | |
| "output_path": str(output_path), | |
| } | |
| # Write metadata alongside the zkey | |
| meta_path = output_path.with_suffix(".json") | |
| meta_path.write_text( | |
| json.dumps(metadata, sort_keys=True, separators=(",", ":"), ensure_ascii=True), | |
| encoding="utf-8", | |
| ) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tools/ceremony_contribute.py` around lines 151 - 159, Replace the
non-canonical timestamp and JSON write: set the metadata "timestamp" using
protocol.timestamps.current_timestamp() instead of
datetime.now(...).isoformat(), and write the metadata JSON canonically by
serializing with json.dumps(metadata, sort_keys=True, separators=(",", ":"),
ensure_ascii=True) and writing it as UTF-8 (e.g., write bytes or open the file
with encoding="utf-8") instead of meta_path.write_text(json.dumps(metadata,
indent=2)); update the code around the metadata dict creation and the meta_path
write call (look for the metadata variable and meta_path.write_text usage in
ceremony_contribute.py).
| def main() -> int: | ||
| logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s") |
There was a problem hiding this comment.
Add a docstring to main()
main() is public and currently undocumented.
As per coding guidelines, "All public functions in Python must have docstrings explaining purpose, args, and returns".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tools/ceremony_contribute.py` around lines 174 - 175, Add a clear docstring
to the public function main() describing its purpose (initializes logging and
runs the CLI/entry logic), any parameters (none) and what it returns (int exit
code), and mention side effects (configures logging). Place the docstring as the
first statement in the main() function (triple-quoted, following PEP 257) and
include a short summary line, a blank line, and an "Returns" section that
specifies the integer exit code.
There was a problem hiding this comment.
Pull request overview
This PR combines three CI/protocol-hardening tasks: unblocking lint failures, adding a dedicated Postgres-based prove/verify workflow, and introducing a new Groth16 ceremony contribution helper. In the broader codebase, it targets release/CI reliability plus the ceremony tooling needed for the project’s pre-public readiness work.
Changes:
- Fixes formatting-only lint blockers in
protocol/parquet_writer.pyand its tests. - Adds a new GitHub Actions workflow intended to exercise insert/prove/verify behavior against Postgres and updates the release anchoring workflow to skip cleanly when Olympus API settings are absent.
- Introduces
tools/ceremony_contribute.pyplus unit tests for ceremony contribution setup and metadata generation.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
tools/ceremony_contribute.py |
Adds a CLI helper for Phase 2 Groth16 ceremony contributions and sidecar metadata output. |
tests/test_parquet_writer.py |
Formatting-only test file cleanup. |
tests/test_ceremony_contribute.py |
Adds unit tests for ceremony prerequisite checks, success path, and snarkjs detection. |
protocol/parquet_writer.py |
Formatting-only lint cleanup in deterministic Parquet helpers. |
.github/workflows/olympus-commit.yml |
Documents release-only behavior and adds a preflight config check before anchoring artifacts. |
.github/workflows/e2e-prove-verify.yml |
Adds a new CI workflow for Postgres-backed insert/prove/verify-related test execution. |
|
|
||
| metadata = { | ||
| "participant": participant_name, | ||
| "timestamp": datetime.now(timezone.utc).isoformat(), |
| class TestCeremonyContributeSuccess: | ||
| def test_metadata_written_on_success(self, tmp_path: Path) -> None: | ||
| from ceremony_contribute import contribute | ||
|
|
||
| ptau = tmp_path / "phase1.ptau" | ||
| ptau.write_bytes(b"fake ptau") | ||
| circuit = tmp_path / "circuit.circom" | ||
| circuit.write_text("pragma circom 2.0.0;") | ||
| r1cs = tmp_path / "circuit.r1cs" | ||
| r1cs.write_bytes(b"fake r1cs") | ||
| output = tmp_path / "contributions" / "test.zkey" | ||
|
|
||
| def fake_run(cmd, **kwargs): | ||
| # Simulate snarkjs writing output files | ||
| if "setup" in cmd: | ||
| # The initial zkey path is the last positional arg: <r1cs> <ptau> <zkey> | ||
| # cmd = ["npx", "snarkjs", "groth16", "setup", r1cs, ptau, zkey] | ||
| initial_zkey_path = Path(cmd[6]) | ||
| initial_zkey_path.parent.mkdir(parents=True, exist_ok=True) | ||
| initial_zkey_path.write_bytes(b"initial zkey") | ||
| elif "contribute" in cmd: | ||
| output.parent.mkdir(parents=True, exist_ok=True) | ||
| output.write_bytes(b"contributed zkey data") | ||
| mock_result = MagicMock() | ||
| mock_result.returncode = 0 | ||
| return mock_result | ||
|
|
||
| with ( | ||
| patch("ceremony_contribute._check_snarkjs", return_value=True), | ||
| patch("ceremony_contribute.subprocess.run", side_effect=fake_run), | ||
| ): | ||
| metadata = contribute( | ||
| ptau_path=ptau, | ||
| circuit_path=circuit, | ||
| participant_name="FPF Test", | ||
| output_path=output, | ||
| ) | ||
|
|
||
| assert metadata["participant"] == "FPF Test" | ||
| assert len(metadata["contribution_hash"]) == 64 # SHA-256 hex | ||
| assert "timestamp" in metadata | ||
|
|
||
| # Verify metadata file was written | ||
| meta_file = output.with_suffix(".json") | ||
| assert meta_file.exists() | ||
| written = json.loads(meta_file.read_text()) | ||
| assert written["participant"] == "FPF Test" | ||
|
|
||
| def test_contribution_hash_is_deterministic(self, tmp_path: Path) -> None: | ||
| """Same output file → same hash. Proves our hashing is stable.""" | ||
| from ceremony_contribute import _sha256_file | ||
|
|
||
| f = tmp_path / "test.zkey" | ||
| f.write_bytes(b"deterministic content") | ||
|
|
||
| h1 = _sha256_file(f) | ||
| h2 = _sha256_file(f) | ||
| assert h1 == h2 | ||
| assert len(h1) == 64 | ||
|
|
||
|
|
||
| class TestCheckSnarkjs: |
| # Compute contribution hash for public attestation | ||
| contribution_hash = _sha256_file(output_path) | ||
| circuit_hash = _sha256_file(circuit_path) | ||
|
|
||
| metadata = { | ||
| "participant": participant_name, | ||
| "timestamp": datetime.now(timezone.utc).isoformat(), | ||
| "contribution_hash": contribution_hash, | ||
| "circuit_hash": circuit_hash, |
| if [ -z "${OLYMPUS_API_URL:-}" ] && [ -z "${OLYMPUS_API_KEY:-}" ]; then | ||
| echo "configured=false" >> "$GITHUB_OUTPUT" | ||
| echo "::notice::Olympus API not configured — skipping artifact anchoring" |
| # proof that it exists in the tree at a specific position. | ||
| # If this fails: users can't get proof their document was recorded. | ||
| run: | | ||
| pytest tests/test_e2e_audit.py tests/test_proof_generator.py -v --tb=short \ |
| - name: "Step 3 of 3 — VERIFY: independently verify the proof is valid" | ||
| # What this tests: the proof generated in Step 2 is cryptographically valid. | ||
| # A third party with only the proof + root hash can confirm the document existed. | ||
| # If this fails: the entire trust model of Olympus is broken. | ||
| run: | | ||
| pytest tests/test_rt_m1_post_persist_verify.py tests/test_merkle_proof_verification.py \ | ||
| tests/test_verify_bundle.py -v --tb=short \ | ||
| --junit-xml=test-results/step3-verify.xml |
| # Step 1: Generate initial phase 2 key | ||
| setup_result = subprocess.run( | ||
| ["npx", "snarkjs", "groth16", "setup", str(r1cs_path), str(ptau_path), str(initial_zkey)], | ||
| capture_output=True, | ||
| text=True, | ||
| ) | ||
| if setup_result.returncode != 0: | ||
| raise RuntimeError( | ||
| f"snarkjs groth16 setup failed (exit {setup_result.returncode}):\n{setup_result.stderr}" | ||
| ) | ||
|
|
||
| # Step 2: Contribute | ||
| contribute_result = subprocess.run( | ||
| [ | ||
| "npx", | ||
| "snarkjs", | ||
| "zkey", | ||
| "contribute", | ||
| str(initial_zkey), | ||
| str(output_path), | ||
| f"--name={participant_name}", | ||
| f"-e={contribution_entropy}", | ||
| ], | ||
| capture_output=True, | ||
| text=True, | ||
| ) | ||
| if contribute_result.returncode != 0: | ||
| raise RuntimeError( | ||
| f"snarkjs zkey contribute failed (exit {contribute_result.returncode}):\n" | ||
| f"{contribute_result.stderr}" | ||
| ) |
|
@copilot Must fix:
Should fix:
Can defer:
|
…_RUST) Agent-Logs-Url: https://github.com/OlympusLedgerOrg/Olympus/sessions/a89aa2c3-104a-48ae-a251-f740c3ba087c Co-authored-by: OlympusLedgerOrg <240737312+OlympusLedgerOrg@users.noreply.github.com>
Done in 3b6411d. Replaced |
Three ruff errors blocked every merge to
main. Simultaneously, the full insert→prove→verify chain and the Groth16 ceremony were missing from CI entirely.Lint fixes (
ruff format --check/ W291, W292)protocol/parquet_writer.py:290— trailing space inside docstring closing"""protocol/parquet_writer.py:302— no newline at EOFtests/test_parquet_writer.py:313— no newline at EOFE2E workflow (
.github/workflows/e2e-prove-verify.yml)Three explicitly labeled steps against a real Postgres service container:
test_ingest_e2e_postgres.pytest_e2e_audit.py,test_proof_generator.pytest_rt_m1_post_persist_verify.py,test_merkle_proof_verification.py,test_verify_bundle.pytest_e2e_audit.pywas previously marked with an unconditionalpytest.mark.skip. It now usespytest.mark.skipif(not HAS_RUST, ...)(sameimportlib.util.find_spec("olympus_core")pattern astest_storage_protocol.py), so it skips locally when the Rust extension isn't built and runs automatically in CI oncematurin build --releasecompletes.Signing key is generated ephemerally at runtime rather than hardcoded:
Groth16 ceremony scaffold (
tools/ceremony_contribute.py)snarkjsinitial_DONOTCOMMIT.zkeyso cleanup scripts can reliably shred itgroth16 setupandzkey contributeand raisesRuntimeErrorwith the output on failure<output>.jsonsidecar with participant name, timestamp, contribution hash, and circuit hash for public attestationtests/test_ceremony_contribute.pycover all error paths and the success path without requiring actual snarkjs or ptau filesolympus-commit.ymlannotationCheck Olympus API is configuredstep that emits::notice::and setsconfigured=falsewhen eitherOLYMPUS_API_URLorOLYMPUS_API_KEYis absent, so the anchoring step is skipped cleanly on forks and unconfigured deployments rather than failingOriginal prompt
Context
The current
mainbranch has failing CI from two minor but blocking lint errors introduced in the parquet_writer PRs. Additionally, three pre-launch gates are not yet wired into CI. This PR fixes all four in a single pass.1. 🔴 Fix immediate CI blocker — trailing whitespace / missing newlines
Why it matters:
ruff format --check(run insmoke-unit) fails with exit code 1 on these files. Every merge tomainis blocked until fixed.Fix the following (do NOT change logic, only whitespace):
protocol/parquet_writer.py"""in theverify_parquet_determinismdocstring. The line should be exactly"""with no trailing whitespace.return _hash_file(path_a) == _hash_file(path_b)must end with a single newline (W292 — no newline at end of file).tests/test_parquet_writer.pypw_module._PYARROW_AVAILABLE = origmust end with a single newline (W292 — no newline at end of file).2. 🟠 Add E2E insert→prove→verify CI workflow
Why it matters: FPF and EFF need to see that the full cryptographic chain — insert a document, generate a Merkle proof, verify that proof — executes correctly on every push to
main. This is the core trust claim of Olympus. Without it in CI, we can't point to a green badge and say "it works."Analogy for non-devs: Like a notary stamp: it only means something if someone verifiable watched the whole signing ceremony and confirmed every step was done correctly, in order.
Create
.github/workflows/e2e-prove-verify.ymlwith: