Files
fips/.github/workflows/ci.yml
T
Johnathan Corgan 9668807ca4 Add Docker sidecar deployment for FIPS
Tailscale-style sidecar pattern: a FIPS container provides mesh
networking, and a companion app container shares its network namespace
via network_mode: service:fips.

Security model:
- iptables enforces strict isolation — the app container can only
  communicate over the FIPS mesh (fd::/8 via fips0)
- No IPv4 access: eth0 restricted to FIPS UDP transport (port 2121)
- No IPv6 on eth0: ip6tables blocks all eth0 IPv6 traffic
- Only fips0 and loopback are reachable from the app container

The sidecar accepts peer configuration via environment variables
(FIPS_NSEC, FIPS_PEER_NPUB, FIPS_PEER_ADDR), so it can be pointed
at any FIPS node without config file generation.

Files:
- testing/sidecar/: Dockerfile, Dockerfile.app, docker-compose.yml,
  entrypoint.sh, .env, resolv.conf, scripts/build.sh
- testing/sidecar/README.md: security model, quick-start, architecture,
  DNS resolution, troubleshooting, production considerations
- testing/sidecar/scripts/test-sidecar.sh: 3-node chain integration
  test verifying link establishment, multi-hop connectivity, and
  network isolation on each app container
- .github/workflows/ci.yml: sidecar integration test matrix entry
2026-02-27 03:02:14 +00:00

