From 49e55e1d719c4372a2e3c52166e725586834096c Mon Sep 17 00:00:00 2001 From: Kelley Loder Date: Tue, 30 Jun 2026 13:37:03 -0700 Subject: [PATCH 1/2] add tool-entity and view-tools to dev permissions --- adminapi/auth/permission_service.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/adminapi/auth/permission_service.go b/adminapi/auth/permission_service.go index 4640118..78ce955 100644 --- a/adminapi/auth/permission_service.go +++ b/adminapi/auth/permission_service.go @@ -522,7 +522,8 @@ func getPermissions(r *http.Request) (permissions []string) { WRITE_FIRMWARE_ALL, READ_FIRMWARE_ALL, WRITE_DCM_ALL, READ_DCM_ALL, WRITE_TELEMETRY_ALL, READ_TELEMETRY_ALL, - READ_CHANGES_ALL, WRITE_CHANGES_ALL} + READ_CHANGES_ALL, WRITE_CHANGES_ALL, + VIEW_TOOLS, WRITE_TOOLS} } else { permissions = xhttp.GetPermissionsFromContext(r) } From 71a8071441dcdb5a6ab347691971c2ac7bcad1c2 Mon Sep 17 00:00:00 2001 From: Kelley Loder Date: Tue, 30 Jun 2026 13:50:49 -0700 Subject: [PATCH 2/2] added corresponding unit tests --- adminapi/auth/permission_service_test.go | 52 ++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/adminapi/auth/permission_service_test.go b/adminapi/auth/permission_service_test.go index 90976a4..a1fbdfc 100644 --- a/adminapi/auth/permission_service_test.go +++ b/adminapi/auth/permission_service_test.go @@ -675,3 +675,55 @@ func TestSATv2UnclassifiedRouteReturns403(t *testing.T) { t.Fatalf("expected 403 authorization denial for unclassified route, got: %v", err) } } + +// Dev profile permissions include VIEW_TOOLS and WRITE_TOOLS so that TOOL_ENTITY +// endpoints (e.g. penetration metrics) pass CanRead/CanWrite checks without a SAT token. +func TestGetPermissionsDevProfileIncludesToolPermissions(t *testing.T) { + oldActive := owcommon.ActiveAuthProfiles + oldDefault := owcommon.DefaultAuthProfiles + owcommon.ActiveAuthProfiles = "dev" + owcommon.DefaultAuthProfiles = "prod" + defer func() { + owcommon.ActiveAuthProfiles = oldActive + owcommon.DefaultAuthProfiles = oldDefault + }() + + r := httptest.NewRequest("GET", "/xconfAdminService/penetrationdata/AA:BB:CC:DD:EE:FF", nil) + permissions := GetPermissionsFunc(r) + + for _, required := range []string{VIEW_TOOLS, WRITE_TOOLS} { + found := false + for _, p := range permissions { + if p == required { + found = true + break + } + } + if !found { + t.Errorf("dev profile permissions missing %q; got: %v", required, permissions) + } + } +} + +// TOOL_ENTITY CanRead succeeds under dev profile without a SAT token when SAT_ON=true. +func TestCanReadToolEntitySucceedsInDevProfileWithSATOn(t *testing.T) { + oldSatOn := owcommon.SatOn + oldActive := owcommon.ActiveAuthProfiles + oldDefault := owcommon.DefaultAuthProfiles + owcommon.SatOn = true + owcommon.ActiveAuthProfiles = "dev" + owcommon.DefaultAuthProfiles = "prod" + defer func() { + owcommon.SatOn = oldSatOn + owcommon.ActiveAuthProfiles = oldActive + owcommon.DefaultAuthProfiles = oldDefault + }() + + // No auth context set — simulates NoAuthMiddleware (test router behaviour) + r := httptest.NewRequest("GET", "/xconfAdminService/penetrationdata/AA:BB:CC:DD:EE:FF", nil) + + _, err := CanRead(r, TOOL_ENTITY) + if err != nil { + t.Fatalf("expected CanRead to succeed for TOOL_ENTITY in dev profile with SAT_ON=true, got: %v", err) + } +}