name: ci # CI for souveraine — Rust crate. Tests + clippy, then the aarch64 artifact, # all on `primary`. # # There used to be a second branch, `public`, which was the only ref that # published, so a green run on `primary` meant the gates passed and NOTHING # SHIPPED — indistinguishable from a run that did. It existed to mirror to # Codeberg; the mirror never worked and nothing else consumed it. Unified # 2026-07-31 after it stranded three commits, including TASK-48's fix. One # branch, one meaning: green on primary means it built and it shipped. on: push: branches: [primary] pull_request: branches: [primary] jobs: rust-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Install system deps # Retried because the runner's ephemeral job containers lose DNS for # minutes at a time (four builds lost on 2026-08-13). A transient # resolver blip must not decide whether our build passes, for the same # reason the tuie pin exists below. # # The retry wraps *both* commands: `apt-get update` exits 0 when every # index fails to download — it warns "old ones used instead" — so only # the install reports the failure. run: | for attempt in 1 2 3; do if sudo apt-get update -qq \ && sudo apt-get install -y -qq libasound2-dev libchafa-dev libwayland-dev; then exit 0 fi echo "system deps attempt $attempt failed; retrying in $((attempt * 15))s" sleep $((attempt * 15)) done echo "system deps unavailable after 3 attempts — check runner DNS" exit 1 # Pinned fork on our Gitea (rgb patch committed there) — upstream HEAD # must never decide whether our build passes. - name: Clone tuie (pinned fork) run: | git -c http.extraheader="Authorization: token ${{ secrets.LOCAL_GITEA_TOKEN }}" \ clone "${GITHUB_SERVER_URL}/Fimeg/tuie.git" /workspace/Fimeg/tuie git -C /workspace/Fimeg/tuie checkout aa43e335c8f5a3cd2c78e397a1a8dfe534a6bc35 # Pinned to a MASTER commit, deliberately, not to a `stable`-branch tip. # The old pin (29eef336, "toolchain: stable") was the tip of that repo's # `stable` branch when it was taken. dtolnay force-moves `stable` on every # Rust release, which orphaned the commit: it still exists as an object on # GitHub, but is reachable from no ref, so act's clone resolves it as # "reference not found" and rust-test dies before it compiles anything. # That failure skipped aarch64-artifact and silently stopped publishing to # `edge` — the phone sat on an old build with nothing saying why. # master is append-only, so a commit on it stays reachable. The toolchain # is chosen by the `toolchain:` input below, never by the branch. - uses: dtolnay/rust-toolchain@2c7215f132e9ebf062739d9130488b56d53c060c with: toolchain: "1.94" components: clippy - name: cargo test run: cargo test # `souveraine-sessiond` is `required-features = ["sessiond"]`, which is # not in `default` — so the line above never compiled the device state # authority, let alone ran its tests. Every sessiond change since the # daemon existed has been type-checked only by the aarch64 cross-build, # which builds and does not test. A green rust-test meant nothing for the # one binary that decides whether the phone is locked. Same trap as the # old primary/public split: a signal that reads like coverage and isn't. - name: cargo test (sessiond) run: cargo test --features sessiond --bin souveraine-sessiond - name: cargo test (USB KVM receiver) run: cargo test --features usb-kvm --bin souveraine-usb-kvm - name: cargo clippy run: cargo clippy -- -D warnings # Advisory, deliberately. Turning this on for the first time surfaced 9 # pre-existing warnings in code clippy had never seen (dead # `update_sensors`, unused re-exports in device_state, a nul-terminated # string built by hand). None are from the change that added this step, # and blocking the phone's only shipping path on them would be the wrong # trade. Read it, burn the list down, then make it -D warnings and hard. - name: cargo clippy (sessiond) continue-on-error: true run: cargo clippy --features sessiond --bin souveraine-sessiond -- -D warnings - name: cargo clippy (USB KVM receiver) run: cargo clippy --features usb-kvm --bin souveraine-usb-kvm -- -D warnings no-ai-attribution: runs-on: ubuntu-latest steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 - name: Check commit messages for AI attribution run: | if [ "${{ github.event_name }}" = "pull_request" ]; then RANGE="${{ github.event.pull_request.base.sha }}..${{ github.sha }}" else RANGE="${{ github.event.before }}..${{ github.sha }}" if [ "${{ github.event.before }}" = "0000000000000000000000000000000000000000" ]; then RANGE="HEAD~10..HEAD" fi fi # CO assembled from fragments so this guard file does not itself trip # the public-branch pre-commit scanner (which bans the literal token). CO="Co-Authored""-By:" PATTERNS="${CO}.*[Cc]laude|${CO}.*OpenAI|${CO}.*ChatGPT|${CO}.*Copilot|${CO}.*Letta|${CO}.*Cursor|Generated by|Generated with|AI-assisted|Auto-generated by" FAIL=0 while IFS= read -r msg; do if echo "$msg" | grep -qiE "$PATTERNS"; then echo "::error::AI attribution found in commit: $msg" FAIL=1 fi done < <(git log --format='%s%n%b' $RANGE 2>/dev/null) if [ "$FAIL" -eq 1 ]; then echo "::error::Commits contain AI attribution lines. Remove them before merging." exit 1 fi echo "No AI attribution found in commits." action-pins: runs-on: ubuntu-latest steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Check for floating action refs run: | if grep -rE 'uses:.*@(v[0-9]+|stable|main|master)(\s|$)' .gitea/workflows/; then echo "::error::Floating action refs found — pin every action to a commit SHA" exit 1 fi echo "All action refs are SHA-pinned." # Phone artifact on green. Runs on the ArchDev build node (host mode, label # archdev) where the aarch64 sysroot lives — no docker, no node, plain shell. # Publishes the cross-built binary to a rolling `edge` prerelease; the phone # updates itself from there instead of waiting on a laptop scp.