715 lines
19 KiB
YAML
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
|