Phases 5, 6, 8: OCI pull/push paths and admin REST API
Phase 5 (OCI pull): internal/oci/ package with manifest GET/HEAD by tag/digest, blob GET/HEAD with repo membership check, tag listing with OCI pagination, catalog listing. Multi-segment repo names via parseOCIPath() right-split routing. DB query layer in internal/db/repository.go. Phase 6 (OCI push): blob uploads (monolithic and chunked) with uploadManager tracking in-progress BlobWriters, manifest push implementing full ARCHITECTURE.md §5 flow in a single SQLite transaction (create repo, upsert manifest, populate manifest_blobs, atomic tag move). Digest verification on both blob commit and manifest push-by-digest. Phase 8 (admin REST): /v1 endpoints for auth (login/logout/health), repository management (list/detail/delete), policy CRUD with engine reload, audit log listing with filters, GC trigger/status stubs. RequireAdmin middleware, platform-standard error format. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
56
internal/server/admin_routes.go
Normal file
56
internal/server/admin_routes.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
|
||||
"git.wntrmute.dev/kyle/mcr/internal/db"
|
||||
)
|
||||
|
||||
// AdminDeps holds the dependencies needed by admin routes.
|
||||
type AdminDeps struct {
|
||||
DB *db.DB
|
||||
Login LoginClient
|
||||
Engine PolicyReloader
|
||||
AuditFn AuditFunc
|
||||
GCState *GCState
|
||||
}
|
||||
|
||||
// MountAdminRoutes adds admin REST endpoints to the router.
|
||||
// Auth middleware is applied at the route group level.
|
||||
func MountAdminRoutes(r chi.Router, validator TokenValidator, serviceName string, deps AdminDeps) {
|
||||
// Health endpoint - no auth required.
|
||||
r.Get("/v1/health", AdminHealthHandler())
|
||||
|
||||
// Auth endpoints - no bearer auth required (login uses credentials).
|
||||
r.Post("/v1/auth/login", AdminLoginHandler(deps.Login))
|
||||
|
||||
// Authenticated endpoints.
|
||||
r.Route("/v1", func(v1 chi.Router) {
|
||||
v1.Use(RequireAuth(validator, serviceName))
|
||||
|
||||
// Logout.
|
||||
v1.Post("/auth/logout", AdminLogoutHandler())
|
||||
|
||||
// Repositories - list and detail require auth, delete requires admin.
|
||||
v1.Get("/repositories", AdminListReposHandler(deps.DB))
|
||||
v1.Get("/repositories/*", AdminGetRepoHandler(deps.DB))
|
||||
v1.With(RequireAdmin()).Delete("/repositories/*", AdminDeleteRepoHandler(deps.DB, deps.AuditFn))
|
||||
|
||||
// Policy - all require admin.
|
||||
v1.Route("/policy/rules", func(pr chi.Router) {
|
||||
pr.Use(RequireAdmin())
|
||||
pr.Get("/", AdminListPolicyRulesHandler(deps.DB))
|
||||
pr.Post("/", AdminCreatePolicyRuleHandler(deps.DB, deps.Engine, deps.AuditFn))
|
||||
pr.Get("/{id}", AdminGetPolicyRuleHandler(deps.DB))
|
||||
pr.Patch("/{id}", AdminUpdatePolicyRuleHandler(deps.DB, deps.Engine, deps.AuditFn))
|
||||
pr.Delete("/{id}", AdminDeletePolicyRuleHandler(deps.DB, deps.Engine, deps.AuditFn))
|
||||
})
|
||||
|
||||
// Audit - requires admin.
|
||||
v1.With(RequireAdmin()).Get("/audit", AdminListAuditHandler(deps.DB))
|
||||
|
||||
// GC - requires admin.
|
||||
v1.With(RequireAdmin()).Post("/gc", AdminTriggerGCHandler(deps.GCState))
|
||||
v1.With(RequireAdmin()).Get("/gc/status", AdminGCStatusHandler(deps.GCState))
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user