Skip to content

Phase 6: Implement in-world identity with per-org Keycloak realms#10

Merged
aidankhogg merged 3 commits into
dev/alphafrom
claude/admiring-lamport-4av0c6
Jun 21, 2026
Merged

Phase 6: Implement in-world identity with per-org Keycloak realms#10
aidankhogg merged 3 commits into
dev/alphafrom
claude/admiring-lamport-4av0c6

Conversation

@aidankhogg

Copy link
Copy Markdown
Contributor

Summary

Implements Phase 6 (In-World Identity) with comprehensive Keycloak deployment for per-organization identity management. This phase creates isolated Keycloak realms for each organization, provisions users from spec, manages OIDC client credentials, and supports event-driven provisioning for new organization admissions.

Key Changes

  • Keycloak Container Management: Added _start_keycloak_container() to deploy Keycloak with TLS certificates for the canonical hostname (default: auth.internal), proper PostgreSQL database configuration, and health check polling with configurable timeout.

  • Per-Organization Realm Architecture: Implements one Keycloak realm per organization for maximum isolation. Each realm is named {org_name}-realm and created during phase execution.

  • User Provisioning: Seeds users from spec via org_users configuration. Users are created in their respective org realms with generated passwords. Includes error handling to continue provisioning even if individual user creation fails.

  • OIDC Client Management: Added _create_org_client() to create per-org OIDC clients with configurable redirect URIs and store credentials in Supabase for durability across restarts. Generates secure client secrets using secrets.token_urlsafe().

  • Event-Driven Provisioning: Implemented _consume_org_admission_events() as a background task that listens to pgmq for org.admitted events and dynamically creates realms and clients for newly admitted organizations. Includes DLQ archival for failed event processing.

  • Event Emission: Added _emit_event() to emit inworld_identity.ready events with causal tracing (correlation_id, parent_event_id) for downstream handlers. Events are queued to pgmq when available.

  • Prerequisite Validation: Phase 6 now validates that Phases 0-5 (Substrate, DNS, PKI, Registries, etc.) have completed before executing. Raises RuntimeError with clear messages if prerequisites are missing.

  • Enhanced Healthcheck: Improved healthcheck to verify:

    • Keycloak container is running
    • OIDC discovery endpoint responds with 200
    • At least one realm exists
    • Proper SSL context handling for self-signed certificates
  • Idempotent Execution: Phase skips if identity_inworld_output already exists in runtime state, enabling safe re-runs.

  • Comprehensive Output Structure: Populates identity_inworld_output with:

    • keycloak_container_id: Running container ID
    • realms_created: List of created realm names
    • credentials_stored: Count of OIDC credentials persisted
    • deployed_at: ISO 8601 timestamp
  • Improved Documentation: Added detailed docstrings for all public and private methods explaining responsibilities, arguments, return values, and exceptions.

  • Test Coverage: Added 429 lines of integration tests covering:

    • Interface compliance with BasePhaseHandler
    • Prerequisite validation
    • Per-org realm creation
    • User provisioning from spec
    • Healthcheck behavior
    • Idempotence
    • Org admission event processing
    • Event emission
    • Output structure validation

Notable Implementation Details

  • Uses aiohttp with custom SSL context (hostname checking disabled, certificate verification disabled) for self-signed certificate support during development.
  • Keycloak health check polls with 2-second intervals up to configurable timeout (default 120s).
  • Gracefully handles missing pgmq_client for M1-M5 testing scenarios (logs events instead of queuing).
  • Supabase credential storage is non-blocking; phase continues if Supabase is unavailable.
  • Event consumer runs as background task via asyncio.create_task() for non-blocking operation.
  • User provisioning continues on individual user creation failures to maximize provisioning success.

https://claude.ai/code/session_01VuzisGGSVDnV8fTHVsxjkv

claude added 3 commits June 21, 2026 23:50
**Changes:**

1. **M1-M2 DNS Enhancement**
   - Add auth.internal, ca.internal, registry.internal stubs to root zone
   - Pre-registers L1 service records (best practice for M6+ DNS)
   - All M1-M2 tests still passing

2. **M6 Complete Rewrite (from skeleton to production-ready)**
   - Per-org Keycloak realms (maximum isolation)
   - User provisioning: seed from spec + event-driven org.admitted events
   - OIDC client credentials stored in Supabase for durability
   - Proper error handling, prerequisite validation, idempotence
   - Background event consumer for dynamic org provisioning
   - Comprehensive health checks with SSL verification
   - Event emission for causal tracing

3. **Architecture Improvements**
   - Proper spec model usage (spec.identity_inworld - not dict access)
   - Full context/DI pattern (no ad-hoc task creation)
   - Correct handler initialization (PKIHandler, DockerHandler, OIDCHandler)
   - Proper SSL context for OIDC discovery endpoint
   - Graceful degradation when pgmq unavailable (M1-M5 testing)

4. **Test Suite**
   - 16 new M6 integration tests (interface, prerequisites, realm creation, user provisioning, healthcheck, idempotence, events)
   - Updated M4-M5 skeleton tests to use new completion tracking API
   - All 68 M1-M6 tests passing

**Design Decisions Locked:**
- One realm per org (isolation)
- User provisioning: seed from spec + event-driven
- OIDC credentials: Supabase storage
- DNS: auth.internal pre-registered by M1-M2 (not managed by M6)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuzisGGSVDnV8fTHVsxjkv
@aidankhogg aidankhogg self-assigned this Jun 21, 2026
@aidankhogg aidankhogg marked this pull request as ready for review June 21, 2026 23:54
@aidankhogg aidankhogg merged commit 6c31513 into dev/alpha Jun 21, 2026
3 checks passed
@aidankhogg aidankhogg deleted the claude/admiring-lamport-4av0c6 branch June 21, 2026 23:54
@aidankhogg aidankhogg added the enhancement New feature or request label Jun 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants