Merge pull request #45 from mrteye/feature-guest-ingress-task-plan-17304586254181847688
docs: add task plan for phase 1 of events guest ingress
This commit is contained in:
commit
e357a26abb
@ -0,0 +1,85 @@
|
||||
# TASK METADATA
|
||||
|
||||
- **Target Files:** `server/routes/auth_forward.ts`, `ui/db_queries.ts`,
|
||||
`ui/mod.ts`, `server/routes/events.ts`, `server/tests/forward_auth.test.ts`,
|
||||
`server/tests/events.test.ts`
|
||||
- **Core Objective:** Implement Phase 1 of the Event & Session Overhaul: Enable
|
||||
Traefik ForwardAuth guest ingress for scoped event attendees, bridge session
|
||||
custom scopes to the Launchpad UI, and wire audit logging on event seat
|
||||
claims.
|
||||
- **Dependencies:** None.
|
||||
- **Additional Important Notes:** Follow zero-trust default-deny principles for
|
||||
ForwardAuth. Guest sessions minting needs to correctly log to the Merkle audit
|
||||
ledger for SIEM visibility.
|
||||
|
||||
---
|
||||
|
||||
### 2. Architectural Considerations & Risks
|
||||
|
||||
- **Risks:**
|
||||
- **ForwardAuth Security:** Modifying ForwardAuth to accept `guest` accounts
|
||||
risks inadvertently allowing guests to access applications they are not
|
||||
explicitly scoped for. Strict validation of `auth.customScopes` against the
|
||||
requested `appRecord.name` is critical.
|
||||
- **Launchpad Leakage:** The `getDashboardApps` query modification must be
|
||||
robust. If the UNION query is not correctly structured, it could leak
|
||||
visibility of unregistered or unauthorized apps to guests.
|
||||
- **Audit Logging Integrity:** Failure to capture the audit events properly
|
||||
during the `join` phase would break SIEM visibility. Using the non-blocking
|
||||
`auditWrapper.auditLog` is required to avoid impacting user request latency
|
||||
while ensuring compliance.
|
||||
|
||||
- **Alternatives:**
|
||||
- We considered a bypass in `ui/db_queries.ts` where guests completely skip
|
||||
the `grants` JOIN. However, using a `UNION` is structurally superior as it
|
||||
seamlessly supports both pure guests and regular active users who might hold
|
||||
delegated scoped passes. It provides a unified data retrieval flow.
|
||||
|
||||
### 3. Proposed Implementation
|
||||
|
||||
#### Phase 1: ForwardAuth Guest Ingress (`server/routes/auth_forward.ts`)
|
||||
|
||||
1. **Permit Guest Accounts:** Update the account status validation to allow
|
||||
`user.account_status === 'guest'` in addition to `'active'`.
|
||||
2. **Custom Scopes Validation:** If the user is a guest (or relying on custom
|
||||
scopes), verify that `auth.customScopes` contains the explicit application
|
||||
grant (e.g., `app:${appRecord.name}`). If not, return a 403 Forbidden.
|
||||
3. **Header Injection:** For guest sessions, compute the scopes to inject into
|
||||
`X-Forwarded-Scopes` by taking the comma-joined list of `auth.customScopes`
|
||||
(`auth.customScopes.join(",")`). This propagates the app scope (e.g.,
|
||||
`app:ed-droid`) and role (e.g., `viewer`) to downstream reverse proxies.
|
||||
|
||||
#### Phase 2: Launchpad App Query (`ui/db_queries.ts` & `ui/mod.ts`)
|
||||
|
||||
1. **Function Signature Update:** Update
|
||||
`getDashboardApps(userId: string, isAdmin: boolean, customScopes?: string[])`
|
||||
to accept the session's custom scopes.
|
||||
2. **UNION Query:** Update the non-admin SQL query to use a `UNION`.
|
||||
- The first part queries explicitly granted apps via the `grants` table.
|
||||
- The second part parses the provided `customScopes` array to extract allowed
|
||||
app names (e.g., stripping the `app:` prefix), querying the `apps` table
|
||||
for those matching names, and assigning them a pseudo-role such as
|
||||
`"Guest (Viewer)"` (or extracting the role from the scopes if possible).
|
||||
3. **UI Integration:** In `ui/mod.ts`, pass `auth.customScopes` from the
|
||||
resolved session into `getDashboardApps`.
|
||||
|
||||
#### Phase 3: Join Audit Logging (`server/routes/events.ts`)
|
||||
|
||||
1. **Audit `POST /api/join` (Web):** Immediately after minting the guest
|
||||
session, invoke
|
||||
`auditWrapper.auditLog(guestUuid, "event_seat_claimed", event.id, { slug: event.slug, name: event.name, seatNumber: event.seats_claimed, method: "web" }, getClientIp(c))`.
|
||||
2. **Audit `GET /join/:slug` (CLI):** Similarly, wire
|
||||
`auditWrapper.auditLog(guestUuid, "event_seat_claimed", event.id, { slug: event.slug, name: event.name, seatNumber: event.seats_claimed, method: "cli" }, getClientIp(c))`
|
||||
into this endpoint before returning the token.
|
||||
|
||||
#### Phase 4: Unit Testing
|
||||
|
||||
1. **ForwardAuth Tests (`server/tests/forward_auth.test.ts`):**
|
||||
- Add tests simulating a guest session with an `app:{name}` scope to ensure a
|
||||
`200 OK` response with correctly formatted `X-Forwarded-Scopes`.
|
||||
- Add tests simulating a guest session without the necessary `app:{name}`
|
||||
scope to ensure a `403 Forbidden` response.
|
||||
2. **Events Tests (`server/tests/events.test.ts`):**
|
||||
- Ensure the `POST /api/join` and `GET /join/:slug` assertions capture the
|
||||
`auditLog` spy calls and verify the exact payload (`event_seat_claimed`
|
||||
action, `event.id` as resource, correct metadata structure).
|
||||
Loading…
x
Reference in New Issue
Block a user