feat(c-sdk): optional version/size fast-path and concurrent block rea… #751
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| # Cancel superseded runs on the same ref (e.g. rapid pushes to a PR). | |
| concurrency: | |
| group: ci-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| # Least-privilege default token. | |
| permissions: | |
| contents: read | |
| env: | |
| CARGO_TERM_COLOR: always | |
| # Fail the build on any warning across the whole workspace. | |
| RUSTFLAGS: "-D warnings" | |
| RUSTDOCFLAGS: "-D warnings" | |
| jobs: | |
| fmt: | |
| name: rustfmt | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install toolchain (rustfmt) | |
| run: rustup component add rustfmt | |
| - name: Check formatting | |
| run: cargo fmt --all --check | |
| clippy: | |
| name: clippy | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install toolchain (clippy) | |
| run: rustup component add clippy | |
| - name: Install protoc | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Lint | |
| run: cargo clippy --workspace --all-targets --all-features | |
| test: | |
| name: test | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install protoc | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Build | |
| run: cargo build --workspace --all-targets --all-features --locked | |
| - name: Test | |
| run: cargo test --workspace --all-features --locked | |
| fuse-mount: | |
| name: fuse mount e2e | |
| runs-on: ubuntu-latest | |
| # The read-path unit/integration tests never touch the kernel (they use mock | |
| # TCP servers). This job mounts a real TalonFuse on /dev/fuse and reads a | |
| # file back through the kernel, asserting byte-exactness end to end — the one | |
| # layer only a real mount can cover. GitHub's Linux runners provide an | |
| # accessible /dev/fuse; macOS and restricted sandboxes do not, which is why | |
| # the test is #[ignore]d and gated behind the `mount` feature by default. | |
| env: | |
| # Turn a missing/unusable /dev/fuse into a hard failure here, so this job | |
| # can never pass without actually exercising the kernel mount path. | |
| TALON_REQUIRE_FUSE: "1" | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Capture the FUSE environment | |
| # /dev/fuse existing is necessary but not sufficient (#405). Capture | |
| # everything that can make an unprivileged mount fail, so a failing run | |
| # is diagnosable from its own log rather than from a second run. | |
| run: | | |
| if [ ! -e /dev/fuse ]; then | |
| echo "::error::/dev/fuse is missing on this runner; the FUSE mount test cannot run" | |
| exit 1 | |
| fi | |
| echo "--- identity (root would bypass fusermount3 entirely) ---" | |
| id | |
| echo "--- /dev/fuse ---" | |
| ls -l /dev/fuse | |
| echo "--- fusermount3 on PATH, and every copy of it ---" | |
| ls -l "$(command -v fusermount3)" 2>/dev/null || echo "(none on PATH)" | |
| ls -l /usr/bin/fusermount3 /usr/local/bin/fusermount3 2>/dev/null || true | |
| echo "--- /etc/fuse.conf ---" | |
| cat /etc/fuse.conf 2>/dev/null || echo "(absent)" | |
| echo "--- apparmor ---" | |
| aa-status --enabled 2>/dev/null && echo "apparmor enabled" || echo "apparmor not enabled or unavailable" | |
| - name: Ensure an unprivileged FUSE mount is possible | |
| # Some runner images carry a second fusermount3 in /usr/local/bin, owned | |
| # by the runner user and without the setuid bit, which shadows the | |
| # system helper on PATH. An unprivileged process invoking it cannot | |
| # mount, which is #405: every mount test then fails with EPERM in the | |
| # same second while /dev/fuse looks perfectly healthy. | |
| # | |
| # Captured from a failing runner: | |
| # -rwxrwxrwx 1 runner runner /usr/local/bin/fusermount3 | |
| # against a passing one: | |
| # -rwsr-xr-x 1 root root /usr/bin/fusermount3 | |
| # | |
| # Remove the shadow rather than chmod-ing it. Adding setuid to a | |
| # runner-writable binary would be worse than the bug, and removing it | |
| # keeps the job exercising the real system helper -- which is the only | |
| # reason this test is worth running. | |
| run: | | |
| shadow=/usr/local/bin/fusermount3 | |
| if [ -e "$shadow" ] && [ ! -u "$shadow" ]; then | |
| echo "removing non-setuid $shadow which shadows the system helper (#405)" | |
| sudo rm -f "$shadow" | |
| hash -r 2>/dev/null || true | |
| fi | |
| helper="$(command -v fusermount3 || true)" | |
| if [ -z "$helper" ] || [ ! -u "$helper" ]; then | |
| echo "::error::no setuid fusermount3 on PATH (found: ${helper:-none}); unprivileged mounts cannot work" | |
| ls -l "$helper" 2>/dev/null || true | |
| exit 1 | |
| fi | |
| ls -l "$helper" | |
| # pjdfstest mounts with allow_other (#419), which needs this enabled. | |
| if ! grep -q '^user_allow_other' /etc/fuse.conf 2>/dev/null; then | |
| echo user_allow_other | sudo tee -a /etc/fuse.conf >/dev/null | |
| fi | |
| grep '^user_allow_other' /etc/fuse.conf | |
| - name: Install protoc | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Run the real-kernel mount test | |
| run: >- | |
| cargo test -p talon-fuse --features mount --test mount_e2e --locked | |
| -- --ignored --nocapture | |
| docs: | |
| name: doc | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install protoc | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Build docs | |
| run: cargo doc --workspace --no-deps --all-features | |
| docs-book: | |
| name: mdbook build | |
| runs-on: ubuntu-latest | |
| # Ensures the mdBook documentation site always builds. Deployment to GitHub | |
| # Pages happens separately (docs.yml) only on merge to main. | |
| env: | |
| MDBOOK_VERSION: "0.4.52" | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Install mdBook | |
| run: cargo install mdbook --version ${MDBOOK_VERSION} --locked | |
| - name: Build the book | |
| run: mdbook build docs/book | |
| config-docs: | |
| name: reference docs drift | |
| runs-on: ubuntu-latest | |
| # The configuration and REST API references are generated from the code / | |
| # OpenAPI spec. Fail if a committed copy is stale so docs cannot drift. | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install protoc | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Configuration reference drift | |
| run: | | |
| cargo run -q -p talon-coordinator --features etcd,kubernetes \ | |
| --bin talon-gen-config-docs > /tmp/config-ref.md | |
| if ! diff -u docs/reference/configuration.md /tmp/config-ref.md; then | |
| echo "::error::docs/reference/configuration.md is stale; run 'just gen-config-docs'" | |
| exit 1 | |
| fi | |
| - name: REST API reference drift | |
| run: | | |
| cargo run -q -p talon-coordinator --bin talon-gen-api-docs > /tmp/api-ref.md | |
| if ! diff -u docs/reference/rest-api.md /tmp/api-ref.md; then | |
| echo "::error::docs/reference/rest-api.md is stale; run 'just gen-api-docs'" | |
| exit 1 | |
| fi | |
| docs-quality: | |
| name: docs quality | |
| runs-on: ubuntu-latest | |
| # Documentation hygiene: spelling (typos) and links (lychee). Config lives | |
| # in typos.toml and lychee.toml; run the same checks locally via | |
| # `just spell` and `just linkcheck`. | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Spell check | |
| uses: crate-ci/typos@master | |
| - name: Link check | |
| # Offline: validate internal / relative links only. External URLs are | |
| # not fetched, so a slow or rate-limited third-party site (e.g. a | |
| # timeout to etcd.io) can never turn the gate red on a false negative. | |
| uses: lycheeverse/lychee-action@v2 | |
| with: | |
| args: >- | |
| --offline --no-progress | |
| README.md DESIGN.md CONTRIBUTING.md BENCHMARKS.md | |
| 'docs/**/*.md' '.github/**/*.md' | |
| fail: true | |
| etcd-contract: | |
| name: etcd backend contract | |
| runs-on: ubuntu-latest | |
| # Exercises the production etcd ClusterStateStore backend against a real | |
| # ephemeral etcd, as required by the state-store contract. etcd is launched | |
| # explicitly rather than as a service container because that image's | |
| # healthcheck is unreliable on GitHub-hosted runners. | |
| env: | |
| ETCD_VERSION: v3.5.16 | |
| TALON_ETCD_TEST_ENDPOINT: 127.0.0.1:2379 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install protoc | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - name: Start ephemeral etcd | |
| run: | | |
| curl -fsSL -o /tmp/etcd.tar.gz \ | |
| "https://github.com/etcd-io/etcd/releases/download/${ETCD_VERSION}/etcd-${ETCD_VERSION}-linux-amd64.tar.gz" | |
| tar xzf /tmp/etcd.tar.gz -C /tmp | |
| ETCD_DIR="/tmp/etcd-${ETCD_VERSION}-linux-amd64" | |
| "$ETCD_DIR/etcd" --data-dir /tmp/etcd-data \ | |
| --listen-client-urls http://127.0.0.1:2379 \ | |
| --advertise-client-urls http://127.0.0.1:2379 & | |
| echo "ETCD_PID=$!" >> "$GITHUB_ENV" | |
| for i in $(seq 1 30); do | |
| if "$ETCD_DIR/etcdctl" --endpoints=127.0.0.1:2379 endpoint health; then | |
| exit 0 | |
| fi | |
| sleep 1 | |
| done | |
| echo "etcd did not become healthy" >&2 | |
| exit 1 | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Run etcd backend contract tests | |
| run: >- | |
| cargo test -p talon-coordinator | |
| --features etcd,state-store-testkit | |
| --test etcd_contract --locked | |
| - name: Run etcd metadata-store contract tests | |
| # Same ephemeral etcd, different store. ADR 0003 §7 keeps TMS and | |
| # ClusterStateStore as separate abstractions under separate prefixes, | |
| # and one of these tests asserts the two cannot collide. | |
| run: >- | |
| cargo test -p talon-metadata | |
| --features etcd | |
| --test etcd_backend --locked | |
| docker-build: | |
| name: docker image build | |
| runs-on: ubuntu-latest | |
| # Smoke-build every container image on PRs (no push) so a broken Dockerfile | |
| # fails CI. A merge to main runs the real, publishing build in | |
| # release-images.yml instead — running both would double the most expensive | |
| # job in the repo for no extra signal, so this job is PR-only. | |
| if: github.event_name == 'pull_request' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: docker/setup-buildx-action@v3 | |
| - name: Validate docker-compose | |
| run: | | |
| docker compose config --quiet | |
| docker compose --profile ha config --quiet | |
| # The latency lab is a standalone stack; validate it parses too. | |
| docker compose -f deploy/testenv/docker-compose.yml config --quiet | |
| docker compose -f deploy/testenv/docker-compose.yml --profile tools config --quiet | |
| # The builds read the main-seeded layer cache (written by | |
| # release-images.yml on every merge) but do not write. This sacrifices | |
| # layer reuse between pushes of one PR (entries written from a PR are | |
| # only readable within that PR) to keep mode=max exports from churning | |
| # the repository's 10GB Actions cache quota, which is already saturated | |
| # by the rust-cache entries every other job depends on. | |
| - name: Build coordinator image | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: deploy/docker/coordinator.Dockerfile | |
| push: false | |
| cache-from: type=gha,scope=coordinator | |
| - name: Build worker image | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: deploy/docker/worker.Dockerfile | |
| push: false | |
| cache-from: type=gha,scope=worker | |
| - name: Build fuse image | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: deploy/docker/fuse.Dockerfile | |
| push: false | |
| cache-from: type=gha,scope=fuse | |
| - name: Build gateway image | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: deploy/docker/gateway.Dockerfile | |
| push: false | |
| cache-from: type=gha,scope=gateway | |
| helm: | |
| name: helm chart | |
| runs-on: ubuntu-latest | |
| # Lint and render the Talon chart across every state backend so a broken | |
| # template or invalid values fails CI. No cluster is required — helm renders | |
| # locally and we structurally validate the output. | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Helm | |
| uses: azure/setup-helm@v4 | |
| with: | |
| version: v3.16.3 | |
| - name: Lint (all backends) | |
| run: | | |
| for be in memory kubernetes etcd; do | |
| rp=3; [ "$be" = memory ] && rp=1 | |
| echo "::group::lint $be" | |
| helm lint deploy/helm/talon --strict \ | |
| --set coordinator.backend="$be" --set coordinator.replicas="$rp" | |
| echo "::endgroup::" | |
| done | |
| - name: Render (all backends) and validate YAML | |
| run: | | |
| for be in memory kubernetes etcd; do | |
| rp=3; [ "$be" = memory ] && rp=1 | |
| echo "::group::template $be" | |
| helm template t deploy/helm/talon \ | |
| --set coordinator.backend="$be" --set coordinator.replicas="$rp" \ | |
| | python3 -c "import sys,yaml; list(yaml.safe_load_all(sys.stdin))" | |
| echo "::endgroup::" | |
| done | |
| - name: Reject invalid configurations | |
| run: | | |
| if helm template t deploy/helm/talon --set coordinator.backend=redis >/dev/null 2>&1; then | |
| echo "::error::unknown backend should have failed"; exit 1 | |
| fi | |
| if helm template t deploy/helm/talon \ | |
| --set coordinator.backend=memory --set coordinator.replicas=3 >/dev/null 2>&1; then | |
| echo "::error::memory backend with HA should have failed"; exit 1 | |
| fi | |
| s3-e2e: | |
| name: s3 backend and gateway e2e (localstack) | |
| runs-on: ubuntu-latest | |
| # Exercises the real S3Backend (SigV4 signing + path-style endpoint) against | |
| # LocalStack, reading bytes an object actually contains. The test skips when | |
| # TALON_S3_TEST_ENDPOINT is unset; this job sets it after seeding the bucket. | |
| services: | |
| localstack: | |
| image: localstack/localstack:3.8 | |
| ports: | |
| - 4566:4566 | |
| env: | |
| SERVICES: s3 | |
| options: >- | |
| --health-cmd "curl -sf http://localhost:4566/_localstack/health || exit 1" | |
| --health-interval 5s --health-timeout 5s --health-retries 20 | |
| env: | |
| AWS_ACCESS_KEY_ID: test | |
| AWS_SECRET_ACCESS_KEY: test | |
| AWS_DEFAULT_REGION: us-east-1 | |
| TALON_S3_TEST_ENDPOINT: http://127.0.0.1:4566 | |
| TALON_S3_TEST_BUCKET: talon-e2e | |
| TALON_S3_TEST_KEY: e2e/object.bin | |
| TALON_S3_TEST_REGION: us-east-1 | |
| TALON_S3_SDK_PYTHON: python | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.11" | |
| - name: Install protoc | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - name: Install S3 client libraries | |
| run: python -m pip install boto3==1.40.0 minio==7.2.16 | |
| - name: Seed the bucket with a deterministic object | |
| run: | | |
| # 4096 bytes where byte i == i % 251 (matches the test's expectation). | |
| python3 - <<'PY' | |
| data = bytes((i % 251) for i in range(4096)) | |
| open("/tmp/object.bin", "wb").write(data) | |
| PY | |
| aws --endpoint-url http://127.0.0.1:4566 s3 mb s3://talon-e2e | |
| aws --endpoint-url http://127.0.0.1:4566 s3 cp /tmp/object.bin s3://talon-e2e/e2e/object.bin | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Run the S3 backend e2e test | |
| run: cargo test -p talon-backend --test s3_e2e --locked -- --nocapture | |
| - name: Run the S3 SDK gateway conformance test | |
| run: cargo test -p talon-gateway --test s3_sdk_e2e --locked -- --nocapture | |
| gcs-e2e: | |
| name: gcs backend e2e (fake-gcs) | |
| runs-on: ubuntu-latest | |
| # Exercises the real GcsBackend (bearer auth + endpoint override) against | |
| # fake-gcs-server, reading bytes an object actually contains. The test skips | |
| # when TALON_GCS_TEST_ENDPOINT is unset; this job sets it after seeding. | |
| # fake-gcs is launched explicitly (docker run) rather than as a service | |
| # container so we can pass `-scheme http` for a plaintext endpoint. | |
| env: | |
| TALON_GCS_TEST_ENDPOINT: http://127.0.0.1:4443 | |
| TALON_GCS_TEST_BUCKET: talon-e2e | |
| TALON_GCS_TEST_KEY: e2e/object.bin | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install protoc | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - name: Start fake-gcs-server and seed a deterministic object | |
| run: | | |
| docker run -d --name fake-gcs -p 4443:4443 \ | |
| fsouza/fake-gcs-server:1.49 \ | |
| -scheme http -port 4443 -public-host 127.0.0.1:4443 | |
| # Wait for it to answer. | |
| for i in $(seq 1 30); do | |
| if curl -sf http://127.0.0.1:4443/storage/v1/b >/dev/null 2>&1; then break; fi | |
| sleep 1 | |
| done | |
| # 4096 bytes where byte i == i % 251 (matches the test's expectation). | |
| python3 -c "open('/tmp/object.bin','wb').write(bytes(i%251 for i in range(4096)))" | |
| curl -sf -X POST "http://127.0.0.1:4443/storage/v1/b?project=talon" \ | |
| -H 'Content-Type: application/json' -d '{"name":"talon-e2e"}' || true | |
| curl -sf -X POST \ | |
| "http://127.0.0.1:4443/upload/storage/v1/b/talon-e2e/o?uploadType=media&name=e2e/object.bin" \ | |
| -H 'Content-Type: application/octet-stream' \ | |
| --data-binary @/tmp/object.bin | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Run the GCS e2e test | |
| run: cargo test -p talon-backend --test gcs_e2e --locked -- --nocapture | |
| azure-e2e: | |
| name: azure backend and gateway e2e (azurite) | |
| runs-on: ubuntu-latest | |
| # Exercises the real AzureBackend (Shared Key signing + path-style endpoint) | |
| # against Azurite, reading bytes an object actually contains. The test skips | |
| # when TALON_AZURE_TEST_ENDPOINT is unset; this job sets it after seeding. | |
| # Azurite is launched explicitly (docker run) so we can pass | |
| # --skipApiVersionCheck: the runner's az CLI sends a newer API version than | |
| # the pinned Azurite supports, which is only relevant to seeding. | |
| env: | |
| TALON_AZURE_TEST_ENDPOINT: http://127.0.0.1:10000 | |
| TALON_AZURE_TEST_CONTAINER: talon-e2e | |
| TALON_AZURE_TEST_KEY: e2e/object.bin | |
| TALON_AZURE_SDK_PYTHON: python | |
| # Azurite's well-known dev connection string (public emulator values). | |
| AZURE_STORAGE_CONNECTION_STRING: "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;" | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.11" | |
| - name: Install protoc | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - name: Install the official Azure Storage SDK | |
| run: python -m pip install azure-storage-blob==12.26.0 | |
| - name: Start Azurite and seed a deterministic object | |
| run: | | |
| docker run -d --name azurite -p 10000:10000 \ | |
| mcr.microsoft.com/azure-storage/azurite:3.33.0 \ | |
| azurite-blob --blobHost 0.0.0.0 --blobPort 10000 --skipApiVersionCheck | |
| # Wait for the blob endpoint to answer. | |
| for i in $(seq 1 30); do | |
| if curl -sf http://127.0.0.1:10000/devstoreaccount1 >/dev/null 2>&1; then break; fi | |
| sleep 1 | |
| done | |
| # 4096 bytes where byte i == i % 251 (matches the test's expectation). | |
| python3 -c "open('/tmp/object.bin','wb').write(bytes(i%251 for i in range(4096)))" | |
| az storage container create --name talon-e2e | |
| az storage blob upload --container-name talon-e2e \ | |
| --name e2e/object.bin --file /tmp/object.bin --overwrite | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Run the Azure backend e2e test | |
| run: cargo test -p talon-backend --test azure_e2e --locked -- --nocapture | |
| - name: Run the Azure SDK gateway conformance test | |
| run: cargo test -p talon-gateway --test azure_sdk_e2e --locked -- --nocapture | |
| python-client: | |
| name: python client | |
| runs-on: ubuntu-latest | |
| # Builds the wheel and drives it against a real coordinator, worker, and | |
| # blob origin. Mocks would only assert that the mocks behave as written; the | |
| # value of the binding is that it exercises the real protocol path. | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: Swatinem/rust-cache@v2 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.11" | |
| - name: Install build and test tooling | |
| run: | | |
| # protoc compiles talon-worker's WAL record schema and the etcd | |
| # client's generated code; both binaries below need it. | |
| sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| python -m pip install --upgrade maturin pytest | |
| - name: Build the release binaries the tests drive | |
| run: | | |
| cargo build --release --locked \ | |
| -p talon-worker --bin talon-worker \ | |
| -p talon-coordinator --bin talon-coordinator | |
| - name: Build and install the wheel | |
| run: | | |
| maturin build --release --manifest-path clients/python/Cargo.toml --out dist | |
| python -m pip install --force-reinstall dist/*.whl | |
| - name: Run the client tests | |
| run: python -m pytest clients/python/tests/ -v | |
| java-client: | |
| name: java client | |
| runs-on: ubuntu-latest | |
| # Two suites: conformance vectors, which guard the hand-written codec | |
| # against drift from the Rust implementation, and an end-to-end read against | |
| # a live cluster. The first is what makes a second protocol implementation | |
| # maintainable; the second proves it actually reads bytes. | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: Swatinem/rust-cache@v2 | |
| - uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| # Matches the pom's maven.compiler.release, so a source-level feature | |
| # newer than the declared minimum fails here rather than at a user. | |
| java-version: "17" | |
| - name: Install protoc | |
| # java_client_e2e.sh builds talon-worker, whose build script compiles | |
| # the WAL record schema. | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - name: Run conformance vectors and the end-to-end suite | |
| run: scripts/java_client_e2e.sh | |
| bench: | |
| name: bench (informational) | |
| runs-on: ubuntu-latest | |
| # Never blocks a merge: shared runners are too noisy for absolute-time | |
| # gating. This posts the baseline diff for visibility only. | |
| continue-on-error: true | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Benchmark check vs committed baseline | |
| id: bench | |
| run: | | |
| python3 scripts/bench.py check main --soft | tee bench-report.md | |
| - name: Publish report to job summary | |
| if: always() | |
| run: cat bench-report.md >> "$GITHUB_STEP_SUMMARY" | |
| coverage: | |
| name: coverage (informational) | |
| runs-on: ubuntu-latest | |
| # Informational. The workspace sits around 81% line coverage; the value of | |
| # this job is making the *per-file* numbers visible so gaps get noticed | |
| # (a new module landing at 0%, a rewrite dropping a file to half), not | |
| # gating on a single aggregate. A threshold can follow once there is a | |
| # baseline to argue from. | |
| continue-on-error: true | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install protoc | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - name: Install toolchain (llvm-tools) | |
| run: rustup component add llvm-tools-preview | |
| - uses: Swatinem/rust-cache@v2 | |
| - uses: taiki-e/install-action@cargo-llvm-cov | |
| - name: Measure coverage | |
| run: cargo llvm-cov --workspace --all-features --summary-only | tee coverage.txt | |
| - name: Publish report to job summary | |
| if: always() | |
| run: | | |
| { | |
| echo '### Coverage' | |
| echo '```' | |
| cat coverage.txt | |
| echo '```' | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| audit: | |
| name: dependency advisories | |
| runs-on: ubuntu-latest | |
| # Blocking, unlike coverage: this has a crisp pass/fail. A crate in the tree | |
| # either carries an unacknowledged RUSTSEC advisory or it does not. Known | |
| # ones are acknowledged with a written justification in deny.toml. | |
| # | |
| # A nightly run lives in audit-schedule.yml: an advisory can be published | |
| # against an already-merged crate, so the check needs a heartbeat that does | |
| # not depend on someone opening a PR. | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: taiki-e/install-action@cargo-deny | |
| - name: Check advisories, bans, and sources | |
| run: cargo deny check advisories bans sources |