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>
57 lines
1.9 KiB
Go
57 lines
1.9 KiB
Go
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))
|
|
})
|
|
}
|