feat!: consume privilege events with go-messaging-amqp (#327)
Unbound Release / Create Tag (push) Skipped
Unbound Release / Check Preconditions (push) Successful in 29s
authz_client / vulnerabilities (push) Skipped
authz_client / test (push) Skipped
pre-commit / pre-commit (push) Successful in 2m36s
Unbound Release / Create Release (push) Successful in 40s
Unbound Release / Generate Changelog and Handle PR (push) Successful in 37s
Release / release (push) Successful in 2m24s

This commit was merged in pull request #327.
This commit is contained in:
argoyle committed 2026-09-11 21:00:41 +00:00
1 parent f5e9eb52a7
commit 6bdf6e1cd3
5 files changed
+193 -68

No files matched your search

+84 -47
View File
@@ -1,6 +1,7 @@
package client
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
@@ -8,28 +9,27 @@ import (
"sync"
"testing"
"github.com/sparetimecoders/goamqp"
goamqp "codeberg.org/messaging/go-messaging-amqp"
spec "codeberg.org/messaging/messaging"
"github.com/stretchr/testify/assert"
)
func TestPrivilegeHandler_Process_InvalidType(t *testing.T) {
handler := New(WithBaseURL("base"))
result, err := handler.Process("abc", goamqp.Headers{})
err := handler.Process("abc")
assert.Nil(t, result)
assert.EqualError(t, err, "unexpected event type: 'string'")
}
func TestPrivilegeHandler_Process_PrivilegeRemoved(t *testing.T) {
handler := New(WithBaseURL("base"))
result, err := handler.Process(&PrivilegeAdded{
err := handler.Process(&PrivilegeAdded{
Email: "jim@example.org",
CompanyID: "abc-123",
Privilege: PrivilegeAdmin,
}, goamqp.Headers{})
assert.Nil(t, result)
})
assert.NoError(t, err)
companies := handler.CompaniesByUser("jim@example.org", func(privileges CompanyPrivileges) bool {
@@ -38,12 +38,11 @@ func TestPrivilegeHandler_Process_PrivilegeRemoved(t *testing.T) {
assert.Equal(t, []string{"abc-123"}, companies)
result, err = handler.Process(&PrivilegeRemoved{
err = handler.Process(&PrivilegeRemoved{
Email: "jim@example.org",
CompanyID: "abc-123",
Privilege: PrivilegeAdmin,
}, goamqp.Headers{})
assert.Nil(t, result)
})
assert.NoError(t, err)
companies = handler.CompaniesByUser("jim@example.org", func(privileges CompanyPrivileges) bool {
@@ -56,18 +55,16 @@ func TestPrivilegeHandler_Process_PrivilegeRemoved(t *testing.T) {
func TestPrivilegeHandler_Process_UserAdded_And_UserRemoved(t *testing.T) {
handler := New(WithBaseURL("base"))
result, err := handler.Process(&UserAdded{
err := handler.Process(&UserAdded{
Email: "jim@example.org",
CompanyID: "abc-123",
}, goamqp.Headers{})
assert.Nil(t, result)
})
assert.NoError(t, err)
result, err = handler.Process(&UserAdded{
err = handler.Process(&UserAdded{
Email: "jim@example.org",
CompanyID: "abc-456",
}, goamqp.Headers{})
assert.Nil(t, result)
})
assert.NoError(t, err)
companies := handler.CompaniesByUser("jim@example.org", func(privileges CompanyPrivileges) bool {
@@ -76,18 +73,16 @@ func TestPrivilegeHandler_Process_UserAdded_And_UserRemoved(t *testing.T) {
sort.Strings(companies)
assert.Equal(t, []string{"abc-123", "abc-456"}, companies)
result, err = handler.Process(&UserRemoved{
err = handler.Process(&UserRemoved{
Email: "jim@example.org",
CompanyID: "abc-123",
}, goamqp.Headers{})
assert.Nil(t, result)
})
assert.NoError(t, err)
result, err = handler.Process(&UserRemoved{
err = handler.Process(&UserRemoved{
Email: "jim@example.org",
CompanyID: "abc-456",
}, goamqp.Headers{})
assert.Nil(t, result)
})
assert.NoError(t, err)
companies = handler.CompaniesByUser("jim@example.org", func(privileges CompanyPrivileges) bool {
@@ -109,11 +104,10 @@ func TestPrivilegeHandler_GetCompanies_Email_Not_Found(t *testing.T) {
func TestPrivilegeHandler_GetCompanies_No_Companies_Found(t *testing.T) {
handler := New(WithBaseURL("base"))
result, err := handler.Process(&UserAdded{
err := handler.Process(&UserAdded{
Email: "jim@example.org",
CompanyID: "abc-123",
}, goamqp.Headers{})
assert.Nil(t, result)
})
assert.NoError(t, err)
companies := handler.CompaniesByUser("jim@example.org", func(privileges CompanyPrivileges) bool {
@@ -128,11 +122,10 @@ func TestPrivilegeHandler_GetCompanies_No_Companies_Found(t *testing.T) {
assert.Equal(t, []string{"abc-123"}, companies)
result, err = handler.Process(&UserRemoved{
err = handler.Process(&UserRemoved{
Email: "jim@example.org",
CompanyID: "abc-123",
}, goamqp.Headers{})
assert.Nil(t, result)
})
assert.NoError(t, err)
companies = handler.CompaniesByUser("jim@example.org", func(privileges CompanyPrivileges) bool {
@@ -144,12 +137,11 @@ func TestPrivilegeHandler_GetCompanies_No_Companies_Found(t *testing.T) {
func TestPrivilegeHandler_GetCompanies_Company_With_Company_Access_Found(t *testing.T) {
handler := New(WithBaseURL("base"))
result, err := handler.Process(&PrivilegeAdded{
err := handler.Process(&PrivilegeAdded{
Email: "jim@example.org",
CompanyID: "abc-123",
Privilege: PrivilegeCompany,
}, goamqp.Headers{})
assert.Nil(t, result)
})
assert.NoError(t, err)
companies := handler.CompaniesByUser("jim@example.org", func(privileges CompanyPrivileges) bool {
@@ -162,12 +154,11 @@ func TestPrivilegeHandler_GetCompanies_Company_With_Company_Access_Found(t *test
func TestPrivilegeHandler_GetCompanies_Company_With_Admin_Access_Found(t *testing.T) {
handler := New(WithBaseURL("base"))
result, err := handler.Process(&PrivilegeAdded{
err := handler.Process(&PrivilegeAdded{
Email: "jim@example.org",
CompanyID: "abc-123",
Privilege: PrivilegeConsumer,
}, goamqp.Headers{})
assert.Nil(t, result)
})
assert.NoError(t, err)
companies := handler.CompaniesByUser("jim@example.org", func(privileges CompanyPrivileges) bool {
@@ -190,11 +181,11 @@ func TestPrivilegeHandler_IsAllowed_Return_False_If_No_Privileges(t *testing.T)
func TestPrivilegeHandler_IsAllowed_Return_True_If_Privilege_Exists(t *testing.T) {
handler := New(WithBaseURL("base"))
_, _ = handler.Process(&PrivilegeAdded{
_ = handler.Process(&PrivilegeAdded{
Email: "jim@example.org",
CompanyID: "abc-123",
Privilege: PrivilegeTime,
}, goamqp.Headers{})
})
result := handler.IsAllowed("jim@example.org", "abc-123", func(privileges CompanyPrivileges) bool {
return privileges.Time
@@ -202,11 +193,11 @@ func TestPrivilegeHandler_IsAllowed_Return_True_If_Privilege_Exists(t *testing.T
assert.True(t, result)
_, _ = handler.Process(&PrivilegeAdded{
_ = handler.Process(&PrivilegeAdded{
Email: "jim@example.org",
CompanyID: "abc-123",
Privilege: PrivilegeInvoicing,
}, goamqp.Headers{})
})
result = handler.IsAllowed("jim@example.org", "abc-123", func(privileges CompanyPrivileges) bool {
return privileges.Invoicing
@@ -214,11 +205,11 @@ func TestPrivilegeHandler_IsAllowed_Return_True_If_Privilege_Exists(t *testing.T
assert.True(t, result)
_, _ = handler.Process(&PrivilegeAdded{
_ = handler.Process(&PrivilegeAdded{
Email: "jim@example.org",
CompanyID: "abc-123",
Privilege: PrivilegeAccounting,
}, goamqp.Headers{})
})
result = handler.IsAllowed("jim@example.org", "abc-123", func(privileges CompanyPrivileges) bool {
return privileges.Accounting
@@ -226,11 +217,11 @@ func TestPrivilegeHandler_IsAllowed_Return_True_If_Privilege_Exists(t *testing.T
assert.True(t, result)
_, _ = handler.Process(&PrivilegeAdded{
_ = handler.Process(&PrivilegeAdded{
Email: "jim@example.org",
CompanyID: "abc-123",
Privilege: PrivilegeSupplier,
}, goamqp.Headers{})
})
result = handler.IsAllowed("jim@example.org", "abc-123", func(privileges CompanyPrivileges) bool {
return privileges.Supplier
@@ -238,11 +229,11 @@ func TestPrivilegeHandler_IsAllowed_Return_True_If_Privilege_Exists(t *testing.T
assert.True(t, result)
_, _ = handler.Process(&PrivilegeAdded{
_ = handler.Process(&PrivilegeAdded{
Email: "jim@example.org",
CompanyID: "abc-123",
Privilege: PrivilegeSalary,
}, goamqp.Headers{})
})
result = handler.IsAllowed("jim@example.org", "abc-123", func(privileges CompanyPrivileges) bool {
return privileges.Salary
@@ -522,11 +513,11 @@ func TestPrivilegeHandler_Concurrent_Process_And_Read(t *testing.T) {
companyID := fmt.Sprintf("company-%d", i%10)
go func(id string) {
defer wg.Done()
_, _ = handler.Process(&PrivilegeAdded{
_ = handler.Process(&PrivilegeAdded{
Email: "jim@example.org",
CompanyID: id,
Privilege: PrivilegeAdmin,
}, goamqp.Headers{})
})
}(companyID)
}
@@ -598,11 +589,11 @@ func TestPrivilegeHandler_Concurrent_Multiple_Operations(t *testing.T) {
wg.Add(1)
go func(idx int) {
defer wg.Done()
_, _ = handler.Process(&PrivilegeAdded{
_ = handler.Process(&PrivilegeAdded{
Email: "jane@example.org",
CompanyID: fmt.Sprintf("company-%d", idx%5),
Privilege: PrivilegeCompany,
}, goamqp.Headers{})
})
}(i)
}
@@ -648,3 +639,49 @@ func TestPrivilegeHandler_Concurrent_Multiple_Operations(t *testing.T) {
expectedJane := []string{"company-0", "company-1", "company-2", "company-3", "company-4"}
assert.Equal(t, expectedJane, janeCompanies)
}
func TestPrivilegeHandler_Setup(t *testing.T) {
handler := New(WithBaseURL("base"))
topology, err := goamqp.CollectTopology("some-service", handler.Setup()...)
assert.NoError(t, err)
wiring := map[string]string{}
for _, e := range topology.Endpoints {
assert.Equal(t, spec.DirectionConsume, e.Direction)
assert.True(t, e.Ephemeral, "%s must be a per-replica consumer", e.RoutingKey)
wiring[e.RoutingKey] = e.MessageType
}
// A key wired to the wrong type could turn a revocation into a grant.
assert.Equal(t, map[string]string{
"User.Added": "client.UserAdded",
"User.Removed": "client.UserRemoved",
"Privilege.Added": "client.PrivilegeAdded",
"Privilege.Removed": "client.PrivilegeRemoved",
}, wiring)
}
func TestPrivilegeHandler_process(t *testing.T) {
ctx := context.Background()
handler := New(WithBaseURL("base"))
admin := func(p CompanyPrivileges) bool { return p.Admin }
assert.NoError(t, process[UserAdded](handler)(ctx, spec.ConsumableEvent[UserAdded]{
Payload: UserAdded{Email: "jim@example.org", CompanyID: "abc-123"},
}))
assert.False(t, handler.IsAllowed("jim@example.org", "abc-123", admin))
assert.NoError(t, process[PrivilegeAdded](handler)(ctx, spec.ConsumableEvent[PrivilegeAdded]{
Payload: PrivilegeAdded{Email: "jim@example.org", CompanyID: "abc-123", Privilege: PrivilegeAdmin},
}))
assert.True(t, handler.IsAllowed("jim@example.org", "abc-123", admin))
assert.NoError(t, process[PrivilegeRemoved](handler)(ctx, spec.ConsumableEvent[PrivilegeRemoved]{
Payload: PrivilegeRemoved{Email: "jim@example.org", CompanyID: "abc-123", Privilege: PrivilegeAdmin},
}))
assert.False(t, handler.IsAllowed("jim@example.org", "abc-123", admin))
assert.NoError(t, process[UserRemoved](handler)(ctx, spec.ConsumableEvent[UserRemoved]{
Payload: UserRemoved{Email: "jim@example.org", CompanyID: "abc-123"},
}))
assert.Empty(t, handler.CompaniesByUser("jim@example.org", func(CompanyPrivileges) bool { return true }))
}