protocol: add canonical Phase 3A contract sources
This commit is contained in:
@@ -0,0 +1,414 @@
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
title: VerseVDI control contract
|
||||
version: 1.0.0
|
||||
description: Bounded Phase 3A control-plane wire contract; no provider or media endpoints.
|
||||
servers:
|
||||
- url: /
|
||||
tags:
|
||||
- name: authentication
|
||||
- name: resources
|
||||
- name: broker
|
||||
- name: events
|
||||
paths:
|
||||
/api/v1/auth/login:
|
||||
post:
|
||||
tags: [authentication]
|
||||
operationId: loginBrowserSession
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/LoginRequest
|
||||
responses:
|
||||
'200':
|
||||
description: Browser session established through secure cookies.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [username, provider, roles, role]
|
||||
properties:
|
||||
username: {type: string, minLength: 1, maxLength: 256}
|
||||
provider: {type: string, minLength: 1, maxLength: 64}
|
||||
roles: {type: array, maxItems: 16, items: {type: string, maxLength: 64}}
|
||||
role: {type: string, enum: [user, admin]}
|
||||
'400': {$ref: '#/components/responses/InvalidRequest'}
|
||||
'401': {$ref: '#/components/responses/Unauthorized'}
|
||||
'503': {$ref: '#/components/responses/Unavailable'}
|
||||
/api/v1/auth/refresh:
|
||||
post:
|
||||
tags: [authentication]
|
||||
operationId: rotateNativeCredential
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/RefreshRequest
|
||||
responses:
|
||||
'200':
|
||||
description: Rotated opaque native credential.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/NativeCredential
|
||||
'400': {$ref: '#/components/responses/InvalidRequest'}
|
||||
'401': {$ref: '#/components/responses/Unauthorized'}
|
||||
/api/v1/auth/session:
|
||||
get:
|
||||
tags: [authentication]
|
||||
operationId: getAuthenticatedSession
|
||||
security:
|
||||
- browserSession: []
|
||||
- nativeBearer: []
|
||||
responses:
|
||||
'200':
|
||||
description: Authenticated subject summary.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [username, provider, roles, role]
|
||||
properties:
|
||||
username: {type: string, minLength: 1, maxLength: 256}
|
||||
provider: {type: string, minLength: 1, maxLength: 64}
|
||||
roles: {type: array, maxItems: 16, items: {type: string, maxLength: 64}}
|
||||
role: {type: string, enum: [user, admin]}
|
||||
'401': {$ref: '#/components/responses/Unauthorized'}
|
||||
/api/v1/auth/reauth:
|
||||
post:
|
||||
tags: [authentication]
|
||||
operationId: issueReauthenticationGrant
|
||||
security:
|
||||
- browserSession: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/ReauthRequest
|
||||
responses:
|
||||
'200':
|
||||
description: Short-lived opaque step-up grant.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/ReauthGrant
|
||||
'400': {$ref: '#/components/responses/InvalidRequest'}
|
||||
'401': {$ref: '#/components/responses/Unauthorized'}
|
||||
/api/v1/auth/logout:
|
||||
post:
|
||||
tags: [authentication]
|
||||
operationId: logoutSession
|
||||
security:
|
||||
- browserSession: []
|
||||
- nativeBearer: []
|
||||
responses:
|
||||
'204': {description: Session revoked and browser cookies cleared.}
|
||||
'401': {$ref: '#/components/responses/Unauthorized'}
|
||||
/api/v1/auth/devices:
|
||||
post:
|
||||
tags: [authentication]
|
||||
operationId: registerDevice
|
||||
security:
|
||||
- browserSession: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/DeviceRegistrationRequest
|
||||
responses:
|
||||
'201':
|
||||
description: Single-use device challenge.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/DeviceChallenge
|
||||
'400': {$ref: '#/components/responses/InvalidRequest'}
|
||||
'401': {$ref: '#/components/responses/Unauthorized'}
|
||||
/api/v1/auth/devices/{device_id}/prove:
|
||||
post:
|
||||
tags: [authentication]
|
||||
operationId: proveDevice
|
||||
security:
|
||||
- browserSession: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DeviceID'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/DeviceProofRequest
|
||||
responses:
|
||||
'200':
|
||||
description: Opaque native credential.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/NativeCredential
|
||||
'400': {$ref: '#/components/responses/InvalidRequest'}
|
||||
'401': {$ref: '#/components/responses/Unauthorized'}
|
||||
/api/v1/auth/devices/{device_id}:
|
||||
delete:
|
||||
tags: [authentication]
|
||||
operationId: revokeDevice
|
||||
security:
|
||||
- browserSession: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DeviceID'
|
||||
responses:
|
||||
'204': {description: Device and its native authority revoked.}
|
||||
'401': {$ref: '#/components/responses/Unauthorized'}
|
||||
'404': {$ref: '#/components/responses/NotFound'}
|
||||
/api/v1/resources:
|
||||
get:
|
||||
tags: [resources]
|
||||
operationId: listResources
|
||||
security:
|
||||
- browserSession: []
|
||||
- nativeBearer: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/Limit'
|
||||
- $ref: '#/components/parameters/Cursor'
|
||||
responses:
|
||||
'200':
|
||||
description: Subject-scoped bounded resources and entitlements.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/ResourceList
|
||||
'400': {$ref: '#/components/responses/InvalidRequest'}
|
||||
'401': {$ref: '#/components/responses/Unauthorized'}
|
||||
/api/v1/broker/sessions:
|
||||
post:
|
||||
tags: [broker]
|
||||
operationId: requestBrokerSession
|
||||
security:
|
||||
- browserSession: []
|
||||
- nativeBearer: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/IdempotencyKey'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/SessionRequest
|
||||
responses:
|
||||
'201':
|
||||
description: Durable broker session.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/BrokerSession
|
||||
'202':
|
||||
description: Durable session waiting for an eligible desktop or capacity.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/BrokerSession
|
||||
'400': {$ref: '#/components/responses/InvalidRequest'}
|
||||
'401': {$ref: '#/components/responses/Unauthorized'}
|
||||
'403': {$ref: '#/components/responses/Forbidden'}
|
||||
'409': {$ref: '#/components/responses/Conflict'}
|
||||
/api/v1/broker/sessions/{session_id}:
|
||||
get:
|
||||
tags: [broker]
|
||||
operationId: getBrokerSession
|
||||
security:
|
||||
- browserSession: []
|
||||
- nativeBearer: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/SessionID'
|
||||
responses:
|
||||
'200':
|
||||
description: Subject-scoped broker session projection.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/BrokerSession
|
||||
'401': {$ref: '#/components/responses/Unauthorized'}
|
||||
'404': {$ref: '#/components/responses/NotFound'}
|
||||
/api/v1/broker/sessions/{session_id}/allocate:
|
||||
post:
|
||||
tags: [broker]
|
||||
operationId: allocateBrokerSession
|
||||
security:
|
||||
- browserSession: []
|
||||
- nativeBearer: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/SessionID'
|
||||
responses:
|
||||
'200':
|
||||
description: Gateway-only launch manifest with a single-use grant.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/ConnectionManifest
|
||||
'202':
|
||||
description: Session remains waiting for an eligible desktop or capacity.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/BrokerSession
|
||||
'401': {$ref: '#/components/responses/Unauthorized'}
|
||||
'404': {$ref: '#/components/responses/NotFound'}
|
||||
'409': {$ref: '#/components/responses/Conflict'}
|
||||
/api/v1/broker/sessions/{session_id}/reconnect:
|
||||
post:
|
||||
tags: [broker]
|
||||
operationId: reconnectBrokerSession
|
||||
security:
|
||||
- browserSession: []
|
||||
- nativeBearer: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/SessionID'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/ReconnectRequest
|
||||
responses:
|
||||
'200':
|
||||
description: Gateway-only reconnect manifest with a monotonic sequence.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/ConnectionManifest
|
||||
'400': {$ref: '#/components/responses/InvalidRequest'}
|
||||
'401': {$ref: '#/components/responses/Unauthorized'}
|
||||
'404': {$ref: '#/components/responses/NotFound'}
|
||||
'409': {$ref: '#/components/responses/Conflict'}
|
||||
/api/v1/broker/sessions/{session_id}/cancel:
|
||||
post:
|
||||
tags: [broker]
|
||||
operationId: cancelBrokerSession
|
||||
security:
|
||||
- browserSession: []
|
||||
- nativeBearer: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/SessionID'
|
||||
responses:
|
||||
'204': {description: Cancellation accepted idempotently.}
|
||||
'401': {$ref: '#/components/responses/Unauthorized'}
|
||||
'404': {$ref: '#/components/responses/NotFound'}
|
||||
'409': {$ref: '#/components/responses/Conflict'}
|
||||
/api/v1/events:
|
||||
get:
|
||||
tags: [events]
|
||||
operationId: resumeUserEvents
|
||||
security:
|
||||
- browserSession: []
|
||||
- nativeBearer: []
|
||||
parameters:
|
||||
- name: version
|
||||
in: query
|
||||
required: false
|
||||
schema: {type: string, enum: ['1']}
|
||||
- name: cursor
|
||||
in: query
|
||||
required: false
|
||||
schema: {type: string, maxLength: 512}
|
||||
- name: Upgrade
|
||||
in: header
|
||||
required: false
|
||||
schema: {type: string, enum: [websocket]}
|
||||
- name: Sec-WebSocket-Version
|
||||
in: header
|
||||
required: false
|
||||
schema: {type: string, enum: ['13']}
|
||||
responses:
|
||||
'200':
|
||||
description: Bounded resumable NDJSON event snapshot; WebSocket upgrades emit the same envelopes as text frames.
|
||||
headers:
|
||||
X-VerseVDI-Event-Cursor:
|
||||
schema: {type: string, maxLength: 512}
|
||||
content:
|
||||
application/x-ndjson:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/EventEnvelope
|
||||
'400': {$ref: '#/components/responses/InvalidRequest'}
|
||||
'401': {$ref: '#/components/responses/Unauthorized'}
|
||||
'409': {$ref: '#/components/responses/Conflict'}
|
||||
'426': {description: WebSocket version 13 is required.}
|
||||
'503': {$ref: '#/components/responses/Unavailable'}
|
||||
components:
|
||||
securitySchemes:
|
||||
browserSession:
|
||||
type: apiKey
|
||||
in: cookie
|
||||
name: versevdi_session
|
||||
nativeBearer:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: opaque
|
||||
parameters:
|
||||
DeviceID:
|
||||
name: device_id
|
||||
in: path
|
||||
required: true
|
||||
schema: {type: string, minLength: 1, maxLength: 128}
|
||||
SessionID:
|
||||
name: session_id
|
||||
in: path
|
||||
required: true
|
||||
schema: {type: string, minLength: 1, maxLength: 128}
|
||||
Limit:
|
||||
name: limit
|
||||
in: query
|
||||
required: false
|
||||
schema: {type: integer, minimum: 1, maximum: 100, default: 100}
|
||||
Cursor:
|
||||
name: cursor
|
||||
in: query
|
||||
required: false
|
||||
schema: {type: string, maxLength: 512}
|
||||
IdempotencyKey:
|
||||
name: Idempotency-Key
|
||||
in: header
|
||||
required: true
|
||||
schema: {type: string, minLength: 1, maxLength: 256}
|
||||
responses:
|
||||
InvalidRequest:
|
||||
description: The request is invalid.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/ErrorEnvelope
|
||||
Unauthorized:
|
||||
description: Authentication or credential validation failed without revealing credential state.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/ErrorEnvelope
|
||||
Forbidden:
|
||||
description: The authenticated subject is not entitled to the requested action.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/ErrorEnvelope
|
||||
NotFound:
|
||||
description: The resource is unavailable to this subject.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/ErrorEnvelope
|
||||
Conflict:
|
||||
description: The expected version, protocol version, idempotency, or event retention boundary conflicts.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/ErrorEnvelope
|
||||
Unavailable:
|
||||
description: The authoritative service is temporarily unavailable.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/control-v1.schema.json#/$defs/ErrorEnvelope
|
||||
Reference in New Issue
Block a user