dad8365e6a
feat(local-identity): Stage 2 — Keycloak export & bootstrap integration (NK-WP-0002-T02)
...
export.py:
- split_fullname(): last-token strategy (Bernd Worsch → firstName/lastName)
- _deterministic_id(): uuid5(DNS, "local-identity.{realm}.{username}") for stable,
re-import-idempotent Keycloak IDs
- user_to_keycloak(): full Keycloak Admin REST API user representation;
production_identity mapping applied to username + realm; isolation attributes
(local_identity_environment, local_identity_generated) always present;
validate_keycloak_user() called on every conversion to catch schema drift
- bulk_export_body(): partial import body (ifResourceExists/realm/users)
cli.py: add `export` subcommand
- export <username> single user, prints Keycloak JSON
- export (no args) bulk; primary users only; stderr note on skipped test users
- export --include-test bulk; all users including generated
- --realm / --if-resource-exists flags
docs/LocalIdentity.md: add two new sections
- Keycloak import procedure: export → partialImport API → password reset → retire
- Isolation guarantee: attribute schema, Keycloak Condition authenticator config,
production_identity mapping walkthrough
tests/test_export.py: 34 new tests (88 total, all passing)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-03-02 00:23:39 +01:00
666a56f4ed
feat(local-identity): add --username and --fullname overrides to init
...
Resolves the system identity mismatch between the Linux username (worsch)
and the bootstrap identity (tegwick / Bernd Worsch / custom email).
Resolution order for all three fields: flag > config > system derivation.
Config is updated on every init so --force reinits are idempotent without
repeating the flags.
- cli.py: extract _resolve_init_params(); add --username / --fullname args;
persist all three fields to config.yaml on init
- tests/test_cli.py: 13 new tests covering flag priority, config fallback,
system derivation, config persistence, idempotent --force reinit
54 tests passing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-03-02 00:11:04 +01:00
4491beaffe
feat(local-identity): implement Stage 1 — core file store (NK-WP-0002-T01)
...
Deliverables:
- src/local_identity/gecos.py: /etc/passwd GECOS parsing, current_username()
- src/local_identity/user.py: UserRecord dataclass, ProductionIdentity, make_test_user()
- Pure test-user derivation: <user>N / +testN email alias / source_user tracking
- src/local_identity/store.py: file store CRUD backed by LOCAL_IDENTITY_HOME
- ~/.local-identity/ mode 700, user files mode 600
- All path lookups dynamic (env-var override enables clean test isolation)
- src/local_identity/cli.py: init/list/show commands; email from flag > config > prompt
- pyproject.toml + uv.lock: pyyaml dep, local-identity script entry point
Tests (41 passing):
- test_gecos.py: 9 tests — simple/comma/empty/non-ASCII/whitespace GECOS, fallback
- test_user.py: 14 tests — test-user derivation, YAML roundtrip, non-ASCII, idempotency
- test_store.py: 18 tests — dir creation, permissions (700/600), CRUD, list, config,
idempotency (reinit with --force produces identical users)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-03-02 00:01:54 +01:00