Continuous integration

The GitHub Action

The same scan, run on every pull request, failing the job when a contract is closer to expiry than your repository allows.

What it catches

A contract’s TTL does not change because you opened a pull request — it changes because time passed. The Action exists so that the passage of time becomes visible at the moment somebody is already looking at the repository, rather than at the moment the contract stops working.

A workflow

name: Contract TTL on: [push, pull_request] jobs: ttl: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: Fatihmaull/evergreen@v1 with: contracts: ${{ vars.SOROBAN_CONTRACT_ID }} threshold: '120960' version: '0.1.1' keys-file: '.evergreen/keys.json'

The Action lives at the repository root, so it is referenced as Fatihmaull/evergreen@<ref> — there is no /actions/… path. The public Action tag is v1; version separately pins the published CLI. This example checks out your repository because the Action reads .evergreen/keys.json from it. Create that file for this one contract with { "dataKeys": [...] } containing its declared persistent and temporary keys. If you know the contract has no data keys, use no-data-keys: 'true' instead of keys-file; do not claim that merely because you have not listed keys.

A contract id is not a secret

Contract ids are public — they are on the ledger. Putting one in secrets costs you the ability to read your own workflow logs and buys nothing, so the example above uses vars.

The Action never signs anything and takes no key. It runs scan, which is read-only by construction. extend is a separate command and is not reachable from here.

Choosing the threshold

The default is the act-now tier — about one day. That is almost certainly too late for CI: a pull request that fails the day before a contract stops working has not given anyone time to do anything. Set it to the warning tier, 120,960 ledgers or about a week, and treat a failure as a task rather than an incident.

Do not treat “incomplete” as a pass

The job’s exit code is the scan’s. 3 means the scan ran and could not conclude — an entry was missing, a TTL was unavailable, or nothing was observed. A workflow that only fails on 1 will pass every time the scan cannot see, which is the one situation you most want to hear about. Action reference

Next Action reference Every input, the one output, and what the runner installs.