Skip to content

Add reproducible-build CI workflows (build + release PR)#3573

Open
italo-sampaio wants to merge 4 commits into
masterfrom
is/reproducible-build-ci
Open

Add reproducible-build CI workflows (build + release PR)#3573
italo-sampaio wants to merge 4 commits into
masterfrom
is/reproducible-build-ci

Conversation

@italo-sampaio

@italo-sampaio italo-sampaio commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Description

Automates the reproducible-build artifacts that today are produced entirely by hand for rsksmart/reproducible-builds. Adds two GitHub Actions workflows plus the templates they render, split by privilege:

  • .github/workflows/reproducible-build.ymlbuild-only, no secrets, contents: read.
  • .github/workflows/reproducible-build-pr.ymlrelease PR, the only holder of secrets + cross-repo write scope.
  • .github/reproducible-build/Dockerfile.tmpl — the pinned, hermetic build.
  • .github/reproducible-build/README.md.tmpl — the published release-directory README.

reproducible-build.yml — build-only

Given a git ref (branch / tag / SHA), it builds the rskj artifacts inside the pinned Dockerfile, computes the sha256 hashes of the produced jars, writes a hashes.txt, and uploads jars + hashes as a run artifact (rskj-repro-artifacts).

Triggered three ways:

  • push to master and *-rc branches — builds that commit and records its canonical hashes.
  • workflow_dispatch — manual, optional ref input (defaults to the checked-out commit).
  • workflow_call — reusable building block: exposes hashes, version, modifier and artifact_name as outputs, consumed by the release-PR workflow below.

It holds no secrets and only contents: read; it opens no PR and publishes nothing.

reproducible-build-pr.yml — release PR

Triggered on a pushed GA release tag; it builds the canonical artifacts via the build-only workflow and opens the corresponding PR against rsksmart/reproducible-builds. Three jobs:

  • guard — classifies the pushed tag as GA or not (all-caps name + three-part version regex, plus a belt-and-suspenders pre-release deny-list for *-PREVIEW / *-TESTNET-* / *-rc / *-RC / *SNAPSHOT* / *-alpha / *-beta). Non-GA tags skip green, not red. push.tags globs can't exclude pre-release tags, so this guard does.
  • builduses: ./.github/workflows/reproducible-build.yml with ref: github.ref_name. Runs only for GA tags.
  • open-pr — the only privileged job. Downloads the build artifact (hashes.txt), renders the Dockerfile + README for the rskj/<version>-<modifier>/ directory (the modifier→lowercase derivation lives here; hashes come straight from the artifact so README == artifact == a verifier's local check), mints a scoped GitHub App token (create-github-app-token v3.2.0, pinned SHA, scoped to owner: rsksmart + repositories: reproducible-builds), clones the target over x-access-token, and opens the PR via the gh CLI. Fails loudly if the release directory already exists (never overwrites a published release), uses a per-tag branch with -B reset, and a gh pr list idempotency check so a re-run never opens a duplicate PR.

Privilege isolation: top-level permissions: contents: read; GITHUB_TOKEN is never elevated. All secrets and all cross-repo writes are confined to open-pr, via the App token only. The PR is opened only, merging and approving are still manual processes.

Motivation and Context

Reproducible-build PRs against rsksmart/reproducible-builds (e.g. [#139](rsksmart/reproducible-builds#139) for VETIVER-9.0.3) are currently produced entirely by hand: build the pinned Dockerfile locally, run sha256sum, hand-template the rskj/<version>-<modifier>/ directory, and open the PR. This is purely mechanical, so it is automated end-to-end here: a hermetic, on-demand / on-push CI build, and a release-tag-triggered workflow that renders the release directory and opens the PR — while preserving the trust model (independent rebuild still gates merge).

How Has This Been Tested?

Validated in forks from both rskj and reproducible-builds:

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • Tests for the changes have been added (for bug fixes / features)
  • Requires Activation Code (Hard Fork)

Copilot AI review requested due to automatic review settings June 18, 2026 18:10
@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

OpenSSF Scorecard

PackageVersionScoreDetails
actions/actions/checkout 9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 🟢 6.9
Details
CheckScoreReason
Code-Review🟢 10all changesets reviewed
Maintained🟢 1016 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Binary-Artifacts🟢 10no binaries found in the repo
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Packaging⚠️ -1packaging workflow not detected
Pinned-Dependencies🟢 3dependency not pinned by hash detected -- score normalized to 3
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
SAST🟢 10SAST tool is run on all commits
actions/actions/upload-artifact 043fb46d1a93c77aae656e7c1c64a875d1fc6a0a 🟢 5.5
Details
CheckScoreReason
Code-Review🟢 10all changesets reviewed
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
Maintained🟢 34 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 3
Packaging⚠️ -1packaging workflow not detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Pinned-Dependencies⚠️ 1dependency not pinned by hash detected -- score normalized to 1
License🟢 10license file detected
Fuzzing⚠️ 0project is not fuzzed
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
SAST🟢 10SAST tool is run on all commits
Branch-Protection⚠️ 0branch protection not enabled on development/release branches

Scanned Files

  • .github/workflows/reproducible-build.yml

Copilot AI 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.

Pull request overview

Adds a new GitHub Actions workflow and supporting templates to run a hermetic, Docker-based reproducible build for published rskj tags, producing sha256 hashes and uploading the built artifacts for downstream verification (e.g., for rsksmart/reproducible-builds).

Changes:

  • Introduces a reproducible-build workflow that runs on manual dispatch (required tag input) and on push of GA-style release tags.
  • Adds Dockerfile and README templates that are rendered by the workflow and included in the job summary alongside computed artifact hashes.
  • Builds the tagged source inside a pinned Docker base image, extracts jars/pom/module, computes sha256 hashes, and uploads them as a workflow artifact.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.

File Description
.github/workflows/reproducible-build.yml New workflow to render templates, build a hermetic Docker image for a tag, compute hashes, and upload artifacts.
.github/reproducible-build/Dockerfile.tmpl Hermetic Docker build template that fetches the tag, verifies inputs via signed checksum material, and builds/publishes artifacts into the image.
.github/reproducible-build/README.md.tmpl README template documenting how to build and verify hashes locally using the generated Dockerfile/image.

Comment thread .github/workflows/reproducible-build.yml Outdated
Comment thread .github/workflows/reproducible-build.yml Outdated
Comment thread .github/workflows/reproducible-build.yml Outdated
Comment thread .github/workflows/reproducible-build.yml Outdated
Comment thread .github/workflows/reproducible-build.yml Outdated
Comment thread .github/workflows/reproducible-build.yml Outdated
Comment thread .github/reproducible-build/Dockerfile.tmpl Outdated
italo-sampaio added a commit that referenced this pull request Jun 18, 2026
Address two review findings on PR #3573 (RSKCORE-5579):

- Add a fail-fast "Validate tag" step. The tag flows into a git refspec and
  into sed `s|__TAG__|...|` substitutions, where a `|` in the value would
  break the delimiter; reject anything outside ^[a-zA-Z0-9._/-]+$ with a
  clear error, matching the gate style in fuzz-test.yml.

- Import the RSK signing key via `curl -sSL ... | gpg --import` instead of
  `gpg --keyserver <https .asc URL> --recv-keys`, which misuses --keyserver
  (it expects an HKP keyserver, not a static .asc file). Matches the import
  approach already used in build_and_test.yml.
@italo-sampaio italo-sampaio force-pushed the is/reproducible-build-ci branch 2 times, most recently from a4858f6 to 2ed66fe Compare June 18, 2026 19:47
@italo-sampaio italo-sampaio requested a review from Copilot June 18, 2026 19:50

Copilot AI 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.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

Comment thread .github/workflows/reproducible-build.yml Outdated
Comment thread .github/workflows/reproducible-build.yml Outdated
Comment thread .github/workflows/reproducible-build.yml Outdated
Comment thread .github/reproducible-build/Dockerfile.tmpl
Comment thread .github/reproducible-build/Dockerfile.tmpl
Comment thread .github/reproducible-build/README.md.tmpl
@italo-sampaio italo-sampaio mentioned this pull request Jun 18, 2026
8 tasks

@fmacleal fmacleal left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Very nicee!

Excited to see it creating automatically a PR in the reproducible build repo. With the ground work done here, it will be easy to do it. :)

I have left some small comments suggestions.

Comment thread .github/workflows/reproducible-build.yml Outdated
Comment thread .github/workflows/reproducible-build.yml
Comment thread .github/workflows/reproducible-build.yml
Comment thread .github/workflows/reproducible-build.yml
@fmacleal fmacleal force-pushed the is/reproducible-build-ci branch from 2ed66fe to e1fe177 Compare June 22, 2026 09:48
Copilot AI review requested due to automatic review settings June 24, 2026 15:58
@italo-sampaio italo-sampaio force-pushed the is/reproducible-build-ci branch from e1fe177 to 4d5ad20 Compare June 24, 2026 15:58

Copilot AI 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.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

Comment thread .github/workflows/reproducible-build.yml Outdated
Comment thread .github/workflows/reproducible-build.yml Outdated
Comment thread .github/workflows/reproducible-build.yml Outdated
@italo-sampaio italo-sampaio force-pushed the is/reproducible-build-ci branch from 4d5ad20 to 7f2a763 Compare June 24, 2026 20:40
@italo-sampaio italo-sampaio changed the title Add reproducible-build CI workflow (manual dispatch + on release tag) Add reproducible-build CI workflow (build-only) Jun 24, 2026
@italo-sampaio italo-sampaio requested a review from Copilot June 24, 2026 21:00
@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown

RSKj Core Automated Tests

rskj node built from is/reproducible-build-ci.

Suite Result Branch tested Run
JSON-RPC ✅ success main run
Hardhat ✅ success main run
K6 ✅ success main run

Copilot AI 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.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

Comment thread .github/workflows/reproducible-build.yml
Comment thread .github/workflows/reproducible-build.yml Outdated
Comment thread .github/workflows/reproducible-build.yml
Comment thread .github/workflows/reproducible-build.yml
@italo-sampaio italo-sampaio changed the title Add reproducible-build CI workflow (build-only) Add reproducible-build CI workflows (build + release PR) Jun 25, 2026
Copilot AI review requested due to automatic review settings June 25, 2026 17:08

Copilot AI 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.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

Comment on lines +96 to +99
case "$REF" in
""|*..*) echo "::error::invalid ref (empty or contains '..'): '$REF'"; exit 1;;
*[!A-Za-z0-9._/-]*) echo "::error::ref has disallowed characters: '$REF'"; exit 1;;
esac
set -euo pipefail
# Same command a verifier runs locally, so the artifact's hashes.txt and
# any downstream README match byte for byte.
hashes=$(docker run --rm rskj-repro:build sh -c 'sha256sum * | grep -v javadoc.jar')
Run the following command to verify the sha256sum of the built artifacts matches the expected values:

