Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
130 commits
Select commit Hold shift + click to select a range
e2a5a6b
Add account-derived LineageWeave RP profile
seonghobae Aug 13, 2026
694f406
Harden account-derived mapper reconciliation
seonghobae Aug 13, 2026
eb7271b
Fix Keycloak realm import and account profile bootstrap
seonghobae Aug 13, 2026
6e96ff0
Run Keycloak image as non-root
seonghobae Aug 13, 2026
cf4dbb9
Harden LineageWeave account claim deployment
seonghobae Aug 13, 2026
7d71024
Merge branch 'main' into codex/per-account-rp-claims
opencode-agent[bot] Aug 14, 2026
4ea8fbc
build: refresh account-unification lockfile
seonghobae Aug 14, 2026
43e7607
docs: separate downstream RP evidence
seonghobae Aug 14, 2026
eed91c9
docs: record product technical gap baseline
seonghobae Aug 20, 2026
eafa344
docs: refresh exact head gap evidence
seonghobae Aug 20, 2026
f9d0159
docs: define lineageweave tenant mapping
seonghobae Aug 20, 2026
65c6290
docs: refresh exact-head PR inventory
seonghobae Aug 20, 2026
826e774
docs: keep live PR evidence non-self-referential
seonghobae Aug 20, 2026
fb5e875
docs: track current SCIM lock PR evidence
seonghobae Aug 20, 2026
b52e0c0
docs: refresh SCIM PR head evidence
seonghobae Aug 20, 2026
cf34b81
docs: refresh SCIM PR head evidence
seonghobae Aug 20, 2026
815332d
docs: correct SCIM PR head hash
seonghobae Aug 20, 2026
271541f
docs: record exact Strix failure evidence
seonghobae Aug 20, 2026
1acf3a5
test(clients): cover malformed observed mapper drift
seonghobae Aug 20, 2026
506c7a1
docs: record workflow registry lifecycle evidence
seonghobae Aug 20, 2026
f785db2
docs: record workflow inventory pagination evidence
seonghobae Aug 20, 2026
d548df1
docs: record uv lock failure evidence
seonghobae Aug 20, 2026
1bd15d0
docs: refresh SCIM PR baseline evidence
seonghobae Aug 20, 2026
9b0069e
docs: record current SCIM review head
seonghobae Aug 20, 2026
c483bd5
docs: refresh live product gap baseline
seonghobae Aug 20, 2026
14193ad
docs: refresh gap baseline doctoring
seonghobae Aug 20, 2026
02baa31
docs: record live oidc acceptance boundary
seonghobae Aug 20, 2026
3777f54
test(realm): cover default validator artifacts
seonghobae Aug 20, 2026
193ea3a
docs: refresh current PR gap evidence
seonghobae Aug 20, 2026
49d8899
docs: record cross-repo cadence dependency
seonghobae Aug 20, 2026
32b69cd
docs: refresh live check failure baseline
seonghobae Aug 20, 2026
fb75994
docs: record stacked lockfile rerun
seonghobae Aug 20, 2026
0cf06bf
docs: record recovered lockfile checks
seonghobae Aug 20, 2026
89a1415
docs: bound storage evidence gap
seonghobae Aug 20, 2026
2b8c59f
docs: reconcile ecosystem dependency evidence
seonghobae Aug 20, 2026
a997826
docs: update current documentation head
seonghobae Aug 20, 2026
8a5ba11
docs: record exact local CI evidence
seonghobae Aug 20, 2026
0d4d1b9
docs: pin latest baseline head
seonghobae Aug 20, 2026
9f6e9b6
docs: reconcile scheduler and check baseline
seonghobae Aug 20, 2026
972ed50
docs: record local PostgreSQL evidence
seonghobae Aug 20, 2026
8e74c4e
docs: record stacked CodeQL checks
seonghobae Aug 20, 2026
b35def4
docs: record dependency stack state
seonghobae Aug 20, 2026
b0748bc
docs: refresh current authorization and cadence checks
seonghobae Aug 20, 2026
1937a6f
docs: record rebased dependency heads
seonghobae Aug 20, 2026
35a0bbd
docs: record encoded start-login remediation
seonghobae Aug 21, 2026
cae142c
docs: refresh current check evidence
seonghobae Aug 21, 2026
99fdd86
docs: record token rotation remediation
seonghobae Aug 21, 2026
e23af12
docs: refresh open PR evidence
seonghobae Aug 21, 2026
6acb064
docs: record current authorization PR head
seonghobae Aug 21, 2026
1604d8e
docs: align baseline with final token fix
seonghobae Aug 21, 2026
dbfea14
docs: refresh exact-head gap evidence
seonghobae Aug 21, 2026
899fb20
docs: correct live gap snapshot
seonghobae Aug 21, 2026
f2c4a15
docs: record stacked dependency updates
seonghobae Aug 21, 2026
58c6bb5
docs: record central coverage dependency
seonghobae Aug 21, 2026
bcd4b15
docs: refresh exact-head gap evidence
seonghobae Aug 21, 2026
6e0c92f
docs: refresh current queue evidence
seonghobae Aug 21, 2026
2c065e9
docs: update latest review evidence
seonghobae Aug 21, 2026
6244402
docs: track open MCP authorization gap
seonghobae Aug 21, 2026
096c12c
docs: record MCP cross-repo boundary
seonghobae Aug 21, 2026
920bed6
docs: record central automation failure evidence
seonghobae Aug 21, 2026
660e02e
docs: track central docstring repair
seonghobae Aug 21, 2026
d2b765f
docs: record scheduler dispatch evidence
seonghobae Aug 21, 2026
fbfbabd
docs: refresh live PR baseline
seonghobae Aug 21, 2026
daf2030
docs: refresh central check rollups
seonghobae Aug 21, 2026
6f3c861
docs: track scheduler hardening PRs
seonghobae Aug 21, 2026
3b35084
docs: record workflow registry lifecycle evidence
seonghobae Aug 21, 2026
cde3910
docs: refresh exact-head gap inventory
seonghobae Aug 21, 2026
f331938
docs: distinguish neutral security evidence
seonghobae Aug 21, 2026
d37d627
docs: refresh live product gap evidence
seonghobae Aug 21, 2026
ee6c13f
docs: correct MCP standards references
seonghobae Aug 21, 2026
7be7b48
docs: record post-snapshot PR heads
seonghobae Aug 21, 2026
630cd32
docs: refresh live PR evidence
seonghobae Aug 21, 2026
cdd0d74
docs: align baseline with current PR head
seonghobae Aug 21, 2026
35db1d2
docs: refresh live PR baseline
seonghobae Aug 21, 2026
0ba998f
docs: record latest MCP PR head
seonghobae Aug 21, 2026
3109b33
docs: refresh MCP PR head evidence
seonghobae Aug 21, 2026
ea74477
docs: clarify realm profile validator contract
seonghobae Aug 21, 2026
1a69a72
docs: refresh exact PR evidence
seonghobae Aug 21, 2026
a8cbafe
fix: preserve realm validation diagnostics
seonghobae Aug 21, 2026
ee96f6d
docs: record validator diagnostics fix
seonghobae Aug 21, 2026
ec78f92
docs: record SCIM coverage refresh
seonghobae Aug 21, 2026
ca075b3
docs: refresh live product gap baseline
seonghobae Aug 21, 2026
0735c81
fix(rp): reserve LineageWeave for account claims
seonghobae Aug 21, 2026
2887258
docs: refresh live PR gap baseline
seonghobae Aug 21, 2026
ac29331
docs: refresh authorization PR evidence
seonghobae Aug 21, 2026
28b69f6
docs: refresh live PR head inventory
seonghobae Aug 21, 2026
57f0cba
docs: refresh exact-head PR baseline
seonghobae Aug 21, 2026
babdb4f
docs: record stacked lockfile remediation state
seonghobae Aug 21, 2026
44f0f74
fix: reconcile Keycloak account profile read-back
seonghobae Aug 21, 2026
4092307
docs: record Keycloak registration remediation
seonghobae Aug 21, 2026
7b0a0c5
docs: refresh live PR queue evidence
seonghobae Aug 21, 2026
641ebe9
docs: record stacked OAuth merge evidence
seonghobae Aug 21, 2026
9a2d806
fix: diagnose missing LineageWeave profile attributes
seonghobae Aug 21, 2026
a92fdcb
docs: record profile bootstrap diagnostics
seonghobae Aug 21, 2026
ede8075
docs: refresh live PR and gap baseline
seonghobae Aug 21, 2026
a360fda
docs: refresh live PR gap evidence
seonghobae Aug 21, 2026
d89d4a6
docs: record fleet lifecycle dependency
seonghobae Aug 21, 2026
d039209
feat: bind hourly gap selection to live queue
seonghobae Aug 21, 2026
50276ff
docs: refresh live queue evidence and OSV RCA
seonghobae Aug 21, 2026
a44370f
docs: synchronize live PR gap baseline
seonghobae Aug 21, 2026
2fd5a77
docs: mark baseline head transition
seonghobae Aug 21, 2026
98c3305
docs: refresh live queue baseline
seonghobae Aug 21, 2026
35b0db0
docs: refresh current control-plane queue
seonghobae Aug 21, 2026
607b120
docs: align queue doctoring head
seonghobae Aug 21, 2026
4ee8689
docs: refresh live PR queue evidence
seonghobae Aug 21, 2026
a2875bc
docs: record current scheduler head
seonghobae Aug 21, 2026
e630eac
docs: bind queue snapshot to current keyverse head
seonghobae Aug 21, 2026
cede667
docs: refresh live hosted queue evidence
seonghobae Aug 21, 2026
c492245
docs: include current central repair stack
seonghobae Aug 21, 2026
2453296
docs: refresh live queue evidence
seonghobae Aug 21, 2026
9c75942
docs: refresh live queue evidence
seonghobae Aug 21, 2026
eb496ba
docs: refresh stacked control-plane evidence
seonghobae Aug 21, 2026
2fbe82a
docs: refresh live PR evidence snapshot
seonghobae Aug 21, 2026
f6a560a
docs: record current central control-plane queue
seonghobae Aug 21, 2026
c70f2cb
docs: bind snapshot to preceding keyverse head
seonghobae Aug 21, 2026
4d0d867
docs: refresh exact control-plane heads
seonghobae Aug 21, 2026
f4f85e9
docs: refresh queued check observations
seonghobae Aug 21, 2026
19ebd86
docs: refresh live control-plane queue
seonghobae Aug 21, 2026
f809c91
docs: refresh exact-head queue evidence
seonghobae Aug 21, 2026
25cf0e6
docs: refresh 2026-08-23 exact-head queue evidence
seonghobae Aug 23, 2026
84e0c75
docs: bind gap baseline to #100 head 25cf0e6
seonghobae Aug 23, 2026
655aaad
docs: bind gap baseline to live #100 head 84e0c75
seonghobae Aug 23, 2026
a1a65b2
docs: bind gap baseline to live #100 head 655aaad
seonghobae Aug 23, 2026
d978e9a
docs: record #100 observation SHA a1a65b2 vs later inventory commit
seonghobae Aug 23, 2026
7ad812b
Merge origin/main into pr-100
seonghobae Aug 31, 2026
e21a8bf
fix(docs): restore RFC 9068 and RFC 9207 after main merge
seonghobae Aug 31, 2026
6de6b65
test(realm): reject malformed user-profile shapes
seonghobae Aug 31, 2026
a473819
fix(realm): fail closed on malformed user profiles
seonghobae Aug 31, 2026
6a2af55
test(docs): require explicit current queue snapshot
seonghobae Aug 31, 2026
29a78ed
test(docs): stop treating dated snapshot as current
seonghobae Aug 31, 2026
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
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ jobs:
run: |
uv run coverage run --branch --source=app -m pytest -q
uv run coverage report --show-missing --fail-under=100
uv run coverage erase
uv run coverage run --branch -m pytest -q tests/test_validate_realm.py
uv run coverage report --include='*/scripts/validate_realm.py' --show-missing --fail-under=100
Comment thread
seonghobae marked this conversation as resolved.
- name: Build distribution
run: uv build --out-dir dist

