Automated PR created via MCP by Copilot on user request: "pr gegen platform-dev". Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #332
132 lines
6.4 KiB
Markdown
132 lines
6.4 KiB
Markdown
# Data Model: Enterprise Access Boundary & Support Access Governance v1
|
|
|
|
**Date**: 2026-05-05
|
|
**Branch**: `276-support-access-governance`
|
|
|
|
## Overview
|
|
|
|
This slice adds one new workspace-owned truth: support-access grant history. Existing `audit_logs`, `BreakGlassSession`, and workspace settings remain in place. The new grant history drives support-access state, approval, expiry, and recovery gating.
|
|
|
|
## Persisted Truth
|
|
|
|
### 1. Support Access Grant
|
|
|
|
**Persistence**: New `support_access_grants` table
|
|
**Ownership**: Workspace-owned
|
|
**Scope**: Many historical rows per workspace, with dedupe preventing overlapping active or pending grants for the same workspace, platform actor, and scope.
|
|
|
|
| Field | Type | Nullable | Validation | Notes |
|
|
|-------|------|----------|------------|-------|
|
|
| `id` | bigint | no | primary key | Internal record id |
|
|
| `workspace_id` | bigint | no | foreign key | Primary customer scope anchor |
|
|
| `requested_by_platform_user_id` | bigint | no | foreign key | Platform actor who requested support access |
|
|
| `approved_by_user_id` | bigint | yes | foreign key | Workspace owner who approved the risky recovery path |
|
|
| `scope` | string | no | one of `audit_view`, `workspace_recovery` | Bounded v1 support scope catalog |
|
|
| `status` | string | no | one of `requested`, `active`, `denied`, `expired`, `ended` | Lifecycle state |
|
|
| `approval_mode` | string | no | one of `auto`, `owner_required`, `ownerless_waiver` | Explains why approval did or did not occur |
|
|
| `reason` | text | no | trimmed, min length 5 | Operator-supplied reason |
|
|
| `waiver_reason` | text | yes | required when `approval_mode=ownerless_waiver` | Explicit ownerless recovery waiver context |
|
|
| `ttl_minutes` | integer | no | positive integer, bounded max from config or policy | Requested active duration |
|
|
| `requested_at` | datetime | no | set on creation | Request timestamp |
|
|
| `approved_at` | datetime | yes | required when owner approval occurs | Approval timestamp |
|
|
| `starts_at` | datetime | yes | required when grant becomes active | Active timestamp |
|
|
| `expires_at` | datetime | yes | required when grant becomes active | Grant expiry |
|
|
| `ended_at` | datetime | yes | set when support access is ended manually | Manual end timestamp |
|
|
| `denied_at` | datetime | yes | set when owner denies a request | Denial timestamp |
|
|
| `created_at` | datetime | no | standard timestamp | Row creation |
|
|
| `updated_at` | datetime | no | standard timestamp | Row update |
|
|
|
|
**Write rules**:
|
|
|
|
- `workspace_id`, `requested_by_platform_user_id`, and `scope` are immutable once created.
|
|
- `requested` is the initial state for every new row.
|
|
- `audit_view` may move directly from `requested` to `active` with `approval_mode=auto`.
|
|
- `workspace_recovery` moves from `requested` to `active` only after owner approval or ownerless waiver.
|
|
- Active grants may transition to `expired` or `ended`. Requested grants may transition to `denied`.
|
|
|
|
**Dedupe rule**:
|
|
|
|
- At most one non-terminal row may exist for the same `workspace_id`, `requested_by_platform_user_id`, and `scope` while `status` is `requested` or `active`.
|
|
|
|
## Existing Persisted Truth Reused
|
|
|
|
### 2. Audit Log
|
|
|
|
**Persistence**: Existing `audit_logs` table
|
|
**Owner**: Existing audit infrastructure
|
|
|
|
This slice reuses `audit_logs` for customer-visible history and export. Support-access events become a first-class audit action family.
|
|
|
|
### 3. Break-Glass Session
|
|
|
|
**Persistence**: Existing session-backed `BreakGlassSession`
|
|
**Owner**: Existing system-plane emergency control
|
|
|
|
Break-glass remains session-backed and system-wide. It is not replaced by support-access grant history, but recovery gating now depends on both.
|
|
|
|
## Code-Owned Truth
|
|
|
|
### 4. Support Scope Catalog
|
|
|
|
**Persistence**: none, code-owned
|
|
|
|
| Scope | Label | Risk class | Requires owner approval? | Allows mutation? |
|
|
|-------|-------|------------|--------------------------|------------------|
|
|
| `audit_view` | Audit trail review | low | no | no |
|
|
| `workspace_recovery` | Workspace recovery | high | yes when owners exist | yes |
|
|
|
|
### 5. Approval Mode Catalog
|
|
|
|
**Persistence**: none, code-owned
|
|
|
|
| Mode | Meaning |
|
|
|------|---------|
|
|
| `auto` | Low-risk support access activated immediately |
|
|
| `owner_required` | Workspace owner must approve before activation |
|
|
| `ownerless_waiver` | No owner existed, so recovery required explicit break-glass-backed waiver |
|
|
|
|
## Derived Truth
|
|
|
|
### 6. Active Support Access Summary
|
|
|
|
**Persistence**: none, derived at runtime
|
|
**Owner**: `SupportAccessGrantResolver`
|
|
|
|
| Field | Type | Required | Notes |
|
|
|-------|------|----------|-------|
|
|
| `workspace_id` | int | yes | Current workspace |
|
|
| `active_grant_id` | int | no | Active grant when present |
|
|
| `pending_grant_id` | int | no | Pending risky grant when present |
|
|
| `scope` | string | no | Current or pending scope |
|
|
| `scope_label` | string | no | Operator-facing scope label |
|
|
| `status` | string | yes | Current support-access state summary |
|
|
| `reason` | string | no | Active or pending reason |
|
|
| `requester_label` | string | no | Platform requester display label |
|
|
| `approval_mode` | string | no | Explains activation path |
|
|
| `approver_label` | string | no | Owner approver display label |
|
|
| `expires_at` | datetime | no | Current expiry |
|
|
| `needs_break_glass` | bool | yes | True only for `workspace_recovery` |
|
|
|
|
### 7. Support Access Export Filter
|
|
|
|
**Persistence**: none, derived at runtime
|
|
**Owner**: existing admin audit-log page
|
|
|
|
The filter preset isolates audit actions that belong to the support-access family and remain in the active workspace scope only.
|
|
|
|
## State Transitions
|
|
|
|
| From | To | Trigger | Consequence |
|
|
|------|----|---------|-------------|
|
|
| none | `requested` | platform operator requests support access | grant becomes pending |
|
|
| `requested` | `active` | auto activation or explicit approval | support access becomes active until expiry or manual end |
|
|
| `requested` | `denied` | workspace owner denies recovery request | no active support access is granted |
|
|
| `active` | `expired` | current time passes `expires_at` | recovery and audit-view access end automatically |
|
|
| `active` | `ended` | platform operator ends support access | support access ends early |
|
|
|
|
## Boundaries Explicitly Preserved
|
|
|
|
- No tenant member impersonation, no direct customer session bridge, and no unrestricted admin browsing are introduced.
|
|
- `workspace_recovery` does not bypass break-glass and `audit_view` does not mutate customer state.
|
|
- Support-access history remains workspace-scoped even when audit rows include tenant references.
|