mirror of
https://github.com/jmcorgan/fips.git
synced 2026-10-06 11:38:24 +00:00
Every scenario in the suite created its interface after the daemons were already running — that ordering is the boot race the suite was written for. But it means both nodes could only ever reach Present through binder_loop, so the inline bind in start_async, which is the ordinary case on a booted router, had no end-to-end coverage at all. That is where the churn guard went unseeded and the first detach stopped reaching node health, and no existing case could reach it: they all detach from a binding the loop created, which seeds the guard as a side effect. Case (f) adds a third node whose single required interface exists before its daemon does. The gate is what buys that ordering — the harness needs a running container to have a netns to move a veth into, but the daemon must not start until after the move, so node-c comes up parked on a file and the harness releases it once the interface is in place. Then one detach, on a binding the loop did not create, and the node must degrade. Verified against the defect rather than only against the fix: with the guard seed reverted, cases (a) through (e) all still pass and (f) is the only failure. A regression test that has never been seen to fail is a claim, not a test. It also asserts the reverse edge, so Degraded stays a level rather than a latch on this path too.
81 lines
3.4 KiB
YAML
81 lines
3.4 KiB
YAML
networks:
|
|
# Management bridge only. The FIPS transport under test is raw Ethernet on a
|
|
# veth pair the harness creates *after* the daemons are already running —
|
|
# that is the whole point of the suite — so no FIPS traffic crosses this
|
|
# network. No subnet is requested, so two concurrent runs cannot collide on
|
|
# one address range.
|
|
#
|
|
# The compose project name is still fixed, so two runs that do not set
|
|
# COMPOSE_PROJECT_NAME share a project and the second `up` recreates the
|
|
# first's containers. The local CI runner scopes it externally
|
|
# (run_iface_binding in ci-local.sh); a bare hand run does not.
|
|
ifb-net:
|
|
driver: bridge
|
|
labels:
|
|
- "com.corganlabs.fips-ci=1"
|
|
|
|
x-fips-common: &fips-common
|
|
build:
|
|
# The harness scopes its build context per run and passes it here; the
|
|
# shared directory is the hand-run default. Compose resolves a relative
|
|
# value against THIS file's directory, so the harness must export an
|
|
# absolute path.
|
|
context: ${FIPS_BUILD_CONTEXT:-../docker}
|
|
image: ${FIPS_TEST_IMAGE:-fips-test:latest}
|
|
entrypoint: ["/usr/local/bin/entrypoint.sh"]
|
|
cap_add:
|
|
- NET_ADMIN
|
|
- NET_RAW
|
|
restart: "no"
|
|
environment:
|
|
# `default`, deliberately — NOT `chaos`. The chaos entrypoint waits up to
|
|
# 30 s for every configured Ethernet interface to appear before it starts
|
|
# the daemon, which is precisely the workaround this mechanism retires. The
|
|
# daemon must do its own waiting here or the suite proves nothing.
|
|
- FIPS_TEST_MODE=default
|
|
- RUST_LOG=info,fips::transport::ethernet=debug,fips::node=debug
|
|
networks:
|
|
- ifb-net
|
|
|
|
services:
|
|
node-a:
|
|
<<: *fips-common
|
|
container_name: fips-ifb-node-a${FIPS_CI_NAME_SUFFIX:-}
|
|
hostname: host-a
|
|
volumes:
|
|
- ../docker/resolv.conf:/etc/resolv.conf:ro
|
|
- ./generated-configs${FIPS_CI_NAME_SUFFIX:-}/node-a/fips.yaml:/etc/fips/fips.yaml:ro
|
|
- ./generated-configs${FIPS_CI_NAME_SUFFIX:-}/node-a/fips.key:/etc/fips/fips.key:ro
|
|
|
|
node-b:
|
|
<<: *fips-common
|
|
container_name: fips-ifb-node-b${FIPS_CI_NAME_SUFFIX:-}
|
|
hostname: host-b
|
|
volumes:
|
|
- ../docker/resolv.conf:/etc/resolv.conf:ro
|
|
- ./generated-configs${FIPS_CI_NAME_SUFFIX:-}/node-b/fips.yaml:/etc/fips/fips.yaml:ro
|
|
- ./generated-configs${FIPS_CI_NAME_SUFFIX:-}/node-b/fips.key:/etc/fips/fips.key:ro
|
|
|
|
# The clean-start case. Its interface exists before its daemon does, which is
|
|
# the ordinary state of a booted router and the one ordering node-a and
|
|
# node-b cannot produce: their interface is created after they are already
|
|
# running, so they can only ever bind through the binder loop.
|
|
#
|
|
# The gate is what buys that ordering. The harness needs a running container
|
|
# to have a netns to move a veth into, but the daemon must not start until
|
|
# after the move — so the container comes up, parks on this file, and the
|
|
# harness releases it once the interface is in place.
|
|
node-c:
|
|
<<: *fips-common
|
|
container_name: fips-ifb-node-c${FIPS_CI_NAME_SUFFIX:-}
|
|
hostname: host-c
|
|
entrypoint: ["/bin/sh", "-c"]
|
|
command:
|
|
- |
|
|
while [ ! -e /tmp/fips-go ]; do sleep 0.2; done
|
|
exec /usr/local/bin/entrypoint.sh
|
|
volumes:
|
|
- ../docker/resolv.conf:/etc/resolv.conf:ro
|
|
- ./generated-configs${FIPS_CI_NAME_SUFFIX:-}/node-c/fips.yaml:/etc/fips/fips.yaml:ro
|
|
- ./generated-configs${FIPS_CI_NAME_SUFFIX:-}/node-c/fips.key:/etc/fips/fips.key:ro
|