Slice 0: per-user subject for device-key upload claims - #152
Merged
Merged
Conversation
…ce keys
When a `subject` field is present in the upload-claim request, the issued
JWT's `sub` and `principal_ref` become
`instance:{tenant_id}:{device_key_id}:user:{normalized_subject}`.
When absent, behavior is unchanged (principal equals the raw device_key_id).
The `grant_principal_ref` used for policy lookup remains device-scoped so
tenant access grant checks are not affected by per-user subjects.
Also removes the three `#[allow(dead_code)]` placeholder attributes added
in Task 1 now that `subject`, `MAX_SUBJECT_LEN`, and `normalize_subject`
are all actively consumed by the new derivation path.
Includes TDD: StubDeviceKeyDb + two new unit tests verified RED then GREEN.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ipals Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…esolution test
Replace the hand-built JWT in `mint_login_link_account_for_subject` with a
call to the real `issue_claim_for_device_key` path via
`trace_upload_claim_issuer_router`. A local `PerUserTestDeviceKeyDb` stub
(in-memory RwLock map, `get_device_key` only) registers the test keypair so
the issuer can verify the Ed25519 request-body signature. The issuer signs
the returned JWT with `TEST_EDDSA_PRIVATE_KEY_PEM`, which the ingest state's
existing `test_eddsa_signed_token_verifier` already trusts.
The test now proves:
- `issue_claim_for_device_key` derives the correct namespaced principal
(`instance:{tenant}:{device_key_id}:user:{subject}` vs raw `device_key_id`)
- the `aud` claim is present and round-trips through the token
- the four account-distinctness / idempotency assertions still hold
Self-skips (early return, exit ok) when `TRACE_COMMONS_PG_TEST_DATABASE_URL`
/ `DATABASE_URL` are unset; the issuer stub and router exercise the full
non-DB path regardless.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jun 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Lets one enrolled device key mint per-user contributor claims by accepting an optional, opaque
subjectin the upload-claim request. This enables a single IronClaw instance to fan out to many per-user Trace Commons accounts within its own tenant (the client-side integration lives in the ironclaw repo).TraceUploadClaimRequestgains optionalsubject: Option<String>+ anormalize_subjectvalidator (≤128 bytes, charset[A-Za-z0-9:_-], non-empty).issue_claim_for_device_key: whensubjectis present, derivessub/principal_ref = instance:{tenant}:{device_key_id}:user:{subject}; absent → unchanged (rawdevice_key_id). The tenant-access-grant principal stays device-scoped in both cases.mint_login_link_handler, proving distinct subjects under one device key resolve to distinct accounts (DB-gated, runs in CI).Properties
subject→ byte-identical to today.tenant_id+device_key_id; a compromised instance can only mis-attribute within its own tenant (RLS). Derivation is injective insubject./v1/account/login-linksas the design assumed.Non-blocking follow-ups
grant_principal_refdevice-scoping regression assertion.normalize_subject128-byte accept-edge test.subject.🤖 Generated with Claude Code