```
$ docker run --rm rskj/__VERSION__-__MODIFIER_LC__ sh -c 'sha256sum * | grep -v javadoc.jar'
Add a GitHub Actions workflow that hermetically builds an rskj git ref and
records the sha256 hashes of the produced jars. It runs on push to master and
*-rc branches, on manual dispatch with a ref input, and as a reusable
workflow_call building block so a later, release-tag-triggered workflow can
reuse it to open the reproducible-builds PR.

The build runs inside a pinned, hermetic Dockerfile that fetches the ref itself
from canonical upstream and verifies the in-tree signed checksums before
building; the runner checkout only supplies the rendered Dockerfile template and
version.properties. The produced jars and a hashes.txt are uploaded as a run
artifact, and the hashes, version and modifier are exposed as workflow outputs
for the calling workflow. A README template for the reproducible-builds entry is
included for that future workflow; this workflow renders only the Dockerfile.

Trust model: this workflow is the first builder only. The hashes it emits are
informational, not an authoritative attestation, and it opens no PR and
publishes nothing (permissions: contents: read, no secrets). A release must
still be independently rebuilt to confirm the same hashes. On a non-tag push
there is moreover no published release to compare against: the run is a hermetic
build and canonical-hash record, not a reproducibility-vs-release check.

All privileged, cross-repo work — minting a token and opening the PR against the
reproducible-builds repo — is intentionally kept out of this workflow and will
live in a separate workflow that holds the only secrets and write scope.

The ref is validated against empty, "..", and a git-ref character allowlist
before it flows into a git refspec and into sed substitution delimiters. The
signing key is imported via `curl | gpg --import` rather than `gpg --keyserver`,
which expects an HKP keyserver rather than a static .asc file.
Adds reproducible-build-pr.yml: on a GA release tag, builds the canonical
jars via the build-only reproducible-build.yml (workflow_call, no secrets),
then mints a scoped GitHub App token and opens a PR against
rsksmart/reproducible-builds with the rskj/<version>-<modifier> dir.

Secrets and cross-repo write scope live solely in the open-pr job; the
build half stays contents:read/no-secrets.
Key the concurrency group by the ref actually being built
(inputs.ref || github.sha) instead of github.ref, so workflow_dispatch
runs building different refs from the same branch no longer share a
group and cancel each other.

Switch to cancel-in-progress: false so an in-flight build is never
aborted — including a release-tag build driven via workflow_call — and
to stay consistent with reproducible-build-pr.yml.
@fmacleal fmacleal force-pushed the is/reproducible-build-ci branch from f1cc5e5 to b14391b Compare July 1, 2026 17:26
fmacleal
fmacleal previously approved these changes Jul 1, 2026

@fmacleal fmacleal left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Cool!

thanks for having addressed the comments!

The security team provisioned access to the reproducible-builds repo by
reusing an existing GitHub App, exposed to this workflow under the secret
names RSK_CORE_GH_APP_ID / RSK_CORE_GH_APP_PRIVATE_KEY. Point the
open-pr App-token step at those names.
Copilot AI review requested due to automatic review settings July 1, 2026 17:45

Copilot AI 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.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

@sonarqubecloud

sonarqubecloud Bot commented Jul 1, 2026

Copy link
Copy Markdown

@fmacleal fmacleal left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

@core-baguira core-baguira 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.

LGTM

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.

4 participants