name: MACP Runtime CI
on:
pull_request:
push:
branches: [ main ]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
env:
CARGO_TERM_COLOR: always
RUST_TOOLCHAIN: "1.96.1"
MSRV_TOOLCHAIN: "1.89.0"
PROTOC_VERSION: "31.x"
jobs:
actionlint:
name: Lint workflows (advisory)
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Run actionlint
run: |
bash <(curl -fsSL https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
./actionlint -color
check:
name: Check (MSRV)
runs-on: ubuntu-latest
env:
RUSTUP_TOOLCHAIN: "1.89.0"
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 with:
toolchain: ${{ env.MSRV_TOOLCHAIN }}
- name: Cache cargo registry and build
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 with:
shared-key: msrv
- name: Install protoc
uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b with:
version: ${{ env.PROTOC_VERSION }}
repo-token: ${{ github.token }}
- name: Verify Cargo.lock is consistent with the manifests
run: cargo metadata --locked --format-version 1 > /dev/null
- name: Cargo check
run: cargo check --all-targets
fmt:
name: Format
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
components: rustfmt
- name: Check formatting
run: cargo fmt --all -- --check
clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
components: clippy
- name: Cache cargo registry and build
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 with:
shared-key: main
- name: Install protoc
uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b with:
version: ${{ env.PROTOC_VERSION }}
repo-token: ${{ github.token }}
- name: Run clippy
run: cargo clippy --all-targets -- -D warnings
docs:
name: Rustdoc
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
- name: Cache cargo registry and build
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 with:
shared-key: main
- name: Install protoc
uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b with:
version: ${{ env.PROTOC_VERSION }}
repo-token: ${{ github.token }}
- name: Build docs (deny warnings)
run: cargo doc --workspace --no-deps
env:
RUSTDOCFLAGS: "-D warnings"
test:
name: Test
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
- name: Cache cargo registry and build
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 with:
shared-key: main
- name: Install protoc
uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b with:
version: ${{ env.PROTOC_VERSION }}
repo-token: ${{ github.token }}
- name: Run tests
run: cargo test --workspace --all-targets
env:
MACP_MEMORY_ONLY: "1"
- name: Run conformance tests
run: cargo test --workspace conformance
env:
MACP_MEMORY_ONLY: "1"
- name: Run policy tests
run: cargo test --workspace policy
env:
MACP_MEMORY_ONLY: "1"
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
- name: Cache cargo registry and build
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 with:
shared-key: release
- name: Install protoc
uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b with:
version: ${{ env.PROTOC_VERSION }}
repo-token: ${{ github.token }}
- name: Build release
run: cargo build --release
deps-isolation:
name: Crate Dependency Isolation
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
- name: Install protoc
uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b with:
version: ${{ env.PROTOC_VERSION }}
repo-token: ${{ github.token }}
- name: macp-core is transport/runtime-free
run: |
deps=$(cargo tree -p macp-core --edges normal)
echo "$deps"
# Strip the parenthesized manifest path before grepping so the check
# matches crate names only — the checkout directory itself is named
# "macp-runtime" and would otherwise trip the forbidden pattern.
if echo "$deps" | sed 's/ ([^)]*)//' | grep -qiE "tonic|tokio|rocksdb|redis|reqwest|macp-storage|macp-auth|macp-modes|macp-runtime"; then
echo "::error::macp-core pulled a forbidden dependency"; exit 1
fi
- name: macp-modes has no concrete policy / transport
run: |
deps=$(cargo tree -p macp-modes --edges normal)
echo "$deps"
if echo "$deps" | sed 's/ ([^)]*)//' | grep -qiE "tonic|macp-policy|macp-storage|macp-auth|macp-runtime|reqwest|rocksdb|redis"; then
echo "::error::macp-modes pulled a forbidden dependency"; exit 1
fi
- name: auth deps stay out of the vocabulary crates
run: |
for crate in macp-core macp-modes macp-policy macp-storage; do
deps=$(cargo tree -p "$crate" --edges normal)
if echo "$deps" | sed 's/ ([^)]*)//' | grep -qiE "jsonwebtoken|reqwest"; then
echo "::error::$crate pulled an auth-only dependency"; exit 1
fi
done
- name: Internal crate versions are in lockstep
run: |
set -euo pipefail
meta=$(cargo metadata --format-version 1 --no-deps)
ws=$(echo "$meta" | jq -r '.packages[] | select(.name=="macp-runtime") | .version')
echo "workspace version = $ws"
fail=0
# 1) Every member's package version matches the workspace version.
while read -r name ver; do
if [ "$ver" != "$ws" ]; then
echo "::error::$name package version $ver != workspace $ws"; fail=1
fi
done < <(echo "$meta" | jq -r '.packages[] | "\(.name) \(.version)"')
# 2) Every internal dependency requirement is exactly ^<workspace ver>.
while read -r from to req; do
if [ "$req" != "^$ws" ]; then
echo "::error::$from depends on $to with req '$req', expected '^$ws'"; fail=1
fi
done < <(echo "$meta" | jq -r '
(.packages | map(.name)) as $members
| .packages[] | . as $p
| $p.dependencies[]
| select([.name] | inside($members))
| "\($p.name) \(.name) \(.req)"')
if [ "$fail" -ne 0 ]; then
echo "::error::workspace crate versions are not in lockstep"; exit 1
fi
echo "All workspace crates and internal deps pinned at $ws"
audit:
name: Security Audit
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Run cargo audit
uses: rustsec/audit-check@69366f33c96575abad1ee0dba8212993eecbe998 with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Install cargo-audit
run: cargo install cargo-audit --locked --version ^0.22
- name: Run cargo audit (integration_tests lockfile)
working-directory: integration_tests
run: cargo audit --file Cargo.lock
coverage:
name: Coverage
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
- name: Cache cargo registry and build
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 with:
shared-key: coverage
- name: Install protoc
uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b with:
version: ${{ env.PROTOC_VERSION }}
repo-token: ${{ github.token }}
- name: Install cargo-tarpaulin
uses: taiki-e/install-action@e67fa11c4b9316fa714ddf0abed07a0c3143b95b with:
tool: cargo-tarpaulin
- name: Generate coverage
run: cargo tarpaulin --workspace --out xml
env:
MACP_MEMORY_ONLY: "1"
- name: Upload coverage to Codecov
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f with:
files: cobertura.xml
fail_ci_if_error: false
features:
name: Feature-gated code (rocksdb, redis, otel)
runs-on: ubuntu-latest
services:
redis:
image: redis:7
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s
--health-timeout 3s
--health-retries 10
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
components: clippy
- name: Cache cargo registry and build
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 with:
shared-key: features
- name: Install protoc
uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b with:
version: ${{ env.PROTOC_VERSION }}
repo-token: ${{ github.token }}
- name: Clippy (feature-gated code)
run: cargo clippy -p macp-storage --features rocksdb-backend,redis-backend --all-targets -- -D warnings
- name: Clippy (otel feature)
run: cargo clippy -p macp-runtime --features otel --all-targets -- -D warnings
- name: Check root crate with all storage backends
run: cargo check -p macp-runtime --features rocksdb-backend,redis-backend --all-targets
- name: Test rocksdb backend
run: cargo test -p macp-storage --features rocksdb-backend
- name: Test redis backend (live service)
run: cargo test -p macp-storage --features redis-backend
env:
MACP_TEST_REDIS_URL: redis://127.0.0.1:6379
- name: Test both backends enabled together
run: cargo test -p macp-storage --features rocksdb-backend,redis-backend
env:
MACP_TEST_REDIS_URL: redis://127.0.0.1:6379
- name: Build runtime binary with storage backends
run: cargo build --features rocksdb-backend,redis-backend
- name: Backend smoke test through gRPC (rocksdb)
working-directory: integration_tests
run: cargo test --test tier1 configured_backend -- --test-threads=1
env:
MACP_TEST_BINARY: ../target/debug/macp-runtime
MACP_TEST_BACKEND: rocksdb
- name: Backend smoke test through gRPC (redis)
working-directory: integration_tests
run: cargo test --test tier1 configured_backend -- --test-threads=1
env:
MACP_TEST_BINARY: ../target/debug/macp-runtime
MACP_TEST_BACKEND: redis
MACP_TEST_REDIS_URL: redis://127.0.0.1:6379
integration:
name: Integration (tier 1 + 2, real gRPC boundary)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
- name: Cache cargo registry and build
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 with:
shared-key: integration
workspaces: |
.
integration_tests
- name: Install protoc
uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b with:
version: ${{ env.PROTOC_VERSION }}
repo-token: ${{ github.token }}
- name: Verify integration_tests/Cargo.lock is consistent with its manifest
run: cargo metadata --locked --manifest-path integration_tests/Cargo.toml --format-version 1 > /dev/null
- name: Build runtime binary
run: cargo build
- name: Run tier-1 + tier-2 suites
working-directory: integration_tests
run: cargo test --test tier1 --test tier1_jwt --test tier2 -- --test-threads=1
env:
MACP_TEST_BINARY: ../target/debug/macp-runtime
timeout-minutes: 15
conformance-oracle:
name: Conformance oracle (spec-repo fixtures)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Checkout spec repo (canonical fixtures)
uses: actions/checkout@v7
with:
repository: multiagentcoordinationprotocol/multiagentcoordinationprotocol
path: spec-repo
- name: Vendored fixtures are byte-identical to canonical
run: |
status=0
# Drift is checked in BOTH directions. The canonical -> vendored loop
# is the load-bearing one: iterating only the vendored side can never
# reach a fixture that was added upstream and never vendored here, so
# the runtime would silently stop covering the canonical set while
# this job stayed green. Mirrors the SDKs' `verify-fixtures` targets.
check_dir() {
local vendored_dir="$1" canonical_dir="$2"
if [ ! -d "$canonical_dir" ]; then
echo "MISSING: canonical directory $canonical_dir does not exist" >&2
status=1
return
fi
# canonical -> vendored: upstream additions and content drift
for f in "$canonical_dir"/*.json; do
[ -e "$f" ] || continue
b=$(basename "$f")
if [ ! -f "$vendored_dir/$b" ]; then
echo "MISSING: $canonical_dir/$b has no vendored copy at $vendored_dir/$b -- vendor it and reference it from the conformance suite" >&2
status=1
elif ! diff -u "$canonical_dir/$b" "$vendored_dir/$b"; then
echo "DRIFT: $b differs from the canonical spec-repo copy ($canonical_dir)" >&2
status=1
fi
done
# vendored -> canonical: local files with no canonical source
for f in "$vendored_dir"/*.json; do
[ -e "$f" ] || continue
b=$(basename "$f")
if [ ! -f "$canonical_dir/$b" ]; then
echo "EXTRA: $vendored_dir/$b has no canonical source at $canonical_dir/$b" >&2
status=1
fi
done
}
check_dir "tests/conformance" "spec-repo/schemas/conformance"
check_dir "tests/conformance/cmt-hash" "spec-repo/schemas/conformance/cmt-hash"
exit $status
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
- name: Cache cargo registry and build
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 with:
shared-key: main
- name: Install protoc
uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b with:
version: ${{ env.PROTOC_VERSION }}
repo-token: ${{ github.token }}
- name: Run conformance suite against canonical fixtures
env:
MACP_CONFORMANCE_FIXTURES_DIR: ${{ github.workspace }}/spec-repo/schemas/conformance
run: cargo test --test conformance_loader
docker-build:
name: Docker Image Build (gate)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e
- name: Build image (no push)
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a with:
context: .
push: false
cache-from: type=gha
cache-to: type=gha,mode=max
ci-pass:
name: All Checks Passed
runs-on: ubuntu-latest
needs: [check, fmt, clippy, docs, test, build, deps-isolation, audit, features, integration, docker-build, conformance-oracle]
steps:
- name: Summary
run: |
echo "All checks passed successfully"
echo " - cargo check (MSRV 1.89.0)"
echo " - cargo fmt"
echo " - cargo clippy"
echo " - cargo doc (deny warnings)"
echo " - cargo test"
echo " - cargo build --release"
echo " - crate dependency isolation"
echo " - security audit (blocking)"
echo " - feature-gated code (rocksdb, redis, otel)"
echo " - tier-1 + tier-2 integration suites"
echo " - docker image build"