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, thenmake differentialagainst the Nile testnet with the four secrets injected as environment variables (see §2).fuzz— checkout, setup-go, thenmake 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.