Skip to content

Add Dialogue feature specification + deferred-specs policy (#281) #391

Add Dialogue feature specification + deferred-specs policy (#281)

Add Dialogue feature specification + deferred-specs policy (#281) #391

Workflow file for this run

name: CI
on:
pull_request:
branches: [main]
push:
branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
changes:
name: Detect changes
runs-on: ubuntu-latest
outputs:
rust: ${{ steps.filter.outputs.rust }}
swift: ${{ steps.filter.outputs.swift }}
proto: ${{ steps.filter.outputs.proto }}
docker: ${{ steps.filter.outputs.docker }}
steps:
- uses: actions/checkout@v6
- uses: dorny/paths-filter@v4
id: filter
with:
filters: |
rust:
- 'runner/**'
- 'proto/**'
swift:
- 'MacApp/**'
- 'proto/**'
proto:
- 'proto/**'
docker:
- 'runner/Dockerfile'
- 'runner/Dockerfile.claude'
- 'docker-compose.yml'
rust:
name: Rust — fmt / clippy / test / build
needs: changes
if: needs.changes.outputs.rust == 'true'
runs-on: ubuntu-latest
env:
SQLX_OFFLINE: 'true'
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt
- uses: Swatinem/rust-cache@v2
with:
workspaces: runner
- name: Install protobuf compiler
run: sudo apt-get update && sudo apt-get install -y protobuf-compiler
- name: Format check
run: cargo fmt --check
working-directory: runner
- name: Clippy (deny warnings, pedantic)
run: cargo clippy --all-targets --all-features -- -D warnings
working-directory: runner
- name: Check for unsafe code
run: |
# Count unsafe blocks — should be minimal and justified
unsafe_count=$(grep -r "unsafe" runner/src/ --include="*.rs" -c 2>/dev/null || echo "0")
echo "Unsafe blocks found: $unsafe_count"
# Don't fail, just report — some unsafe is necessary for PTY/FFI
- name: Tests
run: cargo test
working-directory: runner
- name: Build release
run: cargo build --release
working-directory: runner
security:
name: Rust — cargo audit
needs: changes
if: needs.changes.outputs.rust == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
workspaces: runner
- name: Install cargo-audit
run: cargo install cargo-audit --locked
- name: Audit dependencies
run: cargo audit
working-directory: runner
swift:
name: Swift — build / test
needs: changes
if: needs.changes.outputs.swift == 'true'
runs-on: macos-26
steps:
- uses: actions/checkout@v6
- name: Select Xcode
run: sudo xcode-select -s /Applications/Xcode_26.4.app
- name: Install SwiftLint
run: brew install swiftlint
- name: SwiftLint
run: cd MacApp && swiftlint lint --strict --reporter github-actions-logging
# TODO: Add periphery for dead code detection
# brew install peripheryapp/periphery/periphery
# periphery scan --project MacApp/Relay.xcodeproj --schemes Relay --targets Relay
- name: Build
run: |
xcodebuild build \
-project MacApp/Relay.xcodeproj \
-scheme Relay \
-destination 'platform=macOS,arch=arm64' \
CODE_SIGN_IDENTITY=- \
| xcpretty || true
- name: Test
run: |
xcodebuild test \
-project MacApp/Relay.xcodeproj \
-scheme Relay \
-destination 'platform=macOS,arch=arm64' \
CODE_SIGN_IDENTITY=- \
| xcpretty || true
continue-on-error: true
proto:
name: Proto — buf lint
needs: changes
if: needs.changes.outputs.proto == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: bufbuild/buf-setup-action@v1
- name: Lint
run: buf lint proto/
- name: Breaking change detection
# Compare against the last pushed state on main to catch breaking changes in PRs.
# On push to main this step is skipped (no base to compare against in a clean checkout).
if: github.event_name == 'pull_request'
run: buf breaking proto/ --against "https://github.com/${{ github.repository }}.git#branch=main,subdir=proto"
docker:
name: Docker — build (no push)
needs: changes
if: needs.changes.outputs.docker == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: docker/setup-buildx-action@v4
- name: Build runner image
uses: docker/build-push-action@v7
with:
context: .
file: runner/Dockerfile
platforms: linux/amd64
push: false
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build Claude image (if exists)
if: hashFiles('runner/Dockerfile.claude') != ''
uses: docker/build-push-action@v7
with:
context: .
file: runner/Dockerfile.claude
platforms: linux/amd64
push: false
cache-from: type=gha
cache-to: type=gha,mode=max
# Summary job: branch protection watches only this single check.
# GitHub treats skipped jobs as "not required to pass", so any job that ran
# and failed will surface here via the needs context result values.
ci:
name: CI
if: always()
needs: [rust, security, swift, proto, docker]
runs-on: ubuntu-latest
steps:
- name: Require all triggered jobs to pass
env:
RUST_RESULT: ${{ needs.rust.result }}
SECURITY_RESULT: ${{ needs.security.result }}
SWIFT_RESULT: ${{ needs.swift.result }}
PROTO_RESULT: ${{ needs.proto.result }}
DOCKER_RESULT: ${{ needs.docker.result }}
run: |
failed=()
for job in rust security swift proto docker; do
result_var="${job^^}_RESULT"
result="${!result_var}"
if [[ "$result" == "failure" || "$result" == "cancelled" ]]; then
failed+=("$job ($result)")
fi
done
if [[ ${#failed[@]} -gt 0 ]]; then
echo "Failed jobs: ${failed[*]}"
exit 1
fi
echo "All triggered jobs passed or were skipped."