Deploy services to a Rune cluster
from GitHub Actions. A faithful 1:1 wrapper around rune cast.
- uses: runestack/rune-cast-action@v1
with:
server: ${{ vars.RUNED_HOST }}
token: ${{ secrets.RUNE_TOKEN }}
source: infra/runeset/casts/external-service.yaml
values: infra/runeset/values/stg.yaml
namespace: stgThe token should be a scoped service-account
token,
not a root admin token. Mint one with:
rune admin service create ci-stg --namespace stg --permissions castCast a runeset as a named release (a persisted,
diffable, roll-back-able record). Use release to pin the release name and
yes so a prune/adopt plan doesn't block on a confirmation prompt that has no
TTY in CI:
- uses: runestack/rune-cast-action@v1
with:
server: ${{ vars.RUNED_HOST }}
token: ${{ secrets.RUNE_TOKEN }}
source: https://example.com/runesets/api-1.4.2.runeset.tgz
release: api # overrides the runeset manifest name
values: infra/values/prod.yaml
namespace: prod
atomic: true # roll back if the deploy fails
yes: true # auto-confirm prune/adopt (no TTY in CI)To gate a deploy on the computed plan, render JSON and read the result output:
- id: plan
uses: runestack/rune-cast-action@v1
with:
server: ${{ vars.RUNED_HOST }}
token: ${{ secrets.RUNE_TOKEN }}
source: ./runeset
release: api
dry-run: true
output: json
- run: echo '${{ steps.plan.outputs.result }}' | jq '.plan'Every input maps 1:1 to a rune cast flag (or to a rune login
auth flag). No subset, no opinionated shortcuts. If the CLI doesn't
accept it, this action doesn't either; if the CLI grows a flag, this
action grows the matching input. Source of truth: rune cast --help.
| Input | Description |
|---|---|
server |
Rune gRPC server address (host:port). Maps to rune login --server. |
token |
Bearer token. Piped over stdin so it never appears on argv. Mask as a secret. |
| Input | Description |
|---|---|
source |
Required. Path / directory / glob / URL passed as the positional arg of rune cast <source>. |
| Input | CLI flag | Notes |
|---|---|---|
namespace |
-n / --namespace |
|
values |
-f / --values (repeatable) |
Multi-line input → one -f per non-blank line. |
set |
--set (repeatable) |
Multi-line input → one --set per non-blank line. |
tag |
--tag |
|
release |
--release |
Override the release name from the runeset manifest. |
recursive |
-r / --recursive |
For directory sources. |
create-namespace |
--create-namespace |
|
force |
--force |
Force generation increment. |
dry-run |
--dry-run |
|
render |
--render |
Print rendered manifests, do not apply. |
detach |
--detach |
Return immediately without waiting. |
timeout |
--timeout |
Default 5m. |
adopt |
--adopt |
Take over resources that are unmanaged or owned by another release. |
atomic |
--atomic |
Roll this cast's changes back on failure (verify timeout also triggers rollback). |
yes |
--yes |
Skip the confirmation prompt for plans that prune or adopt. Required in CI for such plans — without it the CLI blocks on a TTY that does not exist. |
output |
-o / --output |
json for a machine-readable plan + result. Also exposed as the result output. |
Boolean inputs accept true / false (and 1 / 0 / yes / no).
| Input | Default | Description |
|---|---|---|
version |
latest |
Rune CLI version (e.g. v0.0.1-dev.26) — passed to runestack/rune-setup. |
github-token |
${{ github.token }} |
Token for the CLI download. |
| Output | Description |
|---|---|
version |
The resolved Rune CLI version that was installed. |
result |
The cast command's stdout. Most useful with output: json, where it is the structured plan + result for a downstream step to parse. |
# Single file — the 90% case.
- uses: runestack/rune-cast-action@v1
with:
server: ${{ vars.RUNED_HOST }}
token: ${{ secrets.RUNE_TOKEN }}
source: infra/runeset/casts/external-service.yaml
values: infra/runeset/values/stg.yaml
namespace: stg
# Full runeset directory.
- uses: runestack/rune-cast-action@v1
with:
server: ${{ vars.RUNED_HOST }}
token: ${{ secrets.RUNE_TOKEN }}
source: infra/runeset/
recursive: true
values: |
infra/runeset/values/base.yaml
infra/runeset/values/prod.yaml
namespace: prod
create-namespace: true
# Override values from the workflow context.
- uses: runestack/rune-cast-action@v1
with:
server: ${{ vars.RUNED_HOST }}
token: ${{ secrets.RUNE_TOKEN }}
source: infra/runeset/
values: infra/runeset/values/stg.yaml
set: |
app.tag=${{ github.sha }}
app.replicas=3
namespace: stg
# Dry-run on PRs.
- uses: runestack/rune-cast-action@v1
if: github.event_name == 'pull_request'
with:
server: ${{ vars.RUNED_HOST }}
token: ${{ secrets.RUNE_TOKEN }}
source: infra/runeset/casts/external-service.yaml
values: infra/runeset/values/stg.yaml
dry-run: true- Use
rune admin service createto mint a scoped service-account token instead of using the root bootstrap token. - Use GitHub Environments
to scope
RUNE_TOKENper environment so thestgjob can never see theprodtoken. - The action calls
::add-mask::on the token and pipes it over stdin viarune login --token-stdin, so it never appears on argv (/proc/<pid>/cmdline,ps, shell history) or in step logs.
If you only want the CLI installed (e.g. to run rune get, rune logs), use runestack/rune-setup-action
directly.
Apache-2.0 — see LICENSE. Matches the licence of Rune itself.