name: ci
on:
workflow_dispatch:
push:
branches:
- main
tags:
- "v*"
pull_request:
permissions:
contents: read
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
msrv:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: 1.88.0
- uses: Swatinem/rust-cache@v2
- name: cargo check --no-default-features (msrv)
run: cargo check --no-default-features
- name: cargo check --features default (msrv)
run: cargo check --features default
- name: cargo test --lib --features default (msrv)
run: cargo test --lib --features default
check:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
rust: [stable, nightly]
profile:
- { name: no-default-features, args: "--no-default-features" }
- { name: default-features, args: "--features default" }
- { name: all-features, args: "--all-features" }
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
- name: cargo check (${{ matrix.profile.name }})
run: cargo check ${{ matrix.profile.args }}
- name: cargo test --lib (${{ matrix.profile.name }})
run: cargo test --lib ${{ matrix.profile.args }}
- name: cargo build --example suite (stable ubuntu)
if: matrix.os == 'ubuntu-latest' && matrix.rust == 'stable'
run: |
cargo build --example pg_to_stdout --features postgres
cargo build --example postgres_to_otel --features postgres,metrics
cargo build --example sqlserver_to_otel --features sqlserver,metrics
cargo build --example regex_filter_transform
cargo build --example uppercase_transform
quality:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
rust: [stable, nightly]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
- name: cargo fmt --check
run: cargo fmt --check
- name: cargo clippy --all-targets --all-features -- -D warnings
run: cargo clippy --all-targets --all-features -- -D warnings
- name: cargo doc --all-features --no-deps
run: cargo doc --all-features --no-deps
env:
RUSTDOCFLAGS: "-D warnings"
transport-security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
- uses: Swatinem/rust-cache@v2
- name: cargo test --lib --features postgres,tls
run: cargo test --lib --features postgres,tls
- name: cargo test --lib --features mysql,tls
run: cargo test --lib --features mysql,tls
- name: cargo test --lib --features sqlserver,tls
run: cargo test --lib --features sqlserver,tls
policy-gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: install policy gate dependencies
run: |
sudo apt-get update
sudo apt-get install -y ripgrep jq
- name: policy gates (schema + deprecated + workflow drift)
run: bash scripts/ci-policy-gate.sh
release-evidence-benchmark-preflight:
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
needs:
- msrv
- check
- quality
- transport-security
- policy-gate
- correctness-smoke
- reliability-core
- latency-core
- integration-postgres
- integration-postgres-encryption
- integration-reliability
- integration-mysql
- integration-mysql-encryption
- integration-mariadb
- integration-mariadb-encryption
- integration-sqlserver
- integration-sqlserver-encryption
runs-on: ubuntu-latest
env:
BENCHMARK_STRICT: "1"
BENCHMARK_REQUIRE_HISTORICAL_BASELINE: "1"
BENCHMARK_ENFORCE_RELEASE_POLICY: "1"
CRITERION_BASELINE: ci-baseline
BENCHMARK_CRITICAL_GROUP_PREFIXES: "quality_gates wasm_transform"
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: install benchmark gate dependencies
run: |
sudo apt-get update
sudo apt-get install -y ripgrep jq
- name: derive benchmark baseline inputs
env:
CONFIGURED_BASELINE_COMMIT: ${{ vars.BENCHMARK_BASELINE_COMMIT }}
CONFIGURED_BASELINE_ARTIFACT: ${{ vars.BENCHMARK_BASELINE_ARTIFACT }}
run: |
set -euo pipefail
baseline_commit="${CONFIGURED_BASELINE_COMMIT}"
baseline_artifact="${CONFIGURED_BASELINE_ARTIFACT}"
if [ -z "$baseline_commit" ]; then
baseline_commit="$(git rev-parse HEAD^)"
fi
if [ -z "$baseline_artifact" ]; then
baseline_artifact="commit:${baseline_commit}"
fi
echo "BENCHMARK_BASELINE_COMMIT=$baseline_commit" >> "$GITHUB_ENV"
echo "BENCHMARK_BASELINE_ARTIFACT=$baseline_artifact" >> "$GITHUB_ENV"
- name: release-evidence benchmark preflight
run: bash scripts/ci-benchmark-gate.sh
correctness-smoke:
runs-on: ubuntu-latest
env:
CDC_RS_RUN_DOCKER_TESTS: "1"
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
- uses: Swatinem/rust-cache@v2
- name: pre-pull postgres image (public ecr mirror)
run: bash scripts/ci-pull-relational-images.sh 16-alpine
- name: pre-pull mysql/mariadb/sqlserver images
run: bash scripts/ci-pull-relational-images.sh --relational-smoke
- name: contract compatibility smoke
run: cargo test --test compatibility_contract --all-features
- name: postgres checkpoint durability smoke
run: cargo test --test checkpoint_file_integration --features postgres
- name: postgres process-crash replay smoke
run: cargo test --test runtime_postgres_process_crash_integration --features postgres --bins
- name: reliability data-loss smoke
run: cargo test --test data_loss_detection --features postgres,test-harnesses
- name: mysql connection integration smoke
run: cargo test --test mysql_connection_integration --features mysql
- name: mariadb connection integration smoke
run: cargo test --test mariadb_connection_integration --features mariadb
- name: sqlserver connection integration smoke
run: cargo test --test sqlserver_connection_integration --features sqlserver
- name: mysql process-crash replay smoke
run: cargo test --test runtime_mysql_process_crash_integration --features mysql --bins
- name: mariadb process-crash replay smoke
run: cargo test --test runtime_mariadb_process_crash_integration --features mariadb --bins
- name: sqlserver process-crash replay smoke
run: cargo test --test runtime_sqlserver_process_crash_integration --features sqlserver --bins
reliability-core:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
suite:
- deterministic_replay_failure_fixtures
- deterministic_replay_golden_fixtures
- runtime_health_states
- wasm_conformance_contract
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
- uses: Swatinem/rust-cache@v2
- name: reliability core suite (${{ matrix.suite }})
run: cargo test --test ${{ matrix.suite }} --features postgres,test-harnesses
latency-core:
runs-on: ubuntu-latest
env:
CDC_RS_RUN_DOCKER_TESTS: "1"
LATENCY_GATE_DEFAULT_P95_MS: "500"
LATENCY_GATE_DEFAULT_P99_MS: "1000"
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
- uses: Swatinem/rust-cache@v2
- name: pre-pull postgres image (public ecr mirror)
run: bash scripts/ci-pull-relational-images.sh 16-alpine
- name: connector-backed latency evidence gate (p95/p99)
run: bash scripts/ci-latency-gate.sh
integration-postgres:
runs-on: ubuntu-latest
env:
CDC_RS_RUN_DOCKER_TESTS: "1"
strategy:
fail-fast: false
matrix:
suite:
- runtime_postgres
- postgres_version_matrix
- postgres_snapshot_integration
- postgres_stream_integration
- postgres_handoff_integration
- checkpoint_file_integration
- runtime_postgres_process_crash_integration
- parallel_snapshot_stress_integration
- otel_metrics_integration
- otel_tracing_integration
- snapshot_resumable_integration
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
- uses: Swatinem/rust-cache@v2
- name: pre-pull postgres images (public ecr mirror)
run: |
tags="16-alpine"
if [[ "${{ matrix.suite }}" == "postgres_version_matrix" ]]; then
tags="12-alpine 14-alpine 15-alpine 16-alpine"
fi
bash scripts/ci-pull-relational-images.sh ${tags}
- name: cargo test --test ${{ matrix.suite }}
if: matrix.suite != 'runtime_postgres_process_crash_integration' && matrix.suite != 'otel_metrics_integration' && matrix.suite != 'otel_tracing_integration'
run: cargo test --test ${{ matrix.suite }} --features postgres
- name: cargo test --test ${{ matrix.suite }} (metrics)
if: matrix.suite == 'otel_metrics_integration' || matrix.suite == 'otel_tracing_integration'
run: cargo test --test ${{ matrix.suite }} --features postgres,metrics
- name: cargo test --test runtime_postgres_process_crash_integration (with bins)
if: matrix.suite == 'runtime_postgres_process_crash_integration'
run: cargo test --test runtime_postgres_process_crash_integration --features postgres --bins
integration-postgres-encryption:
runs-on: ubuntu-latest
env:
CDC_RS_RUN_DOCKER_TESTS: "1"
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
- uses: Swatinem/rust-cache@v2
- name: pre-pull postgres images (public ecr mirror)
run: bash scripts/ci-pull-relational-images.sh 16-alpine
- name: cargo test --test runtime_postgres_process_crash_integration --features postgres,encryption --bins
run: cargo test --test runtime_postgres_process_crash_integration --features postgres,encryption --bins
integration-reliability:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
suite:
- data_loss_detection
- deterministic_replay_failure_fixtures
- deterministic_replay_golden_fixtures
- runtime_health_states
- fault_injection_soak_matrix
- wasm_runtime_integration
- wasm_conformance_contract
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
- uses: Swatinem/rust-cache@v2
- name: cargo test --test ${{ matrix.suite }} --features postgres,test-harnesses
run: cargo test --test ${{ matrix.suite }} --features postgres,test-harnesses
integration-mysql:
runs-on: ubuntu-latest
env:
CDC_RS_RUN_DOCKER_TESTS: "1"
strategy:
fail-fast: false
matrix:
suite:
- mysql_version_matrix
- mysql_connection_integration
- mysql_snapshot_integration
- mysql_stream_integration
- mysql_handoff_integration
- runtime_mysql_process_crash_integration
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
- uses: Swatinem/rust-cache@v2
- name: cargo test --test ${{ matrix.suite }}
if: matrix.suite != 'runtime_mysql_process_crash_integration'
run: cargo test --test ${{ matrix.suite }} --features mysql
- name: cargo test --test runtime_mysql_process_crash_integration (with bins)
if: matrix.suite == 'runtime_mysql_process_crash_integration'
run: cargo test --test runtime_mysql_process_crash_integration --features mysql --bins
integration-mysql-encryption:
runs-on: ubuntu-latest
env:
CDC_RS_RUN_DOCKER_TESTS: "1"
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
- uses: Swatinem/rust-cache@v2
- name: cargo test --test runtime_mysql_process_crash_integration --features mysql,encryption --bins
run: cargo test --test runtime_mysql_process_crash_integration --features mysql,encryption --bins
integration-mariadb:
runs-on: ubuntu-latest
env:
CDC_RS_RUN_DOCKER_TESTS: "1"
strategy:
fail-fast: false
matrix:
suite:
- mariadb_connection_integration
- mariadb_e2e_integration
- runtime_mariadb_process_crash_integration
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
- uses: Swatinem/rust-cache@v2
- name: cargo test --test ${{ matrix.suite }}
if: matrix.suite != 'runtime_mariadb_process_crash_integration'
run: cargo test --test ${{ matrix.suite }} --features mariadb
- name: cargo test --test runtime_mariadb_process_crash_integration (with bins)
if: matrix.suite == 'runtime_mariadb_process_crash_integration'
run: cargo test --test runtime_mariadb_process_crash_integration --features mariadb --bins
integration-mariadb-encryption:
runs-on: ubuntu-latest
env:
CDC_RS_RUN_DOCKER_TESTS: "1"
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
- uses: Swatinem/rust-cache@v2
- name: cargo test --test runtime_mariadb_process_crash_integration --features mariadb,encryption --bins
run: cargo test --test runtime_mariadb_process_crash_integration --features mariadb,encryption --bins
integration-sqlserver:
runs-on: ubuntu-latest
env:
CDC_RS_RUN_DOCKER_TESTS: "1"
strategy:
fail-fast: false
matrix:
suite:
- sqlserver_version_matrix
- sqlserver_snapshot_integration
- sqlserver_stream_integration
- sqlserver_handoff_integration
- runtime_sqlserver_process_crash_integration
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
- uses: Swatinem/rust-cache@v2
- name: cargo test --test ${{ matrix.suite }}
if: matrix.suite != 'runtime_sqlserver_process_crash_integration'
run: cargo test --test ${{ matrix.suite }} --features sqlserver
- name: cargo test --test runtime_sqlserver_process_crash_integration (with bins)
if: matrix.suite == 'runtime_sqlserver_process_crash_integration'
run: cargo test --test runtime_sqlserver_process_crash_integration --features sqlserver --bins
integration-sqlserver-encryption:
runs-on: ubuntu-latest
env:
CDC_RS_RUN_DOCKER_TESTS: "1"
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
- uses: Swatinem/rust-cache@v2
- name: cargo test --test runtime_sqlserver_process_crash_integration --features sqlserver,encryption --bins
run: cargo test --test runtime_sqlserver_process_crash_integration --features sqlserver,encryption --bins
release-evidence:
if: startsWith(github.ref, 'refs/tags/v')
needs:
- msrv
- check
- quality
- transport-security
- policy-gate
- correctness-smoke
- reliability-core
- latency-core
- integration-postgres
- integration-postgres-encryption
- integration-reliability
- integration-mysql
- integration-mysql-encryption
- integration-mariadb
- integration-mariadb-encryption
- integration-sqlserver
- integration-sqlserver-encryption
runs-on: ubuntu-latest
env:
CDC_RS_RUN_DOCKER_TESTS: "1"
BENCHMARK_STRICT: "1"
BENCHMARK_REQUIRE_HISTORICAL_BASELINE: "1"
BENCHMARK_ENFORCE_RELEASE_POLICY: "1"
CRITERION_BASELINE: ci-baseline
BENCHMARK_CRITICAL_GROUP_PREFIXES: "quality_gates wasm_transform"
LATENCY_GATE_DEFAULT_P95_MS: "500"
LATENCY_GATE_DEFAULT_P99_MS: "1000"
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: install release evidence dependencies
run: |
sudo apt-get update
sudo apt-get install -y ripgrep jq
- name: derive benchmark baseline inputs
env:
CONFIGURED_BASELINE_COMMIT: ${{ vars.BENCHMARK_BASELINE_COMMIT }}
CONFIGURED_BASELINE_ARTIFACT: ${{ vars.BENCHMARK_BASELINE_ARTIFACT }}
run: |
set -euo pipefail
current_tag="${GITHUB_REF_NAME}"
baseline_commit="${CONFIGURED_BASELINE_COMMIT}"
baseline_artifact="${CONFIGURED_BASELINE_ARTIFACT}"
if [ -z "$baseline_commit" ]; then
previous_tag="$(git tag --sort=-v:refname | grep '^v' | grep -Fxv "$current_tag" | head -n 1 || true)"
if [ -n "$previous_tag" ]; then
baseline_commit="$(git rev-list -n 1 "$previous_tag")"
if [ -z "$baseline_artifact" ]; then
baseline_artifact="release-tag:${previous_tag}"
fi
fi
fi
if [ -z "$baseline_commit" ]; then
baseline_commit="$(git rev-parse HEAD^)"
fi
if [ -z "$baseline_artifact" ]; then
baseline_artifact="commit:${baseline_commit}"
fi
echo "BENCHMARK_BASELINE_COMMIT=$baseline_commit" >> "$GITHUB_ENV"
echo "BENCHMARK_BASELINE_ARTIFACT=$baseline_artifact" >> "$GITHUB_ENV"
- name: verify tag matches Cargo.toml version
run: |
TAG="${GITHUB_REF_NAME#v}"
CARGO_VERSION=$(cargo metadata --no-deps --format-version 1 \
| jq -r '.packages[] | select(.name == "rustcdc") | .version')
if [ "$TAG" != "$CARGO_VERSION" ]; then
echo "::error::Tag $GITHUB_REF_NAME does not match Cargo.toml version $CARGO_VERSION"
exit 1
fi
- name: cargo package (dry-run)
run: cargo package --no-verify --all-features
- name: policy gate
run: bash scripts/ci-policy-gate.sh
- name: benchmark policy gate
run: bash scripts/ci-benchmark-gate.sh
- name: full integration matrix evidence
run: bash scripts/run_full_integration_matrix_evidence.sh
- name: upload release-gate evidence artifacts
uses: actions/upload-artifact@v4
with:
name: release-gate-evidence
path: |
target/integration-full-matrix-evidence.txt
target/latency-evidence.txt
target/latency-gate.txt
target/postgres-latency-evidence.json
target/postgres-latency-evidence.md
target/mysql-latency-evidence.json
target/mysql-latency-evidence.md
target/sqlserver-latency-evidence.json
target/sqlserver-latency-evidence.md
target/benchmark-ci-gate*.txt
target/benchmark-ci-env.txt
target/criterion
BENCHMARK_REPORT.md
publish:
if: startsWith(github.ref, 'refs/tags/v')
needs: release-evidence
runs-on: ubuntu-latest
environment: crates-io
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: cargo publish
run: cargo publish --no-verify
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}