up
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
Symbols Server CI / symbols-smoke (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-11-24 20:57:49 +02:00
parent 46c8c47d06
commit 7c39058386
92 changed files with 3549 additions and 157 deletions

View File

@@ -4,6 +4,7 @@ using System.Linq;
using System.Collections.Immutable;
using System.Globalization;
using System.Diagnostics;
using System.Reflection;
using System.Text;
using System.Text.Json;
using Microsoft.AspNetCore.Authentication;
@@ -146,6 +147,304 @@ app.MapGet("/excititor/status", async (HttpContext context,
app.MapHealthChecks("/excititor/health");
// OpenAPI discovery (WEB-OAS-61-001)
app.MapGet("/.well-known/openapi", () =>
{
var version = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "0.0.0";
var payload = new
{
service = "excititor",
specVersion = "3.1.0",
version,
format = "application/json",
url = "/openapi/excititor.json",
errorEnvelopeSchema = "#/components/schemas/Error"
};
return Results.Json(payload);
});
app.MapGet("/openapi/excititor.json", () =>
{
var version = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "0.0.0";
var spec = new
{
openapi = "3.1.0",
info = new
{
title = "StellaOps Excititor API",
version,
description = "Aggregation-only VEX observation, timeline, and attestation APIs"
},
paths = new Dictionary<string, object>
{
["/excititor/status"] = new
{
get = new
{
summary = "Service status (aggregation-only metadata)",
responses = new
{
["200"] = new
{
description = "OK",
content = new Dictionary<string, object>
{
["application/json"] = new
{
schema = new { @ref = "#/components/schemas/StatusResponse" },
examples = new Dictionary<string, object>
{
["example"] = new
{
value = new
{
timeUtc = "2025-11-24T00:00:00Z",
mongoBucket = "vex-raw",
gridFsInlineThresholdBytes = 1048576,
artifactStores = new[] { "S3ArtifactStore", "OfflineBundleArtifactStore" }
}
}
}
}
}
}
}
}
},
["/excititor/health"] = new
{
get = new
{
summary = "Health check",
responses = new
{
["200"] = new
{
description = "Healthy",
content = new Dictionary<string, object>
{
["application/json"] = new
{
examples = new Dictionary<string, object>
{
["example"] = new
{
value = new
{
status = "Healthy"
}
}
}
}
}
}
}
}
},
["/obs/excititor/timeline"] = new
{
get = new
{
summary = "VEX timeline stream (SSE)",
parameters = new object[]
{
new { name = "cursor", @in = "query", schema = new { type = "string" }, required = false, description = "Numeric cursor or Last-Event-ID" },
new { name = "limit", @in = "query", schema = new { type = "integer", minimum = 1, maximum = 100 }, required = false }
},
responses = new
{
["200"] = new
{
description = "Event stream",
headers = new Dictionary<string, object>
{
["Deprecation"] = new
{
description = "Set to true when this route is superseded",
schema = new { type = "string" }
},
["Link"] = new
{
description = "Link to OpenAPI description",
schema = new { type = "string" },
example = "</openapi/excititor.json>; rel=\"describedby\"; type=\"application/json\""
}
},
content = new Dictionary<string, object>
{
["text/event-stream"] = new
{
examples = new Dictionary<string, object>
{
["event"] = new
{
value = "id: 123\nretry: 5000\nevent: timeline\ndata: {\"id\":123,\"tenant\":\"acme\",\"kind\":\"vex.status\",\"createdUtc\":\"2025-11-24T00:00:00Z\"}\n\n"
}
}
}
}
},
["400"] = new
{
description = "Invalid cursor",
content = new Dictionary<string, object>
{
["application/json"] = new
{
schema = new { @ref = "#/components/schemas/Error" },
examples = new Dictionary<string, object>
{
["bad-cursor"] = new
{
value = new
{
error = new
{
code = "ERR_CURSOR",
message = "cursor must be integer"
}
}
}
}
}
}
}
}
}
},
["/airgap/v1/vex/import"] = new
{
post = new
{
summary = "Register sealed mirror bundle metadata",
requestBody = new
{
required = true,
content = new Dictionary<string, object>
{
["application/json"] = new
{
schema = new { @ref = "#/components/schemas/AirgapImportRequest" }
}
}
},
responses = new
{
["200"] = new { description = "Accepted" },
["400"] = new
{
description = "Validation error",
content = new Dictionary<string, object>
{
["application/json"] = new
{
schema = new { @ref = "#/components/schemas/Error" },
examples = new Dictionary<string, object>
{
["validation-failed"] = new
{
value = new
{
error = new
{
code = "ERR_VALIDATION",
message = "PayloadHash is required."
}
}
}
}
}
}
},
["403"] = new
{
description = "Trust validation failed",
content = new Dictionary<string, object>
{
["application/json"] = new
{
schema = new { @ref = "#/components/schemas/Error" },
examples = new Dictionary<string, object>
{
["trust-failed"] = new
{
value = new
{
error = new
{
code = "ERR_TRUST",
message = "Signature trust root not recognized."
}
}
}
}
}
}
}
}
}
}
},
components = new
{
schemas = new Dictionary<string, object>
{
["Error"] = new
{
type = "object",
required = new[] { "error" },
properties = new Dictionary<string, object>
{
["error"] = new
{
type = "object",
required = new[] { "code", "message" },
properties = new Dictionary<string, object>
{
["code"] = new { type = "string", example = "ERR_EXAMPLE" },
["message"] = new { type = "string", example = "Details about the error." }
}
}
}
},
["StatusResponse"] = new
{
type = "object",
required = new[] { "timeUtc", "mongoBucket", "artifactStores" },
properties = new Dictionary<string, object>
{
["timeUtc"] = new { type = "string", format = "date-time" },
["mongoBucket"] = new { type = "string" },
["gridFsInlineThresholdBytes"] = new { type = "integer", format = "int64" },
["artifactStores"] = new { type = "array", items = new { type = "string" } }
}
},
["AirgapImportRequest"] = new
{
type = "object",
required = new[] { "bundleId", "mirrorGeneration", "signedAt", "publisher", "payloadHash", "signature" },
properties = new Dictionary<string, object>
{
["bundleId"] = new { type = "string", example = "mirror-2025-11-24" },
["mirrorGeneration"] = new { type = "string", example = "g001" },
["signedAt"] = new { type = "string", format = "date-time" },
["publisher"] = new { type = "string", example = "acme" },
["payloadHash"] = new { type = "string", example = "sha256:..." },
["payloadUrl"] = new { type = "string", nullable = true },
["signature"] = new { type = "string", example = "base64-signature" },
["transparencyLog"] = new { type = "string", nullable = true }
}
}
}
}
};
return Results.Json(spec);
});
app.MapPost("/airgap/v1/vex/import", async (
[FromServices] AirgapImportValidator validator,
[FromServices] AirgapSignerTrustService trustService,