runewarp 0.1.0

Runewarp is an ingress tunneling tool for exposing local services without moving TLS termination to the edge. Clients connect out over QUIC, so you can publish services without putting your backend directly on the Internet or leaking your public IP.
Documentation
name: CI

on:
  pull_request:
  push:
    branches:
      - main

permissions:
  contents: read

concurrency:
  group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

jobs:
  workflow-lint:
    name: Workflow lint
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Check out the repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Install actionlint
        run: |
          mkdir -p "$HOME/.local/bin"
          curl -fsSLo actionlint.tar.gz https://github.com/rhysd/actionlint/releases/download/v1.7.8/actionlint_1.7.8_linux_amd64.tar.gz
          echo 'be92c2652ab7b6d08425428797ceabeb16e31a781c07bc388456b4e592f3e36a  actionlint.tar.gz' | sha256sum --check
          tar -xzf actionlint.tar.gz actionlint
          install -m 0755 actionlint "$HOME/.local/bin/actionlint"
          printf '%s\n' "$HOME/.local/bin" >> "$GITHUB_PATH"

      - name: Lint workflows
        run: actionlint -color

  release-metadata:
    name: Release metadata
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Check out the repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Validate release metadata
        run: ./scripts/validate-release-metadata.sh ci

  install-surface-linux:
    name: Install surface (Linux)
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - name: Check out the repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Install Rust toolchain
        run: |
          rustup set profile minimal
          rustup toolchain install stable
          rustup default stable

      - name: Validate Linux cargo install surface
        run: |
          ./scripts/validate-install-surfaces.sh cargo-install \
            --bin-name runewarp \
            --probe-arg --help \
            --expected-text "Usage: runewarp"

  install-surface-macos:
    name: Install surface (macOS)
    runs-on: macos-latest
    timeout-minutes: 30
    steps:
      - name: Check out the repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Install Rust toolchain
        run: |
          rustup set profile minimal
          rustup toolchain install stable
          rustup default stable

      - name: Validate macOS cargo install surface
        run: |
          ./scripts/validate-install-surfaces.sh cargo-install \
            --bin-name runewarp \
            --probe-arg --help \
            --expected-text "Usage: runewarp"

  package-readiness:
    name: Package readiness
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - name: Check out the repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Install Rust toolchain
        run: |
          rustup set profile minimal
          rustup toolchain install stable
          rustup default stable

      - name: Validate package readiness
        run: ./scripts/validate-install-surfaces.sh package-readiness

  rust-contract:
    name: Rust contract
    runs-on: ubuntu-latest
    timeout-minutes: 30
    env:
      CACHE_SCOPE: ${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || format('trusted-{0}', github.ref_name) }}
    steps:
      - name: Check out the repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Restore Rust build cache
        uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
        with:
          path: |
            ~/.cargo/registry/index/
            ~/.cargo/registry/cache/
            ~/.cargo/git/db/
            target/
          key: ${{ runner.os }}-rust-contract-${{ env.CACHE_SCOPE }}-${{ hashFiles('Cargo.lock') }}
          restore-keys: |
            ${{ runner.os }}-rust-contract-${{ env.CACHE_SCOPE }}-

      - name: Install Rust toolchain
        run: |
          rustup set profile minimal
          rustup toolchain install stable --component clippy,rustfmt
          rustup default stable

      - name: Check Rust formatting
        run: cargo fmt --check

      - name: Run Clippy
        run: cargo clippy --all-targets -- -D warnings

      - name: Run Rust tests
        run: cargo test --quiet

      - name: Build documentation
        run: cargo doc --no-deps

  docker-contract:
    name: Docker contract
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - name: Check out the repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Validate Docker image surface
        run: |
          ./scripts/validate-install-surfaces.sh docker-image \
            --probe-arg --help \
            --expected-text "Usage: runewarp" \
            --image-tag runewarp:ci

      - name: Run Docker smoke test
        run: ./examples/docker/smoke.sh

  ci:
    name: CI
    if: always()
    runs-on: ubuntu-latest
    timeout-minutes: 5
    needs:
      - workflow-lint
      - release-metadata
      - install-surface-linux
      - install-surface-macos
      - package-readiness
      - rust-contract
      - docker-contract
    steps:
      - name: Enforce aggregate success
        env:
          WORKFLOW_LINT_RESULT: ${{ needs.workflow-lint.result }}
          RELEASE_METADATA_RESULT: ${{ needs.release-metadata.result }}
          INSTALL_SURFACE_LINUX_RESULT: ${{ needs.install-surface-linux.result }}
          INSTALL_SURFACE_MACOS_RESULT: ${{ needs.install-surface-macos.result }}
          PACKAGE_READINESS_RESULT: ${{ needs.package-readiness.result }}
          RUST_CONTRACT_RESULT: ${{ needs.rust-contract.result }}
          DOCKER_CONTRACT_RESULT: ${{ needs.docker-contract.result }}
        run: |
          for check in \
            "workflow-lint:$WORKFLOW_LINT_RESULT" \
            "release-metadata:$RELEASE_METADATA_RESULT" \
            "install-surface-linux:$INSTALL_SURFACE_LINUX_RESULT" \
            "install-surface-macos:$INSTALL_SURFACE_MACOS_RESULT" \
            "package-readiness:$PACKAGE_READINESS_RESULT" \
            "rust-contract:$RUST_CONTRACT_RESULT" \
            "docker-contract:$DOCKER_CONTRACT_RESULT"; do
            name="${check%%:*}"
            result="${check#*:}"
            if [[ "$result" != "success" ]]; then
              printf 'error: required job %s finished with %s\n' "$name" "$result" >&2
              exit 1
            fi
          done