Expand All @@ -56,7 +59,7 @@ jobs:
with:
python-version: "3.12"
- name: Validate Keycloak realm config-as-code
run: python scripts/validate_realm.py deploy/keycloak/realm-cwl.json
run: python scripts/validate_realm.py deploy/keycloak/cwl-realm.json
- name: Validate deployment template JSON
run: |
python - <<'PY'
Expand Down
14 changes: 10 additions & 4 deletions .github/workflows/hourly-product-development.yml
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,9 @@ jobs:

Inspect CLAUDE.md, README.md, CHANGELOG.md, docs/, deploy/templates/,
services/account_unification/app/, and services/account_unification/tests/.
Read docs/product-technical-gap-baseline.md and the current exact-head open
PR/issue inventory before selecting a gap; preserve active stack dependencies
and never treat predecessor Checks or reviews as current evidence.
Select exactly one highest-impact buyer-visible product gap that can be
completed safely in one bounded pull request. If the protected branch is not
healthy, restoring it is the only permitted objective.
Expand Down Expand Up @@ -498,9 +501,9 @@ jobs:
install -d -m 0750 "$agent_workspace" "$agent_home" "$agent_home/tmp"
git archive HEAD | tar -x -C "$agent_workspace"

cat >"${agent_workspace}/opencode.json" <<'CONFIG'
cat >"${agent_workspace}/opencode.json" <<CONFIG
{
"$schema": "https://opencode.ai/config.json",
"\$schema": "https://opencode.ai/config.json",
"enabled_providers": ["nvidia-nim"],
"lsp": false,
"mcp": {},
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
Expand Down Expand Up @@ -562,7 +565,7 @@ jobs:
NVIDIA_API_KEY=keyverse-local-broker \
OPENCODE_DISABLE_AUTOUPDATE=1 \
/bin/bash -c \
'ulimit -u 256; ulimit -n 1024; cd "$1"; exec opencode run "$2" --model "$3"' \
"ulimit -u 256; ulimit -n 1024; cd \"\$1\"; exec opencode run \"\$2\" --model \"\$3\"" \
bash "$agent_workspace" "$prompt" "$model"; then
sudo pkill -KILL -u 65532 >/dev/null 2>&1 || true
successful_workspace="$agent_workspace"
Expand Down Expand Up @@ -739,9 +742,12 @@ jobs:
uv run coverage erase
uv run coverage run --branch --source=app -m pytest -q
uv run coverage report --show-missing --fail-under=100
uv run coverage erase
uv run coverage run --branch -m pytest -q tests/test_validate_realm.py
uv run coverage report --include='*/scripts/validate_realm.py' --show-missing --fail-under=100
uv build --out-dir dist
)
python scripts/validate_realm.py deploy/keycloak/realm-cwl.json
python scripts/validate_realm.py deploy/keycloak/cwl-realm.json
docker compose -f docker-compose.yml config >/dev/null
while IFS= read -r -d '' template; do
python -m json.tool "$template" >/dev/null
Expand Down
6 changes: 4 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ queue owner.
- SAML/OIDC preflight performs no metadata/discovery fetch. LDAP preflight
performs no DNS, socket, bind, search, storage, or Keycloak call.
- OIDC relying-party mapper support stays closed: one self-pinned audience plus
only canonical `role`, `org`, and `workspace` hardcoded claims. Do not add
scripts, user attributes, groups, regex, arbitrary claims, new audiences, or
only canonical `role`, `org`, and `workspace` hardcoded claims, except the
ADR-0009 `lineageweave-web` profile which maps only a same-client account role
and the exact `org`/`workspace` account attributes. Do not add scripts,
other user attributes, groups, regex, arbitrary claims, new audiences, or
extra token destinations without a separately reviewed profile and RED test.
- Treat generated Keycloak mapper IDs and vendor ordering as normalization-only
metadata. Unknown, malformed, duplicate, or semantically changed live mappers
Expand Down
41 changes: 32 additions & 9 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,26 +158,42 @@ redirect/origin/logout policy, public/confidential client consistency, bounded
token metadata, and an exact portable scope set.

