Files

90 lines
6.1 KiB
Markdown

## ADDED Requirements
### Requirement: Versioned user authentication routes
The public API SHALL expose username/password login, logout, current-user, and password-change operations under `/v1/auth/...`, with login as the only anonymously callable user-authentication operation.
#### Scenario: Browser logs in
- **WHEN** a caller submits valid credentials to `/v1/auth/login`
- **THEN** the API establishes the secure user session and returns the user's non-secret identity, role, and effective scopes
#### Scenario: Caller gets the current user
- **WHEN** a caller presents a valid user session to `/v1/auth/me`
- **THEN** the API returns the current user's non-secret identity, role, effective scopes, and forced-password-change state
#### Scenario: Anonymous caller invokes another auth operation
- **WHEN** an anonymous caller invokes logout, current-user, or password-change
- **THEN** the API returns an authentication error without executing the operation
### Requirement: Versioned user administration routes
The public API SHALL expose user listing, creation, update, password reset, and session-revocation operations under `/v1/users/...`, all protected by `users:admin`.
#### Scenario: Administrator lists users
- **WHEN** a principal with `users:admin` lists users
- **THEN** the API returns bounded non-secret account records and no password hash, session digest, CSRF value, or login credential
#### Scenario: User administration lacks scope
- **WHEN** an authenticated principal without `users:admin` invokes any `/v1/users/...` operation
- **THEN** the API returns an authorization error before reading or changing protected user state
### Requirement: Existing bearer authentication remains compatible
The public and internal APIs SHALL continue to accept existing configured public, Host, enrollment, and dynamically enrolled Host bearer credentials with their previous scope and host-binding semantics after user authentication is enabled.
#### Scenario: CloudClient uses a configured token
- **WHEN** an existing `CloudClient` sends a valid configured public bearer token
- **THEN** its permitted resource operation succeeds without a browser session or CSRF header
#### Scenario: Host Agent uses its bearer credential
- **WHEN** an existing Host Agent authenticates to an internal Host route
- **THEN** host identity binding and authorization behave exactly as before the user system was added
## MODIFIED Requirements
### Requirement: Pluggable authentication hook with a safe default
The system SHALL evaluate every protected route through a configurable scope-aware `AuthProvider` chain that can authenticate existing bearer credentials or a valid repository-backed user session, and the deployable Cloud Control Plane SHALL reject anonymous resource access unless an explicit insecure-development override is enabled outside production.
#### Scenario: Production starts without a safe authentication mechanism
- **WHEN** the Cloud Control Plane is configured as production without user-session authentication, a usable bearer provider, or other safe public authentication provider
- **THEN** startup or readiness fails rather than exposing anonymous platform routes
#### Scenario: Explicit local anonymous override
- **WHEN** a non-production operator explicitly enables the insecure anonymous-development override
- **THEN** platform routes may use an anonymous principal and the application records that insecure mode is active
#### Scenario: Custom AuthProvider is honored
- **WHEN** a caller configures a custom `AuthProvider` that rejects a request or omits its required scope
- **THEN** the platform SDK route returns an authentication or authorization error without executing its handler operation
#### Scenario: User session provider is honored
- **WHEN** the authentication chain resolves a valid user session to a principal with the required scope
- **THEN** the protected route authorizes that principal through the same scope check used for bearer callers
### Requirement: Python SDK client mirrors the REST API
The system SHALL provide a Python `CloudClient` exposing methods corresponding to the `/v1/...` resource, user-authentication, and user-administration routes, with cookie persistence for login sessions and continued support for injected bearer authentication.
#### Scenario: Client submits a task and retrieves status
- **WHEN** a caller uses `CloudClient` to submit a task and then fetch its status by the returned id
- **THEN** the client's methods produce the same result as calling the corresponding `/v1/...` endpoints directly over HTTP
#### Scenario: Client authenticates a user session
- **WHEN** a caller uses `CloudClient` to log in with valid user credentials and then requests the current user
- **THEN** the client preserves the session cookies and returns the same non-secret user representation as the direct REST calls
#### Scenario: Bearer administrator manages users
- **WHEN** a caller configures `CloudClient` with a bearer token having `users:admin` and invokes a user-administration method
- **THEN** the client sends bearer authentication and returns the corresponding user-administration result without requiring cookie login
### Requirement: Public API operations enforce scopes
The public platform API SHALL require operation-specific scopes for task submission, task reading, pool reading, plugin reading, plugin administration, and user administration, regardless of whether the principal came from a bearer credential or user session.
#### Scenario: Submit principal has task scope
- **WHEN** a bearer or user principal with `tasks:submit` calls the task-submission endpoint
- **THEN** the request is authorized subject to normal task validation
#### Scenario: Non-admin principal attempts plugin registration
- **WHEN** an authenticated principal without `plugins:admin` calls plugin registration
- **THEN** the API rejects the request before resolving or loading the plugin target
#### Scenario: Non-admin principal attempts user administration
- **WHEN** an authenticated principal without `users:admin` calls a user-administration endpoint
- **THEN** the API rejects the request before reading or changing protected user state