Files
git.stella-ops.org/docs/api/notify-openapi.yaml
StellaOps Bot 150b3730ef
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
up
2025-11-24 07:52:25 +02:00

614 lines
19 KiB
YAML

# OpenAPI 3.1 specification for StellaOps Notifier WebService (draft)
openapi: 3.1.0
info:
title: StellaOps Notifier API
version: 0.6.0-draft
description: |
Contract for Notifications Studio (Notifier) covering rules, templates, incidents,
and quiet hours. Uses the platform error envelope and tenant header `X-StellaOps-Tenant`.
servers:
- url: https://api.stellaops.example.com
description: Production
- url: https://api.dev.stellaops.example.com
description: Development
security:
- oauth2: [notify.viewer]
- oauth2: [notify.operator]
- oauth2: [notify.admin]
paths:
/api/v1/notify/rules:
get:
summary: List notification rules
tags: [Rules]
parameters:
- $ref: '#/components/parameters/Tenant'
- $ref: '#/components/parameters/PageSize'
- $ref: '#/components/parameters/PageToken'
responses:
'200':
description: Paginated rule list
content:
application/json:
schema:
type: object
properties:
items:
type: array
items: { $ref: '#/components/schemas/NotifyRule' }
nextPageToken:
type: string
examples:
default:
value:
items:
- ruleId: rule-critical
tenantId: tenant-dev
name: Critical scanner verdicts
enabled: true
match:
eventKinds: [scanner.report.ready]
minSeverity: critical
actions:
- actionId: act-slack-critical
channel: chn-slack-soc
template: tmpl-critical
digest: instant
nextPageToken: null
default:
$ref: '#/components/responses/Error'
post:
summary: Create a notification rule
tags: [Rules]
parameters:
- $ref: '#/components/parameters/Tenant'
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/NotifyRule' }
examples:
create-rule:
value:
ruleId: rule-attest-fail
tenantId: tenant-dev
name: Attestation failures → SOC
enabled: true
match:
eventKinds: [attestor.verification.failed]
actions:
- actionId: act-soc
channel: chn-webhook-soc
template: tmpl-attest-verify-fail
responses:
'201':
description: Rule created
content:
application/json:
schema: { $ref: '#/components/schemas/NotifyRule' }
default:
$ref: '#/components/responses/Error'
/api/v1/notify/rules/{ruleId}:
get:
summary: Fetch a rule
tags: [Rules]
parameters:
- $ref: '#/components/parameters/Tenant'
- $ref: '#/components/parameters/RuleId'
responses:
'200':
description: Rule
content:
application/json:
schema: { $ref: '#/components/schemas/NotifyRule' }
default:
$ref: '#/components/responses/Error'
patch:
summary: Update a rule (partial)
tags: [Rules]
parameters:
- $ref: '#/components/parameters/Tenant'
- $ref: '#/components/parameters/RuleId'
requestBody:
required: true
content:
application/json:
schema:
type: object
description: JSON Merge Patch
responses:
'200':
description: Updated rule
content:
application/json:
schema: { $ref: '#/components/schemas/NotifyRule' }
default:
$ref: '#/components/responses/Error'
/api/v1/notify/templates:
get:
summary: List templates
tags: [Templates]
parameters:
- $ref: '#/components/parameters/Tenant'
- name: key
in: query
description: Filter by template key
schema: { type: string }
responses:
'200':
description: Templates
content:
application/json:
schema:
type: array
items: { $ref: '#/components/schemas/NotifyTemplate' }
default:
$ref: '#/components/responses/Error'
post:
summary: Create a template
tags: [Templates]
parameters:
- $ref: '#/components/parameters/Tenant'
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/NotifyTemplate' }
responses:
'201':
description: Template created
content:
application/json:
schema: { $ref: '#/components/schemas/NotifyTemplate' }
default:
$ref: '#/components/responses/Error'
/api/v1/notify/templates/{templateId}:
get:
summary: Fetch a template
tags: [Templates]
parameters:
- $ref: '#/components/parameters/Tenant'
- $ref: '#/components/parameters/TemplateId'
responses:
'200':
description: Template
content:
application/json:
schema: { $ref: '#/components/schemas/NotifyTemplate' }
default:
$ref: '#/components/responses/Error'
patch:
summary: Update a template (partial)
tags: [Templates]
parameters:
- $ref: '#/components/parameters/Tenant'
- $ref: '#/components/parameters/TemplateId'
requestBody:
required: true
content:
application/json:
schema:
type: object
description: JSON Merge Patch
responses:
'200':
description: Updated template
content:
application/json:
schema: { $ref: '#/components/schemas/NotifyTemplate' }
default:
$ref: '#/components/responses/Error'
/api/v1/notify/incidents:
get:
summary: List incidents (paged)
tags: [Incidents]
parameters:
- $ref: '#/components/parameters/Tenant'
- $ref: '#/components/parameters/PageSize'
- $ref: '#/components/parameters/PageToken'
responses:
'200':
description: Incident page
content:
application/json:
schema:
type: object
properties:
items:
type: array
items: { $ref: '#/components/schemas/Incident' }
nextPageToken: { type: string }
default:
$ref: '#/components/responses/Error'
post:
summary: Raise an incident (ops/toggle/override)
tags: [Incidents]
parameters:
- $ref: '#/components/parameters/Tenant'
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/Incident' }
examples:
start-incident:
value:
incidentId: inc-telemetry-outage
kind: outage
severity: major
startedAt: 2025-11-17T04:02:00Z
shortDescription: "Telemetry pipeline degraded; burn-rate breach"
metadata:
source: slo-evaluator
responses:
'202':
description: Incident accepted
default:
$ref: '#/components/responses/Error'
/api/v1/notify/incidents/{incidentId}/ack:
post:
summary: Acknowledge an incident notification
tags: [Incidents]
parameters:
- $ref: '#/components/parameters/Tenant'
- $ref: '#/components/parameters/IncidentId'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
ackToken:
type: string
description: DSSE-signed acknowledgement token
responses:
'204':
description: Acknowledged
default:
$ref: '#/components/responses/Error'
/api/v1/notify/quiet-hours:
get:
summary: Get quiet-hours schedule
tags: [QuietHours]
parameters:
- $ref: '#/components/parameters/Tenant'
responses:
'200':
description: Quiet hours schedule
content:
application/json:
schema: { $ref: '#/components/schemas/QuietHours' }
examples:
current:
value:
quietHoursId: qh-default
windows:
- timezone: UTC
days: [Mon, Tue, Wed, Thu, Fri]
start: "22:00"
end: "06:00"
exemptions:
- eventKinds: [attestor.verification.failed]
reason: "Always alert for attestation failures"
default:
$ref: '#/components/responses/Error'
post:
summary: Set quiet-hours schedule
tags: [QuietHours]
parameters:
- $ref: '#/components/parameters/Tenant'
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/QuietHours' }
responses:
'200':
description: Updated quiet hours
content:
application/json:
schema: { $ref: '#/components/schemas/QuietHours' }
default:
$ref: '#/components/responses/Error'
/api/v1/notify/pack-approvals:
post:
summary: Ingest pack approval decision
tags: [PackApprovals]
operationId: ingestPackApproval
security:
- oauth2: [notify.operator]
- hmac: []
parameters:
- $ref: '#/components/parameters/Tenant'
- $ref: '#/components/parameters/IdempotencyKey'
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/PackApprovalEvent' }
examples:
approval-granted:
value:
eventId: "20e4e5fe-3d4a-4f57-9f9b-b1a1c1111111"
issuedAt: "2025-11-17T16:00:00Z"
kind: "pack.approval.granted"
packId: "offline-kit-2025-11"
policy:
id: "policy-123"
version: "v5"
decision: "approved"
actor: "task-runner"
resumeToken: "rt-abc123"
summary: "All required attestations verified."
labels:
environment: "prod"
approver: "ops"
responses:
'202':
description: Accepted; durable write queued for processing.
headers:
X-Resume-After:
description: Resume token echo or replacement
schema: { type: string }
default:
$ref: '#/components/responses/Error'
/api/v1/notify/pack-approvals/{packId}/ack:
post:
summary: Acknowledge a pack approval notification
tags: [PackApprovals]
operationId: ackPackApproval
parameters:
- $ref: '#/components/parameters/Tenant'
- name: packId
in: path
required: true
schema: { type: string }
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
ackToken: { type: string }
required: [ackToken]
responses:
'204':
description: Acknowledged
default:
$ref: '#/components/responses/Error'
components:
securitySchemes:
oauth2:
type: oauth2
flows:
clientCredentials:
tokenUrl: https://auth.stellaops.example.com/oauth/token
scopes:
notify.viewer: Read-only Notifier access
notify.operator: Manage rules/templates/incidents within tenant
notify.admin: Tenant-scoped administration
hmac:
type: http
scheme: bearer
description: Pre-shared HMAC token (air-gap friendly) referenced by secretRef.
parameters:
Tenant:
name: X-StellaOps-Tenant
in: header
required: true
description: Tenant slug
schema: { type: string }
IdempotencyKey:
name: Idempotency-Key
in: header
required: true
description: Stable UUID to dedupe retries.
schema: { type: string, format: uuid }
PageSize:
name: pageSize
in: query
schema: { type: integer, minimum: 1, maximum: 200, default: 50 }
PageToken:
name: pageToken
in: query
schema: { type: string }
RuleId:
name: ruleId
in: path
required: true
schema: { type: string }
TemplateId:
name: templateId
in: path
required: true
schema: { type: string }
IncidentId:
name: incidentId
in: path
required: true
schema: { type: string }
responses:
Error:
description: Standard error envelope
content:
application/json:
schema: { $ref: '#/components/schemas/ErrorEnvelope' }
examples:
validation:
value:
error:
code: validation_failed
message: "quietHours.windows[0].start must be HH:mm"
traceId: "f62f3c2b9c8e4c53"
schemas:
ErrorEnvelope:
type: object
required: [error]
properties:
error:
type: object
required: [code, message, traceId]
properties:
code: { type: string }
message: { type: string }
traceId: { type: string }
NotifyRule:
type: object
required: [ruleId, tenantId, name, match, actions]
properties:
ruleId: { type: string }
tenantId: { type: string }
name: { type: string }
description: { type: string }
enabled: { type: boolean, default: true }
match: { $ref: '#/components/schemas/RuleMatch' }
actions:
type: array
items: { $ref: '#/components/schemas/RuleAction' }
labels:
type: object
additionalProperties: { type: string }
metadata:
type: object
additionalProperties: { type: string }
RuleMatch:
type: object
properties:
eventKinds:
type: array
items: { type: string }
minSeverity: { type: string, enum: [info, low, medium, high, critical] }
verdicts:
type: array
items: { type: string }
labels:
type: array
items: { type: string }
kevOnly: { type: boolean }
RuleAction:
type: object
required: [actionId, channel]
properties:
actionId: { type: string }
channel: { type: string }
template: { type: string }
digest: { type: string, description: "Digest window key e.g. instant|5m|15m|1h|1d" }
throttle: { type: string, description: "ISO-8601 duration, e.g. PT5M" }
locale: { type: string }
enabled: { type: boolean, default: true }
metadata:
type: object
additionalProperties: { type: string }
NotifyTemplate:
type: object
required: [templateId, tenantId, key, channelType, locale, body, renderMode, format]
properties:
templateId: { type: string }
tenantId: { type: string }
key: { type: string }
channelType: { type: string, enum: [slack, teams, email, webhook, custom] }
locale: { type: string, description: "BCP-47, lower-case" }
renderMode: { type: string, enum: [Markdown, Html, AdaptiveCard, PlainText, Json] }
format: { type: string, enum: [slack, teams, email, webhook, json] }
description: { type: string }
body: { type: string }
metadata:
type: object
additionalProperties: { type: string }
Incident:
type: object
required: [incidentId, kind, severity, startedAt]
properties:
incidentId: { type: string }
kind: { type: string, description: "outage|degradation|security|ops-drill" }
severity: { type: string, enum: [minor, major, critical] }
startedAt: { type: string, format: date-time }
endedAt: { type: string, format: date-time }
shortDescription: { type: string }
description: { type: string }
metadata:
type: object
additionalProperties: { type: string }
PackApprovalEvent:
type: object
required:
- eventId
- issuedAt
- kind
- packId
- decision
- actor
properties:
eventId: { type: string, format: uuid }
issuedAt: { type: string, format: date-time }
kind:
type: string
enum: [pack.approval.granted, pack.approval.denied, pack.policy.override]
packId: { type: string }
policy:
type: object
properties:
id: { type: string }
version: { type: string }
decision:
type: string
enum: [approved, denied, overridden]
actor: { type: string }
resumeToken:
type: string
description: Opaque token for at-least-once resume.
summary: { type: string }
labels:
type: object
additionalProperties: { type: string }
QuietHours:
type: object
required: [quietHoursId, windows]
properties:
quietHoursId: { type: string }
windows:
type: array
items: { $ref: '#/components/schemas/QuietHoursWindow' }
exemptions:
type: array
description: Event kinds that bypass quiet hours
items:
type: object
properties:
eventKinds:
type: array
items: { type: string }
reason: { type: string }
QuietHoursWindow:
type: object
required: [timezone, days, start, end]
properties:
timezone: { type: string, description: "IANA TZ, e.g., UTC" }
days:
type: array
items:
type: string
enum: [Mon, Tue, Wed, Thu, Fri, Sat, Sun]
start: { type: string, description: "HH:mm" }
end: { type: string, description: "HH:mm" }