feat: Add in-memory implementations for issuer audit, key, repository, and trust management
Some checks failed
devportal-offline / build-offline (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
oas-ci / oas-validate (push) Has been cancelled

- Introduced InMemoryIssuerAuditSink to retain audit entries for testing.
- Implemented InMemoryIssuerKeyRepository for deterministic key storage.
- Created InMemoryIssuerRepository to manage issuer records in memory.
- Added InMemoryIssuerTrustRepository for managing issuer trust overrides.
- Each repository utilizes concurrent collections for thread-safe operations.
- Enhanced deprecation tracking with a comprehensive YAML schema for API governance.
This commit is contained in:
master
2025-12-11 19:47:43 +02:00
parent ab22181e8b
commit ce5ec9c158
48 changed files with 1898 additions and 1580 deletions

View File

@@ -0,0 +1,35 @@
{
"schemaVersion": "notify.template.api-deprecation@1",
"templateId": "api-deprecation-email",
"tenantId": "_system",
"channelType": "email",
"key": "api.deprecation.announced",
"locale": "en-US",
"subject": "[StellaOps] API Deprecation Notice: {{method}} {{path}} ({{service}})",
"description": "Email notification template for API deprecation announcements",
"body": "<!DOCTYPE html>\n<html>\n<head>\n <style>\n body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }\n .container { max-width: 600px; margin: 0 auto; padding: 20px; }\n .header { background: #f59e0b; color: white; padding: 20px; border-radius: 8px 8px 0 0; }\n .content { background: #f9fafb; padding: 20px; border: 1px solid #e5e7eb; border-top: none; border-radius: 0 0 8px 8px; }\n .warning-icon { font-size: 24px; }\n h1 { margin: 0; font-size: 20px; }\n .detail-row { margin: 12px 0; }\n .label { font-weight: 600; color: #6b7280; }\n .value { font-family: 'SF Mono', Monaco, monospace; background: #e5e7eb; padding: 2px 6px; border-radius: 4px; }\n .sunset-warning { background: #fef3c7; border: 1px solid #f59e0b; padding: 12px; border-radius: 6px; margin: 16px 0; }\n .btn { display: inline-block; padding: 10px 20px; background: #3b82f6; color: white; text-decoration: none; border-radius: 6px; margin-right: 10px; }\n .btn-secondary { background: #6b7280; }\n .footer { margin-top: 20px; font-size: 12px; color: #9ca3af; }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"header\">\n <span class=\"warning-icon\">⚠️</span>\n <h1>API Deprecation Notice</h1>\n </div>\n <div class=\"content\">\n <div class=\"detail-row\">\n <span class=\"label\">Service:</span>\n <span class=\"value\">{{service}}</span>\n </div>\n <div class=\"detail-row\">\n <span class=\"label\">Endpoint:</span>\n <span class=\"value\">{{method}} {{path}}</span>\n </div>\n {{#operationId}}\n <div class=\"detail-row\">\n <span class=\"label\">Operation:</span>\n <span class=\"value\">{{operationId}}</span>\n </div>\n {{/operationId}}\n <div class=\"detail-row\">\n <span class=\"label\">Deprecated:</span>\n <span>{{deprecatedAt}}</span>\n </div>\n <div class=\"sunset-warning\">\n <strong>Sunset Date:</strong> {{sunsetAt}}<br>\n <strong>{{daysUntilSunset}} days remaining</strong>\n </div>\n {{#reason}}\n <div class=\"detail-row\">\n <span class=\"label\">Reason:</span>\n <p>{{reason}}</p>\n </div>\n {{/reason}}\n {{#successorPath}}\n <div class=\"detail-row\">\n <span class=\"label\">Replacement Endpoint:</span>\n <span class=\"value\">{{successorPath}}</span>\n </div>\n {{/successorPath}}\n <div style=\"margin-top: 20px;\">\n {{#migrationGuide}}<a href=\"{{migrationGuide}}\" class=\"btn\">Migration Guide</a>{{/migrationGuide}}\n {{#changelogUrl}}<a href=\"{{changelogUrl}}\" class=\"btn btn-secondary\">View Changelog</a>{{/changelogUrl}}\n </div>\n <div class=\"footer\">\n <p>Please update your integrations before the sunset date to avoid service disruption.</p>\n <p>This is an automated notification from StellaOps API Governance.</p>\n </div>\n </div>\n </div>\n</body>\n</html>",
"renderMode": "html",
"format": "email",
"metadata": {
"priority": "high",
"category": "api-governance",
"tags": ["deprecation", "api", "migration"]
},
"placeholders": [
{ "name": "service", "description": "Service name owning the deprecated endpoint", "example": "authority", "required": true },
{ "name": "path", "description": "API path of the deprecated endpoint", "example": "/v1/tokens", "required": true },
{ "name": "method", "description": "HTTP method", "example": "POST", "required": true },
{ "name": "operationId", "description": "OpenAPI operation ID", "example": "createToken", "required": false },
{ "name": "deprecatedAt", "description": "When the endpoint was deprecated", "example": "2025-01-15", "required": true },
{ "name": "sunsetAt", "description": "When the endpoint will be removed", "example": "2025-07-15", "required": true },
{ "name": "daysUntilSunset", "description": "Days remaining until sunset", "example": "180", "required": true },
{ "name": "reason", "description": "Deprecation reason", "example": "Replaced by v2 endpoint", "required": false },
{ "name": "successorPath", "description": "Replacement endpoint path", "example": "/v2/tokens", "required": false },
{ "name": "migrationGuide", "description": "URL to migration documentation", "example": "https://docs.stella-ops.org/migration/tokens-v2", "required": false },
{ "name": "changelogUrl", "description": "URL to the changelog entry", "example": "https://docs.stella-ops.org/changelog#2025-01-15", "required": false }
],
"createdBy": "api-governance-guild",
"createdAt": "2025-12-11T00:00:00Z",
"updatedBy": "api-governance-guild",
"updatedAt": "2025-12-11T00:00:00Z"
}

View File

@@ -0,0 +1,35 @@
{
"schemaVersion": "notify.template.api-deprecation@1",
"templateId": "api-deprecation-slack",
"tenantId": "_system",
"channelType": "slack",
"key": "api.deprecation.announced",
"locale": "en-US",
"subject": null,
"description": "Slack notification template for API deprecation announcements",
"body": ":warning: *API Deprecation Notice*\n\n*Service:* `{{service}}`\n*Endpoint:* `{{method}} {{path}}`\n{{#operationId}}*Operation:* `{{operationId}}`\n{{/operationId}}\n*Deprecated:* {{deprecatedAt}}\n*Sunset Date:* {{sunsetAt}} ({{daysUntilSunset}} days remaining)\n\n{{#reason}}*Reason:* {{reason}}\n{{/reason}}\n{{#successorPath}}*Replacement:* `{{successorPath}}`\n{{/successorPath}}\n{{#migrationGuide}}:book: <{{migrationGuide}}|Migration Guide>\n{{/migrationGuide}}{{#changelogUrl}}:page_facing_up: <{{changelogUrl}}|Changelog>\n{{/changelogUrl}}\n\n_Please update your integrations before the sunset date._",
"renderMode": "markdown",
"format": "slack",
"metadata": {
"priority": "high",
"category": "api-governance",
"tags": ["deprecation", "api", "migration"]
},
"placeholders": [
{ "name": "service", "description": "Service name owning the deprecated endpoint", "example": "authority", "required": true },
{ "name": "path", "description": "API path of the deprecated endpoint", "example": "/v1/tokens", "required": true },
{ "name": "method", "description": "HTTP method", "example": "POST", "required": true },
{ "name": "operationId", "description": "OpenAPI operation ID", "example": "createToken", "required": false },
{ "name": "deprecatedAt", "description": "When the endpoint was deprecated", "example": "2025-01-15", "required": true },
{ "name": "sunsetAt", "description": "When the endpoint will be removed", "example": "2025-07-15", "required": true },
{ "name": "daysUntilSunset", "description": "Days remaining until sunset", "example": "180", "required": true },
{ "name": "reason", "description": "Deprecation reason", "example": "Replaced by v2 endpoint", "required": false },
{ "name": "successorPath", "description": "Replacement endpoint path", "example": "/v2/tokens", "required": false },
{ "name": "migrationGuide", "description": "URL to migration documentation", "example": "https://docs.stella-ops.org/migration/tokens-v2", "required": false },
{ "name": "changelogUrl", "description": "URL to the changelog entry", "example": "https://docs.stella-ops.org/changelog#2025-01-15", "required": false }
],
"createdBy": "api-governance-guild",
"createdAt": "2025-12-11T00:00:00Z",
"updatedBy": "api-governance-guild",
"updatedAt": "2025-12-11T00:00:00Z"
}

View File

@@ -0,0 +1,35 @@
{
"schemaVersion": "notify.template.api-deprecation@1",
"templateId": "api-deprecation-teams",
"tenantId": "_system",
"channelType": "teams",
"key": "api.deprecation.announced",
"locale": "en-US",
"subject": null,
"description": "Microsoft Teams Adaptive Card template for API deprecation announcements",
"body": "{\n \"type\": \"AdaptiveCard\",\n \"$schema\": \"http://adaptivecards.io/schemas/adaptive-card.json\",\n \"version\": \"1.4\",\n \"body\": [\n {\n \"type\": \"TextBlock\",\n \"text\": \"⚠️ API Deprecation Notice\",\n \"weight\": \"Bolder\",\n \"size\": \"Large\",\n \"color\": \"Warning\"\n },\n {\n \"type\": \"FactSet\",\n \"facts\": [\n { \"title\": \"Service\", \"value\": \"{{service}}\" },\n { \"title\": \"Endpoint\", \"value\": \"{{method}} {{path}}\" },\n { \"title\": \"Operation\", \"value\": \"{{operationId}}\" },\n { \"title\": \"Deprecated\", \"value\": \"{{deprecatedAt}}\" },\n { \"title\": \"Sunset Date\", \"value\": \"{{sunsetAt}} ({{daysUntilSunset}} days)\" }\n ]\n },\n {\n \"type\": \"TextBlock\",\n \"text\": \"{{reason}}\",\n \"wrap\": true,\n \"isSubtle\": true\n },\n {\n \"type\": \"TextBlock\",\n \"text\": \"Replacement: `{{successorPath}}`\",\n \"wrap\": true\n }\n ],\n \"actions\": [\n {\n \"type\": \"Action.OpenUrl\",\n \"title\": \"Migration Guide\",\n \"url\": \"{{migrationGuide}}\"\n },\n {\n \"type\": \"Action.OpenUrl\",\n \"title\": \"Changelog\",\n \"url\": \"{{changelogUrl}}\"\n }\n ]\n}",
"renderMode": "adaptiveCard",
"format": "teams",
"metadata": {
"priority": "high",
"category": "api-governance",
"tags": ["deprecation", "api", "migration"]
},
"placeholders": [
{ "name": "service", "description": "Service name owning the deprecated endpoint", "example": "authority", "required": true },
{ "name": "path", "description": "API path of the deprecated endpoint", "example": "/v1/tokens", "required": true },
{ "name": "method", "description": "HTTP method", "example": "POST", "required": true },
{ "name": "operationId", "description": "OpenAPI operation ID", "example": "createToken", "required": false },
{ "name": "deprecatedAt", "description": "When the endpoint was deprecated", "example": "2025-01-15", "required": true },
{ "name": "sunsetAt", "description": "When the endpoint will be removed", "example": "2025-07-15", "required": true },
{ "name": "daysUntilSunset", "description": "Days remaining until sunset", "example": "180", "required": true },
{ "name": "reason", "description": "Deprecation reason", "example": "Replaced by v2 endpoint", "required": false },
{ "name": "successorPath", "description": "Replacement endpoint path", "example": "/v2/tokens", "required": false },
{ "name": "migrationGuide", "description": "URL to migration documentation", "example": "https://docs.stella-ops.org/migration/tokens-v2", "required": false },
{ "name": "changelogUrl", "description": "URL to the changelog entry", "example": "https://docs.stella-ops.org/changelog#2025-01-15", "required": false }
],
"createdBy": "api-governance-guild",
"createdAt": "2025-12-11T00:00:00Z",
"updatedBy": "api-governance-guild",
"updatedAt": "2025-12-11T00:00:00Z"
}

View File

@@ -0,0 +1,36 @@
{
"schemaVersion": "notify.template.api-deprecation@1",
"templateId": "api-deprecation-webhook",
"tenantId": "_system",
"channelType": "webhook",
"key": "api.deprecation.announced",
"locale": "en-US",
"subject": null,
"description": "Webhook payload template for API deprecation announcements (JSON format for external integrations)",
"body": "{\n \"event\": \"api.deprecation.announced\",\n \"version\": \"1\",\n \"timestamp\": \"{{timestamp}}\",\n \"data\": {\n \"service\": \"{{service}}\",\n \"endpoint\": {\n \"path\": \"{{path}}\",\n \"method\": \"{{method}}\",\n \"operationId\": \"{{operationId}}\"\n },\n \"deprecation\": {\n \"deprecatedAt\": \"{{deprecatedAt}}\",\n \"sunsetAt\": \"{{sunsetAt}}\",\n \"daysUntilSunset\": {{daysUntilSunset}},\n \"reason\": \"{{reason}}\"\n },\n \"migration\": {\n \"successorPath\": \"{{successorPath}}\",\n \"migrationGuide\": \"{{migrationGuide}}\",\n \"changelogUrl\": \"{{changelogUrl}}\"\n }\n }\n}",
"renderMode": "json",
"format": "webhook",
"metadata": {
"priority": "high",
"category": "api-governance",
"tags": ["deprecation", "api", "migration", "integration"]
},
"placeholders": [
{ "name": "timestamp", "description": "Event timestamp in ISO 8601 format", "example": "2025-12-11T10:00:00Z", "required": true },
{ "name": "service", "description": "Service name owning the deprecated endpoint", "example": "authority", "required": true },
{ "name": "path", "description": "API path of the deprecated endpoint", "example": "/v1/tokens", "required": true },
{ "name": "method", "description": "HTTP method", "example": "POST", "required": true },
{ "name": "operationId", "description": "OpenAPI operation ID", "example": "createToken", "required": false },
{ "name": "deprecatedAt", "description": "When the endpoint was deprecated", "example": "2025-01-15T00:00:00Z", "required": true },
{ "name": "sunsetAt", "description": "When the endpoint will be removed", "example": "2025-07-15T00:00:00Z", "required": true },
{ "name": "daysUntilSunset", "description": "Days remaining until sunset (integer)", "example": "180", "required": true },
{ "name": "reason", "description": "Deprecation reason", "example": "Replaced by v2 endpoint", "required": false },
{ "name": "successorPath", "description": "Replacement endpoint path", "example": "/v2/tokens", "required": false },
{ "name": "migrationGuide", "description": "URL to migration documentation", "example": "https://docs.stella-ops.org/migration/tokens-v2", "required": false },
{ "name": "changelogUrl", "description": "URL to the changelog entry", "example": "https://docs.stella-ops.org/changelog#2025-01-15", "required": false }
],
"createdBy": "api-governance-guild",
"createdAt": "2025-12-11T00:00:00Z",
"updatedBy": "api-governance-guild",
"updatedAt": "2025-12-11T00:00:00Z"
}

View File

@@ -0,0 +1,127 @@
{
"$id": "https://stella-ops.org/schemas/notify/api-deprecation@1.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "API Deprecation Notification Template",
"description": "Notification template schema for API deprecation announcements. Used by Notify service to render channel-specific messages.",
"type": "object",
"required": [
"schemaVersion",
"templateId",
"tenantId",
"channelType",
"key",
"locale",
"body",
"renderMode",
"format",
"createdAt",
"updatedAt"
],
"properties": {
"schemaVersion": {
"type": "string",
"const": "notify.template.api-deprecation@1"
},
"templateId": {
"type": "string",
"pattern": "^api-deprecation-[a-z]+(-[a-z0-9]+)*$",
"description": "Template identifier following api-deprecation-{channel}[-variant] pattern."
},
"tenantId": {
"type": "string",
"description": "Tenant scope for the template. Use '_system' for platform-wide defaults."
},
"channelType": {
"type": "string",
"enum": ["slack", "teams", "email", "webhook"],
"description": "Target notification channel."
},
"key": {
"type": "string",
"const": "api.deprecation.announced",
"description": "Event key this template handles."
},
"locale": {
"type": "string",
"default": "en-US",
"description": "Locale for the template content."
},
"body": {
"type": "string",
"description": "Template body with Mustache/Handlebars placeholders for deprecation fields."
},
"subject": {
"type": "string",
"description": "Email subject line (for email channel only)."
},
"description": {
"type": "string",
"description": "Human-readable description of the template."
},
"renderMode": {
"type": "string",
"enum": ["markdown", "html", "adaptiveCard", "plainText", "json"],
"description": "How the body should be rendered."
},
"format": {
"type": "string",
"enum": ["slack", "teams", "email", "webhook", "json"],
"description": "Output format for the rendered message."
},
"metadata": {
"type": "object",
"properties": {
"priority": {
"type": "string",
"enum": ["low", "normal", "high", "urgent"],
"default": "normal"
},
"category": {
"type": "string",
"const": "api-governance"
},
"tags": {
"type": "array",
"items": { "type": "string" }
}
},
"additionalProperties": { "type": "string" }
},
"placeholders": {
"type": "array",
"description": "Documented placeholders available in the template body.",
"items": {
"$ref": "#/$defs/placeholder"
}
},
"createdBy": { "type": "string" },
"createdAt": { "type": "string", "format": "date-time" },
"updatedBy": { "type": "string" },
"updatedAt": { "type": "string", "format": "date-time" }
},
"additionalProperties": false,
"$defs": {
"placeholder": {
"type": "object",
"required": ["name", "description"],
"properties": {
"name": {
"type": "string",
"description": "Placeholder name (e.g., {{service}})."
},
"description": {
"type": "string",
"description": "Description of what the placeholder contains."
},
"example": {
"type": "string",
"description": "Example value for the placeholder."
},
"required": {
"type": "boolean",
"default": true
}
}
}
}
}