fix(api/v2): expose v2-only token route groups via the routes endpoint
This commit is contained in:
parent
74510bb00a
commit
4a558fc57a
|
|
@ -29,8 +29,8 @@ var apiTokenRoutes = map[string]APITokenRoute{}
|
|||
|
||||
// apiTokenRoutesV2 holds /api/v2 routes under the same (group, permission)
|
||||
// keys as v1, so a token granted e.g. labels.read_one authorises both
|
||||
// versions. The frontend token UI still reads only apiTokenRoutes;
|
||||
// CanDoAPIRoute consults both tables.
|
||||
// versions. CanDoAPIRoute consults both tables; GetAPITokenRoutes (the /routes
|
||||
// exposure the frontend reads) merges v2-only groups so they're discoverable.
|
||||
var apiTokenRoutesV2 = map[string]APITokenRoute{}
|
||||
|
||||
func init() {
|
||||
|
|
@ -346,10 +346,30 @@ func CollectRoutesForAPITokenUsage(route echo.RouteInfo, requiresJWT bool) {
|
|||
|
||||
}
|
||||
|
||||
// GetAPITokenRoutes exposes the registered scoped-token routes so tests
|
||||
// and the /api/v1/routes handler share a single source of truth.
|
||||
// GetAPITokenRoutes exposes the registered scoped-token routes for the /routes
|
||||
// handler and tests. v1 is the base; v2-only groups and permissions (a v2-only
|
||||
// resource like time-entries has no v1 counterpart) are merged in so tokens can
|
||||
// discover and grant them. Shared (group, permission) keys keep their v1 entry —
|
||||
// CanDoAPIRoute authorises both versions off the same key regardless.
|
||||
func GetAPITokenRoutes() map[string]APITokenRoute {
|
||||
return apiTokenRoutes
|
||||
merged := make(map[string]APITokenRoute, len(apiTokenRoutes))
|
||||
for group, perms := range apiTokenRoutes {
|
||||
merged[group] = make(APITokenRoute, len(perms))
|
||||
for perm, rd := range perms {
|
||||
merged[group][perm] = rd
|
||||
}
|
||||
}
|
||||
for group, perms := range apiTokenRoutesV2 {
|
||||
if merged[group] == nil {
|
||||
merged[group] = make(APITokenRoute)
|
||||
}
|
||||
for perm, rd := range perms {
|
||||
if merged[group][perm] == nil {
|
||||
merged[group][perm] = rd
|
||||
}
|
||||
}
|
||||
}
|
||||
return merged
|
||||
}
|
||||
|
||||
// GetAvailableAPIRoutesForToken returns a list of all API routes which are available for token usage.
|
||||
|
|
|
|||
|
|
@ -147,6 +147,29 @@ func TestCollectRoutes_TimeEntriesV2(t *testing.T) {
|
|||
assert.Equal(t, "DELETE", te["delete"].Method)
|
||||
}
|
||||
|
||||
// TestGetAPITokenRoutes_ExposesV2Only verifies the /routes payload merges
|
||||
// v2-only groups (time-entries has no v1 counterpart) so token clients can
|
||||
// discover and grant them, without mutating the v1 table itself.
|
||||
func TestGetAPITokenRoutes_ExposesV2Only(t *testing.T) {
|
||||
apiTokenRoutes = make(map[string]APITokenRoute)
|
||||
apiTokenRoutesV2 = make(map[string]APITokenRoute)
|
||||
|
||||
CollectRoutesForAPITokenUsage(echo.RouteInfo{Method: "GET", Path: "/api/v1/labels"}, true)
|
||||
CollectRoutesForAPITokenUsage(echo.RouteInfo{Method: "GET", Path: "/api/v2/time-entries"}, true)
|
||||
|
||||
routes := GetAPITokenRoutes()
|
||||
|
||||
_, hasLabels := routes["labels"]
|
||||
assert.True(t, hasLabels, "v1 groups stay exposed")
|
||||
|
||||
te, hasTE := routes["time-entries"]
|
||||
require.True(t, hasTE, "v2-only time-entries must be exposed via /routes")
|
||||
assert.Equal(t, "GET", te["read_all"].Method)
|
||||
|
||||
_, v1HasTE := apiTokenRoutes["time-entries"]
|
||||
assert.False(t, v1HasTE, "the merge must not mutate the v1 table")
|
||||
}
|
||||
|
||||
// TestGetRouteDetail_V2Verbs verifies the v2 verb mapping: POST→create,
|
||||
// PUT/PATCH→update. v1 inverts POST and PUT so we need a separate mapping
|
||||
// path.
|
||||
|
|
|
|||
Loading…
Reference in New Issue