feat(RAILIANCE-WP-0027): add contained callback role update
Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a02b90-83bf-75c2-81c8-aa705414e4d4
This commit is contained in:
parent
c89187c064
commit
d18649fc6e
4 changed files with 164 additions and 0 deletions
|
|
@ -29,6 +29,22 @@ http://127.0.0.1:18200/ui/vault/auth/netkingdom/oidc/callback
|
||||||
Record only a value-safe attended-login result. Do not record the authorization
|
Record only a value-safe attended-login result. Do not record the authorization
|
||||||
code, token, accessor, callback query, browser storage, or screenshots.
|
code, token, accessor, callback query, browser storage, or screenshots.
|
||||||
|
|
||||||
|
KeyCape admission is applied by the Net Kingdom owner procedure. Apply the
|
||||||
|
OpenBao half through the governed contained login lane; the child command is
|
||||||
|
silent and Warden self-revokes the attended session:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
warden plan \
|
||||||
|
"attended OpenBao platform administration to add the exact operator-tunneled OIDC callback to auth/netkingdom/role/platform-admin" \
|
||||||
|
--json
|
||||||
|
warden access openbao-platform-admin-login --exec -- \
|
||||||
|
scripts/openbao-apply-operator-loopback-callback.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The plan must return `founder_required` and select
|
||||||
|
`openbao-platform-admin-login`. Do not run the owner command directly with a
|
||||||
|
persistent token.
|
||||||
|
|
||||||
## Guarded sequence
|
## Guarded sequence
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
|
||||||
63
scripts/openbao-apply-operator-loopback-callback.sh
Executable file
63
scripts/openbao-apply-operator-loopback-callback.sh
Executable file
|
|
@ -0,0 +1,63 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Silent owner command for the governed openbao-platform-admin-login lane.
|
||||||
|
# Warden rejects any child output and self-revokes the attended session after
|
||||||
|
# this command exits. The role payload contains no secret values.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROLE_PATH="auth/netkingdom/role/platform-admin"
|
||||||
|
CALLBACK_URI="http://127.0.0.1:18200/ui/vault/auth/netkingdom/oidc/callback"
|
||||||
|
PAYLOAD="$(mktemp "${TMPDIR:-/tmp}/openbao-platform-admin-role.XXXXXX.json")"
|
||||||
|
READBACK="$(mktemp "${TMPDIR:-/tmp}/openbao-platform-admin-readback.XXXXXX.json")"
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
rm -f "$PAYLOAD" "$READBACK"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT INT TERM
|
||||||
|
chmod 0600 "$PAYLOAD" "$READBACK"
|
||||||
|
|
||||||
|
command -v bao >/dev/null 2>&1
|
||||||
|
command -v python3 >/dev/null 2>&1
|
||||||
|
|
||||||
|
cat >"$PAYLOAD" <<'ROLE_JSON'
|
||||||
|
{
|
||||||
|
"role_type": "oidc",
|
||||||
|
"user_claim": "sub",
|
||||||
|
"groups_claim": "groups",
|
||||||
|
"oidc_scopes": ["openid", "profile", "email", "groups"],
|
||||||
|
"allowed_redirect_uris": [
|
||||||
|
"http://localhost:8250/oidc/callback",
|
||||||
|
"http://127.0.0.1:8250/oidc/callback",
|
||||||
|
"http://127.0.0.1:18200/ui/vault/auth/netkingdom/oidc/callback",
|
||||||
|
"https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback",
|
||||||
|
"https://bao.coulomb.social/ui/vault/auth/keycape/oidc/callback"
|
||||||
|
],
|
||||||
|
"bound_claims": {
|
||||||
|
"groups": ["net-kingdom-admins"]
|
||||||
|
},
|
||||||
|
"claim_mappings": {
|
||||||
|
"email": "email",
|
||||||
|
"preferred_username": "username"
|
||||||
|
},
|
||||||
|
"policies": ["platform-admin"],
|
||||||
|
"ttl": "1h"
|
||||||
|
}
|
||||||
|
ROLE_JSON
|
||||||
|
|
||||||
|
bao write "$ROLE_PATH" @"$PAYLOAD" >/dev/null 2>&1
|
||||||
|
bao read -format=json "$ROLE_PATH" >"$READBACK" 2>/dev/null
|
||||||
|
python3 - "$READBACK" "$CALLBACK_URI" <<'PY' >/dev/null 2>&1
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
path, callback = sys.argv[1:]
|
||||||
|
with open(path, encoding="utf-8") as handle:
|
||||||
|
role = json.load(handle).get("data") or {}
|
||||||
|
|
||||||
|
if callback not in role.get("allowed_redirect_uris", []):
|
||||||
|
raise SystemExit(1)
|
||||||
|
if role.get("role_type") != "oidc":
|
||||||
|
raise SystemExit(1)
|
||||||
|
if "platform-admin" not in role.get("token_policies", role.get("policies", [])):
|
||||||
|
raise SystemExit(1)
|
||||||
|
PY
|
||||||
78
tests/test_openbao_operator_loopback_callback.py
Normal file
78
tests/test_openbao_operator_loopback_callback.py
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
SCRIPT = REPO_ROOT / "scripts/openbao-apply-operator-loopback-callback.sh"
|
||||||
|
CALLBACK = "http://127.0.0.1:18200/ui/vault/auth/netkingdom/oidc/callback"
|
||||||
|
|
||||||
|
|
||||||
|
def _fake_bao(tmp_path: Path) -> tuple[Path, Path]:
|
||||||
|
capture = tmp_path / "written-role.json"
|
||||||
|
executable = tmp_path / "bao"
|
||||||
|
executable.write_text(
|
||||||
|
"""#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
if [ "$1" = "write" ]; then
|
||||||
|
cp "${3#@}" "$BAO_CAPTURE"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
if [ "$1" = "read" ]; then
|
||||||
|
if [ "${BAO_FAKE_MISSING_CALLBACK:-false}" = "true" ]; then
|
||||||
|
printf '%s\\n' '{"data":{"role_type":"oidc","token_policies":["platform-admin"],"allowed_redirect_uris":[]}}'
|
||||||
|
else
|
||||||
|
printf '%s\\n' '{"data":{"role_type":"oidc","token_policies":["platform-admin"],"allowed_redirect_uris":["http://127.0.0.1:18200/ui/vault/auth/netkingdom/oidc/callback"]}}'
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
exit 2
|
||||||
|
""",
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
executable.chmod(0o755)
|
||||||
|
return executable, capture
|
||||||
|
|
||||||
|
|
||||||
|
def _run(tmp_path: Path, *, missing_callback: bool = False) -> tuple[subprocess.CompletedProcess[str], Path]:
|
||||||
|
_, capture = _fake_bao(tmp_path)
|
||||||
|
env = dict(os.environ)
|
||||||
|
env.update(
|
||||||
|
{
|
||||||
|
"PATH": f"{tmp_path}:{env['PATH']}",
|
||||||
|
"TMPDIR": str(tmp_path),
|
||||||
|
"BAO_CAPTURE": str(capture),
|
||||||
|
"BAO_FAKE_MISSING_CALLBACK": str(missing_callback).lower(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
result = subprocess.run(
|
||||||
|
[str(SCRIPT)],
|
||||||
|
cwd=REPO_ROOT,
|
||||||
|
env=env,
|
||||||
|
text=True,
|
||||||
|
capture_output=True,
|
||||||
|
check=False,
|
||||||
|
)
|
||||||
|
return result, capture
|
||||||
|
|
||||||
|
|
||||||
|
def test_contained_command_is_silent_and_writes_exact_role(tmp_path: Path) -> None:
|
||||||
|
result, capture = _run(tmp_path)
|
||||||
|
assert result.returncode == 0
|
||||||
|
assert result.stdout == ""
|
||||||
|
assert result.stderr == ""
|
||||||
|
|
||||||
|
role = json.loads(capture.read_text(encoding="utf-8"))
|
||||||
|
assert CALLBACK in role["allowed_redirect_uris"]
|
||||||
|
assert role["policies"] == ["platform-admin"]
|
||||||
|
assert role["bound_claims"] == {"groups": ["net-kingdom-admins"]}
|
||||||
|
assert not list(tmp_path.glob("openbao-platform-admin-*.json"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_verification_failure_remains_silent_and_nonzero(tmp_path: Path) -> None:
|
||||||
|
result, _ = _run(tmp_path, missing_callback=True)
|
||||||
|
assert result.returncode != 0
|
||||||
|
assert result.stdout == ""
|
||||||
|
assert result.stderr == ""
|
||||||
|
assert not list(tmp_path.glob("openbao-platform-admin-*.json"))
|
||||||
|
|
@ -69,5 +69,12 @@ lifecycle-healthy and reaches the expected overlay. Then execute the guarded
|
||||||
retraction, coordinate public DNS withdrawal with railiance-infra, and return
|
retraction, coordinate public DNS withdrawal with railiance-infra, and return
|
||||||
non-secret acceptance evidence to Railiance Master.
|
non-secret acceptance evidence to Railiance Master.
|
||||||
|
|
||||||
|
Net Kingdom revision `61aeafe` additionally applied the exact KeyCape callback
|
||||||
|
live and proved the public authorization endpoint accepts it. Railiance
|
||||||
|
Platform now carries the silent, narrowly scoped
|
||||||
|
`scripts/openbao-apply-operator-loopback-callback.sh` owner command for the
|
||||||
|
governed `openbao-platform-admin-login` lane. The remaining hold is one
|
||||||
|
attended OIDC/MFA execution of that command followed by one loopback UI login.
|
||||||
|
|
||||||
This workplan authorizes no OpenBao seal/unseal, policy broadening, PVC or
|
This workplan authorizes no OpenBao seal/unseal, policy broadening, PVC or
|
||||||
Secret mutation, reboot, restore, or RMASTER-WP-0020-T08 cleanup.
|
Secret mutation, reboot, restore, or RMASTER-WP-0020-T08 cleanup.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue