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:
94
PROGRESS.md
94
PROGRESS.md
@@ -6,7 +6,7 @@ See `PROJECT_PLAN.md` for the implementation roadmap and
|
||||
|
||||
## Current State
|
||||
|
||||
**Phase:** 9 complete, ready for Phase 10
|
||||
**Phase:** 10 complete, ready for Phase 11
|
||||
**Last updated:** 2026-03-19
|
||||
|
||||
### Completed
|
||||
@@ -21,6 +21,7 @@ See `PROJECT_PLAN.md` for the implementation roadmap and
|
||||
- Phase 7: OCI delete path (all 2 steps)
|
||||
- Phase 8: Admin REST API (all 5 steps)
|
||||
- Phase 9: Garbage collection (all 2 steps)
|
||||
- Phase 10: gRPC admin API (all 4 steps)
|
||||
- `ARCHITECTURE.md` — Full design specification (18 sections)
|
||||
- `CLAUDE.md` — AI development guidance
|
||||
- `PROJECT_PLAN.md` — Implementation plan (14 phases, 40+ steps)
|
||||
@@ -28,13 +29,100 @@ See `PROJECT_PLAN.md` for the implementation roadmap and
|
||||
|
||||
### Next Steps
|
||||
|
||||
1. Phase 10 (gRPC admin API)
|
||||
2. Phase 11 (CLI tool) and Phase 12 (web UI)
|
||||
1. Phase 11 (CLI tool) and Phase 12 (web UI)
|
||||
|
||||
---
|
||||
|
||||
## Log
|
||||
|
||||
### 2026-03-19 — Phase 10: gRPC admin API
|
||||
|
||||
**Task:** Implement the gRPC admin API server with the same business
|
||||
logic as the REST admin API, per ARCHITECTURE.md section 7.
|
||||
|
||||
**Changes:**
|
||||
|
||||
Step 10.1 — Proto definitions (`proto/mcr/v1/`):
|
||||
- `common.proto`: `PaginationRequest` shared type
|
||||
- `registry.proto`: `RegistryService` with `ListRepositories`,
|
||||
`GetRepository`, `DeleteRepository`, `GarbageCollect`, `GetGCStatus` RPCs
|
||||
- `policy.proto`: `PolicyService` with `ListPolicyRules`,
|
||||
`CreatePolicyRule`, `GetPolicyRule`, `UpdatePolicyRule`,
|
||||
`DeletePolicyRule` RPCs; `UpdatePolicyRuleRequest` includes field mask
|
||||
- `audit.proto`: `AuditService` with `ListAuditEvents` RPC; filter
|
||||
fields for event_type, actor_id, repository, time range
|
||||
- `admin.proto`: `AdminService` with `Health` RPC
|
||||
|
||||
Step 10.2 — Generated code (`gen/mcr/v1/`):
|
||||
- Hand-written message types and gRPC service descriptors matching
|
||||
protoc-gen-go v1.36+ and protoc-gen-go-grpc v1.5+ output patterns
|
||||
- `codec.go`: JSON codec implementing `encoding.CodecV2` via
|
||||
`mem.BufferSlice`, registered globally via `init()` as stand-in
|
||||
until protobuf code generation is available
|
||||
- Handler functions properly delegate to interceptor chain (critical
|
||||
for auth/admin enforcement; handlers that ignore the interceptor
|
||||
parameter bypass security checks entirely)
|
||||
- Client and server interfaces with `mustEmbedUnimplemented*Server()`
|
||||
for forward compatibility
|
||||
|
||||
Step 10.3 — Interceptor chain (`internal/grpcserver/interceptors.go`):
|
||||
- `loggingInterceptor`: logs method, peer IP, status code, duration;
|
||||
never logs the authorization metadata value
|
||||
- `authInterceptor`: extracts `authorization` metadata, validates
|
||||
bearer token via `TokenValidator` interface, injects claims into
|
||||
context; `Health` bypasses auth via `authBypassMethods` map
|
||||
- `adminInterceptor`: requires admin role for GC, policy, delete,
|
||||
audit RPCs via `adminRequiredMethods` map; returns
|
||||
`codes.PermissionDenied` for insufficient role
|
||||
- gRPC errors: `codes.Unauthenticated` for missing/invalid token,
|
||||
`codes.PermissionDenied` for insufficient role
|
||||
|
||||
Step 10.4 — Server implementation (`internal/grpcserver/`):
|
||||
- `server.go`: `New(certFile, keyFile, deps)` creates configured
|
||||
gRPC server with TLS 1.3 minimum (skips TLS if paths empty for
|
||||
testing); `Serve()`, `GracefulStop()`
|
||||
- `registry.go`: `registryService` implementing all 5 RPCs with
|
||||
same DB calls as REST handlers; GC runs asynchronously with its
|
||||
own `GCStatus` tracking (separate from REST's `GCState` since
|
||||
`GCState.mu` is unexported); shares `gc.Collector` for actual GC
|
||||
- `policy.go`: `policyService` implementing all 5 RPCs with
|
||||
validation (effect, actions, priority), field mask updates, engine
|
||||
reload, audit events
|
||||
- `audit.go`: `auditService` implementing `ListAuditEvents` with
|
||||
pagination and filter pass-through to `db.ListAuditEvents`
|
||||
- `admin.go`: `adminService` implementing `Health` (returns "ok")
|
||||
|
||||
**Dependencies added:**
|
||||
- `google.golang.org/grpc` v1.79.3
|
||||
- `google.golang.org/protobuf` v1.36.11
|
||||
- Transitive: `golang.org/x/net`, `golang.org/x/text`,
|
||||
`google.golang.org/genproto/googleapis/rpc`
|
||||
|
||||
**Verification:**
|
||||
- `make all` passes: vet clean, lint 0 issues, all tests passing,
|
||||
all 3 binaries built
|
||||
- Interceptor tests (12 new): Health bypasses auth, no token rejected
|
||||
(Unauthenticated), invalid token rejected (Unauthenticated), valid
|
||||
token accepted, non-admin denied policy RPCs (PermissionDenied),
|
||||
admin allowed policy RPCs, admin required methods completeness
|
||||
check, auth bypass methods completeness check, delete repo requires
|
||||
admin, GC requires admin, audit requires admin
|
||||
- Registry service tests (7 new): list repositories empty, get repo
|
||||
not found, get repo empty name (InvalidArgument), delete repo not
|
||||
found, delete repo empty name, GC status initial (not running),
|
||||
GC trigger returns ID
|
||||
- Policy service tests (8 new): create policy rule (with engine
|
||||
reload verification), create validation (5 subtests: zero priority,
|
||||
empty description, invalid effect, no actions, invalid action), get
|
||||
policy rule, get not found, list policy rules, delete + verify
|
||||
gone + reload count, delete not found, update with field mask
|
||||
- Audit service tests (3 new): list empty, list with data (verify
|
||||
fields and details map), list with pagination
|
||||
- Admin service tests (2 new): Health returns "ok", Health without
|
||||
auth succeeds
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-19 — Phase 9: Garbage collection
|
||||
|
||||
**Task:** Implement the two-phase GC algorithm for removing unreferenced
|
||||
|
||||
Reference in New Issue
Block a user