Files
git.stella-ops.org/docs/aoc/guard-library.md
master 3a2100aa78 Add unit and integration tests for VexCandidateEmitter and SmartDiff repositories
- Implemented comprehensive unit tests for VexCandidateEmitter to validate candidate emission logic based on various scenarios including absent and present APIs, confidence thresholds, and rate limiting.
- Added integration tests for SmartDiff PostgreSQL repositories, covering snapshot storage and retrieval, candidate storage, and material risk change handling.
- Ensured tests validate correct behavior for storing, retrieving, and querying snapshots and candidates, including edge cases and expected outcomes.
2025-12-16 19:00:43 +02:00

131 lines
5.7 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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/ingestion/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 RFC7807 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 contracts 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 BEBase Platform guild and reference `WEB-AOC-19-001`.