feat(audit): decorate write endpoints in 4 services (AUDIT-002 wave C)
Sprint SPRINT_20260408_004 AUDIT-002, second completion criterion
("at least write endpoints decorated with AuditActionAttribute").
Vertical slice using the existing .Audited(module, action, resourceType)
helper from AuditedRouteGroupExtensions:
- Graph.Api (4 endpoints):
* POST /api/graphs/builds -> graph.create graph_build
* POST /api/graphs/overlays -> graph.create graph_overlay
* POST /graphs/{g}/saved-views -> graph.create graph_saved_view
* DELETE /graphs/{g}/saved-views/{v} -> graph.delete graph_saved_view
- SbomService (4 endpoints):
* POST /sbom/upload + /api/v1/sbom/upload -> sbom.create sbom
* POST /entrypoints -> sbom.update sbom_entrypoint
* POST /internal/orchestrator/sources -> sbom.create orchestrator_source
* POST /internal/orchestrator/control -> sbom.update orchestrator_control
- Policy.Gateway ExceptionApproval (4 governance endpoints):
* POST /exception/request -> policy.create exception_approval_request
* POST /exception/{id}/approve -> policy.approve ""
* POST /exception/{id}/reject -> policy.reject ""
* POST /exception/{id}/cancel -> policy.cancel ""
- Notifier EscalationEndpoints (9 endpoints):
* policies CRUD -> notifier.{create,update,delete} escalation_policy
* on-call schedules CRUD -> notifier.{create,update,delete} oncall_schedule
* escalation start/escalate/stop -> notifier.execute incident_escalation
All 4 projects build clean. Events will flow to Timeline
/api/v1/audit/ingest once the services boot and execute these endpoints.
BinaryIndex uses MVC controllers — audit decoration for that style
requires a different wiring approach and is deferred to a follow-up.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ using System.Collections.Concurrent;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using StellaOps.Audit.Emission;
|
||||
using StellaOps.Graph.Api.Contracts;
|
||||
using StellaOps.Graph.Api.Security;
|
||||
using StellaOps.Graph.Indexer.Ingestion.Sbom;
|
||||
@@ -47,7 +48,7 @@ public static class CartographerEndpoints
|
||||
CartographerJobId = jobId,
|
||||
GraphSnapshotId = state.GraphSnapshotId
|
||||
});
|
||||
});
|
||||
}).Audited("graph", "create", resourceType: "graph_build");
|
||||
|
||||
app.MapGet("/api/graphs/builds/{jobId}", (string jobId) =>
|
||||
{
|
||||
@@ -94,7 +95,7 @@ public static class CartographerEndpoints
|
||||
Status = state.Status,
|
||||
GraphSnapshotId = state.GraphSnapshotId
|
||||
});
|
||||
});
|
||||
}).Audited("graph", "create", resourceType: "graph_overlay");
|
||||
|
||||
app.MapGet("/api/graphs/overlays/{jobId}", (string jobId) =>
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using StellaOps.Audit.Emission;
|
||||
using StellaOps.Auth.ServerIntegration.Tenancy;
|
||||
using StellaOps.Graph.Api.Contracts;
|
||||
using StellaOps.Graph.Api.Security;
|
||||
@@ -450,7 +451,8 @@ public static class CompatibilityEndpoints
|
||||
var created = await store.CreateAsync(tenantId, graphId, request, ct);
|
||||
return Results.Created($"/graphs/{graphId}/saved-views/{created.ViewId}", created);
|
||||
})
|
||||
.RequireTenant();
|
||||
.RequireTenant()
|
||||
.Audited("graph", "create", resourceType: "graph_saved_view");
|
||||
|
||||
app.MapDelete("/graphs/{graphId}/saved-views/{viewId}", async Task<IResult> (
|
||||
string graphId,
|
||||
@@ -476,7 +478,8 @@ public static class CompatibilityEndpoints
|
||||
? Results.NoContent()
|
||||
: Results.NotFound();
|
||||
})
|
||||
.RequireTenant();
|
||||
.RequireTenant()
|
||||
.Audited("graph", "delete", resourceType: "graph_saved_view");
|
||||
}
|
||||
|
||||
private static async Task<(string? TenantId, IResult? Failure)> AuthorizeAsync(
|
||||
|
||||
Reference in New Issue
Block a user