Merge branch 'master' into next

Integrates PR #50 (peer ACL enforcement) into the XX handshake
architecture. ACL enforcement points adapted for XX's deferred
identity learning: InboundHandshake check moves from handle_msg1
to handle_msg3 (responder learns initiator identity), OutboundHandshake
check remains in handle_msg2 (initiator learns responder identity).
Borrow scopes restructured to release connection borrows before
authorize_peer calls.
This commit is contained in:
Johnathan Corgan
2026-04-16 06:11:03 +00:00
19 changed files with 2094 additions and 79 deletions
+1
View File
@@ -0,0 +1 @@
generated-configs
+164
View File
@@ -0,0 +1,164 @@
# ACL Allowlist Test
Six Docker nodes use per-node ACL files mounted at the hardcoded runtime paths:
- `node-a` and `node-b` carry the insider allowlist (`node-a`, `node-b`, `node-e`, `node-f`)
- `node-c` and `node-d` each carry a broad allowlist containing every node alias
- `node-e` and `node-f` do not mount any ACL files locally
- every node gets a generated `/etc/fips/hosts` with aliases for `node-a` through `node-f`
This lets us test three different node behaviors at once:
- insiders (`a`, `b`) explicitly allow `a`, `b`, `e`, and `f`
- outsiders (`c`, `d`) allow everyone locally, but still cannot join because insiders reject them
- allowed remotes (`e`, `f`) rely on the insider ACLs and do not need local ACL files
## Test Identities
Allowed:
- `node-a`
- `npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m`
- `0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20`
- `node-b`
- `npub1tdwa4vjrjl33pcjdpf2t4p027nl86xrx24g4d3avg4vwvayr3g8qhd84le`
- `b102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fb0`
Denied:
- `node-c`
- `npub1cld9yay0u24davpu6c35l4vldrhzvaq66pcqtg9a0j2cnjrn9rtsxx2pe6`
- `c102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fc0`
- `node-d`
- `npub1n9lpnv0592cc2ps6nm0ca3qls642vx7yjsv35rkxqzj2vgds52sqgpverl`
- `d102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fd0`
Additional allowed:
- `node-e`
- `npub1x5z9rwzzm26q9verutx4aajhf2zw2pyp34c6whhde2zduxqav40qgq36l6`
- `nsec1egyrmekfw3u4l88v8zhrak9uht503s2kvn9v49tqgp6c5l2yuxgsv386l0`
- `node-f`
- `npub1ytrut7gjncn2zfnhn56c0zgftf0w6p99gf6fu8j73hzw5603zglqc9av6c`
- `nsec1afh3nysthqh47awpdewcw59wvvp499f8dvlyclmnv4gvpxdk56dsa6eqsn`
The generated `fips.key` fixtures use a mix of bare hex and `nsec1...` values.
FIPS accepts either format in key files.
## Run
Build the Linux binaries and test image:
```bash
./testing/scripts/build.sh --no-docker
```
Start the ACL test mesh:
```bash
./testing/acl-allowlist/generate-configs.sh
docker compose -f testing/acl-allowlist/docker-compose.yml up -d --build
```
Or run the full integration check:
```bash
./testing/acl-allowlist/test.sh
```
`test.sh` regenerates the ACL fixtures automatically before starting Docker.
The generated ACL files use alias names, and the generated hosts file makes
those aliases resolvable at runtime.
The ACL harness pins the expected test entrypoint explicitly so it does not
accidentally reuse an older `fips-test:latest` image with a different startup
script.
Docker service/container/hostname identifiers in this harness intentionally use
`service-*`, `fips-acl-container-*`, and `host-*` names so they do not collide with the logical FIPS aliases
`node-a` through `node-f`. For data-plane checks and operator examples, use the
explicit FIPS names such as `node-a.fips` and `node-d.fips`.
ACL paths are fixed in this branch:
- `/etc/fips/peers.allow`
- `/etc/fips/peers.deny`
Mounted ACL files in this harness:
- `node-a` and `node-b`: insider allowlist plus `ALL` deny fallback
- `node-c` and `node-d`: broad local allowlist used by outsider nodes trying to blend in
- `node-e` and `node-f`: no ACL files mounted
- all nodes: `/etc/fips/hosts` aliases for `node-a` through `node-f`
Generated fixture location:
- `testing/acl-allowlist/generated-configs/`
Inspect peer state:
```bash
docker exec fips-acl-container-a fipsctl show peers
docker exec fips-acl-container-b fipsctl show peers
docker exec fips-acl-container-c fipsctl show peers
docker exec fips-acl-container-d fipsctl show peers
docker exec fips-acl-container-e fipsctl show peers
docker exec fips-acl-container-f fipsctl show peers
```
Inspect the loaded ACL state directly:
```bash
docker exec fips-acl-container-a fipsctl acl show
```
Use explicit `.fips` names when checking reachability through the FIPS overlay:
```bash
docker exec fips-acl-container-a ping node-d.fips
docker exec fips-acl-container-a ping npub1n9lpnv0592cc2ps6nm0ca3qls642vx7yjsv35rkxqzj2vgds52sqgpverl.fips
```
The output shows both the original ACL file entries and the resolved
effective npub entries.
Expected:
- `node-a` sees `node-b`, `node-e`, and `node-f`
- `node-b` sees `node-a`
- `node-c` sees no peers
- `node-d` sees no peers
- `node-e` sees `node-a`
- `node-f` sees `node-a`
Visible rejection logs:
```bash
docker compose -f testing/acl-allowlist/docker-compose.yml logs -f service-a service-b service-c service-d service-e service-f
```
On startup, `node-c` and `node-d` immediately try their configured outbound
static connection to `node-a`. Their own ACLs permit that attempt, but the
insider ACL on `node-a` still rejects both peers. Because `node-a` also has
static peer stanzas for `node-c` and `node-d`, you may see both
`outbound_connect` and `inbound_handshake` rejection messages during startup.
The outsider-initiated path emits messages like:
```text
Rejected peer by ACL ... context=inbound_handshake decision=denylist match
```
Those messages are now emitted at debug level. This harness enables
`RUST_LOG=info,fips::node=debug` so the ACL rejection details stay visible in
test logs, and operators can temporarily raise log level the same way when
diagnosing ACL issues locally.
A later `ping6` from `node-c.fips` does not emit a new `inbound_handshake` message.
The ping uses the data-plane session path, and since no peer session to
`node-a.fips` was established, it just times out.
Stop and clean up:
```bash
docker compose -f testing/acl-allowlist/docker-compose.yml down
```
+111
View File
@@ -0,0 +1,111 @@
networks:
acl-net:
driver: bridge
ipam:
config:
- subnet: 172.31.0.0/24
x-fips-common: &fips-common
build:
context: ../docker
image: fips-test:latest
entrypoint: ["/usr/local/bin/entrypoint.sh"]
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
sysctls:
- net.ipv6.conf.all.disable_ipv6=0
restart: "no"
environment:
- FIPS_TEST_MODE=default
- RUST_LOG=info,fips::node=debug
volumes:
- ../docker/resolv.conf:/etc/resolv.conf:ro
services:
service-a:
<<: *fips-common
container_name: fips-acl-container-a
hostname: host-a
volumes:
- ../docker/resolv.conf:/etc/resolv.conf:ro
- ./generated-configs/node-a/hosts:/etc/fips/hosts:ro
- ./generated-configs/node-a/peers.allow:/etc/fips/peers.allow:ro
- ./generated-configs/node-a/peers.deny:/etc/fips/peers.deny:ro
- ./generated-configs/node-a/fips.yaml:/etc/fips/fips.yaml:ro
- ./generated-configs/node-a/fips.key:/etc/fips/fips.key:ro
networks:
acl-net:
ipv4_address: 172.31.0.10
service-b:
<<: *fips-common
container_name: fips-acl-container-b
hostname: host-b
volumes:
- ../docker/resolv.conf:/etc/resolv.conf:ro
- ./generated-configs/node-b/hosts:/etc/fips/hosts:ro
- ./generated-configs/node-b/peers.allow:/etc/fips/peers.allow:ro
- ./generated-configs/node-b/peers.deny:/etc/fips/peers.deny:ro
- ./generated-configs/node-b/fips.yaml:/etc/fips/fips.yaml:ro
- ./generated-configs/node-b/fips.key:/etc/fips/fips.key:ro
networks:
acl-net:
ipv4_address: 172.31.0.11
service-c:
<<: *fips-common
container_name: fips-acl-container-c
hostname: host-c
volumes:
- ../docker/resolv.conf:/etc/resolv.conf:ro
- ./generated-configs/node-c/hosts:/etc/fips/hosts:ro
- ./generated-configs/node-c/peers.allow:/etc/fips/peers.allow:ro
- ./generated-configs/node-c/peers.deny:/etc/fips/peers.deny:ro
- ./generated-configs/node-c/fips.yaml:/etc/fips/fips.yaml:ro
- ./generated-configs/node-c/fips.key:/etc/fips/fips.key:ro
networks:
acl-net:
ipv4_address: 172.31.0.12
service-d:
<<: *fips-common
container_name: fips-acl-container-d
hostname: host-d
volumes:
- ../docker/resolv.conf:/etc/resolv.conf:ro
- ./generated-configs/node-d/hosts:/etc/fips/hosts:ro
- ./generated-configs/node-d/peers.allow:/etc/fips/peers.allow:ro
- ./generated-configs/node-d/peers.deny:/etc/fips/peers.deny:ro
- ./generated-configs/node-d/fips.yaml:/etc/fips/fips.yaml:ro
- ./generated-configs/node-d/fips.key:/etc/fips/fips.key:ro
networks:
acl-net:
ipv4_address: 172.31.0.13
service-e:
<<: *fips-common
container_name: fips-acl-container-e
hostname: host-e
volumes:
- ../docker/resolv.conf:/etc/resolv.conf:ro
- ./generated-configs/node-e/hosts:/etc/fips/hosts:ro
- ./generated-configs/node-e/fips.yaml:/etc/fips/fips.yaml:ro
- ./generated-configs/node-e/fips.key:/etc/fips/fips.key:ro
networks:
acl-net:
ipv4_address: 172.31.0.14
service-f:
<<: *fips-common
container_name: fips-acl-container-f
hostname: host-f
volumes:
- ../docker/resolv.conf:/etc/resolv.conf:ro
- ./generated-configs/node-f/hosts:/etc/fips/hosts:ro
- ./generated-configs/node-f/fips.yaml:/etc/fips/fips.yaml:ro
- ./generated-configs/node-f/fips.key:/etc/fips/fips.key:ro
networks:
acl-net:
ipv4_address: 172.31.0.15
+306
View File
@@ -0,0 +1,306 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
GENERATED_DIR="$SCRIPT_DIR/generated-configs"
write_file() {
local path="$1"
mkdir -p "$(dirname "$path")"
cat > "$path"
}
write_hosts_file() {
local node="$1"
write_file "$GENERATED_DIR/$node/hosts" <<'EOF'
node-a npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m
node-b npub1tdwa4vjrjl33pcjdpf2t4p027nl86xrx24g4d3avg4vwvayr3g8qhd84le
node-c npub1cld9yay0u24davpu6c35l4vldrhzvaq66pcqtg9a0j2cnjrn9rtsxx2pe6
node-d npub1n9lpnv0592cc2ps6nm0ca3qls642vx7yjsv35rkxqzj2vgds52sqgpverl
node-e npub1x5z9rwzzm26q9verutx4aajhf2zw2pyp34c6whhde2zduxqav40qgq36l6
node-f npub1ytrut7gjncn2zfnhn56c0zgftf0w6p99gf6fu8j73hzw5603zglqc9av6c
EOF
}
echo "Generating ACL allowlist fixtures..."
rm -rf "$GENERATED_DIR"
write_file "$GENERATED_DIR/node-a/fips.yaml" <<'EOF'
node:
identity:
persistent: true
tun:
enabled: true
name: fips0
mtu: 1280
dns:
enabled: true
bind_addr: "127.0.0.1"
transports:
udp:
bind_addr: "0.0.0.0:2121"
peers:
- npub: "npub1tdwa4vjrjl33pcjdpf2t4p027nl86xrx24g4d3avg4vwvayr3g8qhd84le"
alias: "node-b"
addresses:
- transport: udp
addr: "172.31.0.11:2121"
connect_policy: auto_connect
- npub: "npub1cld9yay0u24davpu6c35l4vldrhzvaq66pcqtg9a0j2cnjrn9rtsxx2pe6"
alias: "node-c"
addresses:
- transport: udp
addr: "172.31.0.12:2121"
connect_policy: auto_connect
- npub: "npub1n9lpnv0592cc2ps6nm0ca3qls642vx7yjsv35rkxqzj2vgds52sqgpverl"
alias: "node-d"
addresses:
- transport: udp
addr: "172.31.0.13:2121"
connect_policy: auto_connect
- npub: "npub1x5z9rwzzm26q9verutx4aajhf2zw2pyp34c6whhde2zduxqav40qgq36l6"
alias: "node-e"
addresses:
- transport: udp
addr: "172.31.0.14:2121"
connect_policy: auto_connect
- npub: "npub1ytrut7gjncn2zfnhn56c0zgftf0w6p99gf6fu8j73hzw5603zglqc9av6c"
alias: "node-f"
addresses:
- transport: udp
addr: "172.31.0.15:2121"
connect_policy: auto_connect
EOF
write_file "$GENERATED_DIR/node-a/fips.key" <<'EOF'
0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20
EOF
write_file "$GENERATED_DIR/node-a/peers.allow" <<'EOF'
node-a
node-b
node-e
node-f
EOF
write_file "$GENERATED_DIR/node-a/peers.deny" <<'EOF'
ALL
EOF
write_file "$GENERATED_DIR/node-b/fips.yaml" <<'EOF'
node:
identity:
persistent: true
tun:
enabled: true
name: fips0
mtu: 1280
dns:
enabled: true
bind_addr: "127.0.0.1"
transports:
udp:
bind_addr: "0.0.0.0:2121"
peers:
- npub: "npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m"
alias: "node-a"
addresses:
- transport: udp
addr: "172.31.0.10:2121"
connect_policy: auto_connect
- npub: "npub1cld9yay0u24davpu6c35l4vldrhzvaq66pcqtg9a0j2cnjrn9rtsxx2pe6"
alias: "node-c"
addresses:
- transport: udp
addr: "172.31.0.12:2121"
connect_policy: auto_connect
- npub: "npub1n9lpnv0592cc2ps6nm0ca3qls642vx7yjsv35rkxqzj2vgds52sqgpverl"
alias: "node-d"
addresses:
- transport: udp
addr: "172.31.0.13:2121"
connect_policy: auto_connect
EOF
write_file "$GENERATED_DIR/node-b/fips.key" <<'EOF'
b102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fb0
EOF
write_file "$GENERATED_DIR/node-b/peers.allow" <<'EOF'
node-a
node-b
node-e
node-f
EOF
write_file "$GENERATED_DIR/node-b/peers.deny" <<'EOF'
ALL
EOF
write_file "$GENERATED_DIR/node-c/fips.yaml" <<'EOF'
node:
identity:
persistent: true
tun:
enabled: true
name: fips0
mtu: 1280
dns:
enabled: true
bind_addr: "127.0.0.1"
transports:
udp:
bind_addr: "0.0.0.0:2121"
peers:
- npub: "npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m"
alias: "node-a"
addresses:
- transport: udp
addr: "172.31.0.10:2121"
connect_policy: auto_connect
EOF
write_file "$GENERATED_DIR/node-c/fips.key" <<'EOF'
c102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fc0
EOF
write_file "$GENERATED_DIR/node-c/peers.allow" <<'EOF'
node-a
node-b
node-c
node-d
node-e
node-f
EOF
write_file "$GENERATED_DIR/node-c/peers.deny" <<'EOF'
# Intentionally empty.
EOF
write_file "$GENERATED_DIR/node-d/fips.yaml" <<'EOF'
node:
identity:
persistent: true
tun:
enabled: true
name: fips0
mtu: 1280
dns:
enabled: true
bind_addr: "127.0.0.1"
transports:
udp:
bind_addr: "0.0.0.0:2121"
peers:
- npub: "npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m"
alias: "node-a"
addresses:
- transport: udp
addr: "172.31.0.10:2121"
connect_policy: auto_connect
EOF
write_file "$GENERATED_DIR/node-d/fips.key" <<'EOF'
d102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fd0
EOF
write_file "$GENERATED_DIR/node-d/peers.allow" <<'EOF'
node-a
node-b
node-c
node-d
node-e
node-f
EOF
write_file "$GENERATED_DIR/node-d/peers.deny" <<'EOF'
# Intentionally empty.
EOF
write_file "$GENERATED_DIR/node-e/fips.yaml" <<'EOF'
node:
identity:
persistent: true
tun:
enabled: true
name: fips0
mtu: 1280
dns:
enabled: true
bind_addr: "127.0.0.1"
transports:
udp:
bind_addr: "0.0.0.0:2121"
peers:
- npub: "npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m"
alias: "node-a"
addresses:
- transport: udp
addr: "172.31.0.10:2121"
connect_policy: auto_connect
EOF
write_file "$GENERATED_DIR/node-e/fips.key" <<'EOF'
nsec1egyrmekfw3u4l88v8zhrak9uht503s2kvn9v49tqgp6c5l2yuxgsv386l0
EOF
write_file "$GENERATED_DIR/node-f/fips.yaml" <<'EOF'
node:
identity:
persistent: true
tun:
enabled: true
name: fips0
mtu: 1280
dns:
enabled: true
bind_addr: "127.0.0.1"
transports:
udp:
bind_addr: "0.0.0.0:2121"
peers:
- npub: "npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m"
alias: "node-a"
addresses:
- transport: udp
addr: "172.31.0.10:2121"
connect_policy: auto_connect
EOF
write_file "$GENERATED_DIR/node-f/fips.key" <<'EOF'
nsec1afh3nysthqh47awpdewcw59wvvp499f8dvlyclmnv4gvpxdk56dsa6eqsn
EOF
write_hosts_file node-a
write_hosts_file node-b
write_hosts_file node-c
write_hosts_file node-d
write_hosts_file node-e
write_hosts_file node-f
echo "ACL allowlist fixtures written to $GENERATED_DIR"
+150
View File
@@ -0,0 +1,150 @@
#!/bin/bash
# Integration test for the ACL allowlist harness.
#
# Usage: ./test.sh [--skip-build] [--keep-up]
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
TESTING_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
COMPOSE_FILE="$SCRIPT_DIR/docker-compose.yml"
GENERATE_CONFIGS="$SCRIPT_DIR/generate-configs.sh"
SKIP_BUILD=false
KEEP_UP=false
while [ $# -gt 0 ]; do
case "$1" in
--skip-build) SKIP_BUILD=true; shift ;;
--keep-up) KEEP_UP=true; shift ;;
*) echo "Unknown option: $1" >&2; exit 1 ;;
esac
done
cleanup() {
if [ "$KEEP_UP" = false ]; then
docker compose -f "$COMPOSE_FILE" down >/dev/null 2>&1 || true
fi
}
trap cleanup EXIT
log() {
echo "=== $*"
}
peer_npubs() {
local container="$1"
docker exec "$container" fipsctl show peers \
| python3 -c 'import json,sys; data=json.load(sys.stdin); print(" ".join(sorted(p["npub"] for p in data.get("peers", []) if p.get("connectivity") == "connected")))'
}
acl_field() {
local container="$1"
local field="$2"
docker exec "$container" fipsctl acl show \
| python3 -c 'import json,sys; data=json.load(sys.stdin); field=sys.argv[1]; value=data.get(field); print(" ".join(sorted(value)) if isinstance(value, list) else ("" if value is None else value))' "$field"
}
assert_peer_set() {
local container="$1"
local expected="$2"
local actual
actual="$(peer_npubs "$container")"
if [ "$actual" != "$expected" ]; then
echo "FAIL: $container peers mismatch" >&2
echo " expected: $expected" >&2
echo " actual: $actual" >&2
exit 1
fi
echo "PASS: $container peers match expected set"
}
assert_acl_field() {
local container="$1"
local field="$2"
local expected="$3"
local actual
actual="$(acl_field "$container" "$field")"
if [ "$actual" != "$expected" ]; then
echo "FAIL: $container ACL field $field mismatch" >&2
echo " expected: $expected" >&2
echo " actual: $actual" >&2
exit 1
fi
echo "PASS: $container ACL field $field matches expected value"
}
wait_for_peers_exact() {
local container="$1"
local expected_count="$2"
local timeout="${3:-30}"
for _ in $(seq 1 "$timeout"); do
local count
count=$(docker exec "$container" fipsctl show peers 2>/dev/null \
| python3 -c 'import json,sys; data=json.load(sys.stdin); print(sum(1 for p in data.get("peers", []) if p.get("connectivity") == "connected"))' 2>/dev/null || echo 0)
if [ "$count" -eq "$expected_count" ]; then
return 0
fi
sleep 1
done
echo "FAIL: $container did not reach $expected_count connected peers in ${timeout}s" >&2
docker exec "$container" fipsctl show peers >&2 || true
exit 1
}
assert_log_contains() {
local container="$1"
local pattern="$2"
local logs
logs="$(docker logs "$container" 2>&1 | python3 -c 'import re,sys; print(re.sub(r"\x1b\[[0-9;]*m", "", sys.stdin.read()), end="")' || true)"
if ! printf '%s' "$logs" | grep -F "$pattern" >/dev/null; then
echo "FAIL: missing log pattern in $container: $pattern" >&2
exit 1
fi
echo "PASS: $container logs contain expected ACL rejection"
}
if [ "$SKIP_BUILD" = false ]; then
log "Building Linux test binaries"
"$TESTING_DIR/scripts/build.sh" --no-docker
fi
log "Generating ACL allowlist fixtures"
"$GENERATE_CONFIGS"
log "Starting ACL allowlist harness"
docker compose -f "$COMPOSE_FILE" down >/dev/null 2>&1 || true
docker compose -f "$COMPOSE_FILE" up -d --build
log "Waiting for expected peer convergence"
wait_for_peers_exact fips-acl-container-a 3 40
wait_for_peers_exact fips-acl-container-b 1 40
wait_for_peers_exact fips-acl-container-c 0 5
wait_for_peers_exact fips-acl-container-d 0 5
wait_for_peers_exact fips-acl-container-e 1 40
wait_for_peers_exact fips-acl-container-f 1 40
log "Verifying peer sets"
assert_peer_set fips-acl-container-a "npub1tdwa4vjrjl33pcjdpf2t4p027nl86xrx24g4d3avg4vwvayr3g8qhd84le npub1x5z9rwzzm26q9verutx4aajhf2zw2pyp34c6whhde2zduxqav40qgq36l6 npub1ytrut7gjncn2zfnhn56c0zgftf0w6p99gf6fu8j73hzw5603zglqc9av6c"
assert_peer_set fips-acl-container-b "npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m"
assert_peer_set fips-acl-container-c ""
assert_peer_set fips-acl-container-d ""
assert_peer_set fips-acl-container-e "npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m"
assert_peer_set fips-acl-container-f "npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m"
log "Checking alias-based ACL resolution"
assert_acl_field fips-acl-container-a allow_file_entries "node-a node-b node-e node-f"
assert_acl_field fips-acl-container-a allow_entries "npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m npub1tdwa4vjrjl33pcjdpf2t4p027nl86xrx24g4d3avg4vwvayr3g8qhd84le npub1x5z9rwzzm26q9verutx4aajhf2zw2pyp34c6whhde2zduxqav40qgq36l6 npub1ytrut7gjncn2zfnhn56c0zgftf0w6p99gf6fu8j73hzw5603zglqc9av6c"
assert_acl_field fips-acl-container-c allow_file_entries "node-a node-b node-c node-d node-e node-f"
assert_acl_field fips-acl-container-c allow_entries "npub1cld9yay0u24davpu6c35l4vldrhzvaq66pcqtg9a0j2cnjrn9rtsxx2pe6 npub1n9lpnv0592cc2ps6nm0ca3qls642vx7yjsv35rkxqzj2vgds52sqgpverl npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m npub1tdwa4vjrjl33pcjdpf2t4p027nl86xrx24g4d3avg4vwvayr3g8qhd84le npub1x5z9rwzzm26q9verutx4aajhf2zw2pyp34c6whhde2zduxqav40qgq36l6 npub1ytrut7gjncn2zfnhn56c0zgftf0w6p99gf6fu8j73hzw5603zglqc9av6c"
log "Checking ACL rejection logs"
assert_log_contains fips-acl-container-a "npub1cld9yay0u24davpu6c35l4vldrhzvaq66pcqtg9a0j2cnjrn9rtsxx2pe6"
assert_log_contains fips-acl-container-a "npub1n9lpnv0592cc2ps6nm0ca3qls642vx7yjsv35rkxqzj2vgds52sqgpverl"
assert_log_contains fips-acl-container-a "context=inbound_handshake"
assert_log_contains fips-acl-container-a "decision=denylist match"
log "ACL allowlist integration test passed"