key-cape/scripts/test-scenario-b.sh

69 lines
2.7 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
Make the replacement harness runnable and target a live issuer Closes the runnable half of gap G04. The Scenario B and C scripts could not execute: absent compose files, binaries sought at src/bin where the Makefile builds to bin/, --base-dn passed to a generator whose flag is --basedn, and a hardcoded workstation Go path invoked from outside the module. Repairing the shell alone would have proved nothing. Both scripts set KEYCAPE_TEST_ISSUER while the profile suite built its own httptest server and never read it, so they passed identically whether or not a provider was running. A harness that cannot fail for the reason it exists is worse than a missing one. src/tests/conformance targets the issuer named by KEYCAPE_TEST_ISSUER over HTTP: discovery, the profile authorization surface, published keys parsed under the runtime's own rules, excluded grants, and -- with credentials -- a real token exchange verified against those keys. It skips when the variable is unset, so make test is unchanged. Run against Keycloak 26.0 rather than asserted to work. Discovery, authorization surface and key checks passed, and a client_credentials exchange produced a token that verified against Keycloak's published JWKS through internal/jose. It also failed, correctly: stock Keycloak advertises the excluded implicit and password grants, and in Keycloak those are server capabilities rather than per-client toggles, so no emitted realm removes them. A migrated Keycloak has a wider grant surface than KeyCape, which substantiates with evidence what SCOPE previously asserted without it. Scenario B legitimately reports failure today. Directory migration, credential and MFA preservation and relying-party behaviour remain unexercised, and Scenario C has never been run end to end, so G04 does not fully close. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P Assistant: claude-code Assistant-Model: opus Assistant-Process: 713576@bnt-lap001 Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-07 23:32:11 +02:00
# test-scenario-b.sh — Scenario B: IAM swap (KeyCape -> Keycloak, same LLDAP directory).
#
Make the replacement harness runnable and target a live issuer Closes the runnable half of gap G04. The Scenario B and C scripts could not execute: absent compose files, binaries sought at src/bin where the Makefile builds to bin/, --base-dn passed to a generator whose flag is --basedn, and a hardcoded workstation Go path invoked from outside the module. Repairing the shell alone would have proved nothing. Both scripts set KEYCAPE_TEST_ISSUER while the profile suite built its own httptest server and never read it, so they passed identically whether or not a provider was running. A harness that cannot fail for the reason it exists is worse than a missing one. src/tests/conformance targets the issuer named by KEYCAPE_TEST_ISSUER over HTTP: discovery, the profile authorization surface, published keys parsed under the runtime's own rules, excluded grants, and -- with credentials -- a real token exchange verified against those keys. It skips when the variable is unset, so make test is unchanged. Run against Keycloak 26.0 rather than asserted to work. Discovery, authorization surface and key checks passed, and a client_credentials exchange produced a token that verified against Keycloak's published JWKS through internal/jose. It also failed, correctly: stock Keycloak advertises the excluded implicit and password grants, and in Keycloak those are server capabilities rather than per-client toggles, so no emitted realm removes them. A migrated Keycloak has a wider grant surface than KeyCape, which substantiates with evidence what SCOPE previously asserted without it. Scenario B legitimately reports failure today. Directory migration, credential and MFA preservation and relying-party behaviour remain unexercised, and Scenario C has never been run end to end, so G04 does not fully close. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P Assistant: claude-code Assistant-Model: opus Assistant-Process: 713576@bnt-lap001 Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-07 23:32:11 +02:00
# Exports the canonical directory, transforms it into a Keycloak realm, starts
# Keycloak over that realm, and runs the external conformance suite against it.
#
Make the replacement harness runnable and target a live issuer Closes the runnable half of gap G04. The Scenario B and C scripts could not execute: absent compose files, binaries sought at src/bin where the Makefile builds to bin/, --base-dn passed to a generator whose flag is --basedn, and a hardcoded workstation Go path invoked from outside the module. Repairing the shell alone would have proved nothing. Both scripts set KEYCAPE_TEST_ISSUER while the profile suite built its own httptest server and never read it, so they passed identically whether or not a provider was running. A harness that cannot fail for the reason it exists is worse than a missing one. src/tests/conformance targets the issuer named by KEYCAPE_TEST_ISSUER over HTTP: discovery, the profile authorization surface, published keys parsed under the runtime's own rules, excluded grants, and -- with credentials -- a real token exchange verified against those keys. It skips when the variable is unset, so make test is unchanged. Run against Keycloak 26.0 rather than asserted to work. Discovery, authorization surface and key checks passed, and a client_credentials exchange produced a token that verified against Keycloak's published JWKS through internal/jose. It also failed, correctly: stock Keycloak advertises the excluded implicit and password grants, and in Keycloak those are server capabilities rather than per-client toggles, so no emitted realm removes them. A migrated Keycloak has a wider grant surface than KeyCape, which substantiates with evidence what SCOPE previously asserted without it. Scenario B legitimately reports failure today. Directory migration, credential and MFA preservation and relying-party behaviour remain unexercised, and Scenario C has never been run end to end, so G04 does not fully close. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P Assistant: claude-code Assistant-Model: opus Assistant-Process: 713576@bnt-lap001 Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-07 23:32:11 +02:00
# Prerequisites: docker, docker compose, and `make build` (binaries land in bin/).
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$REPO_ROOT"
Make the replacement harness runnable and target a live issuer Closes the runnable half of gap G04. The Scenario B and C scripts could not execute: absent compose files, binaries sought at src/bin where the Makefile builds to bin/, --base-dn passed to a generator whose flag is --basedn, and a hardcoded workstation Go path invoked from outside the module. Repairing the shell alone would have proved nothing. Both scripts set KEYCAPE_TEST_ISSUER while the profile suite built its own httptest server and never read it, so they passed identically whether or not a provider was running. A harness that cannot fail for the reason it exists is worse than a missing one. src/tests/conformance targets the issuer named by KEYCAPE_TEST_ISSUER over HTTP: discovery, the profile authorization surface, published keys parsed under the runtime's own rules, excluded grants, and -- with credentials -- a real token exchange verified against those keys. It skips when the variable is unset, so make test is unchanged. Run against Keycloak 26.0 rather than asserted to work. Discovery, authorization surface and key checks passed, and a client_credentials exchange produced a token that verified against Keycloak's published JWKS through internal/jose. It also failed, correctly: stock Keycloak advertises the excluded implicit and password grants, and in Keycloak those are server capabilities rather than per-client toggles, so no emitted realm removes them. A migrated Keycloak has a wider grant surface than KeyCape, which substantiates with evidence what SCOPE previously asserted without it. Scenario B legitimately reports failure today. Directory migration, credential and MFA preservation and relying-party behaviour remain unexercised, and Scenario C has never been run end to end, so G04 does not fully close. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P Assistant: claude-code Assistant-Model: opus Assistant-Process: 713576@bnt-lap001 Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-07 23:32:11 +02:00
BUILD_DIR="$REPO_ROOT/build/scenario-b"
COMPOSE="docker compose -f docker-compose.scenario-b.yml"
ISSUER_URL="http://localhost:8080/realms/netkingdom"
Make the replacement harness runnable and target a live issuer Closes the runnable half of gap G04. The Scenario B and C scripts could not execute: absent compose files, binaries sought at src/bin where the Makefile builds to bin/, --base-dn passed to a generator whose flag is --basedn, and a hardcoded workstation Go path invoked from outside the module. Repairing the shell alone would have proved nothing. Both scripts set KEYCAPE_TEST_ISSUER while the profile suite built its own httptest server and never read it, so they passed identically whether or not a provider was running. A harness that cannot fail for the reason it exists is worse than a missing one. src/tests/conformance targets the issuer named by KEYCAPE_TEST_ISSUER over HTTP: discovery, the profile authorization surface, published keys parsed under the runtime's own rules, excluded grants, and -- with credentials -- a real token exchange verified against those keys. It skips when the variable is unset, so make test is unchanged. Run against Keycloak 26.0 rather than asserted to work. Discovery, authorization surface and key checks passed, and a client_credentials exchange produced a token that verified against Keycloak's published JWKS through internal/jose. It also failed, correctly: stock Keycloak advertises the excluded implicit and password grants, and in Keycloak those are server capabilities rather than per-client toggles, so no emitted realm removes them. A migrated Keycloak has a wider grant surface than KeyCape, which substantiates with evidence what SCOPE previously asserted without it. Scenario B legitimately reports failure today. Directory migration, credential and MFA preservation and relying-party behaviour remain unexercised, and Scenario C has never been run end to end, so G04 does not fully close. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P Assistant: claude-code Assistant-Model: opus Assistant-Process: 713576@bnt-lap001 Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-07 23:32:11 +02:00
die() { echo "scenario-b: $*" >&2; exit 1; }
# Check every prerequisite up front: failing half way through leaves a running
# stack and a half-written realm, which is harder to diagnose than not starting.
for binary in lldap-export keycape-to-keycloak; do
[ -x "bin/$binary" ] || die "bin/$binary is missing; run 'make build' first"
done
command -v docker >/dev/null || die "docker is not installed"
command -v go >/dev/null || die "go is not installed"
cleanup() { $COMPOSE down -v >/dev/null 2>&1 || true; }
trap cleanup EXIT
mkdir -p "$BUILD_DIR/realm"
echo "=== Scenario B: IAM replacement ==="
echo "--- Step 1: start the directory ---"
$COMPOSE up -d lldap
timeout 120 bash -c 'until (exec 3<>/dev/tcp/127.0.0.1/3890) 2>/dev/null; do sleep 2; done' \
|| die "LLDAP did not accept connections within 120s"
echo "--- Step 2: export the canonical directory ---"
./bin/lldap-export \
--url "${LLDAP_URL:-ldap://localhost:3890}" \
--bind-dn "${LLDAP_BIND_DN:-cn=admin,ou=people,dc=netkingdom,dc=local}" \
--bind-pw "${LLDAP_BIND_PW:-adminpassword}" \
Make the replacement harness runnable and target a live issuer Closes the runnable half of gap G04. The Scenario B and C scripts could not execute: absent compose files, binaries sought at src/bin where the Makefile builds to bin/, --base-dn passed to a generator whose flag is --basedn, and a hardcoded workstation Go path invoked from outside the module. Repairing the shell alone would have proved nothing. Both scripts set KEYCAPE_TEST_ISSUER while the profile suite built its own httptest server and never read it, so they passed identically whether or not a provider was running. A harness that cannot fail for the reason it exists is worse than a missing one. src/tests/conformance targets the issuer named by KEYCAPE_TEST_ISSUER over HTTP: discovery, the profile authorization surface, published keys parsed under the runtime's own rules, excluded grants, and -- with credentials -- a real token exchange verified against those keys. It skips when the variable is unset, so make test is unchanged. Run against Keycloak 26.0 rather than asserted to work. Discovery, authorization surface and key checks passed, and a client_credentials exchange produced a token that verified against Keycloak's published JWKS through internal/jose. It also failed, correctly: stock Keycloak advertises the excluded implicit and password grants, and in Keycloak those are server capabilities rather than per-client toggles, so no emitted realm removes them. A migrated Keycloak has a wider grant surface than KeyCape, which substantiates with evidence what SCOPE previously asserted without it. Scenario B legitimately reports failure today. Directory migration, credential and MFA preservation and relying-party behaviour remain unexercised, and Scenario C has never been run end to end, so G04 does not fully close. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P Assistant: claude-code Assistant-Model: opus Assistant-Process: 713576@bnt-lap001 Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-07 23:32:11 +02:00
--base-dn "${LLDAP_BASE_DN:-dc=netkingdom,dc=local}" \
--output "$BUILD_DIR/canonical-export.yaml"
Make the replacement harness runnable and target a live issuer Closes the runnable half of gap G04. The Scenario B and C scripts could not execute: absent compose files, binaries sought at src/bin where the Makefile builds to bin/, --base-dn passed to a generator whose flag is --basedn, and a hardcoded workstation Go path invoked from outside the module. Repairing the shell alone would have proved nothing. Both scripts set KEYCAPE_TEST_ISSUER while the profile suite built its own httptest server and never read it, so they passed identically whether or not a provider was running. A harness that cannot fail for the reason it exists is worse than a missing one. src/tests/conformance targets the issuer named by KEYCAPE_TEST_ISSUER over HTTP: discovery, the profile authorization surface, published keys parsed under the runtime's own rules, excluded grants, and -- with credentials -- a real token exchange verified against those keys. It skips when the variable is unset, so make test is unchanged. Run against Keycloak 26.0 rather than asserted to work. Discovery, authorization surface and key checks passed, and a client_credentials exchange produced a token that verified against Keycloak's published JWKS through internal/jose. It also failed, correctly: stock Keycloak advertises the excluded implicit and password grants, and in Keycloak those are server capabilities rather than per-client toggles, so no emitted realm removes them. A migrated Keycloak has a wider grant surface than KeyCape, which substantiates with evidence what SCOPE previously asserted without it. Scenario B legitimately reports failure today. Directory migration, credential and MFA preservation and relying-party behaviour remain unexercised, and Scenario C has never been run end to end, so G04 does not fully close. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P Assistant: claude-code Assistant-Model: opus Assistant-Process: 713576@bnt-lap001 Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-07 23:32:11 +02:00
echo "--- Step 3: transform into a Keycloak realm ---"
./bin/keycape-to-keycloak \
--input "$BUILD_DIR/canonical-export.yaml" \
--realm netkingdom \
Make the replacement harness runnable and target a live issuer Closes the runnable half of gap G04. The Scenario B and C scripts could not execute: absent compose files, binaries sought at src/bin where the Makefile builds to bin/, --base-dn passed to a generator whose flag is --basedn, and a hardcoded workstation Go path invoked from outside the module. Repairing the shell alone would have proved nothing. Both scripts set KEYCAPE_TEST_ISSUER while the profile suite built its own httptest server and never read it, so they passed identically whether or not a provider was running. A harness that cannot fail for the reason it exists is worse than a missing one. src/tests/conformance targets the issuer named by KEYCAPE_TEST_ISSUER over HTTP: discovery, the profile authorization surface, published keys parsed under the runtime's own rules, excluded grants, and -- with credentials -- a real token exchange verified against those keys. It skips when the variable is unset, so make test is unchanged. Run against Keycloak 26.0 rather than asserted to work. Discovery, authorization surface and key checks passed, and a client_credentials exchange produced a token that verified against Keycloak's published JWKS through internal/jose. It also failed, correctly: stock Keycloak advertises the excluded implicit and password grants, and in Keycloak those are server capabilities rather than per-client toggles, so no emitted realm removes them. A migrated Keycloak has a wider grant surface than KeyCape, which substantiates with evidence what SCOPE previously asserted without it. Scenario B legitimately reports failure today. Directory migration, credential and MFA preservation and relying-party behaviour remain unexercised, and Scenario C has never been run end to end, so G04 does not fully close. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P Assistant: claude-code Assistant-Model: opus Assistant-Process: 713576@bnt-lap001 Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-07 23:32:11 +02:00
--issuer "${ISSUER:-$ISSUER_URL}" \
--output "$BUILD_DIR/realm/netkingdom-realm.json"
Make the replacement harness runnable and target a live issuer Closes the runnable half of gap G04. The Scenario B and C scripts could not execute: absent compose files, binaries sought at src/bin where the Makefile builds to bin/, --base-dn passed to a generator whose flag is --basedn, and a hardcoded workstation Go path invoked from outside the module. Repairing the shell alone would have proved nothing. Both scripts set KEYCAPE_TEST_ISSUER while the profile suite built its own httptest server and never read it, so they passed identically whether or not a provider was running. A harness that cannot fail for the reason it exists is worse than a missing one. src/tests/conformance targets the issuer named by KEYCAPE_TEST_ISSUER over HTTP: discovery, the profile authorization surface, published keys parsed under the runtime's own rules, excluded grants, and -- with credentials -- a real token exchange verified against those keys. It skips when the variable is unset, so make test is unchanged. Run against Keycloak 26.0 rather than asserted to work. Discovery, authorization surface and key checks passed, and a client_credentials exchange produced a token that verified against Keycloak's published JWKS through internal/jose. It also failed, correctly: stock Keycloak advertises the excluded implicit and password grants, and in Keycloak those are server capabilities rather than per-client toggles, so no emitted realm removes them. A migrated Keycloak has a wider grant surface than KeyCape, which substantiates with evidence what SCOPE previously asserted without it. Scenario B legitimately reports failure today. Directory migration, credential and MFA preservation and relying-party behaviour remain unexercised, and Scenario C has never been run end to end, so G04 does not fully close. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P Assistant: claude-code Assistant-Model: opus Assistant-Process: 713576@bnt-lap001 Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-07 23:32:11 +02:00
echo "--- Step 4: start Keycloak over the migrated realm ---"
$COMPOSE up -d keycloak
timeout 180 bash -c "until curl -sf '$ISSUER_URL/.well-known/openid-configuration' >/dev/null; do sleep 3; done" \
|| die "Keycloak did not serve discovery within 180s"
Make the replacement harness runnable and target a live issuer Closes the runnable half of gap G04. The Scenario B and C scripts could not execute: absent compose files, binaries sought at src/bin where the Makefile builds to bin/, --base-dn passed to a generator whose flag is --basedn, and a hardcoded workstation Go path invoked from outside the module. Repairing the shell alone would have proved nothing. Both scripts set KEYCAPE_TEST_ISSUER while the profile suite built its own httptest server and never read it, so they passed identically whether or not a provider was running. A harness that cannot fail for the reason it exists is worse than a missing one. src/tests/conformance targets the issuer named by KEYCAPE_TEST_ISSUER over HTTP: discovery, the profile authorization surface, published keys parsed under the runtime's own rules, excluded grants, and -- with credentials -- a real token exchange verified against those keys. It skips when the variable is unset, so make test is unchanged. Run against Keycloak 26.0 rather than asserted to work. Discovery, authorization surface and key checks passed, and a client_credentials exchange produced a token that verified against Keycloak's published JWKS through internal/jose. It also failed, correctly: stock Keycloak advertises the excluded implicit and password grants, and in Keycloak those are server capabilities rather than per-client toggles, so no emitted realm removes them. A migrated Keycloak has a wider grant surface than KeyCape, which substantiates with evidence what SCOPE previously asserted without it. Scenario B legitimately reports failure today. Directory migration, credential and MFA preservation and relying-party behaviour remain unexercised, and Scenario C has never been run end to end, so G04 does not fully close. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P Assistant: claude-code Assistant-Model: opus Assistant-Process: 713576@bnt-lap001 Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-07 23:32:11 +02:00
echo "--- Step 5: run the external conformance suite against Keycloak ---"
# The suite reads KEYCAPE_TEST_ISSUER and talks to the running issuer over HTTP.
# Run it from the module directory: the Go module root is src/, not the repo root.
KEYCAPE_TEST_ISSUER="$ISSUER_URL" \
go -C src test ./tests/conformance/... -v -count=1
echo "=== Scenario B PASSED ==="
Make the replacement harness runnable and target a live issuer Closes the runnable half of gap G04. The Scenario B and C scripts could not execute: absent compose files, binaries sought at src/bin where the Makefile builds to bin/, --base-dn passed to a generator whose flag is --basedn, and a hardcoded workstation Go path invoked from outside the module. Repairing the shell alone would have proved nothing. Both scripts set KEYCAPE_TEST_ISSUER while the profile suite built its own httptest server and never read it, so they passed identically whether or not a provider was running. A harness that cannot fail for the reason it exists is worse than a missing one. src/tests/conformance targets the issuer named by KEYCAPE_TEST_ISSUER over HTTP: discovery, the profile authorization surface, published keys parsed under the runtime's own rules, excluded grants, and -- with credentials -- a real token exchange verified against those keys. It skips when the variable is unset, so make test is unchanged. Run against Keycloak 26.0 rather than asserted to work. Discovery, authorization surface and key checks passed, and a client_credentials exchange produced a token that verified against Keycloak's published JWKS through internal/jose. It also failed, correctly: stock Keycloak advertises the excluded implicit and password grants, and in Keycloak those are server capabilities rather than per-client toggles, so no emitted realm removes them. A migrated Keycloak has a wider grant surface than KeyCape, which substantiates with evidence what SCOPE previously asserted without it. Scenario B legitimately reports failure today. Directory migration, credential and MFA preservation and relying-party behaviour remain unexercised, and Scenario C has never been run end to end, so G04 does not fully close. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P Assistant: claude-code Assistant-Model: opus Assistant-Process: 713576@bnt-lap001 Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-07 23:32:11 +02:00
echo "Note: this proves the migrated realm serves a conforming OIDC surface."
echo "It does not prove credential, MFA or relying-party behaviour was preserved."