Skip to content

CI.md — Continuous Integration

Living reference for the GitHub Actions pipeline (.github/workflows/). Tier-1 authority remains docs/ARCHITECTURE.md; this file records the how of the automated gates. Three workflows, each with a single responsibility: a hermetic per-change gate, a nightly real-network validation, and a tag-driven release.


1. Workflows

Workflow Trigger Runner Runs permissions
ci.yml push to main and pull_request to main ubuntu-latest make check → make e2e contents: read
differential.yml schedule — cron 0 3 * * * (03:00 UTC) only ubuntu-latest make differential (job differential) and make fuzz (job fuzz), in parallel contents: read
release.yml push of a tag matching v* ubuntu-latest make release → attach artifacts contents: write

ci.yml — the per-change gate

Runs on every push to main and every pull request targeting main. Steps: checkout (actions/checkout@v4), actions/setup-go@v5 (go-version: 1.26.x, cache: true), make install-tools, put $(go env GOPATH)/bin on PATH (so the module-built staticcheck is found), then make check followed by make e2e.

100% hermetic — no network, no secrets. This is the same gate contributors run locally (docs/BUILD.md, CONTRIBUTING.md): build + vet + staticcheck + hermetic unit tests, then the real-binary end-to-end flows. A red run blocks the PR.

differential.yml — the nightly

Runs once a day at 03:00 UTC. No push, pull_request, or workflow_dispatch trigger — the schedule is the only entry point. Two parallel jobs:

  • differential — checkout, setup-go, make install-tools, PATH, then make differential against the Nile testnet with the four secrets injected as environment variables (see §2).
  • fuzz — checkout, setup-go, then make fuzz (30s per target). Uses no secrets and touches no network.

A red nightly blocks nothing: it is visible in the Actions tab and nowhere else. There are no external notifications, no issue filing, no Slack/email integrations — by design. The nightly is a signal to read, not a gate to pass.

release.yml — the release

Runs when a v* tag is pushed. Steps: checkout, setup-go, make release (the 6-binary static matrix — linux|darwin|windows × amd64|arm64 via CGO_ENABLED=0 cross-compilation — plus SHA256SUMS), then softprops/action-gh-release@v2 attaching release/sun-* and release/SHA256SUMS to the GitHub Release. This is the only workflow that requests contents: write.


2. Secrets

The nightly differential job reads four secrets. They are configured by the repository owner in Settings → Secrets and variables → Actions and never live in the repository. The secret names match the environment variables the differential suite reads 1:1:

Secret / env var Canonical Nile value (owner reference)
NILE_GRPC grpc.nile.trongrid.io:50051
NILE_SOLIDITY_GRPC grpc.nile.trongrid.io:50061
NILE_JSONRPC https://nile.trongrid.io/jsonrpc
NILE_PRIVATE_KEY a funded Nile key (never published)

NILE_PRIVATE_KEY funds the deploy-based batteries; keep it topped up with Nile test TRX. The endpoint values above are the public Nile endpoints and are recorded here only for the owner's reference when populating the secrets — no value is committed.

TRON_PRO_API_KEY — intentionally not wired

The differential suite does not consume a TronGrid API key, so none is configured. If the public Nile endpoints start rate-limiting the nightly, a TRON_PRO_API_KEY secret can be added later; until there is a reason, it is deliberately absent.


3. Platform coverage

Windows binaries are cross-compiled by make release and unit-tested in the hermetic suite — the SAIL_HOME path logic (internal/config/paths.go, ExeSuffix/ManagedBinPath) is covered by cross-platform unit tests that run under ci.yml on Linux. They are not executed on a Windows runner in CI.

This is a deliberate, honest boundary: it closes the previously-deferred Windows-execution debt at the unit level and states plainly what CI does not do. There is no windows-smoke job, no macOS matrix, and no workflow_dispatch — by owner decision.


4. Branch protection

Option A: the owner keeps direct push access to main. Those pushes are checked after the fact — ci.yml triggers on push to main as well as on pull requests — while contributor PRs are checked before merge. Every change to main is therefore covered by the hermetic gate, whether it arrives by direct push or by PR.