Files
ss-tools/specs/025-clean-release-compliance/contracts/clean-release-api.openapi.yaml
2026-03-09 16:52:46 +03:00

715 lines
19 KiB
YAML

openapi: 3.1.0
info:
title: Clean Release API
version: 0.1.0
description: API-first contract for clean release candidate lifecycle, compliance runs, approvals and publications.
servers:
- url: /api
x-interface-actor-mapping:
description: External API request payloads use domain-specific actor fields; interface adapters may accept a unified actor context internally but must persist canonical *_by fields.
mappings:
candidate_register: created_by
manifest_build: created_by
compliance_run: requested_by
approval_or_reject: decided_by
publish: published_by
revoke: actor
paths:
/clean-release/candidates:
post:
summary: Register a release candidate
operationId: registerCleanReleaseCandidate
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RegisterCandidateRequest'
responses:
'201':
description: Candidate created
content:
application/json:
schema:
$ref: '#/components/schemas/CandidateOverview'
get:
summary: List release candidates
operationId: listCleanReleaseCandidates
responses:
'200':
description: Candidate list
content:
application/json:
schema:
type: object
required: [items]
properties:
items:
type: array
items:
$ref: '#/components/schemas/CandidateOverview'
/clean-release/candidates/{candidate_id}:
get:
summary: Get candidate overview
operationId: getCleanReleaseCandidate
parameters:
- $ref: '#/components/parameters/CandidateId'
responses:
'200':
description: Candidate overview
content:
application/json:
schema:
$ref: '#/components/schemas/CandidateOverview'
'404':
$ref: '#/components/responses/NotFound'
/clean-release/candidates/{candidate_id}/artifacts/import:
post:
summary: Import candidate artifacts
operationId: importCleanReleaseArtifacts
parameters:
- $ref: '#/components/parameters/CandidateId'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ImportArtifactsRequest'
responses:
'200':
description: Artifacts imported
content:
application/json:
schema:
type: object
required: [candidate_id, imported_count, status]
properties:
candidate_id:
type: string
imported_count:
type: integer
status:
type: string
/clean-release/candidates/{candidate_id}/artifacts:
get:
summary: List candidate artifacts
operationId: listCleanReleaseArtifacts
parameters:
- $ref: '#/components/parameters/CandidateId'
responses:
'200':
description: Candidate artifacts
content:
application/json:
schema:
type: object
required: [items]
properties:
items:
type: array
items:
$ref: '#/components/schemas/CandidateArtifact'
/clean-release/candidates/{candidate_id}/manifest:
post:
summary: Build a new manifest snapshot
operationId: buildCleanReleaseManifest
parameters:
- $ref: '#/components/parameters/CandidateId'
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
requested_by:
type: string
responses:
'201':
description: Manifest created
content:
application/json:
schema:
$ref: '#/components/schemas/DistributionManifest'
/clean-release/candidates/{candidate_id}/manifests:
get:
summary: List manifests for candidate
operationId: listCleanReleaseManifests
parameters:
- $ref: '#/components/parameters/CandidateId'
responses:
'200':
description: Candidate manifests
content:
application/json:
schema:
type: object
required: [items]
properties:
items:
type: array
items:
$ref: '#/components/schemas/DistributionManifest'
/clean-release/manifests/{manifest_id}:
get:
summary: Get manifest snapshot
operationId: getCleanReleaseManifest
parameters:
- name: manifest_id
in: path
required: true
schema:
type: string
responses:
'200':
description: Manifest snapshot
content:
application/json:
schema:
$ref: '#/components/schemas/DistributionManifest'
'404':
$ref: '#/components/responses/NotFound'
/clean-release/candidates/{candidate_id}/compliance-runs:
post:
summary: Request a compliance run
operationId: createCleanReleaseComplianceRun
parameters:
- $ref: '#/components/parameters/CandidateId'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateComplianceRunRequest'
responses:
'202':
description: Compliance run accepted
content:
application/json:
schema:
$ref: '#/components/schemas/ComplianceRun'
'404':
$ref: '#/components/responses/NotFound'
'409':
$ref: '#/components/responses/Conflict'
/clean-release/compliance-runs/{run_id}:
get:
summary: Get compliance run status
operationId: getCleanReleaseComplianceRun
parameters:
- name: run_id
in: path
required: true
schema:
type: string
responses:
'200':
description: Compliance run
content:
application/json:
schema:
$ref: '#/components/schemas/ComplianceRun'
'404':
$ref: '#/components/responses/NotFound'
/clean-release/compliance-runs/{run_id}/stages:
get:
summary: List stage results for a run
operationId: listCleanReleaseComplianceStages
parameters:
- name: run_id
in: path
required: true
schema:
type: string
responses:
'200':
description: Stage list
content:
application/json:
schema:
type: object
required: [items]
properties:
items:
type: array
items:
$ref: '#/components/schemas/ComplianceStageRun'
/clean-release/compliance-runs/{run_id}/violations:
get:
summary: List violations for a run
operationId: listCleanReleaseComplianceViolations
parameters:
- name: run_id
in: path
required: true
schema:
type: string
responses:
'200':
description: Violation list
content:
application/json:
schema:
type: object
required: [items]
properties:
items:
type: array
items:
$ref: '#/components/schemas/ComplianceViolation'
/clean-release/compliance-runs/{run_id}/report:
get:
summary: Get final report for a run
operationId: getCleanReleaseComplianceReport
parameters:
- name: run_id
in: path
required: true
schema:
type: string
responses:
'200':
description: Compliance report
content:
application/json:
schema:
$ref: '#/components/schemas/ComplianceReport'
'404':
$ref: '#/components/responses/NotFound'
/clean-release/candidates/{candidate_id}/approve:
post:
summary: Approve a candidate using a report
operationId: approveCleanReleaseCandidate
parameters:
- $ref: '#/components/parameters/CandidateId'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ApprovalRequest'
responses:
'200':
description: Approval created
content:
application/json:
schema:
$ref: '#/components/schemas/ApprovalDecision'
'409':
$ref: '#/components/responses/Conflict'
/clean-release/candidates/{candidate_id}/reject:
post:
summary: Reject a candidate using a report
operationId: rejectCleanReleaseCandidate
parameters:
- $ref: '#/components/parameters/CandidateId'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ApprovalRequest'
responses:
'200':
description: Rejection created
content:
application/json:
schema:
$ref: '#/components/schemas/ApprovalDecision'
'409':
$ref: '#/components/responses/Conflict'
/clean-release/candidates/{candidate_id}/publish:
post:
summary: Publish an approved candidate
operationId: publishCleanReleaseCandidate
parameters:
- $ref: '#/components/parameters/CandidateId'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PublishRequest'
responses:
'200':
description: Publication created
content:
application/json:
schema:
$ref: '#/components/schemas/PublicationRecord'
'409':
$ref: '#/components/responses/Conflict'
/clean-release/publications/{publication_id}/revoke:
post:
summary: Revoke a publication
operationId: revokeCleanReleasePublication
parameters:
- name: publication_id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RevokePublicationRequest'
responses:
'200':
description: Publication revoked
content:
application/json:
schema:
$ref: '#/components/schemas/PublicationRecord'
'404':
$ref: '#/components/responses/NotFound'
'409':
$ref: '#/components/responses/Conflict'
components:
parameters:
CandidateId:
name: candidate_id
in: path
required: true
schema:
type: string
responses:
NotFound:
description: Entity not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
Conflict:
description: Illegal lifecycle transition or conflicting state
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
schemas:
RegisterCandidateRequest:
type: object
required: [candidate_id, version, source_snapshot_ref, created_by]
properties:
candidate_id:
type: string
version:
type: string
source_snapshot_ref:
type: string
build_id:
type: string
created_by:
type: string
provenance_ref:
type: string
ImportArtifactsRequest:
type: object
required: [artifacts]
properties:
artifacts:
type: array
items:
$ref: '#/components/schemas/CandidateArtifactInput'
CandidateArtifactInput:
type: object
required: [path, sha256, size]
properties:
path:
type: string
sha256:
type: string
size:
type: integer
declared_category:
type: string
detected_category:
type: string
source_uri:
type: string
source_host:
type: string
metadata:
type: object
additionalProperties: true
CreateComplianceRunRequest:
type: object
required: [requested_by]
properties:
manifest_id:
type: string
requested_by:
type: string
ApprovalRequest:
type: object
required: [report_id, decided_by]
properties:
report_id:
type: string
decided_by:
type: string
comment:
type: string
PublishRequest:
type: object
required: [report_id, target_channel, actor]
properties:
report_id:
type: string
target_channel:
type: string
actor:
type: string
RevokePublicationRequest:
type: object
required: [actor, reason]
properties:
actor:
type: string
reason:
type: string
CandidateOverview:
type: object
required: [candidate_id, version, source_snapshot_ref, status]
properties:
candidate_id:
type: string
version:
type: string
source_snapshot_ref:
type: string
status:
type: string
latest_manifest_id:
type: string
latest_manifest_digest:
type: string
latest_run_id:
type: string
latest_run_status:
type: string
latest_report_id:
type: string
latest_report_final_status:
type: string
latest_policy_snapshot_id:
type: string
latest_policy_version:
type: string
latest_registry_snapshot_id:
type: string
latest_registry_version:
type: string
latest_approval_decision:
type: string
latest_publication_id:
type: string
latest_publication_status:
type: string
CandidateArtifact:
type: object
required: [id, candidate_id, path, sha256, size, metadata]
properties:
id:
type: string
candidate_id:
type: string
path:
type: string
sha256:
type: string
size:
type: integer
detected_category:
type: string
declared_category:
type: string
source_uri:
type: string
source_host:
type: string
metadata:
type: object
additionalProperties: true
DistributionManifest:
type: object
required: [id, candidate_id, manifest_version, manifest_digest, artifacts_digest, created_at, created_by, source_snapshot_ref, content_json, immutable]
properties:
id:
type: string
candidate_id:
type: string
manifest_version:
type: integer
manifest_digest:
type: string
artifacts_digest:
type: string
created_at:
type: string
format: date-time
created_by:
type: string
source_snapshot_ref:
type: string
content_json:
type: object
additionalProperties: true
immutable:
type: boolean
ComplianceRun:
type: object
required: [run_id, candidate_id, status, task_id]
properties:
run_id:
type: string
candidate_id:
type: string
manifest_id:
type: string
manifest_digest:
type: string
policy_snapshot_id:
type: string
registry_snapshot_id:
type: string
requested_by:
type: string
requested_at:
type: string
format: date-time
started_at:
type: string
format: date-time
finished_at:
type: string
format: date-time
status:
type: string
final_status:
type: string
failure_reason:
type: string
report_id:
type: string
task_id:
type: string
ComplianceStageRun:
type: object
required: [id, run_id, stage_name, status, details_json]
properties:
id:
type: string
run_id:
type: string
stage_name:
type: string
status:
type: string
started_at:
type: string
format: date-time
finished_at:
type: string
format: date-time
decision:
type: string
details_json:
type: object
additionalProperties: true
ComplianceViolation:
type: object
required: [id, run_id, stage_name, code, severity, message, evidence_json]
properties:
id:
type: string
run_id:
type: string
stage_name:
type: string
code:
type: string
severity:
type: string
artifact_path:
type: string
artifact_sha256:
type: string
message:
type: string
evidence_json:
type: object
additionalProperties: true
ComplianceReport:
type: object
required: [report_id, run_id, candidate_id, final_status, summary_json, generated_at, immutable]
properties:
report_id:
type: string
run_id:
type: string
candidate_id:
type: string
final_status:
type: string
summary_json:
type: object
additionalProperties: true
generated_at:
type: string
format: date-time
immutable:
type: boolean
ApprovalDecision:
type: object
required: [id, candidate_id, report_id, decision, decided_by, decided_at]
properties:
id:
type: string
candidate_id:
type: string
report_id:
type: string
decision:
type: string
decided_by:
type: string
decided_at:
type: string
format: date-time
comment:
type: string
PublicationRecord:
type: object
required: [id, candidate_id, report_id, published_by, published_at, target_channel, status]
properties:
id:
type: string
candidate_id:
type: string
report_id:
type: string
published_by:
type: string
published_at:
type: string
format: date-time
target_channel:
type: string
publication_ref:
type: string
status:
type: string
ErrorResponse:
type: object
required: [code, message]
properties:
code:
type: string
message:
type: string
details:
type: object
additionalProperties: true