Skip to content

audit: baseline the segment-close receiver's identity-verification he… #441

audit: baseline the segment-close receiver's identity-verification he…

audit: baseline the segment-close receiver's identity-verification he… #441

Workflow file for this run

name: ci
on:
push:
branches: [main, slate]
pull_request:
schedule:
# SR2-5: the noisy-neighbor campaign runs NIGHTLY (03:17 UTC), not
# as a one-time recorded receipt. Locked thresholds live in the
# script; a regression fails this workflow.
- cron: "17 3 * * *"
# Product-surface spec appendix §7: the required CI topology. The
# dual-surface equivalence corpus, DST scenarios, and product
# conformance run inside `cargo test --release` (dst::dst_tests);
# request-cost budgets are asserted by the postings/planner tests in
# the same suite. The upstream Durable Streams server suite runs as
# its own job against a fresh namespace.
jobs:
# Job: rust build + full suite (product conformance, dual-surface
# equivalence corpus, DST safety/liveness, request-cost budgets).
rust:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Check
run: cargo check --all-targets
# SR-6: the two multitenancy gates run as NAMED steps so a
# failure is legible at a glance. The audit is the fingerprint
# inventory (identity-neutral categories, baseline-diffed); the
# syn lint is the zero-unmarked-residual security gate and also
# runs inside the full suite — here it prints the reviewed
# exemption-marker inventory into the CI log for certification.
- name: Multitenancy audit (bare, never piped)
run: bash scripts/multitenancy-audit.sh
- name: Multitenancy identity lint (exemption inventory)
run: cargo test --release --bin streams-slate multitenancy_identity_lint -- --nocapture
- name: Test (product conformance + dual-surface + DST + cost budgets)
run: |
cargo test --release 2>&1 | tee /tmp/suite.log
grep -E "^test result" /tmp/suite.log
if grep -E "^test result" /tmp/suite.log | grep -qv " 0 failed"; then
echo "suite has failures"; exit 1
fi
# Job: the REAL enforce-mode noisy-neighbor campaign (SR2-5),
# nightly. Reduced herd for the 4-core runner (24 noisy, 100 idle)
# with the SAME locked thresholds; the contract-scale 48/200 run is
# part of RC promotion (scripts/promote-rc.sh).
noisy-campaign:
if: github.event_name == 'schedule'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Noisy-neighbor campaign (locked thresholds)
run: NOISY=24 IDLE=100 WINDOW_SECS=20 node scripts/mt-noisy-campaign.mjs
# Job: the platform end-to-end battery (docs/CONTROL-PLANE-
# INTEGRATION.md §15) — the TS emulator mints real credentials,
# tokens and feed files; a REAL streams-slate consumes them under
# the full release posture (workload identity, no static token);
# the SDK exchanges through tokenProvider. Phase-A scenarios.
platform-e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Build SDK dist
run: cd sdk && npm ci && npm run build
- name: Platform end-to-end battery
run: node scripts/platform-e2e.mjs
# Job: the shared-cell certification smoke at CONTRACT scale
# (docs/MULTITENANCY.md §18 Stage 8 / SR-6). The suite's default run
# exercises the same test at 128 projects; this job runs the
# 1,000-project posture (48 noisy, shared workspaces, same-name
# streams, suspension/revocation cutoffs, reconciliation, journaled
# denials) on every push so the at-scale posture cannot rot.
mt-cert-1000:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Certification smoke at 1,000 projects
run: MT_CERT_PROJECTS=1000 cargo test --release --bin streams-slate shared_cell_certification_smoke -- --nocapture
# Job: the SDK ships as an npm package, so CI validates the PACKAGE,
# not the source tree: build, pack, install the tarball into a clean
# project, and run the end-to-end smoke through the package specifier
# on the oldest supported runtime (engines: >=18) and on current Node.
sdk-package:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Typecheck + build + pack
run: |
cd sdk
npm ci
npx tsc --noEmit -p tsconfig.json
npm run build
# npm >=10 does not create the destination directory; without
# it, pack dies with ENOENT on the tarball path.
mkdir -p /tmp/pkg
npm pack --pack-destination /tmp/pkg
- name: Install the tarball into a clean project
run: |
mkdir -p /tmp/consumer && cd /tmp/consumer
npm init -y >/dev/null
npm install /tmp/pkg/prisma-streams-*.tgz
node -e "require('node:assert').ok(require('node:fs').existsSync('node_modules/@prisma/streams/dist/index.js'))"
- name: Build server
run: cargo build --release --bin s3lite --bin streams-slate
- name: Smoke through the package (current Node)
run: |
./target/release/s3lite --listen 127.0.0.1:9500 --latency-ms 2 &
sleep 1
./target/release/streams-slate --listen 127.0.0.1:8090 \
--s3-endpoint http://127.0.0.1:9500 --bucket sdk22-$RANDOM \
--max-unflushed-bytes 67108864 &
sleep 2
cd /tmp/consumer
STREAMS_SDK=@prisma/streams node $GITHUB_WORKSPACE/sdk/smoke.mjs http://127.0.0.1:8090
- uses: actions/setup-node@v4
with:
node-version: 18
- name: Smoke through the package (Node 18, the engines floor)
run: |
./target/release/streams-slate --listen 127.0.0.1:8091 \
--s3-endpoint http://127.0.0.1:9500 --bucket sdk18-$RANDOM \
--max-unflushed-bytes 67108864 &
sleep 2
cd /tmp/consumer
STREAMS_SDK=@prisma/streams node $GITHUB_WORKSPACE/sdk/smoke.mjs http://127.0.0.1:8091
# The SDK claims Bun and Deno too, so gate them rather than assert
# them. Both run the same package through the same smoke.
- uses: oven-sh/setup-bun@v2
- name: Smoke through the package (Bun)
run: |
./target/release/streams-slate --listen 127.0.0.1:8092 \
--s3-endpoint http://127.0.0.1:9500 --bucket sdkbun-$RANDOM \
--max-unflushed-bytes 67108864 &
sleep 2
cd /tmp/consumer
STREAMS_SDK=@prisma/streams bun $GITHUB_WORKSPACE/sdk/smoke.mjs http://127.0.0.1:8092
- uses: denoland/setup-deno@v2
with:
deno-version: v2.x
- name: Smoke through the package (Deno)
run: |
./target/release/streams-slate --listen 127.0.0.1:8093 \
--s3-endpoint http://127.0.0.1:9500 --bucket sdkdeno-$RANDOM \
--max-unflushed-bytes 67108864 &
sleep 2
cd /tmp/consumer
STREAMS_SDK=@prisma/streams deno run -A --node-modules-dir \
$GITHUB_WORKSPACE/sdk/smoke.mjs http://127.0.0.1:8093
# Job: the pinned upstream Durable Streams server conformance suite,
# UNMODIFIED, against a fresh namespace (spec appendix §7). The
# version here must match src/protocol_pin.rs.
durable-streams-server-conformance:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Build server
run: cargo build --release --bin s3lite --bin streams-slate --bin streams-keys
- name: Run pinned suite (fresh namespace)
run: |
./target/release/s3lite --listen 127.0.0.1:9500 --latency-ms 2 &
sleep 1
KEY=$(./target/release/streams-keys generate)
# Group commit is required: the suite's property tests run
# ~240 sequential appends inside vitest's 5 s budget, and the
# default flush cadence makes them latency-marginal. This is
# what field deployments run anyway (see CONFORMANCE.md).
./target/release/streams-slate --listen 127.0.0.1:8090 \
--s3-endpoint http://127.0.0.1:9500 --bucket conf-$RANDOM \
--max-unflushed-bytes 67108864 \
--flush-interval-ms 1 --wal-flush-gap-ms 2 \
--conformance-default-key "$KEY" &
sleep 2
# The runner lives in conformance/ with a committed lock and an
# exact expected outcome. It does NOT use the package's npx
# CLI, whose include glob misses its own runner and exits 0
# having run nothing.
cd conformance
npm ci
CONFORMANCE_TEST_URL=http://127.0.0.1:8090 npm test
# Job: the product field corpus (scripts/field-gate.mjs) — the same
# 20 checks the cloud campaign runs, against a local server with
# aggressive split thresholds so a real scaler split fires inside CI.
# Negative auth, raw create replay, product seal replay, fork replay,
# a real automatic split, and raw/product default-key isolation.
product-field-gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Build server
run: cargo build --release --bin s3lite --bin streams-slate
- name: Run the field gate (auth enabled, deterministic split)
run: |
./target/release/s3lite --listen 127.0.0.1:9500 --latency-ms 2 &
sleep 1
# Low, deterministic scaler thresholds: one hot evaluation
# over a 10 s window splits, so the "load drove a real split"
# check fires within the gate's own load phase instead of
# racing production cadence.
SCALE_EVAL_SECS=5 SCALE_RATE_WINDOW_SECS=10 \
SCALE_HOT_PCT=1 SCALE_HOT_EVALS=1 SCALE_COOLDOWN_SECS=5 \
./target/release/streams-slate --listen 127.0.0.1:8092 \
--s3-endpoint http://127.0.0.1:9500 --bucket fg-$RANDOM \
--max-unflushed-bytes 67108864 \
--flush-interval-ms 1 --wal-flush-gap-ms 2 \
--auth-token ci-gate-token &
sleep 2
STREAMS_TOKEN=ci-gate-token node scripts/field-gate.mjs http://127.0.0.1:8092