An optional closed `protocolMappers` profile carries exactly one self-pinned
`oidc-audience-mapper` plus zero to three canonical hardcoded claims named
`role`, `org`, and `workspace`. Mapper count, names, classes, destinations,
claim values, and ordering are bounded; scripts, user attributes, groups, regex,
arbitrary claims, unknown fields, and credential material are rejected.
`deploy/templates/oidc-rp-naruon.json` is the reviewed public-client instance of
that profile. Its routing claim values are deployment data and must not contain
credentials or personal secrets.
`oidc-audience-mapper` plus either zero to three canonical hardcoded claims or
the ADR-0009 LineageWeave account-derived trio. The latter is limited to a
same-client `oidc-usermodel-client-role-mapper` for multivalued `role` and two
scalar `oidc-usermodel-attribute-mapper` entries from exact `org` and
`workspace` account attributes. The three dynamic claims must appear together
and cannot mix with hardcoded claims. Mapper count, names, classes,
destinations, claim values, and ordering are bounded; scripts, other user
attributes, groups, regex, arbitrary claims, unknown fields, and credential
material are rejected. `deploy/templates/oidc-rp-naruon.json` is the reviewed
public-client instance of the static profile; `deploy/templates/oidc-rp-lineageweave.json`
is the confidential account-derived contract. The reserved `lineageweave-web`
client cannot use the static hardcoded profile; the validator rejects that
client-specific downgrade. Neither template contains a credential or proves a
live account login.

