Phase 10: gRPC admin API with interceptor chain

Proto definitions for 4 services (RegistryService, PolicyService,
AuditService, AdminService) with hand-written Go stubs using JSON
codec until protobuf tooling is available.

Interceptor chain: logging (method, peer IP, duration, never logs
auth metadata) → auth (bearer token via MCIAS, Health bypasses) →
admin (role check for GC, policy, delete, audit RPCs).

All RPCs share business logic with REST handlers via internal/db
and internal/gc packages. TLS 1.3 minimum on gRPC listener.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-19 20:46:21 -07:00
parent 562b69e875
commit 185b68ff6d
30 changed files with 3616 additions and 4 deletions

View File

@@ -0,0 +1,61 @@
package grpcserver
import (
"context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
pb "git.wntrmute.dev/kyle/mcr/gen/mcr/v1"
"git.wntrmute.dev/kyle/mcr/internal/db"
)
// auditService implements pb.AuditServiceServer.
type auditService struct {
pb.UnimplementedAuditServiceServer
db *db.DB
}
func (s *auditService) ListAuditEvents(_ context.Context, req *pb.ListAuditEventsRequest) (*pb.ListAuditEventsResponse, error) {
limit := int32(50)
offset := int32(0)
if req.GetPagination() != nil {
if req.Pagination.Limit > 0 {
limit = req.Pagination.Limit
}
if req.Pagination.Offset >= 0 {
offset = req.Pagination.Offset
}
}
filter := db.AuditFilter{
EventType: req.GetEventType(),
ActorID: req.GetActorId(),
Repository: req.GetRepository(),
Since: req.GetSince(),
Until: req.GetUntil(),
Limit: int(limit),
Offset: int(offset),
}
events, err := s.db.ListAuditEvents(filter)
if err != nil {
return nil, status.Errorf(codes.Internal, "internal error")
}
var result []*pb.AuditEvent
for _, e := range events {
result = append(result, &pb.AuditEvent{
Id: e.ID,
EventTime: e.EventTime,
EventType: e.EventType,
ActorId: e.ActorID,
Repository: e.Repository,
Digest: e.Digest,
IpAddress: e.IPAddress,
Details: e.Details,
})
}
return &pb.ListAuditEventsResponse{Events: result}, nil
}