NOISSUE - Fix Alarms roles (#3546)
Property Based Tests / api-test (push) Has been cancelled
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled

Signed-off-by: Arvindh <arvindh91@gmail.com>
This commit is contained in:
Arvindh
2026-07-06 20:56:39 +05:30
committed by GitHub
parent e078e00f73
commit 52645e2c39
4 changed files with 102 additions and 5 deletions
+13
View File
@@ -140,6 +140,9 @@ func (am *authorizationMiddleware) ListAlarms(ctx context.Context, session authn
session.SuperAdmin = true
case errors.Contains(err, svcerr.ErrSuperAdminAction):
if err := am.authorizeTenantAlarm(ctx, operations.OpViewAlarm, session); err != nil {
if alarmErr := am.authorizeAlarmType(ctx, operations.OpViewAlarm, session, ""); alarmErr == nil {
break
}
if pm.RuleID != "" {
if ruleErr := am.authorizeRuleRead(ctx, session, pm.RuleID); ruleErr != nil {
return alarms.AlarmsPage{}, errors.Wrap(errDomainViewAlarms, err)
@@ -183,6 +186,9 @@ func (am *authorizationMiddleware) authorizeAlarmOrRule(ctx context.Context, op
if tenantErr == nil {
return nil
}
if err := am.authorizeAlarmType(ctx, op, session, alarm.ID); err == nil {
return nil
}
if alarm.RuleID == "" {
return tenantErr
}
@@ -197,6 +203,9 @@ func (am *authorizationMiddleware) authorizeViewAlarm(ctx context.Context, sessi
if tenantErr == nil {
return nil
}
if err := am.authorizeAlarmType(ctx, operations.OpViewAlarm, session, alarm.ID); err == nil {
return nil
}
if alarm.RuleID == "" {
return tenantErr
}
@@ -210,6 +219,10 @@ func (am *authorizationMiddleware) authorizeTenantAlarm(ctx context.Context, op
return am.authorize(ctx, op, session, policies.DomainType, session.DomainID, atom.KindAlarm)
}
func (am *authorizationMiddleware) authorizeAlarmType(ctx context.Context, op permissions.Operation, session authn.Session, alarmID string) error {
return am.authorize(ctx, op, session, policies.AlarmsType, alarmID, atom.KindAlarm)
}
func (am *authorizationMiddleware) authorizeRuleRead(ctx context.Context, session authn.Session, ruleID string) error {
if am.atomAuthz != nil {
return atom.Authorize(ctx, am.atomAuthz, session, policies.ViewPermission, policies.RulesType, ruleID, atom.KindRule)
+77 -5
View File
@@ -85,7 +85,12 @@ func TestListAlarmsFiltersToReadableRulesWhenTenantAlarmReadDenied(t *testing.T)
_, err = wrapped.ListAlarms(context.Background(), authn.Session{UserID: "user-1", DomainID: "domain-1"}, pm)
require.NoError(t, err)
require.Len(t, authz.reqs, 1)
require.Len(t, authz.reqs, 2)
assert.Equal(t, "alarm_read", authz.reqs[0].Action)
assert.Equal(t, "tenant", authz.reqs[0].ObjectKind)
assert.Equal(t, "alarm_read", authz.reqs[1].Action)
assert.Equal(t, "resource", authz.reqs[1].ObjectKind)
assert.Equal(t, "alarms", authz.reqs[1].Context["legacy_object_type"])
require.Len(t, authz.queries, 1)
assert.Equal(t, atom.AuthorizedObjectIDsQuery{
SubjectID: "user-1",
@@ -115,9 +120,38 @@ func TestListAlarmsWithRuleFilterAuthorizesRuleRead(t *testing.T) {
_, err = wrapped.ListAlarms(context.Background(), session, pm)
require.NoError(t, err)
require.Len(t, authz.reqs, 2)
require.Len(t, authz.reqs, 3)
assert.Equal(t, "alarm_read", authz.reqs[0].Action)
assert.Equal(t, "read", authz.reqs[1].Action)
assert.Equal(t, "alarm_read", authz.reqs[1].Action)
assert.Equal(t, "resource", authz.reqs[1].ObjectKind)
assert.Equal(t, "alarms", authz.reqs[1].Context["legacy_object_type"])
assert.Equal(t, "read", authz.reqs[2].Action)
}
func TestListAlarmsAuthorizesAlarmTypeWhenTenantDenied(t *testing.T) {
svc := mocks.NewService(t)
pm := alarms.PageMetadata{Limit: 10}
expectedPM := pm
expectedPM.DomainID = "domain-1"
session := authn.Session{UserID: "user-1", DomainID: "domain-1"}
authz := &recordingAtomAuthorizer{
allow: func(req atom.AuthzRequest) bool {
return req.Action == "alarm_read" &&
req.ObjectKind == "resource" &&
req.Context["legacy_object_type"] == "alarms"
},
}
wrapped, err := NewAtomAuthorizationMiddleware(svc, authz, testEntitiesOps(t))
require.NoError(t, err)
svc.On("ListAlarms", mock.Anything, session, expectedPM).Return(alarms.AlarmsPage{Limit: 10}, nil).Once()
_, err = wrapped.ListAlarms(context.Background(), session, pm)
require.NoError(t, err)
require.Len(t, authz.reqs, 2)
assert.Equal(t, "tenant", authz.reqs[0].ObjectKind)
assert.Equal(t, "resource", authz.reqs[1].ObjectKind)
require.Empty(t, authz.queries)
}
func TestListAlarmsSuperAdminSkipsListAuthorization(t *testing.T) {
@@ -158,7 +192,7 @@ func TestAcknowledgeAlarmAuthorizesRuleAlarmActionWhenTenantDenied(t *testing.T)
_, err = wrapped.UpdateAlarm(context.Background(), session, update)
require.NoError(t, err)
require.Len(t, authz.reqs, 2)
require.Len(t, authz.reqs, 3)
assert.Equal(t, atom.AuthzRequest{
SubjectID: "user-1",
Action: "alarm_acknowledge",
@@ -170,6 +204,17 @@ func TestAcknowledgeAlarmAuthorizesRuleAlarmActionWhenTenantDenied(t *testing.T)
"legacy_object_type": "domain",
},
}, authz.reqs[0])
assert.Equal(t, atom.AuthzRequest{
SubjectID: "user-1",
Action: "alarm_acknowledge",
ResourceID: "alarm-1",
ObjectKind: "resource",
ObjectID: "alarm-1",
Context: map[string]any{
"domain_id": "domain-1",
"legacy_object_type": "alarms",
},
}, authz.reqs[1])
assert.Equal(t, atom.AuthzRequest{
SubjectID: "user-1",
Action: "alarm_acknowledge",
@@ -180,7 +225,34 @@ func TestAcknowledgeAlarmAuthorizesRuleAlarmActionWhenTenantDenied(t *testing.T)
"domain_id": "domain-1",
"legacy_object_type": "rules",
},
}, authz.reqs[1])
}, authz.reqs[2])
}
func TestAcknowledgeAlarmAuthorizesAlarmTypeWhenTenantDenied(t *testing.T) {
svc := mocks.NewService(t)
session := authn.Session{UserID: "user-1", DomainID: "domain-1"}
current := alarms.Alarm{ID: "alarm-1", RuleID: "rule-1", DomainID: "domain-1"}
update := alarms.Alarm{ID: "alarm-1", AcknowledgedBy: "user-1"}
authz := &recordingAtomAuthorizer{
allow: func(req atom.AuthzRequest) bool {
return req.Action == "alarm_acknowledge" &&
req.ObjectKind == "resource" &&
req.ObjectID == "alarm-1" &&
req.Context["legacy_object_type"] == "alarms"
},
}
wrapped, err := NewAtomAuthorizationMiddleware(svc, authz, testEntitiesOps(t))
require.NoError(t, err)
svc.On("ViewAlarm", mock.Anything, session, "alarm-1").Return(current, nil).Once()
svc.On("UpdateAlarm", mock.Anything, session, update).Return(update, nil).Once()
_, err = wrapped.UpdateAlarm(context.Background(), session, update)
require.NoError(t, err)
require.Len(t, authz.reqs, 2)
assert.Equal(t, "tenant", authz.reqs[0].ObjectKind)
assert.Equal(t, "resource", authz.reqs[1].ObjectKind)
assert.Equal(t, "alarms", authz.reqs[1].Context["legacy_object_type"])
}
func testEntitiesOps(t *testing.T) permissions.EntitiesOperations[permissions.Operation] {
+6
View File
@@ -72,6 +72,12 @@ var magistralaActionApplicability = []CapabilityApplicabilitySpec{
{ActionName: atomActionDelete, ObjectKind: atomObjectKindResource, ObjectType: atomObjectTypeResourceAlarm},
{ActionName: atomActionManage, ObjectKind: atomObjectKindResource, ObjectType: atomObjectTypeResourceAlarm},
{ActionName: atomActionList, ObjectKind: atomObjectKindResource, ObjectType: atomObjectTypeResourceAlarm},
{ActionName: atomActionAlarmRead, ObjectKind: atomObjectKindResource, ObjectType: atomObjectTypeResourceAlarm},
{ActionName: atomActionAlarmUpdate, ObjectKind: atomObjectKindResource, ObjectType: atomObjectTypeResourceAlarm},
{ActionName: atomActionAlarmDelete, ObjectKind: atomObjectKindResource, ObjectType: atomObjectTypeResourceAlarm},
{ActionName: atomActionAlarmAssign, ObjectKind: atomObjectKindResource, ObjectType: atomObjectTypeResourceAlarm},
{ActionName: atomActionAlarmAcknowledge, ObjectKind: atomObjectKindResource, ObjectType: atomObjectTypeResourceAlarm},
{ActionName: atomActionAlarmResolve, ObjectKind: atomObjectKindResource, ObjectType: atomObjectTypeResourceAlarm},
}
var magistralaActionAssignmentRules = []ActionAssignmentRuleSpec{
+6
View File
@@ -135,6 +135,12 @@ func TestBootstrapMagistralaActionsCreatesMissingActionsAndApplicability(t *test
assertApplicability(t, applicability, "list-id", atomObjectKindResource, "resource:report")
assertApplicability(t, applicability, "manage-id", atomObjectKindResource, "resource:alarm")
assertApplicability(t, applicability, "list-id", atomObjectKindResource, "resource:alarm")
assertApplicability(t, applicability, "alarm_read-id", atomObjectKindResource, "resource:alarm")
assertApplicability(t, applicability, "alarm_update-id", atomObjectKindResource, "resource:alarm")
assertApplicability(t, applicability, "alarm_delete-id", atomObjectKindResource, "resource:alarm")
assertApplicability(t, applicability, "alarm_assign-id", atomObjectKindResource, "resource:alarm")
assertApplicability(t, applicability, "alarm_acknowledge-id", atomObjectKindResource, "resource:alarm")
assertApplicability(t, applicability, "alarm_resolve-id", atomObjectKindResource, "resource:alarm")
if len(assignmentRules) != len(magistralaActionAssignmentRules) {
t.Fatalf("unexpected assignment guardrail count: got %d want %d", len(assignmentRules), len(magistralaActionAssignmentRules))
}