docs consolidation and others
This commit is contained in:
13
docs/modules/aoc/guides/aoc-guardrails.md
Normal file
13
docs/modules/aoc/guides/aoc-guardrails.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Aggregation-Only Contract (AOC) Guardrails
|
||||
|
||||
The Aggregation-Only Contract keeps ingestion services deterministic and policy-neutral. Use these checkpoints whenever you add or modify backlog items:
|
||||
|
||||
1. **Ingestion writes raw facts only.** Concelier and Excititor append immutable observations/linksets. No precedence, severity, suppression, or "safe fix" hints may be computed at ingest time.
|
||||
2. **Derived semantics live elsewhere.** Policy Engine overlays, Vuln Explorer composition, and downstream reporting layers attach severity, precedence, policy verdicts, and UI hints.
|
||||
3. **Provenance is mandatory.** Every ingestion write must include original source metadata, digests, and signing/provenance evidence when available. Reject writes lacking provenance.
|
||||
4. **Deterministic outputs.** Given the same inputs, ingestion must produce identical documents, hashes, and event payloads across reruns.
|
||||
5. **Guardrails everywhere.** Roslyn analyzers, schema validators, and CI smoke tests should fail builds that attempt forbidden writes.
|
||||
|
||||
For detailed roles and ownership boundaries, see `AGENTS.md` at the repo root and the module-specific dossiers under `docs/modules/<module>/architecture.md`.
|
||||
|
||||
Need the full contract? Read the [Aggregation-Only Contract reference](aggregation-only-contract.md) for schemas, error codes, and migration guidance.
|
||||
130
docs/modules/aoc/guides/guard-library.md
Normal file
130
docs/modules/aoc/guides/guard-library.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# Aggregation-Only Guard Library Reference
|
||||
|
||||
> **Packages:** `StellaOps.Aoc`, `StellaOps.Aoc.AspNetCore`
|
||||
> **Related tasks:** `WEB-AOC-19-001`, `WEB-AOC-19-003`, `DEVOPS-AOC-19-001`
|
||||
> **Audience:** Concelier/Excititor service owners, Platform guild, QA
|
||||
|
||||
The Aggregation-Only Contract (AOC) guard library enforces the canonical ingestion
|
||||
rules described in `docs/modules/concelier/guides/aggregation-only-contract.md`. Service owners
|
||||
should use the guard whenever raw advisory or VEX payloads are accepted so that
|
||||
forbidden fields are rejected long before they reach PostgreSQL.
|
||||
|
||||
## Packages
|
||||
|
||||
### `StellaOps.Aoc`
|
||||
- `IAocGuard` / `AocWriteGuard` — validate JSON payloads and emit `AocGuardResult`.
|
||||
- `AocGuardOptions` — toggles for signature enforcement, tenant requirements, and required top-level fields.
|
||||
- `AocViolation` / `AocViolationCode` — structured violations surfaced to callers.
|
||||
- `AocError` — canonical error DTO (`code`, `message`, `violations[]`) re-used by HTTP helpers, CLI tooling, and telemetry.
|
||||
- `ServiceCollectionExtensions.AddAocGuard()` — DI helper that registers the singleton guard.
|
||||
- `AocGuardExtensions.ValidateOrThrow()` — throws `AocGuardException` when validation fails.
|
||||
|
||||
### `StellaOps.Aoc.AspNetCore`
|
||||
- `AocGuardEndpointFilter<TRequest>` — Minimal API endpoint filter that evaluates request payloads through the guard before invoking handlers.
|
||||
- `AocHttpResults.Problem()` — Produces a RFC 7807 payload that includes violation codes, suitable for API responses.
|
||||
|
||||
## Minimal API integration
|
||||
|
||||
```csharp
|
||||
using StellaOps.Aoc;
|
||||
using StellaOps.Aoc.AspNetCore.Routing;
|
||||
using StellaOps.Aoc.AspNetCore.Results;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Services.AddAocGuard();
|
||||
builder.Services.Configure<AocGuardOptions>(options =>
|
||||
{
|
||||
options.RequireSignatureMetadata = true;
|
||||
options.RequireTenant = true;
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
app.MapPost("/ingest", async (IngestionRequest request, IAocGuard guard, ILogger<Program> logger) =>
|
||||
{
|
||||
// additional application logic
|
||||
return Results.Accepted();
|
||||
})
|
||||
.AddEndpointFilter(new AocGuardEndpointFilter<IngestionRequest>(
|
||||
request => new object?[] { request.Payload },
|
||||
serializerOptions: null,
|
||||
guardOptions: null))
|
||||
.ProducesProblem(StatusCodes.Status400BadRequest)
|
||||
.WithTags("AOC");
|
||||
|
||||
app.UseExceptionHandler(errorApp =>
|
||||
{
|
||||
errorApp.Run(async context =>
|
||||
{
|
||||
var exceptionHandler = context.Features.Get<IExceptionHandlerFeature>();
|
||||
if (exceptionHandler?.Error is AocGuardException guardException)
|
||||
{
|
||||
var result = AocHttpResults.Problem(context, guardException);
|
||||
await result.ExecuteAsync(context);
|
||||
return;
|
||||
}
|
||||
|
||||
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Key points:
|
||||
- Register the guard singleton before wiring repositories or worker services.
|
||||
- Use `AocGuardEndpointFilter<TRequest>` to protect Minimal API endpoints. The `payloadSelector`
|
||||
can yield multiple payloads (e.g. batch ingestion) and the filter will validate each one.
|
||||
- Prefer the `RequireAocGuard` extension when wiring endpoints; it wraps `AddEndpointFilter`
|
||||
and handles single-payload scenarios without additional boilerplate.
|
||||
- Wrap guard exceptions with `AocHttpResults.Problem` to ensure clients receive machine-readable codes (`ERR_AOC_00x`). The helper now emits the serialized `AocError` under the `error` extension for consumers that want a typed payload.
|
||||
|
||||
### Allowed top-level fields
|
||||
|
||||
`AocWriteGuard` enforces the contract’s top-level allowlist: `_id`, `tenant`, `source`, `upstream`,
|
||||
`content`, `identifiers`, `linkset`, `supersedes`, `createdAt`/`created_at`, `ingestedAt`/`ingested_at`, and `attributes`.
|
||||
Unknown fields produce `ERR_AOC_007` violations. When staging schema changes, extend the allowlist through
|
||||
`AocGuardOptions.AllowedTopLevelFields`:
|
||||
|
||||
```csharp
|
||||
builder.Services.Configure<AocGuardOptions>(options =>
|
||||
{
|
||||
options.AllowedTopLevelFields =
|
||||
options.AllowedTopLevelFields.Add("experimental_field");
|
||||
});
|
||||
```
|
||||
|
||||
## Worker / repository usage
|
||||
|
||||
Inject `IAocGuard` (or a module-specific wrapper such as `IVexRawWriteGuard`) anywhere documents
|
||||
are persisted. Call `ValidateOrThrow` before writes to guarantee fail-fast behaviour, for example:
|
||||
|
||||
```csharp
|
||||
public sealed class AdvisoryRawRepository
|
||||
{
|
||||
private readonly IAocGuard _guard;
|
||||
|
||||
public AdvisoryRawRepository(IAocGuard guard) => _guard = guard;
|
||||
|
||||
public Task WriteAsync(JsonDocument document, CancellationToken cancellationToken)
|
||||
{
|
||||
_guard.ValidateOrThrow(document.RootElement);
|
||||
// proceed with storage logic
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration tips
|
||||
|
||||
- Adjust `AocGuardOptions.RequiredTopLevelFields` when staging new schema changes. All configured names are case-insensitive.
|
||||
- Extend `AllowedTopLevelFields` for temporary schema experiments so that guard runs stay clean while the contract is updated.
|
||||
- Set `RequireSignatureMetadata = false` for legacy feeds that do not provide signature envelopes yet; track the waiver in the module backlog.
|
||||
- Use module-specific wrappers (`AddConcelierAocGuards`, `AddExcititorAocGuards`) to combine guard registration with domain exceptions and metrics.
|
||||
|
||||
## Testing guidance
|
||||
|
||||
- Unit-test guard behaviour with fixture payloads (see `src/Aoc/__Tests`).
|
||||
- Service-level tests should assert that ingestion endpoints return `ERR_AOC_*` codes via `AocHttpResults`.
|
||||
- CI must run `stella aoc verify` once CLI support lands (`DEVOPS-AOC-19-002`).
|
||||
- Roslyn analyzer enforcement (`WEB-AOC-19-003`) will ensure the guard is registered; keep services wired through the shared extensions to prepare for that gate.
|
||||
|
||||
For questions or updates, coordinate with the BE‑Base Platform guild and reference `WEB-AOC-19-001`.
|
||||
Reference in New Issue
Block a user