The post-import `org` and `workspace` account attributes remain scalar and
administrator-managed but are optional during initial passwordless account
creation because Keycloak validates administrator-only required fields on its
Admin REST create path. An identity-only account cannot enter LineageWeave
routing until an operator assigns both values and the receiving application
accepts the resulting claims.

Stateful reconciliation keys intent by validated `clientId`, classifies zero,
one, or multiple exact Keycloak clients, and never mutates duplicates. Create or
update is re-observed before a canonical receipt is written. Delete is remote-
first. For mapper comparison, Keyverse ignores only a valid generated mapper
`id`, canonicalizes the known mapper order, revalidates the closed shape, and
treats unknown, malformed, duplicate, or semantically changed mappers as drift.
Keycloak's account-role mapper may omit an empty `rolePrefix` on read-back;
reconciliation restores only that exact empty default for the exact `role`
account-role mapper and continues to reject all other missing or changed fields.
The accepted representation has no client-secret field; credential provisioning
remains an independent secret-management responsibility.

Native loopback/private-use redirects, different resource audiences, and claim
expansion beyond `role`, `org`, and `workspace` remain separate reviewed
profiles.
expansion beyond the two closed profiles remain separate reviewed profiles.

Each downstream RP is a separate trust boundary. The RP must validate the
Keyverse issuer, signature/algorithm, expiry, subject, and audience, map the
Expand Down Expand Up @@ -221,6 +237,13 @@ explicitly documented deployment-controller responsibility.

