feat(auth): connect Memoria identity and scoped memory - #704
feat(auth): connect Memoria identity and scoped memory#704loveRhythm1990 wants to merge 5 commits into
Conversation
XuPeng-SH
left a comment
There was a problem hiding this comment.
Conclusion: Request changes
The direction is valuable: a scoped key is safer than a Server master key, the CLI does not persist the Memoria secret, and read/write checks fail closed. However, this head introduces a parallel authentication and credential lifecycle and does not yet preserve Astra identity, consent, or deployment boundaries.
1. P1 — external identity is not namespaced by issuer and bypasses the canonical provider identity path
login_verified_identity derives the Astra account from only memoria_user_id, and the new table also keys only that subject. If MEMORIA_BASE_URL moves to another self-hosted instance, the same subject value is mapped to the existing Astra account. That is an account-confusion or takeover boundary: an external principal is (issuer, subject), never just subject.
The repository already has a provider-scoped external identity path using provider_id + external_subject, but this PR adds a Memoria-only table and emits tokens with origin internal, losing authentication provenance. Extend the canonical external identity/session lifecycle, or extract a generic verified-provider path keyed by a stable issuer/provider identifier. Do not add a second identity state machine.
2. P1 — one verified key can be sent to a different Memoria endpoint
/auth/memoria verifies against state.memoria_base_url, but the Server loop, background extraction, and session-end governance independently re-read MemoriaSettings::from_env(). build_server_state(settings) and AppState::with_memoria_config are explicit composition boundaries, so an injected setting or override can verify the secret against endpoint A and later decrypt and transmit it to endpoint B.
Carry one application-scoped Memoria provider identity/configuration and one user-credential resolver through every proxy, prompt recall, extraction, compaction, and governance path. A generic with_pool method must not implicitly select an external transport.
3. P1 — login and credential lifecycle is neither atomic nor revocable
The handler commits an Astra account and refresh session first, then writes the encrypted connection key in a separate transaction. A failure in the second phase returns login failure after durable session creation. Concurrent first logins can also race on account creation, and concurrent key replacements can leave more than one active row because auth_tokens has no unique active binding generation.
There is also no unlink/disconnect endpoint. astra logout revokes only one Astra refresh token, while the active encrypted Memoria bearer remains retained indefinitely. The schema inventory says removal happens through an explicit unlink or account-deletion workflow, but this PR implements neither. Put identity, session, and credential binding behind one service-owned transaction/state machine; add idempotent link, relink, revoke/unlink, and account-deletion behavior with an explicit retention contract.
4. P1 — access modes are checked too late in the runtime lifecycle
with_pool installs a Memoria port for every database-backed run. Accounts with no binding therefore attempt optional recall and report Unavailable instead of NotAttempted. For a read-only binding, background extraction can load memory, resolve an LLM selector, generate an update, and only then fail when store calls client(true). This creates repeated cost and error noise for work that consent already made inadmissible.
Resolve a typed per-user binding generation and access mode at the operation admission boundary. No binding or none should be a normal disabled state; read-only must not schedule write-oriented extraction, reflection, consolidation, or cleanup.
5. P1 — the default CLI journey breaks local and self-hosted Astra
No-argument astra login now always opens https://thememoria.ai, replacing the existing interactive username/password flow. The all-in-one stack points Astra Server at the local http://memoria:8100 and its documentation tells users to run no-argument astra login; a cloud website key cannot authenticate against that local issuer. The CLI-selected MEMORIA_WEB_URL is not discovered from or bound to the Astra Server configuration.
Preserve the existing login journey or present an explicit provider choice discovered from the target Server. The Server must own the trusted issuer and authorization URL. Also reject plaintext remote MEMORIA_WEB_URL values, and test the callback launcher on Windows: cmd /C start receives a URL containing & separators.
Required verification and documentation
The new tests cover a scope classifier, one callback parser happy path, and client-side secret persistence. They do not exercise the public auth route, a real identity/credential transaction, issuer changes, concurrent login/relink, partial failure, revocation/unlink, no-credential turns, read-only extraction, or callback rejection/platform behavior. Add focused DB and HTTP contract tests for these unhappy paths and an Astra-to-Memoria contract test pinned to the scoped-key API.
This PR changes a public endpoint, the default CLI command, configuration, credential retention, and the memory runtime contract but updates no public or design documentation. Update the CLI/API/configuration/deployment and memory/auth contracts in the same change.
Current CI is green and the merge tree is clean, but those facts do not cover the ownership and lifecycle failures above. The branch is behind current main; rebase after the design is corrected.
Summary
Tests
cargo fmt --all -- --checkcargo check -p astra-runtime -p astra-cliDepends on the Memoria scoped-key API and memoria-website connection flow.