Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions .github/workflows/canary.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Front-runs the next boringssl bump instead of waiting for it: BoringSSL is
# live-at-head and its BCR snapshots carry no API/behavior guarantees, so the
# question "is the next snapshot safe?" otherwise gets answered by reading
# upstream commit logs after Renovate opens the PR. This job answers it by
# test, ahead of time, and doubles as the real consumer scenario in which
# another dependency's MVS claim drags boringssl past our pin: it forces the
# newest BCR snapshot onto the graph and runs the suites that pin TLS
# behavior (version floor/ceiling, cipher policy, ALPN — beast_client_test)
# plus the out-of-tree consumer's acceptance tests, which terminate real TLS
# handshakes. A red run here means the *next* Renovate boringssl PR needs a
# human look; nothing on main changed.
name: canary

on:
schedule:
# Mon + Thu, early UTC: BCR boringssl snapshots land roughly twice a
# week, so this cadence checks each one about once without burning a
# daily slot.
- cron: "23 5 * * 1,4"
workflow_dispatch:

permissions:
contents: read

jobs:
boringssl-latest:
name: bazel vs latest BCR boringssl
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
- uses: bazel-contrib/setup-bazel@0.19.0
with:
bazelisk-cache: true
repository-cache: true
disk-cache: canary
- name: resolve the newest boringssl in the BCR
id: latest
run: |
latest=$(curl -fsSL https://bcr.bazel.build/modules/boringssl/metadata.json \
| jq -r '.versions[]' | sort -V | tail -1)
# Registry data is external input: refuse anything that is not a
# plain version string before it gets spliced into a MODULE.bazel.
[[ "$latest" =~ ^[0-9A-Za-z._-]+$ ]] || { echo "unexpected version: $latest" >&2; exit 1; }
echo "latest boringssl in the BCR: ${latest}"
echo "version=${latest}" >> "$GITHUB_OUTPUT"
# single_version_override only takes effect in the root module, and the
# runtime suite and the consumer suite have different roots — so both
# MODULE.bazel files get the override. Appended, not committed: the
# checkout is discarded with the runner. The override makes the
# checked-in lockfiles stale by construction, so the test steps pass
# --lockfile_mode=off explicitly rather than leaning on Bazel's default
# (update) — a future default of error would otherwise fail the run
# before any test executes.
- name: force the newest boringssl onto both module graphs
env:
LATEST: ${{ steps.latest.outputs.version }}
run: |
for module in MODULE.bazel examples/bazel-consumer/MODULE.bazel; do
printf '\nsingle_version_override(module_name = "boringssl", version = "%s")\n' \
"$LATEST" >> "$module"
done
- name: runtime TLS suites vs latest boringssl
run: >
bazelisk test //runtime:beast_client_test //runtime:beast_transport_test
//runtime:beast_websocket_test --config=ci --lockfile_mode=off
- name: consumer suite vs latest boringssl
working-directory: examples/bazel-consumer
run: bazelisk test //... --config=werror --lockfile_mode=off --verbose_failures
34 changes: 34 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,40 @@ jobs:
if: matrix.os == 'ubuntu-24.04'
working-directory: examples/bazel-consumer
run: ./model-evolution-check.sh
# The consumer's resolved boringssl must be exactly the version
# smithy_cpp pins — MVS would silently select anything higher that a
# transitive dep requests, and every leg above stays green while
# consumers link a TLS library no job tested. Resolution is
# platform-independent, so one OS suffices.
- name: resolved boringssl matches the pin
if: matrix.os == 'ubuntu-24.04'
working-directory: examples/bazel-consumer
run: ./boringssl-resolution-check.sh

# MODULE.bazel.lock records the registry state resolution actually saw.
# Every other leg runs with the default --lockfile_mode=update, which
# silently re-resolves — so a dependency bump that forgets to repin still
# rides green and the diff no longer shows which versions CI tested. This
# leg makes staleness a red check instead: a MODULE.bazel edit lands
# together with its lockfile, and dependency PRs (Renovate's included)
# stay auditable from the diff alone. Same posture as the codegen job's
# golden-fixture freshness check. Repin with:
# bazelisk mod deps --lockfile_mode=update (root and examples/bazel-consumer)
lockfiles:
name: lockfiles (resolution freshness)
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
- uses: bazel-contrib/setup-bazel@0.19.0
with:
bazelisk-cache: true
repository-cache: true
disk-cache: lockfiles
- name: root module lockfile is current
run: bazelisk mod deps --lockfile_mode=error
- name: consumer module lockfile is current
working-directory: examples/bazel-consumer
run: bazelisk mod deps --lockfile_mode=error

codegen:
name: codegen (gradle)
Expand Down
16 changes: 13 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ BAZEL ?= bazelisk
GRADLE ?= gradle

# What CI gates a PR on: the bazel test matrix (one platform of it), the
# gradle build + format check, golden freshness, and the format/starlark lint.
# gradle build + format check, golden freshness, lockfile freshness, and the
# format/starlark lint.
.PHONY: verify
verify: test codegen goldens lint
verify: test lockfiles codegen goldens lint
@echo "verify: OK"

# verify plus the slower jobs: sanitizers, fuzzer smoke runs, the out-of-tree
Expand Down Expand Up @@ -75,7 +76,16 @@ fuzz-smoke:

.PHONY: consumer
consumer:
cd examples/bazel-consumer && $(BAZEL) test //... --config=werror && ./model-evolution-check.sh
cd examples/bazel-consumer && $(BAZEL) test //... --config=werror \
&& ./model-evolution-check.sh && ./boringssl-resolution-check.sh

# The checked-in MODULE.bazel.lock files must match what resolution would
# produce today; --lockfile_mode=error (the CI leg's mode) overrides the
# `off` that .bazelrc.user sets for the git-overrides flow.
.PHONY: lockfiles
lockfiles:
$(BAZEL) mod deps --lockfile_mode=error
cd examples/bazel-consumer && $(BAZEL) mod deps --lockfile_mode=error

# Line coverage for the runtime; the combined lcov report path prints at the
# end (render with genhtml, or read the CI job's artifact).
Expand Down
14 changes: 9 additions & 5 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ Two build trees live in this repository (see PLAN §3.1):
## Building and testing

One command verifies everything the CI gate checks (bazel tests, gradle
build + format, golden freshness, lint):
build + format, golden freshness, lockfile freshness, lint):

```sh
make verify # what CI gates a PR on
make verify-full # + sanitizers, fuzzer smoke runs, the consumer module, clang-tidy
```

Each aggregate is also callable piecemeal (`make test codegen goldens lint
sanitize fuzz-smoke consumer tidy coverage benchmarks format`); the recipes
mirror `.github/workflows/ci.yml`, one target per job. The underlying
commands:
Each aggregate is also callable piecemeal (`make test lockfiles codegen
goldens lint sanitize fuzz-smoke consumer tidy coverage benchmarks format`);
the recipes mirror `.github/workflows/ci.yml`, one target per job. The
underlying commands:

```sh
# C++ runtime: build + run all tests, warnings-as-errors like CI
Expand All @@ -35,6 +35,10 @@ bazel test //... --config=werror
# With sanitizers (clang recommended: CC=clang CXX=clang++)
bazel test //... --config=asan --config=ubsan

# Module lockfiles: fail if a MODULE.bazel changed without its repin
# (run in the repo root and in examples/bazel-consumer)
bazel mod deps --lockfile_mode=error

# Codegen: build + unit tests + format check
cd codegen && gradle build spotlessCheck
```
Expand Down
Loading
Loading