GitHub Actions
Being rolled out. The interface described here is the one of the next release: it may still change, and may not be enabled on your tenant yet.
Same principle as for GitLab: the job obtains an OIDC token from GitHub, the CLI exchanges it for a tenant session. No secret in the repository secrets.
Prerequisites
sng tenant oidc create github-deploy \
--github-repo acme/infra --ref main \
--claim repository_id=123456789
sng tenant policy attach readwrite --oidc-trust github-deploy
sng tenant oidc create github-review --github-repo acme/infra --ref '*' --claim repository_id=123456789
sng tenant policy attach readonly --oidc-trust github-review
The repository ID can be read with gh api repos/acme/infra --jq .id.
The sub of a token issued for a pull request is repo:acme/infra:pull_request, not a
branch. To validate PRs, add a trust with --subject 'repo:acme/infra:pull_request'
or use --ref '*' and accept that PRs share the review trust.
Install the CLI in the workflow
Since binaries are not published yet, the workflow builds the CLI from source.
The sng-cli repository is private: you need a read access token for the repository, stored as a
GitHub secret (SNG_CLI_TOKEN). It is the only secret of the workflow, and it grants no
rights on your tenant.
name: deploy
on:
push:
branches: [main]
pull_request:
permissions:
id-token: write # the job can request an OIDC token
contents: read
env:
STNG_TENANT: acme
STNG_OIDC_AUDIENCE: https://api.dev.stackngo.fr
jobs:
sng:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.27"
- name: Build sng
run: |
git clone --depth 1 "https://oauth2:${{ secrets.SNG_CLI_TOKEN }}@gitlab.com/stackngo/sng-cli.git" /tmp/sng-cli
make -C /tmp/sng-cli build
sudo install /tmp/sng-cli/bin/sng /usr/local/bin/sng
sng config create
- name: Validate
run: |
sng validate infra/
sng plan infra/
- name: Deploy
if: github.ref == 'refs/heads/main'
env:
STNG_OIDC_TRUST: github-deploy
run: |
sng apply infra/
sng app describe api
Under GitHub Actions, the CLI reads ACTIONS_ID_TOKEN_REQUEST_URL and
ACTIONS_ID_TOKEN_REQUEST_TOKEN, provided by the runner when permissions: id-token: write
is present, and itself requests a token with audience STNG_OIDC_AUDIENCE each time
it opens a session.
Wait for convergence
- name: Wait for Ready
if: github.ref == 'refs/heads/main'
run: |
for i in $(seq 1 30); do
if sng app describe api --json | jq -e '.ready' >/dev/null; then exit 0; fi
sleep 10
done
sng app describe api; exit 1
Useful variables
| Variable | Role |
|---|---|
STNG_TENANT | Target tenant (required) |
STNG_OIDC_AUDIENCE | Audience of the token requested from GitHub (default: the API URL) |
STNG_OIDC_TRUST | Disambiguates if several trusts match |
STNG_CLUSTER | Alternative to sng config use-cluster |
Troubleshooting
no CI OIDC token:permissions: id-token: writeis missing from the workflow or the job.401 invalid identity token: thesub(repo:acme/infra:ref:refs/heads/feature-x,repo:acme/infra:pull_request) matches no trust.sng tenant oidc getshows the expected pattern.403 forbiddenonapply:STNG_OIDC_TRUSTpoints to thereadonlytrust.- A fork does not receive an OIDC token for PRs: this is a GitHub protection, not a StackNGO one.