Skip to main content

Continuous integration

Three actions, each named for what comes out of it. A game pins one version — the engine's — and gets the engine, its runtime templates and the actions that know its flags from the same tag.

uses:Produces
balaurengine/balaur/.github/actions/setup@v0.2.0a published balaur on PATH, verified against the release's SHA256SUMS, with the runtime templates you name
balaurengine/balaur/.github/actions/export-game@v0.2.0a signed build per target, uploaded as an artifact with build provenance
balaurengine/balaur/.github/actions/build-engine@v0.2.0the editor and runtime templates built from source, for features the published build does not carry

setup installs the release its own ref names, so @v0.2.0 installs v0.2.0 and the version is written down once. @main follows the rolling nightly.

A build on every tag

name: Build
on:
push:
tags: ["v*"]

jobs:
export:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: balaurengine/balaur/.github/actions/setup@v0.2.0
with:
targets: "linux-x64 windows-x64 web"
- uses: balaurengine/balaur/.github/actions/export-game@v0.2.0
with:
targets: "linux-x64 windows-x64 web"

That is the whole file for an unsigned build. No secret, no account, and no Rust toolchain: setup downloads the engine and export-game runs it.

Signing

Every signature is applied by balaur export itself, never by a step beside it, so a build CI signed can be reproduced by exporting it by hand. An action's job is to put each credential where that platform's own tool looks and hand the exporter the identity's name.

- uses: balaurengine/balaur/.github/actions/export-game@v0.2.0
with:
targets: "macos-universal ios"
macos-identity: "Developer ID Application: Studio (AB12CD34EF)"
macos-certificate: ${{ secrets.MACOS_CERTIFICATE_P12 }}
macos-certificate-password: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
notarize: true
notary-key: ${{ secrets.ASC_KEY_P8 }}
notary-key-id: ${{ secrets.ASC_KEY_ID }}
notary-issuer: ${{ secrets.ASC_ISSUER_ID }}

Every file-shaped secret — a .p12, a .p8, a .mobileprovision, a .jks, a .pfx — is stored base64-encoded, because a GitHub secret holds text:

base64 -i certificate.p12 | pbcopy # macOS
base64 -w0 release.jks # Linux

What each target needs:

TargetNeedsRunner
linux-x64, linux-arm64nothing; a Linux download is vouched for by its provenance attestation rather than a signatureany
windows-x64windows-certificate and its password, or an Azure Trusted Signing metadata JSON when the key is in a cloud HSMany; a non-Windows runner signs through osslsigncode
macos-universalmacos-certificate, macos-identity, and the three notary-* inputs to notarizemacOS
iosios-certificate, ios-identity and ios-profile; ipa: true for TestFlightmacOS
androidandroid-keystore, android-key and the passwords; without them the build takes Android's debug identity, which installs but ships nowhereany with the SDK
webnothing; a browser trusts the originany

Identities, team ids and keystore aliases are not secrets, and may live in the project's [export] table instead, so a click in the editor and a run on a runner sign the same way. The passwords never do.

Provenance

Both building actions can attach Sigstore build provenance to what they upload, which gh attestation verify checks with no certificate and no account of your own. The job needs two extra permissions:

permissions:
contents: read
id-token: write
attestations: write
steps:
- uses: balaurengine/balaur/.github/actions/export-game@v0.2.0
with:
attest: true

A custom engine

The published templates are built with window and extensions, plus apple on macOS. A game that needs a different set — a smaller web build, or one without the networking stack — builds the engine itself:

- uses: actions/checkout@v7
with:
repository: balaurengine/balaur
ref: v0.2.0
- uses: ./.github/actions/build-engine
with:
target: linux-x64
features: "window,extensions,audio"

Build size says what each feature costs. build-engine produces the same balaur-editor-*, balaur-runtime-* and balaur-template-* files a release holds, so a later export-game uses them by pointing BALAUR_TEMPLATES at where they landed.

What a run costs

A macOS or iOS export needs a macos-* runner, billed at ten times a Linux minute; Linux, Windows, Android and web all export on a Linux runner. Group targets by the host they need rather than giving each its own job, so a game with four targets spends one Mac job's minutes and not four.