Skip to content

fix(wire): recover nested file_id and stop doubling reusable fileTabl… #380

fix(wire): recover nested file_id and stop doubling reusable fileTabl…

fix(wire): recover nested file_id and stop doubling reusable fileTabl… #380

Workflow file for this run

name: ci
permissions:
contents: read
on:
push:
branches: [main]
pull_request:
paths-ignore:
- "**.md"
schedule:
- cron: "0 2 * * *"
workflow_dispatch:
inputs:
profile:
description: "Property profile: fast (default) or intensive"
required: false
default: "fast"
jobs:
rust-lint:
runs-on: [self-hosted, preloop-cpane]
timeout-minutes: 20
env:
CARGO_BUILD_JOBS: "6"
RUSTFLAGS: "-C link-arg=-fuse-ld=lld"
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
lfs: false
- uses: dtolnay/rust-toolchain@6bed0761d98439e5a578e2877258200ad565ba87 # stable
with:
toolchain: "1.97"
components: rustfmt,clippy
- name: Install lld linker
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends lld
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
# A failing lint run still primes the cache for the next one; the
# default skips the save step on failure, so nothing is ever stored
# while a break is being fixed.
cache-on-failure: true
- run: cargo fmt --all --check
- run: |
cargo clippy --locked -p preloop-gha-protocol -p preloop-gha-parser -p preloop-gha-expressions -p preloop-cache -p preloop-artifacts -p runner-watch -p preloop-conformance --all-targets -- -D warnings
cargo clippy --locked -p preloop-runner -p preloop-runner-server -p preloop-runner-client -p preloop-dap --all-targets
# nextest does not run doctests; keep them on the lint job (seconds).
- run: cargo test --locked --workspace --doc
env:
RUSTFLAGS: "-A warnings -C link-arg=-fuse-ld=lld"
rust-test:
# Sharded unit/integration suite. Each shard runs 1/4 of the tests (split
# by test-name hash, so no manual bookkeeping) on its own runner; wall
# clock is setup + slowest shard instead of setup + everything.
# NOTE: these display names are load-bearing — the `main` ruleset gates
# on them. Renaming a shard name requires updating the ruleset to match.
name: rust shard ${{ matrix.shard }} of 4
runs-on: [self-hosted, preloop-cpane]
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4]
env:
CARGO_BUILD_JOBS: "6"
PROPTEST_CASES: "8"
RUST_TEST_THREADS: "6"
RUSTFLAGS: "-C link-arg=-fuse-ld=lld"
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
lfs: false
- name: Materialize conformance goldens
run: |
# Only these nine captures are read by workspace tests:
# eight acquirejob parser fixtures plus runner-watch's scenario-07
# replay metadata. Fetch each flow directly instead of the complete
# pinned corpus (which also contains 100+ MB container captures).
version=$(python3 -c 'import tomllib; print(tomllib.load(open("versions.toml", "rb"))["runner_version"])')
git lfs install --local --force
includes=""
for scenario in \
06-multi-step 07-step-failure 08-job-outputs-needs \
10-uses-checkout 11-cache-roundtrip 12-artifact \
13-composite-action 14-annotations 15-oidc-id-token; do
path=".runner-watch/golden/v${version}/${scenario}/flows.jsonl"
includes="${includes:+$includes,}$path"
done
git lfs pull --include="$includes"
for scenario in \
06-multi-step 07-step-failure 08-job-outputs-needs \
10-uses-checkout 11-cache-roundtrip 12-artifact \
13-composite-action 14-annotations 15-oidc-id-token; do
fixture=".runner-watch/golden/v${version}/${scenario}/flows.jsonl"
test -s "$fixture"
if grep -q '^version https://git-lfs.github.com/spec/' "$fixture"; then
echo "LFS fixture was not materialized: $fixture" >&2
exit 1
fi
done
- uses: dtolnay/rust-toolchain@6bed0761d98439e5a578e2877258200ad565ba87 # stable
with:
toolchain: "1.97"
components: rustfmt,clippy
- name: Install lld linker
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends lld
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
# All four shards build the same workspace and differ only in which
# tests they select, so they share one cache entry instead of each
# keying on its own job name and starting cold.
shared-key: rust-test
# Shards fail while a regression is being fixed. The save step is
# skipped on failure by default, so nothing was ever cached and the
# next run recompiled from scratch.
cache-on-failure: true
- name: Install cargo-nextest
run: |
# `cargo install` built nextest from source on every cold cache
# (~300s per shard). Install the published binary, pinned by version
# and verified by digest.
set -euo pipefail
version=0.9.144
case "$(uname -m)" in
x86_64)
asset=linux
digest=8a4f726272b0a1c499bd87ca3978bfbb1a8c20bb08ccf075b9996e2081bd1e1e
;;
aarch64|arm64)
asset=linux-arm
digest=7fecfd431b810c05c589d800524286b8f80ce2fe9fb1fef05caf16d095cea407
;;
*)
echo "no pinned cargo-nextest build for $(uname -m)" >&2
exit 1
;;
esac
archive="$RUNNER_TEMP/cargo-nextest.tar.gz"
curl -fsSL --retry 3 -o "$archive" "https://get.nexte.st/${version}/${asset}"
echo "${digest} ${archive}" | sha256sum -c -
mkdir -p "$HOME/.local/bin"
tar -xzf "$archive" -C "$HOME/.local/bin" cargo-nextest
"$HOME/.local/bin/cargo-nextest" --version
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
- run: cargo nextest run --locked --workspace --partition hash:${{ matrix.shard }}/4
env:
RUSTFLAGS: "-A warnings -C link-arg=-fuse-ld=lld"
property-tests-fast:
runs-on: [self-hosted, preloop-cpane]
timeout-minutes: 30
if: github.event_name != 'schedule'
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@6bed0761d98439e5a578e2877258200ad565ba87 # stable
with:
toolchain: "1.97"
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
cache-on-failure: true
- name: Verify property filters match tests
run: |
# One `--list` pass per crate. Keep each server filter separate so
# removing a property module cannot hide behind a broad match.
server_list=$(PROPTEST_CASES=1 cargo test -p preloop-runner-server -- --list 2>/dev/null)
legacy=$(printf '%s\n' "$server_list" | grep -Ec '^concurrency::properties(:|$)' || true)
pure=$(printf '%s\n' "$server_list" | grep -Ec '^concurrency_properties::pure(:|$)' || true)
scheduler=$(printf '%s\n' "$server_list" | grep -Ec '^concurrency_properties::state_machine(:|$)' || true)
http=$(printf '%s\n' "$server_list" | grep -Ec '^concurrency_http_properties(:|$)' || true)
runner=$(cargo test -p preloop-runner -- --list 2>/dev/null | grep -c 'timespan_tests' || true)
parser=$(cargo test -p preloop-gha-parser -- --list 2>/dev/null | grep -c 'concurrency_' || true)
if [ "$legacy" -eq 0 ] || [ "$pure" -eq 0 ] || [ "$scheduler" -eq 0 ] || [ "$http" -eq 0 ] || [ "$runner" -eq 0 ] || [ "$parser" -eq 0 ]; then
echo "ERROR: zero matching tests (legacy=$legacy pure=$pure scheduler=$scheduler http=$http runner=$runner parser=$parser)" >&2
exit 1
fi
echo "server filters: legacy=$legacy pure=$pure scheduler=$scheduler http=$http; runner=$runner parser=$parser"
- name: Check no sleep() in property test files
run: |
files="crates/preloop-runner-server/src/concurrency_properties.rs crates/preloop-runner-server/src/concurrency_http_properties.rs"
bad=0
for f in $files; do
if [ -f "$f" ] && grep -q 'sleep(' "$f"; then
echo "ERROR: sleep() found in $f" >&2
bad=1
fi
done
if [ "$bad" -ne 0 ]; then exit 1; fi
echo "Sleep guard: OK"
- name: Pure concurrency properties
run: |
PROPTEST_CASES=256 cargo test -p preloop-runner-server \
'concurrency::properties' -- --test-threads=1
PROPTEST_CASES=256 cargo test -p preloop-runner-server \
concurrency_properties::pure -- --test-threads=1
- name: Scheduler model properties
run: |
PROPTEST_CASES=256 cargo test -p preloop-runner-server \
concurrency_properties::state_machine -- --test-threads=1
- name: Expression and parser properties
run: |
PROPTEST_CASES=256 cargo test -p preloop-gha-expressions -- --test-threads=1
cargo test -p preloop-gha-parser concurrency_ -- --test-threads=1
- name: Runner dispatcher properties
run: |
cargo test -p preloop-runner timespan_tests -- --test-threads=1
- name: HTTP sequence properties
run: |
PROPTEST_CASES=64 cargo test -p preloop-runner-server \
concurrency_http_properties -- --test-threads=1
- name: Differential harness dry-run (schema + algebraic validation)
run: |
python3 benchmarks/real-world/run-concurrency-property-probes.py \
--dry-run \
--corpus benchmarks/real-world/concurrency-property-cases.json
- name: Differential harness rejects contaminated fixture
run: |
set +e
python3 benchmarks/real-world/run-concurrency-property-probes.py \
--dry-run \
--corpus benchmarks/real-world/fixtures/contaminated-case.json
status=$?
set -e
if [ "$status" -eq 0 ]; then
echo "ERROR: harness did not reject contaminated fixture (expected nonzero exit)" >&2
exit 1
fi
echo "Contamination rejection: OK (exit $status)"
- name: Upload proptest regressions
if: failure()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: proptest-regressions-fast
path: |
crates/**/proptest-regressions/
if-no-files-found: ignore
property-tests-intensive:
runs-on: [self-hosted, preloop-cpane]
timeout-minutes: 120
if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.profile == 'intensive')
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@6bed0761d98439e5a578e2877258200ad565ba87 # stable
with:
toolchain: "1.97"
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
cache-on-failure: true
- name: Verify property filters match tests
run: |
server_list=$(PROPTEST_CASES=1 cargo test -p preloop-runner-server -- --list 2>/dev/null)
legacy=$(printf '%s\n' "$server_list" | grep -Ec '^concurrency::properties(:|$)' || true)
properties=$(printf '%s\n' "$server_list" | grep -Ec '^concurrency_properties(:|$)' || true)
http=$(printf '%s\n' "$server_list" | grep -Ec '^concurrency_http_properties(:|$)' || true)
runner=$(cargo test -p preloop-runner -- --list 2>/dev/null | grep -c 'timespan_tests' || true)
parser=$(cargo test -p preloop-gha-parser -- --list 2>/dev/null | grep -c 'concurrency_' || true)
if [ "$legacy" -eq 0 ] || [ "$properties" -eq 0 ] || [ "$http" -eq 0 ] || [ "$runner" -eq 0 ] || [ "$parser" -eq 0 ]; then
echo "ERROR: zero matching tests (legacy=$legacy properties=$properties http=$http runner=$runner parser=$parser)" >&2
exit 1
fi
echo "server filters: legacy=$legacy properties=$properties http=$http; runner=$runner parser=$parser"
- name: Check no sleep() in property test files
run: |
bad=0
for f in \
crates/preloop-runner-server/src/concurrency_properties.rs \
crates/preloop-runner-server/src/concurrency_http_properties.rs; do
if [ -f "$f" ] && grep -q 'sleep(' "$f"; then
echo "ERROR: sleep() found in $f" >&2
bad=1
fi
done
if [ "$bad" -ne 0 ]; then exit 1; fi
- name: Intensive property profile (release)
run: |
PROPTEST_CASES=10000 PROPTEST_MAX_SHRINK_ITERS=100000 \
cargo test -p preloop-runner-server 'concurrency::properties' \
--release -- --test-threads=1
PROPTEST_CASES=10000 PROPTEST_MAX_SHRINK_ITERS=100000 \
cargo test -p preloop-runner-server concurrency_properties \
--release -- --test-threads=1
- name: Intensive runner timing profile (release)
run: cargo test -p preloop-runner timespan_tests --release -- --test-threads=1
- name: Intensive expression / parser profile (release)
run: |
PROPTEST_CASES=10000 cargo test -p preloop-gha-expressions \
--release -- --test-threads=1
cargo test -p preloop-gha-parser concurrency_ \
--release -- --test-threads=1
- name: Intensive HTTP sequence profile (release)
run: |
PROPTEST_CASES=1000 PROPTEST_MAX_SHRINK_ITERS=100000 \
cargo test -p preloop-runner-server concurrency_http_properties \
--release -- --test-threads=1
- name: Differential harness dry-run
run: |
python3 benchmarks/real-world/run-concurrency-property-probes.py \
--dry-run \
--corpus benchmarks/real-world/concurrency-property-cases.json
- name: Differential harness rejects contaminated fixture
run: |
set +e
python3 benchmarks/real-world/run-concurrency-property-probes.py \
--dry-run \
--corpus benchmarks/real-world/fixtures/contaminated-case.json
status=$?
set -e
if [ "$status" -eq 0 ]; then
echo "ERROR: harness did not reject contaminated fixture" >&2
exit 1
fi
- name: Upload proptest regressions
if: failure()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: proptest-regressions-intensive
path: |
crates/**/proptest-regressions/
if-no-files-found: ignore