## Automation boundaries

- GitHub Actions source files and the Actions workflow registry are separate
control-plane state. The central `.github` lifecycle inventory binds a
paginated registry observation to the exact protected default-branch tree and
reports dynamic identities separately from repository-path identities. The
inventory is read-only; any registry disablement requires a separately
reviewed, immediately revalidated operator action and a post-action
reconciliation.
- The hourly PR steward advances only trusted same-repository PRs with exact-head
approvals and required Checks.
- The hourly product-development workflow runs OpenCode through
Expand Down
71 changes: 71 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,29 @@ Keep a Changelog, and releases use semantic versioning.

### Added

- The hourly product-development prompt now reads the exact-head gap baseline and
open PR/issue inventory before selecting an independent buyer-visible slice.
- A dated product and technical gap baseline that records the live PR/Issue
queue, exact-head Check evidence, buyer-visible authorization and runtime
acceptance gaps, and the protected hourly loop.
- ADR-0008 and the non-fork RP authorization matrix, requiring explicit
Keyverse token validation, tenant/resource ABAC, bounded RBAC, and
cross-tenant acceptance evidence per application.
- A closed optional OIDC relying-party mapper profile with one self-pinned
access-token audience, bounded `role`, `org`, and `workspace` hardcoded claims,
canonical mapper ordering, Keycloak-generated-ID/order normalization, and a
secret-free `naruon-web` runtime desired-state template.
- ADR-0009's confidential `lineageweave-web` account-derived mapper profile:
same-client roles plus exact scalar `org` and `workspace` account attributes,
with no static/dynamic mixing, a secret-free deployment template, and
reconciliation regression coverage.
- The reserved `lineageweave-web` client now rejects hardcoded authorization
claims, while Compose keeps the account service fail-closed until its
post-import account-profile bootstrap succeeds.
- A normative LineageWeave tenant mapping: `org` is the opaque external tenant
key, `workspace` is its child namespace, ambiguous or multi-membership
resolution fails closed, and lifecycle changes require a new token or
session renewal; no generic `tenant` mapper was introduced.
- Durable, secret-free OIDC relying-party desired-state CRUD and reconciliation
with exact `clientId` matching, duplicate fail-closed behavior, post-mutation
re-observation, canonical apply receipts, realm-rebuild recovery, per-client
Expand Down Expand Up @@ -55,6 +71,47 @@ Keep a Changelog, and releases use semantic versioning.

