mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2026-10-07 05:46:27 +00:00
feat(security): exclude hidden/masked columns from create and update payloads
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
package security
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type wsCtx struct {
|
||||
data interface{}
|
||||
model interface{}
|
||||
user bool
|
||||
}
|
||||
|
||||
func (c *wsCtx) GetContext() context.Context {
|
||||
if c.user {
|
||||
return context.WithValue(context.Background(), UserIDKey, 7)
|
||||
}
|
||||
return context.Background()
|
||||
}
|
||||
func (c *wsCtx) GetUserID() (int, bool) { return 7, c.user }
|
||||
func (c *wsCtx) GetUserRef() (any, bool) { return 7, c.user }
|
||||
func (c *wsCtx) GetSchema() string { return "public" }
|
||||
func (c *wsCtx) GetEntity() string { return "items" }
|
||||
func (c *wsCtx) GetModel() interface{} { return c.model }
|
||||
func (c *wsCtx) GetQuery() interface{} { return nil }
|
||||
func (c *wsCtx) SetQuery(interface{}) {}
|
||||
func (c *wsCtx) GetResult() interface{} { return nil }
|
||||
func (c *wsCtx) SetResult(interface{}) {}
|
||||
func (c *wsCtx) GetData() interface{} { return c.data }
|
||||
func (c *wsCtx) SetData(d interface{}) { c.data = d }
|
||||
|
||||
type wsModel struct {
|
||||
ID int `json:"id" bun:"id,pk"`
|
||||
Name string `json:"name" bun:"name"`
|
||||
Email string `json:"email" gorm:"column:email_addr"`
|
||||
Other string `json:"other" bun:"other"`
|
||||
}
|
||||
|
||||
func wsList(rules ...ColumnSecurity) *SecurityList {
|
||||
l := &SecurityList{ColumnSecurity: map[string][]ColumnSecurity{"public.items@7": rules}}
|
||||
if rules == nil {
|
||||
l.ColumnSecurity["public.items@7"] = []ColumnSecurity{}
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
func TestApplyWriteColumnSecurityStripsHiddenAndMasked(t *testing.T) {
|
||||
list := wsList(
|
||||
ColumnSecurity{Path: []string{"Name"}, Accesstype: "hide"},
|
||||
ColumnSecurity{Path: []string{"email_addr"}, Accesstype: "mask"},
|
||||
ColumnSecurity{Path: []string{"other"}, Accesstype: "allow"},
|
||||
ColumnSecurity{Path: []string{"id", "sub"}, Accesstype: "hide"},
|
||||
)
|
||||
tests := map[string]struct{ in, want interface{} }{
|
||||
"map": {
|
||||
map[string]interface{}{"id": 1, "name": "a", "email": "e", "other": "o"},
|
||||
map[string]interface{}{"id": 1, "other": "o"},
|
||||
},
|
||||
"slice": {
|
||||
[]interface{}{map[string]interface{}{"NAME": "a", "id": 1}, map[string]interface{}{"email_addr": "e"}},
|
||||
[]interface{}{map[string]interface{}{"id": 1}, map[string]interface{}{}},
|
||||
},
|
||||
}
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
c := &wsCtx{data: tc.in, model: &wsModel{}, user: true}
|
||||
if err := ApplyWriteColumnSecurity(c, list); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(c.data, tc.want) {
|
||||
t.Fatalf("got %v want %v", c.data, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyWriteColumnSecurityNoRulesKeepsPayload(t *testing.T) {
|
||||
c := &wsCtx{data: map[string]interface{}{"name": "a"}, model: &wsModel{}, user: true}
|
||||
if err := ApplyWriteColumnSecurity(c, wsList()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, ok := c.data.(map[string]interface{})["name"]; !ok {
|
||||
t.Fatal("payload changed without rules")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyWriteColumnSecurityFailsClosedWhenRulesNotLoaded(t *testing.T) {
|
||||
c := &wsCtx{data: map[string]interface{}{"name": "a"}, model: &wsModel{}, user: true}
|
||||
if err := ApplyWriteColumnSecurity(c, &SecurityList{}); err == nil {
|
||||
t.Fatal("expected an error when rules are not loaded")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyWriteColumnSecuritySkipsWithoutUser(t *testing.T) {
|
||||
c := &wsCtx{data: map[string]interface{}{"name": "a"}, model: &wsModel{}}
|
||||
if err := ApplyWriteColumnSecurity(c, &SecurityList{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user