104 lines
6.9 KiB
Markdown
104 lines
6.9 KiB
Markdown
# platform-sdk Specification
|
|
|
|
## Purpose
|
|
TBD - created by archiving change cloud-runtime. Update Purpose after archive.
|
|
## Requirements
|
|
### Requirement: Versioned public API surface
|
|
The system SHALL expose the platform SDK's REST endpoints under a versioned URL prefix (`/v1/...`), distinct from the `mcp-tool-server` and `console-status-api`/`console-config-api` surfaces, so external integrators have a stable base path that will not silently change shape.
|
|
|
|
#### Scenario: Routes are mounted under the version prefix
|
|
- **WHEN** the platform SDK's router is mounted into an application
|
|
- **THEN** every route it exposes (task submission, status queries, device/host listing, plugin listing/registration) is reachable only under the `/v1/` prefix
|
|
|
|
### Requirement: Task submission and status via the SDK
|
|
The system SHALL allow an external integrator to submit a task (goal or workflow reference plus constraints) through the platform SDK's API, and to query that task's current status by id, backed by the `task-scheduler` capability.
|
|
|
|
#### Scenario: Submit a task via the API
|
|
- **WHEN** an integrator calls the task-submission endpoint with a valid goal and optional constraints
|
|
- **THEN** the API returns a task id that can be used to poll status, and the underlying `task-scheduler` records a new `queued` `ScheduledTask`
|
|
|
|
#### Scenario: Query status of a known task
|
|
- **WHEN** an integrator requests status for a task id that exists
|
|
- **THEN** the API returns that task's current status (`queued`, `assigned`, `dispatched`, `done`, or `failed`)
|
|
|
|
#### Scenario: Query status of an unknown task
|
|
- **WHEN** an integrator requests status for a task id that does not exist
|
|
- **THEN** the API returns a not-found response rather than an unhandled server error
|
|
|
|
### Requirement: Device and host visibility via the SDK
|
|
The system SHALL allow an external integrator to list devices and hosts known to the `device-pool` capability through the platform SDK's API.
|
|
|
|
#### Scenario: List devices across the pool
|
|
- **WHEN** an integrator calls the device-listing endpoint
|
|
- **THEN** the API returns every `PooledDevice` known to the pool, including owning host id and current (possibly `unreachable`) status
|
|
|
|
#### Scenario: List registered hosts
|
|
- **WHEN** an integrator calls the host-listing endpoint
|
|
- **THEN** the API returns every `HostRegistration` known to the pool, including last-seen timestamp
|
|
|
|
### Requirement: Plugin listing and registration via the SDK
|
|
The system SHALL allow an external integrator to list registered plugins and submit a new plugin manifest for registration through the platform SDK's API, backed by the `plugin-system` capability.
|
|
|
|
#### Scenario: List registered plugins
|
|
- **WHEN** an integrator calls the plugin-listing endpoint
|
|
- **THEN** the API returns every registered `PluginManifest`, including its `entry_point_kind` and whether it is wired to an execution path
|
|
|
|
#### Scenario: Register a new plugin manifest
|
|
- **WHEN** an integrator submits a valid plugin manifest to the plugin-registration endpoint
|
|
- **THEN** the API registers it via `plugin-system`'s `PluginRegistry` and returns the stored manifest, or a clear validation/conflict error if registration fails
|
|
|
|
### Requirement: Pluggable authentication hook with a safe default
|
|
The system SHALL evaluate every platform SDK route through a configurable scope-aware `AuthProvider` hook, and the deployable Cloud Control Plane SHALL reject anonymous access unless an explicit insecure-development override is enabled outside production.
|
|
|
|
#### Scenario: Production starts without configured credentials
|
|
- **WHEN** the Cloud Control Plane is configured as production without a usable public authentication provider or credentials
|
|
- **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
|
|
|
|
### Requirement: Python SDK client mirrors the REST API
|
|
The system SHALL provide a Python client (`CloudClient`) exposing methods corresponding to each `/v1/...` route (submit task, get task status, list devices, list hosts, list plugins, register plugin), so integrators do not need to hand-construct HTTP requests.
|
|
|
|
#### 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
|
|
|
|
### Requirement: Public API operations enforce scopes
|
|
The public platform API SHALL require operation-specific scopes, including task submission, task reading, pool reading, plugin reading, and plugin administration.
|
|
|
|
#### Scenario: Submit token has task scope
|
|
- **WHEN** a principal with `tasks:submit` calls the task-submission endpoint
|
|
- **THEN** the request is authorized subject to normal task validation
|
|
|
|
#### Scenario: Non-admin token 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
|
|
|
|
### Requirement: Distributed task status exposes attempt outcomes
|
|
The task-status API SHALL expose the existing lifecycle status and SHALL include non-secret assignment, attempt, and terminal failure metadata needed to diagnose distributed execution.
|
|
|
|
#### Scenario: Query an active remote task
|
|
- **WHEN** an authorized caller queries an assigned or dispatched task
|
|
- **THEN** the response includes its status, assigned host/device, current attempt number, and lease expiry without exposing the lease credential
|
|
|
|
#### Scenario: Query a failed remote task
|
|
- **WHEN** an authorized caller queries a task that exhausted retries or failed during Runtime execution
|
|
- **THEN** the response includes the terminal failure reason and attempt count
|
|
|
|
### Requirement: Python SDK supports authenticated requests
|
|
The Python `CloudClient` SHALL accept bearer credentials or an injectable authentication mechanism and SHALL apply authentication consistently to every public API method.
|
|
|
|
#### Scenario: Client configured with bearer token
|
|
- **WHEN** a caller constructs `CloudClient` with a valid bearer token and invokes a permitted method
|
|
- **THEN** the client sends the authorization credential and returns the corresponding API result
|
|
|
|
#### Scenario: Client receives authorization failure
|
|
- **WHEN** the configured credential is missing, invalid, or lacks the required scope
|
|
- **THEN** the client raises a typed HTTP/API error that preserves the response status without exposing the credential
|