Entra ID sign-in page, filters that stick to a thread, and an agent picker - #70
Merged
Merged
Conversation
The agent picker listed every agent and mode pair as its own entry, so one agent showed up several times with internal mode names. /api/models now returns one entry per agent with its modes nested. The mode picker sits behind "Avansert", and the default mode is the one the backend marks. When two agents share a short name, the namespace tells them apart. The backend stores the filter a thread was started with but never returns it. Reopening a thread therefore lost the filter, and follow-up questions used whatever the client sent. The server now remembers the filter when it creates a thread and applies it to every later turn. It returns the filter with the conversation detail and drops it when the thread is deleted. Smaller fixes in the chat view: - Turns are tracked by id rather than by question text, so asking the same question twice still settles the second answer. - Switching threads clears the live turn. - An aborted request says "Avbrutt." instead of reporting a connection failure. - Stop replaces the send button instead of being a separate button. - The composer is hidden on the home screen, and the sources panel starts closed. - Facets are fetched again a few times if the backend is not ready yet. - The combobox no longer overflows with long selections.
Supabase one-time codes were only a stopgap while the Entra ID app registration waited for admin consent. That consent is now granted, so the second mechanism is dead weight: another sign-in path to secure, throttle and document. Sign-in is now either Entra ID or off for local development. /auth/login now shows a login page with a button that starts the Microsoft flow. Callback failures, such as a cancelled login, a stale state or a disallowed domain, show that page with the error in place of a bare text response. The sidebar shows who is signed in and has a logout link. The deployment moves to qa.kunnskap.digdir.cloud. The Bicep template takes the custom domain as publicHost, derives APP_ORIGIN and the Entra callback from it, and requires the Entra client id and secret, because sign-in is always on.
The email domain allowlist duplicated what the single-tenant app registration already enforces. Its guest-UPN parsing was also fragile. Drop ALLOWED_EMAIL_DOMAINS so Entra ID alone decides who gets in. Because of that, AUTH_MODE=off now refuses to start unless APP_ORIGIN is localhost. An unauthenticated deployment is no longer one missing variable away. Tighten the rest while here: - Session and return-to cookies use the __Host- prefix outside localhost. - safeReturnTo resolves the path before rejecting /auth/ routes, so dot segments cannot sneak a logout through. - /api/* bodies are capped at 64 KiB. - Filters from /api/ask are reduced to known fields with bounded string lists. A thread with no remembered filter can then safely fall back to the one the client sent. - Recalling a thread's filter refreshes it, so filters for active threads are not evicted before idle ones. The deployed URL in the README now points at the custom domain.
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
Three commits on top of #68:
9d44742)3e71f8d)6e80ff1)Live: https://qa.kunnskap.digdir.cloud, which currently runs
main. This branch is not deployed yet.1. Agent picker and thread flow
The composer picks an agent rather than a raw tool, with the agent's description beside it. The agent's modes sit behind "Avansert".
The thread flow now matches the old app:
message/config), but its conversation API does not return it, so this is a stopgap until it does.2. Entra ID is the only login
/auth/loginshows a card with an Azure AD button instead of redirecting straight to Microsoft. The button links to/auth/start, which starts the flow.form-action 'self'would block a form post that redirects to Microsoft.AUTH_MODEisentraoroff.publicHostparameter setsAPP_ORIGINand the callback for the custom domain.3. Hardening after a security audit
Three reviewers covered auth and sessions, the request handling, and the frontend, infrastructure and branch history. They found nothing Critical or High, and no secrets in the history. This commit fixes the rest:
/api/*has a 64 KB body limit. A signed-in user could otherwise fill the container's memory through the filter field.ALLOWED_EMAIL_DOMAINSis removed.safeReturnTonormalises dot segments before refusing/auth/paths.__Host-prefix on https.AUTH_MODE=offrefuses to start unlessAPP_ORIGINis localhost.Deploying
ALLOWED_EMAIL_DOMAINS,SUPABASE_URL,SUPABASE_PUBLISHABLE_KEYand thesupabase-publishable-keysecret are no longer read, and can be removed from the container app.https://qa.kunnskap.digdir.cloud/auth/callback, andhttps://qa.kunnskap.digdir.cloud/for the logout return. Local development runs withAUTH_MODE=off.Testing
npm run typecheck,npm test(60 server, 55 web),npm run buildandaz bicep buildpass.Verified locally against a local backend:
AUTH_MODE=offwith a publicAPP_ORIGINexits.