Fix OCI route mounting — integrate into authenticated /v2 group

NewRouter now accepts an optional OCI handler to mount inside the
authenticated /v2 route group, avoiding chi's Mount conflict on
an existing path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-25 22:22:31 -07:00
parent 8cf26895a3
commit 15a306dc4a
3 changed files with 15 additions and 9 deletions

View File

@@ -123,9 +123,7 @@ func runServer(configPath string) error {
// Create OCI handler and HTTP router. // Create OCI handler and HTTP router.
ociHandler := oci.NewHandler(database, store, policyEngine, auditFn) ociHandler := oci.NewHandler(database, store, policyEngine, auditFn)
router := server.NewRouter(authClient, authClient, cfg.MCIAS.ServiceName) router := server.NewRouter(authClient, authClient, cfg.MCIAS.ServiceName, ociHandler.Router())
// Mount OCI endpoints at /v2.
router.Mount("/v2", ociHandler.Router())
// Mount admin REST endpoints. // Mount admin REST endpoints.
gcState := &server.GCState{ gcState := &server.GCState{
Collector: collector, Collector: collector,

View File

@@ -1,10 +1,15 @@
package server package server
import "github.com/go-chi/chi/v5" import (
"net/http"
"github.com/go-chi/chi/v5"
)
// NewRouter builds the chi router with all OCI Distribution Spec // NewRouter builds the chi router with all OCI Distribution Spec
// endpoints and auth middleware wired up. // endpoints and auth middleware wired up. If ociRouter is non-nil,
func NewRouter(validator TokenValidator, loginClient LoginClient, serviceName string) *chi.Mux { // its routes are mounted under /v2 behind the auth middleware.
func NewRouter(validator TokenValidator, loginClient LoginClient, serviceName string, ociRouter http.Handler) *chi.Mux {
r := chi.NewRouter() r := chi.NewRouter()
// Token endpoint is NOT behind RequireAuth — clients use Basic auth // Token endpoint is NOT behind RequireAuth — clients use Basic auth
@@ -15,6 +20,9 @@ func NewRouter(validator TokenValidator, loginClient LoginClient, serviceName st
r.Route("/v2", func(v2 chi.Router) { r.Route("/v2", func(v2 chi.Router) {
v2.Use(RequireAuth(validator, serviceName)) v2.Use(RequireAuth(validator, serviceName))
v2.Get("/", V2Handler()) v2.Get("/", V2Handler())
if ociRouter != nil {
v2.Mount("/", ociRouter)
}
}) })
return r return r

View File

@@ -15,7 +15,7 @@ func TestRoutesV2Authenticated(t *testing.T) {
claims: &auth.Claims{Subject: "alice", AccountType: "user", Roles: []string{"reader"}}, claims: &auth.Claims{Subject: "alice", AccountType: "user", Roles: []string{"reader"}},
} }
loginClient := &fakeLoginClient{token: "tok-abc", expiresIn: 3600} loginClient := &fakeLoginClient{token: "tok-abc", expiresIn: 3600}
router := NewRouter(validator, loginClient, "mcr-test") router := NewRouter(validator, loginClient, "mcr-test", nil)
req := httptest.NewRequest(http.MethodGet, "/v2/", nil) req := httptest.NewRequest(http.MethodGet, "/v2/", nil)
req.Header.Set("Authorization", "Bearer valid-token") req.Header.Set("Authorization", "Bearer valid-token")
@@ -42,7 +42,7 @@ func TestRoutesV2Unauthenticated(t *testing.T) {
t.Helper() t.Helper()
validator := &fakeValidator{claims: nil, err: auth.ErrUnauthorized} validator := &fakeValidator{claims: nil, err: auth.ErrUnauthorized}
loginClient := &fakeLoginClient{} loginClient := &fakeLoginClient{}
router := NewRouter(validator, loginClient, "mcr-test") router := NewRouter(validator, loginClient, "mcr-test", nil)
req := httptest.NewRequest(http.MethodGet, "/v2/", nil) req := httptest.NewRequest(http.MethodGet, "/v2/", nil)
// No Authorization header. // No Authorization header.
@@ -66,7 +66,7 @@ func TestRoutesTokenEndpoint(t *testing.T) {
// The validator should never be called for /v2/token. // The validator should never be called for /v2/token.
validator := &fakeValidator{claims: nil, err: auth.ErrUnauthorized} validator := &fakeValidator{claims: nil, err: auth.ErrUnauthorized}
loginClient := &fakeLoginClient{token: "tok-from-login", expiresIn: 1800} loginClient := &fakeLoginClient{token: "tok-from-login", expiresIn: 1800}
router := NewRouter(validator, loginClient, "mcr-test") router := NewRouter(validator, loginClient, "mcr-test", nil)
req := httptest.NewRequest(http.MethodGet, "/v2/token", nil) req := httptest.NewRequest(http.MethodGet, "/v2/token", nil)
req.SetBasicAuth("bob", "password") req.SetBasicAuth("bob", "password")