### Changed

- Separated PR #100 observation SHA `a1a65b26c1ebcd3ce964e56b1f0976e132d33cb9`
from the later inventory commit SHA in the gap baseline so docs-only binds
are not recursively re-named; pending Strix and Devin Review stay unverified.
- Rebound the product and technical gap baseline to live Keyverse PR #100 exact
head `655aaad57678e2503ac83a74fa8e19d6efc5f598`, recording zero unresolved
threads and treating pending Strix and Devin Review as unverified rather than
inheriting predecessor `84e0c75` Checks, then stopped further docs-only
pushes unless a source-fault Check fails.
- Rebound the product and technical gap baseline to live Keyverse PR #100 exact
head `84e0c759f9d757452f109b9c5c96253d54b85853`, recording zero unresolved
threads and treating pending Strix and Devin Review as unverified rather than
inheriting predecessor `25cf0e6` Checks.
- Bound the product and technical gap baseline to Keyverse PR #100 exact head
`25cf0e63760cf22cf73a1322eb1953b0dd2aada7` with zero unresolved threads and
an in-progress Strix Check recorded as unverified, and re-listed #113, #112,
#103, #101, #83 plus `.github` #1233/#1252 with no source-fault Check
failures.
- Refreshed the product and technical gap baseline to the 2026-08-23 exact-head
queue (#113, #112, #103, #101, #100, #83), recorded independent approval as
the remaining merge blocker, closed #110/#111 and stacked #115 as historical
rather than open-PR work, and named G0 then G4 as the next buyer-visible
order while the queue stays non-empty.
- Refreshed the product and technical gap baseline with the current exact-head
PR inventory, including the lockfile repair review gate and the requeued
`lineageweave-web` Checks; predecessor evidence remains non-transferable.
- Added the active PR #113 SCIM deactivation-lock state and the current PR #103
Strix/IDOR evidence to the gap baseline; neither is represented as protected
main until exact-head review and merge evidence exists.
- Refreshed the PR #103 Strix evidence with its exact failed run/job and kept
the contradictory operator-admin IDOR interpretation fail-closed pending
independent security validation.
- The Helm realm-import operator runbook now migrates the legacy
`realm-cwl.json` ConfigMap key to `cwl-realm.json` before rollout, preserving
a rollback copy and requiring post-rollout realm discovery verification.
- Account-derived OIDC claim mappers are now limited to the ADR-0009
`lineageweave-web` profile, and a non-string observed mapper type is treated
as reconciliation drift rather than causing an exception. Operator guides now
consistently name issued `org` (company) and `workspace` (PU) claims.
- The post-import LineageWeave profile bootstrap now reports which required
`org` or `workspace` account attribute is missing from the read-back profile
before it stops the dependent service.
- Federation PUT and apply now report `applied_to_keycloak: true` only after a
fresh live Keycloak identity-provider observation matches the desired
observable representation. Keycloak's fixed mask for the known
Expand Down Expand Up @@ -111,6 +168,20 @@ Keep a Changelog, and releases use semantic versioning.

### Fixed

- Prevented Keycloak's omitted empty account-role `rolePrefix` read-back from
causing perpetual relying-party drift, while retaining fail-closed handling
for all other missing or changed mapper configuration.
- Allowed passwordless registration to create an identity-only account before
administrator assignment of `org` and `workspace`; routing remains blocked
until both claims are assigned and downstream validation accepts them.
- Disabled 37 orphaned active GitHub Actions registry identities whose
repository paths were absent from protected `main`, while preserving the
four supported workflow identities and two GitHub-owned dynamic Dependabot
identities; recorded exact before/after reconciliation and operational smoke
evidence for issue #99.
- Packaged the portable Keycloak realm under the required `cwl-realm.json`
directory-import name in Compose and mapped it in Helm, with a deployment
contract that prevents a healthy-but-empty identity realm.
- Prevented relying-party inventory from silently accepting a KV key/body
identity mismatch, rejected unsafe live or `Location`-derived client UUIDs,
and aligned exact client discovery with Keycloak's documented
Expand Down
18 changes: 10 additions & 8 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ make ready # poll readiness (deploy/scripts/healthz.sh)
make install # install the admin service development environment
make test # run account-unification unit tests
make lint # run Ruff + interrogate docstring coverage
make validate-realm # validate deploy/keycloak/realm-cwl.json
make validate-realm # validate deploy/keycloak/cwl-realm.json
make seed-bootstrap # create a local SQLite KV bootstrap store
```

Expand Down Expand Up @@ -110,10 +110,11 @@ is required by the normal suite.
`kcadm-bootstrap.sh`. The realm contains no employer-specific federation.
- `deploy/templates/` — explicit private deployment contracts. SAML/OIDC use
Keyverse desired-state endpoints. `oidc-rp-naruon.json` is the reviewed public
Naruon runtime RP profile with one audience mapper and bounded routing claims.
LDAP is preflighted through Keyverse and then applied through private Keycloak
Admin REST in this release. All `{{placeholders}}` are resolved from KV before
use.
Naruon runtime profile; `oidc-rp-lineageweave.json` is the ADR-0009
confidential profile that projects an account's same-client role and exact
`org`/`workspace` attributes. LDAP is preflighted through Keyverse and then
applied through private Keycloak Admin REST in this release. All
`{{placeholders}}` are resolved from KV before use.
- `deploy/bootstrap/` — the bootstrap pointer locating the KV/DB config store.
- `helm/cwl-idp/` — the same three components; Keycloak and Postgres may be
disabled in favor of externally managed services. Secrets come from
Expand Down Expand Up @@ -142,9 +143,10 @@ is required by the normal suite.
- **OIDC relying-party metadata is secret-free desired state.** Validate with
`POST /clients/relying-parties:validate`, persist with `PUT`, and require exact
post-mutation observation before accepting a receipt. The optional mapper
profile permits exactly one audience mapper plus only canonical `role`, `org`,
and `workspace` hardcoded claims. Never expand mapper classes, claim names,
resource audiences, or token destinations by configuration alone.
profile permits static canonical claims, plus the separately reviewed
ADR-0009 `lineageweave-web` account-derived profile. Never expand mapper
classes, claim names, resource audiences, or token destinations by
configuration alone.
- **Treat mapper normalization narrowly.** Ignore only a valid generated mapper
`id` and canonicalize known mapper order. Unknown, malformed, duplicate, or
semantically changed live mapper state is drift. Mapper configuration does not
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ seed-bootstrap: ## Create a local sqlite KV bootstrap store for dev
python $(SERVICE_DIR)/tools/seed_config_store.py

validate-realm: ## Validate the Keycloak realm config-as-code
python scripts/validate_realm.py deploy/keycloak/realm-cwl.json
python scripts/validate_realm.py deploy/keycloak/cwl-realm.json

install: ## Install the admin service with dev extras
cd $(SERVICE_DIR) && python -m pip install -e '.[dev]'
Expand Down
Loading
Loading