282 lines
10 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: CI
on:
push:
branches: ["**"]
pull_request:
workflow_dispatch:
inputs:
skip_integration:
description: "Skip integration tests"
type: boolean
default: false
permissions:
checks: write
contents: read
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
# ─────────────────────────────────────────────────────────────────────────────
# Job 1 Build matrix
#
# Builds on Linux x86_64 and Linux aarch64. macOS and Windows are in a
# separate ci-compat.yml workflow so their failures don't mark this run red.
# ─────────────────────────────────────────────────────────────────────────────
jobs:
build:
name: Build (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
- os: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo registry + build
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-
- name: Build
run: cargo build --release
# Upload the Linux binary so integration jobs can use it without rebuilding
- name: Upload Linux binary
if: matrix.os == 'ubuntu-latest'
uses: actions/upload-artifact@v4
with:
name: fips-linux
path: |
target/release/fips
target/release/fipsctl
retention-days: 1
# ─────────────────────────────────────────────────────────────────────────────
# Job 2 Unit tests
#
# Runs `cargo test` on Linux. Gated on the build matrix completing so we
# don't waste runner time if compilation is broken.
# ─────────────────────────────────────────────────────────────────────────────
test:
name: Unit tests
runs-on: ubuntu-latest
needs: [build]
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo registry + build
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-
- name: Install cargo-nextest
uses: taiki-e/install-action@nextest
- name: Run unit tests
run: cargo nextest run --all --profile ci
- name: Publish test report (Checks tab)
uses: dorny/test-reporter@v2
if: always()
with:
name: Unit Tests
path: target/nextest/ci/junit.xml
reporter: java-junit
fail-on-error: false
- name: Publish test report (run summary)
uses: mikepenz/action-junit-report@v4
if: always()
with:
report_paths: target/nextest/ci/junit.xml
check_name: Unit Tests Summary
fail_on_failure: false
# ─────────────────────────────────────────────────────────────────────────────
# Job 3 Integration tests (static mesh + chaos simulation)
#
# Runs only when both build and test succeed. Each topology / scenario is a
# separate matrix entry so they run in parallel.
#
# Static topologies → build Docker images, start containers, ping-test
# Chaos scenarios → build sim image, run stochastic simulation
# ─────────────────────────────────────────────────────────────────────────────
integration:
name: Integration (${{ matrix.suite }})
runs-on: ubuntu-latest
needs: [build, test]
if: ${{ !inputs.skip_integration }}
strategy:
fail-fast: false
matrix:
include:
# ── Static mesh topologies ─────────────────────────────────────────
- suite: static-mesh
type: static
topology: mesh
- suite: static-chain
type: static
topology: chain
# ── Chaos / stochastic scenarios ───────────────────────────────────
- suite: chaos-smoke-10
type: chaos
scenario: smoke-10
- suite: chaos-10
type: chaos
scenario: chaos-10
- suite: ethernet-mesh
type: chaos
scenario: ethernet-mesh
- suite: ethernet-only
type: chaos
scenario: ethernet-only
- suite: bottleneck-parent
type: chaos
scenario: bottleneck-parent
- suite: cost-avoidance
type: chaos
scenario: cost-avoidance
- suite: cost-mixed-7node
type: chaos
scenario: cost-mixed-7node
- suite: cost-reeval
type: chaos
scenario: cost-reeval
- suite: cost-stability
type: chaos
scenario: cost-stability
- suite: depth-vs-cost
type: chaos
scenario: depth-vs-cost
- suite: mixed-technology
type: chaos
scenario: mixed-technology
# ── Sidecar deployment ──────────────────────────────────────────
- suite: sidecar
type: sidecar
steps:
- uses: actions/checkout@v4
# Fetch the pre-built Linux binary from job 1
- name: Download Linux binary
uses: actions/download-artifact@v4
with:
name: fips-linux
path: _bin
# ── Static topology ────────────────────────────────────────────────────
- name: Install binary (static)
if: matrix.type == 'static'
run: |
chmod +x _bin/fips _bin/fipsctl
cp _bin/fips testing/static/fips
cp _bin/fipsctl testing/static/fipsctl
- name: Generate configs (static)
if: matrix.type == 'static'
run: bash testing/static/scripts/generate-configs.sh ${{ matrix.topology }}
- name: Build Docker images (static)
if: matrix.type == 'static'
run: |
docker compose -f testing/static/docker-compose.yml \
--profile ${{ matrix.topology }} build
- name: Start containers (static)
if: matrix.type == 'static'
run: |
docker compose -f testing/static/docker-compose.yml \
--profile ${{ matrix.topology }} up -d
- name: Run ping test (static)
if: matrix.type == 'static'
run: bash testing/static/scripts/ping-test.sh ${{ matrix.topology }}
- name: Collect logs on failure (static)
if: matrix.type == 'static' && failure()
run: |
docker compose -f testing/static/docker-compose.yml \
--profile ${{ matrix.topology }} logs --no-color
- name: Stop containers (static)
if: matrix.type == 'static' && always()
run: |
docker compose -f testing/static/docker-compose.yml \
--profile ${{ matrix.topology }} down --volumes --remove-orphans
# ── Chaos simulation ───────────────────────────────────────────────────
- name: Install Python deps (chaos)
if: matrix.type == 'chaos'
run: pip3 install --quiet pyyaml jinja2
- name: Install binary (chaos)
if: matrix.type == 'chaos'
run: |
chmod +x _bin/fips _bin/fipsctl
cp _bin/fips testing/chaos/fips
cp _bin/fipsctl testing/chaos/fipsctl
- name: Build chaos Docker image
if: matrix.type == 'chaos'
run: docker build -t fips-chaos:latest testing/chaos
- name: Run chaos scenario
if: matrix.type == 'chaos'
run: bash testing/chaos/scripts/chaos.sh ${{ matrix.scenario }}
- name: Upload sim results on failure (chaos)
if: matrix.type == 'chaos' && failure()
uses: actions/upload-artifact@v4
with:
name: sim-results-${{ matrix.scenario }}
path: testing/chaos/sim-results/
retention-days: 7
# ── Sidecar deployment ──────────────────────────────────────────────
- name: Install binary (sidecar)
if: matrix.type == 'sidecar'
run: |
chmod +x _bin/fips _bin/fipsctl
cp _bin/fips testing/sidecar/fips
cp _bin/fipsctl testing/sidecar/fipsctl
- name: Run sidecar integration test
if: matrix.type == 'sidecar'
run: bash testing/sidecar/scripts/test-sidecar.sh
- name: Collect logs on failure (sidecar)
if: matrix.type == 'sidecar' && failure()
run: |
for node in a b c; do
echo "--- sidecar-${node} logs ---"
docker logs "sidecar-${node}-fips-1" 2>&1 || true
echo ""
done