Files
mcr/internal/grpcserver/policy_test.go
Kyle Isom d5580f01f2 Migrate module path from kyle/ to mc/ org
All import paths updated to git.wntrmute.dev/mc/. Bumps mcdsl to v1.2.0.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 02:05:59 -07:00

307 lines
7.5 KiB
Go

package grpcserver
import (
"testing"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
pb "git.wntrmute.dev/mc/mcr/gen/mcr/v1"
"git.wntrmute.dev/mc/mcr/internal/policy"
)
type fakePolicyReloader struct {
reloadCount int
}
func (f *fakePolicyReloader) Reload(_ policy.RuleStore) error {
f.reloadCount++
return nil
}
func TestCreatePolicyRule(t *testing.T) {
deps := adminDeps(t)
reloader := &fakePolicyReloader{}
deps.Engine = reloader
cc := startTestServer(t, deps)
client := pb.NewPolicyServiceClient(cc)
resp, err := client.CreatePolicyRule(adminCtx(), &pb.CreatePolicyRuleRequest{
Priority: 10,
Description: "allow pull for all",
Effect: "allow",
Actions: []string{"registry:pull"},
Enabled: true,
})
if err != nil {
t.Fatalf("CreatePolicyRule: %v", err)
}
if resp.GetId() == 0 {
t.Fatal("expected non-zero ID")
}
if resp.GetDescription() != "allow pull for all" {
t.Fatalf("description: got %q, want %q", resp.Description, "allow pull for all")
}
if resp.GetEffect() != "allow" {
t.Fatalf("effect: got %q, want %q", resp.Effect, "allow")
}
if !resp.GetEnabled() {
t.Fatal("expected enabled=true")
}
if reloader.reloadCount != 1 {
t.Fatalf("reloadCount: got %d, want 1", reloader.reloadCount)
}
}
func TestCreatePolicyRuleValidation(t *testing.T) {
deps := adminDeps(t)
cc := startTestServer(t, deps)
client := pb.NewPolicyServiceClient(cc)
tests := []struct {
name string
req *pb.CreatePolicyRuleRequest
code codes.Code
}{
{
name: "zero priority",
req: &pb.CreatePolicyRuleRequest{
Priority: 0,
Description: "test",
Effect: "allow",
Actions: []string{"registry:pull"},
},
code: codes.InvalidArgument,
},
{
name: "empty description",
req: &pb.CreatePolicyRuleRequest{
Priority: 1,
Effect: "allow",
Actions: []string{"registry:pull"},
},
code: codes.InvalidArgument,
},
{
name: "invalid effect",
req: &pb.CreatePolicyRuleRequest{
Priority: 1,
Description: "test",
Effect: "maybe",
Actions: []string{"registry:pull"},
},
code: codes.InvalidArgument,
},
{
name: "no actions",
req: &pb.CreatePolicyRuleRequest{
Priority: 1,
Description: "test",
Effect: "allow",
},
code: codes.InvalidArgument,
},
{
name: "invalid action",
req: &pb.CreatePolicyRuleRequest{
Priority: 1,
Description: "test",
Effect: "allow",
Actions: []string{"registry:fly"},
},
code: codes.InvalidArgument,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := client.CreatePolicyRule(adminCtx(), tt.req)
if err == nil {
t.Fatal("expected error")
}
st, ok := status.FromError(err)
if !ok {
t.Fatalf("expected gRPC status, got %v", err)
}
if st.Code() != tt.code {
t.Fatalf("code: got %v, want %v", st.Code(), tt.code)
}
})
}
}
func TestGetPolicyRule(t *testing.T) {
deps := adminDeps(t)
cc := startTestServer(t, deps)
client := pb.NewPolicyServiceClient(cc)
// Create a rule first.
created, err := client.CreatePolicyRule(adminCtx(), &pb.CreatePolicyRuleRequest{
Priority: 5,
Description: "test rule",
Effect: "deny",
Actions: []string{"registry:push"},
Enabled: true,
})
if err != nil {
t.Fatalf("CreatePolicyRule: %v", err)
}
// Fetch it.
got, err := client.GetPolicyRule(adminCtx(), &pb.GetPolicyRuleRequest{Id: created.Id})
if err != nil {
t.Fatalf("GetPolicyRule: %v", err)
}
if got.Id != created.Id {
t.Fatalf("id: got %d, want %d", got.Id, created.Id)
}
if got.Effect != "deny" {
t.Fatalf("effect: got %q, want %q", got.Effect, "deny")
}
}
func TestGetPolicyRuleNotFound(t *testing.T) {
deps := adminDeps(t)
cc := startTestServer(t, deps)
client := pb.NewPolicyServiceClient(cc)
_, err := client.GetPolicyRule(adminCtx(), &pb.GetPolicyRuleRequest{Id: 99999})
if err == nil {
t.Fatal("expected error")
}
st, ok := status.FromError(err)
if !ok {
t.Fatalf("expected gRPC status, got %v", err)
}
if st.Code() != codes.NotFound {
t.Fatalf("code: got %v, want NotFound", st.Code())
}
}
func TestListPolicyRules(t *testing.T) {
deps := adminDeps(t)
cc := startTestServer(t, deps)
client := pb.NewPolicyServiceClient(cc)
// Create two rules.
for i := range 2 {
_, err := client.CreatePolicyRule(adminCtx(), &pb.CreatePolicyRuleRequest{
Priority: int32(i + 1),
Description: "rule",
Effect: "allow",
Actions: []string{"registry:pull"},
Enabled: true,
})
if err != nil {
t.Fatalf("CreatePolicyRule %d: %v", i, err)
}
}
resp, err := client.ListPolicyRules(adminCtx(), &pb.ListPolicyRulesRequest{})
if err != nil {
t.Fatalf("ListPolicyRules: %v", err)
}
if len(resp.GetRules()) < 2 {
t.Fatalf("expected at least 2 rules, got %d", len(resp.Rules))
}
}
func TestDeletePolicyRule(t *testing.T) {
deps := adminDeps(t)
reloader := &fakePolicyReloader{}
deps.Engine = reloader
cc := startTestServer(t, deps)
client := pb.NewPolicyServiceClient(cc)
// Create then delete.
created, err := client.CreatePolicyRule(adminCtx(), &pb.CreatePolicyRuleRequest{
Priority: 1,
Description: "to be deleted",
Effect: "allow",
Actions: []string{"registry:pull"},
Enabled: true,
})
if err != nil {
t.Fatalf("CreatePolicyRule: %v", err)
}
initialReloads := reloader.reloadCount
_, err = client.DeletePolicyRule(adminCtx(), &pb.DeletePolicyRuleRequest{Id: created.Id})
if err != nil {
t.Fatalf("DeletePolicyRule: %v", err)
}
// Verify it was reloaded.
if reloader.reloadCount != initialReloads+1 {
t.Fatalf("reloadCount: got %d, want %d", reloader.reloadCount, initialReloads+1)
}
// Verify it's gone.
_, err = client.GetPolicyRule(adminCtx(), &pb.GetPolicyRuleRequest{Id: created.Id})
if err == nil {
t.Fatal("expected error after deletion")
}
st, ok := status.FromError(err)
if !ok {
t.Fatalf("expected gRPC status, got %v", err)
}
if st.Code() != codes.NotFound {
t.Fatalf("code: got %v, want NotFound", st.Code())
}
}
func TestDeletePolicyRuleNotFound(t *testing.T) {
deps := adminDeps(t)
cc := startTestServer(t, deps)
client := pb.NewPolicyServiceClient(cc)
_, err := client.DeletePolicyRule(adminCtx(), &pb.DeletePolicyRuleRequest{Id: 99999})
if err == nil {
t.Fatal("expected error")
}
st, ok := status.FromError(err)
if !ok {
t.Fatalf("expected gRPC status, got %v", err)
}
if st.Code() != codes.NotFound {
t.Fatalf("code: got %v, want NotFound", st.Code())
}
}
func TestUpdatePolicyRule(t *testing.T) {
deps := adminDeps(t)
reloader := &fakePolicyReloader{}
deps.Engine = reloader
cc := startTestServer(t, deps)
client := pb.NewPolicyServiceClient(cc)
// Create a rule.
created, err := client.CreatePolicyRule(adminCtx(), &pb.CreatePolicyRuleRequest{
Priority: 10,
Description: "original",
Effect: "allow",
Actions: []string{"registry:pull"},
Enabled: true,
})
if err != nil {
t.Fatalf("CreatePolicyRule: %v", err)
}
// Update description.
updated, err := client.UpdatePolicyRule(adminCtx(), &pb.UpdatePolicyRuleRequest{
Id: created.Id,
Description: "updated description",
UpdateMask: []string{"description"},
})
if err != nil {
t.Fatalf("UpdatePolicyRule: %v", err)
}
if updated.Description != "updated description" {
t.Fatalf("description: got %q, want %q", updated.Description, "updated description")
}
// Effect should be unchanged.
if updated.Effect != "allow" {
t.Fatalf("effect: got %q, want %q", updated.Effect, "allow")
}
}