Sidebar 5-group restructure + demo data badges + audit emission infrastructure
Sprint 4 — Sidebar restructure (S4-T01+T02):
5 groups: Release Control, Security, Operations, Audit & Evidence, Setup & Admin
Groups 4+5 collapsed by default for new users
Operations extracted from Release Control into own group
Audit extracted from Security into own group
groupOrder and resolveMenuGroupLabel updated
Approvals badge moved to section-level
Sprint 2 — Demo data badges (S2-T04+T05):
Backend: isDemo=true on all compatibility/seed responses in
PackAdapterEndpoints, QuotaCompatibilityEndpoints, VulnerabilitiesController
Frontend: "(Demo)" badges on Usage & Limits page quotas
Frontend: "(Demo)" badges on triage artifact list when seed data
New PlatformItemResponse/PlatformListResponse with IsDemo field
Sprint 6 — Audit emission infrastructure (S6-T01+T02):
New shared library: src/__Libraries/StellaOps.Audit.Emission/
- AuditActionAttribute: [AuditAction("module", "action")] endpoint tag
- AuditActionFilter: IEndpointFilter that auto-emits UnifiedAuditEvent
- HttpAuditEventEmitter: POSTs to Timeline /api/v1/audit/ingest
- Single-line DI: services.AddAuditEmission(configuration)
Timeline service: POST /api/v1/audit/ingest ingestion endpoint
- IngestAuditEventStore: 10k-event ring buffer
- CompositeUnifiedAuditEventProvider: merges HTTP-polled + ingested
Documentation: docs/modules/audit/AUDIT_EMISSION_GUIDE.md
Angular build: 0 errors. .NET builds: 0 errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
136
docs/modules/audit/AUDIT_EMISSION_GUIDE.md
Normal file
136
docs/modules/audit/AUDIT_EMISSION_GUIDE.md
Normal file
@@ -0,0 +1,136 @@
|
||||
# Audit Event Emission Guide
|
||||
|
||||
This guide explains how to add automatic audit event emission to any StellaOps service using the shared `StellaOps.Audit.Emission` library.
|
||||
|
||||
## Overview
|
||||
|
||||
The audit emission infrastructure provides:
|
||||
|
||||
1. **`AuditActionAttribute`** -- marks an endpoint for automatic audit event emission
|
||||
2. **`AuditActionFilter`** -- ASP.NET Core endpoint filter that creates and sends `UnifiedAuditEvent` payloads
|
||||
3. **`HttpAuditEventEmitter`** -- posts events to the Timeline service's `POST /api/v1/audit/ingest` endpoint
|
||||
4. **`AddAuditEmission()`** -- single-line DI registration
|
||||
|
||||
Events flow: **Service endpoint** -> `AuditActionFilter` -> `HttpAuditEventEmitter` -> **Timeline `/api/v1/audit/ingest`** -> `IngestAuditEventStore` -> merged into unified audit query results.
|
||||
|
||||
## Step 1: Add project reference
|
||||
|
||||
In your service's `.csproj`, add a reference to the shared library:
|
||||
|
||||
```xml
|
||||
<ProjectReference Include="..\..\__Libraries\StellaOps.Audit.Emission\StellaOps.Audit.Emission.csproj" />
|
||||
```
|
||||
|
||||
Adjust the relative path as needed for your service's location in the repo.
|
||||
|
||||
## Step 2: Register in DI (Program.cs)
|
||||
|
||||
Add a single line to your service's `Program.cs`:
|
||||
|
||||
```csharp
|
||||
using StellaOps.Audit.Emission;
|
||||
|
||||
// After other service registrations:
|
||||
builder.Services.AddAuditEmission(builder.Configuration);
|
||||
```
|
||||
|
||||
This registers:
|
||||
- `AuditActionFilter` (scoped endpoint filter)
|
||||
- `HttpAuditEventEmitter` as `IAuditEventEmitter` (singleton)
|
||||
- `AuditEmissionOptions` bound from configuration
|
||||
|
||||
## Step 3: Tag endpoints
|
||||
|
||||
Add the `AuditActionFilter` and `AuditActionAttribute` metadata to any endpoint you want audited:
|
||||
|
||||
```csharp
|
||||
using StellaOps.Audit.Emission;
|
||||
|
||||
app.MapPost("/api/v1/environments", CreateEnvironment)
|
||||
.AddEndpointFilter<AuditActionFilter>()
|
||||
.WithMetadata(new AuditActionAttribute("concelier", "create"));
|
||||
|
||||
app.MapPut("/api/v1/environments/{id}", UpdateEnvironment)
|
||||
.AddEndpointFilter<AuditActionFilter>()
|
||||
.WithMetadata(new AuditActionAttribute("concelier", "update"));
|
||||
|
||||
app.MapDelete("/api/v1/environments/{id}", DeleteEnvironment)
|
||||
.AddEndpointFilter<AuditActionFilter>()
|
||||
.WithMetadata(new AuditActionAttribute("concelier", "delete"));
|
||||
```
|
||||
|
||||
### Attribute parameters
|
||||
|
||||
| Parameter | Required | Description |
|
||||
|---------------|----------|-------------|
|
||||
| `module` | Yes | Module name from `UnifiedAuditCatalog.Modules` (e.g., `"authority"`, `"policy"`, `"jobengine"`, `"vex"`, `"scanner"`, `"integrations"`) |
|
||||
| `action` | Yes | Action name from `UnifiedAuditCatalog.Actions` (e.g., `"create"`, `"update"`, `"delete"`, `"promote"`, `"approve"`) |
|
||||
| `ResourceType` | No | Optional resource type override. If omitted, inferred from the URL path segment after the version prefix. |
|
||||
|
||||
## Step 4: Configuration (optional)
|
||||
|
||||
The emitter reads configuration from the `AuditEmission` section or environment variables:
|
||||
|
||||
```json
|
||||
{
|
||||
"AuditEmission": {
|
||||
"TimelineBaseUrl": "http://timeline.stella-ops.local",
|
||||
"Enabled": true,
|
||||
"TimeoutSeconds": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Environment variable overrides:
|
||||
- `STELLAOPS_TIMELINE_URL` -- overrides `TimelineBaseUrl`
|
||||
- `AuditEmission__Enabled` -- set to `false` to disable emission
|
||||
- `AuditEmission__TimeoutSeconds` -- HTTP timeout for ingest calls
|
||||
|
||||
## How the filter works
|
||||
|
||||
1. The endpoint executes normally and returns its result to the caller.
|
||||
2. After execution, the filter checks for `AuditActionAttribute` metadata.
|
||||
3. If present, it builds an `AuditEventPayload` containing:
|
||||
- **Module** and **Action** from the attribute
|
||||
- **Actor** from `HttpContext.User` claims (`sub`, `name`, `email`, `stellaops:tenant`)
|
||||
- **Resource** from route parameters (first matching `id`, `resourceId`, etc., or first GUID value)
|
||||
- **Severity** inferred from HTTP response status code (2xx=info, 4xx=warning, 5xx=error)
|
||||
- **Description** auto-generated: `"{Action} {module} resource {resourceId}"`
|
||||
- **CorrelationId** from `X-Correlation-Id` header or `HttpContext.TraceIdentifier`
|
||||
4. The event is posted asynchronously (fire-and-forget) to `POST /api/v1/audit/ingest`.
|
||||
5. Failures are logged but never propagated -- audit emission must not affect the endpoint response.
|
||||
|
||||
## Timeline ingest endpoint
|
||||
|
||||
The Timeline service exposes:
|
||||
|
||||
```
|
||||
POST /api/v1/audit/ingest
|
||||
```
|
||||
|
||||
- **Auth**: Requires `timeline:write` scope
|
||||
- **Body**: JSON matching the `AuditEventPayload` schema (camelCase)
|
||||
- **Response**: `202 Accepted` with `{ "eventId": "...", "status": "accepted" }`
|
||||
- **Gateway route**: Already covered by the existing `/api/v1/audit(.*)` route in `router-gateway-local.json`
|
||||
|
||||
Ingested events are stored in an in-memory ring buffer (max 10,000 events) and merged with the HTTP-polled events from other modules (JobEngine, Policy, EvidenceLocker, Notify) in the unified audit query results.
|
||||
|
||||
## Architecture decisions
|
||||
|
||||
- **Fire-and-forget emission**: Audit events are sent asynchronously after the endpoint responds. This ensures zero latency impact on the audited endpoint.
|
||||
- **No compile-time dependency on Timeline**: The `AuditEventPayload` DTOs in the emission library are wire-compatible with `UnifiedAuditEvent` but live in a separate namespace, avoiding circular dependencies.
|
||||
- **In-memory ingest store**: For the alpha phase, ingested events are stored in memory. A future sprint will add Postgres persistence for the ingest store.
|
||||
- **Composite event provider**: The Timeline service merges HTTP-polled events with ingested events, so all audit data appears in a single unified stream.
|
||||
|
||||
## File locations
|
||||
|
||||
| File | Path |
|
||||
|------|------|
|
||||
| Shared library | `src/__Libraries/StellaOps.Audit.Emission/` |
|
||||
| Attribute | `src/__Libraries/StellaOps.Audit.Emission/AuditActionAttribute.cs` |
|
||||
| Filter | `src/__Libraries/StellaOps.Audit.Emission/AuditActionFilter.cs` |
|
||||
| Emitter | `src/__Libraries/StellaOps.Audit.Emission/HttpAuditEventEmitter.cs` |
|
||||
| DI extension | `src/__Libraries/StellaOps.Audit.Emission/AuditEmissionServiceExtensions.cs` |
|
||||
| Ingest endpoint | `src/Timeline/StellaOps.Timeline.WebService/Endpoints/UnifiedAuditEndpoints.cs` |
|
||||
| Ingest store | `src/Timeline/StellaOps.Timeline.WebService/Audit/IngestAuditEventStore.cs` |
|
||||
| Composite provider | `src/Timeline/StellaOps.Timeline.WebService/Audit/CompositeUnifiedAuditEventProvider.cs` |
|
||||
Reference in New Issue
Block a user