Files
mcr/internal/policy/policy_test.go
Kyle Isom c67601c7f6 Allow all authenticated users to push/pull (not just human+user role)
The previous default policy required both AccountTypes=["human"] and
Roles=["user"], but MCIAS validate responses don't reliably include
these fields. For a private registry, any successfully authenticated
caller should have content access. Admin-only operations (policy
management) still require the admin role.

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

338 lines
8.2 KiB
Go

package policy
import "testing"
func TestEvaluateAdminWildcard(t *testing.T) {
rules := DefaultRules()
input := PolicyInput{
Subject: "admin-uuid",
AccountType: "human",
Roles: []string{"admin"},
Action: ActionPush,
Repository: "myapp",
}
effect, rule := Evaluate(input, rules)
if effect != Allow {
t.Fatalf("admin push: got %s, want allow", effect)
}
if rule == nil || rule.ID != -1 {
t.Fatalf("admin push: expected admin wildcard rule (ID -1), got %+v", rule)
}
}
func TestEvaluateUserAllow(t *testing.T) {
rules := DefaultRules()
input := PolicyInput{
Subject: "user-uuid",
AccountType: "human",
Roles: []string{"user"},
Action: ActionPull,
Repository: "myapp",
}
effect, rule := Evaluate(input, rules)
if effect != Allow {
t.Fatalf("user pull: got %s, want allow", effect)
}
if rule == nil || rule.ID != -2 {
t.Fatalf("user pull: expected user content rule (ID -2), got %+v", rule)
}
}
func TestEvaluateSystemAccountAllow(t *testing.T) {
rules := DefaultRules()
input := PolicyInput{
Subject: "system-uuid",
AccountType: "system",
Action: ActionPull,
Repository: "myapp",
}
effect, rule := Evaluate(input, rules)
if effect != Allow {
t.Fatalf("system pull: got %s, want allow", effect)
}
if rule == nil || rule.ID != -2 {
t.Fatalf("system pull: expected authenticated content rule (ID -2), got %+v", rule)
}
}
func TestEvaluateExactRepoMatch(t *testing.T) {
rules := append(DefaultRules(), Rule{
ID: 1,
Priority: 50,
Effect: Allow,
SubjectUUID: "ci-uuid",
Actions: []Action{ActionPull},
Repositories: []string{"myapp"},
})
input := PolicyInput{
Subject: "ci-uuid",
AccountType: "system",
Action: ActionPull,
Repository: "myapp",
}
effect, _ := Evaluate(input, rules)
if effect != Allow {
t.Fatalf("exact repo match: got %s, want allow", effect)
}
// Different repo still allowed via default rule -2 (authenticated users).
input.Repository = "other"
effect, _ = Evaluate(input, rules)
if effect != Allow {
t.Fatalf("different repo: got %s, want allow", effect)
}
}
func TestEvaluateGlobMatch(t *testing.T) {
rules := append(DefaultRules(), Rule{
ID: 1,
Priority: 50,
Effect: Allow,
SubjectUUID: "ci-uuid",
Actions: []Action{ActionPush, ActionPull},
Repositories: []string{"production/*"},
})
input := PolicyInput{
Subject: "ci-uuid",
AccountType: "system",
Action: ActionPush,
Repository: "production/myapp",
}
effect, _ := Evaluate(input, rules)
if effect != Allow {
t.Fatalf("glob match production/myapp: got %s, want allow", effect)
}
// Nested repo does not match the glob rule, but default rule -2
// (authenticated users) allows it.
input.Repository = "production/team/myapp"
effect, _ = Evaluate(input, rules)
if effect != Allow {
t.Fatalf("glob no-match production/team/myapp: got %s, want allow", effect)
}
}
func TestEvaluateDenyWins(t *testing.T) {
rules := []Rule{
{
ID: 1,
Priority: 50,
Effect: Allow,
SubjectUUID: "agent-uuid",
Actions: []Action{ActionPull},
},
{
ID: 2,
Priority: 10,
Effect: Deny,
SubjectUUID: "agent-uuid",
Actions: []Action{ActionPull},
},
}
input := PolicyInput{
Subject: "agent-uuid",
AccountType: "system",
Action: ActionPull,
Repository: "myapp",
}
effect, rule := Evaluate(input, rules)
if effect != Deny {
t.Fatalf("deny-wins: got %s, want deny", effect)
}
if rule == nil || rule.ID != 2 {
t.Fatalf("deny-wins: expected deny rule (ID 2), got %+v", rule)
}
}
func TestEvaluatePriorityOrdering(t *testing.T) {
rules := []Rule{
{
ID: 1,
Priority: 100,
Effect: Allow,
Actions: []Action{ActionPull},
},
{
ID: 2,
Priority: 10,
Effect: Deny,
Actions: []Action{ActionPull},
},
}
input := PolicyInput{
Subject: "any",
AccountType: "system",
Action: ActionPull,
Repository: "myapp",
}
effect, _ := Evaluate(input, rules)
if effect != Deny {
t.Fatalf("priority: got %s, want deny", effect)
}
}
func TestEvaluateEmptyRepoGlobalOperation(t *testing.T) {
rules := DefaultRules()
// Admin should be allowed for catalog (admin wildcard, empty Repositories = wildcard).
input := PolicyInput{
Subject: "admin-uuid",
AccountType: "human",
Roles: []string{"admin"},
Action: ActionCatalog,
}
effect, _ := Evaluate(input, rules)
if effect != Allow {
t.Fatalf("admin catalog: got %s, want allow", effect)
}
// System account catalog: default rule -2 (authenticated users)
// allows catalog with no repo restriction, so this is allowed even
// though the custom repo-scoped rule would not match.
rules = append(rules, Rule{
ID: 1,
Priority: 50,
Effect: Allow,
SubjectUUID: "ci-uuid",
Actions: []Action{ActionCatalog},
Repositories: []string{"myapp"},
})
input = PolicyInput{
Subject: "ci-uuid",
AccountType: "system",
Action: ActionCatalog,
}
effect, _ = Evaluate(input, rules)
if effect != Allow {
t.Fatalf("system catalog: got %s, want allow", effect)
}
}
func TestEvaluateMultipleMatchingRules(t *testing.T) {
rules := []Rule{
{
ID: 1,
Priority: 50,
Effect: Allow,
Actions: []Action{ActionPull},
},
{
ID: 2,
Priority: 100,
Effect: Allow,
Actions: []Action{ActionPull, ActionPush},
},
}
input := PolicyInput{
Subject: "any",
AccountType: "system",
Action: ActionPull,
Repository: "myapp",
}
effect, rule := Evaluate(input, rules)
if effect != Allow {
t.Fatalf("multiple allow: got %s, want allow", effect)
}
if rule == nil || rule.ID != 1 {
t.Fatalf("multiple allow: expected rule ID 1 (higher priority), got %+v", rule)
}
}
// --- Default rules tests (Step 4.2) ---
func TestDefaultRulesAdminAllActions(t *testing.T) {
rules := DefaultRules()
actions := []Action{
ActionVersionCheck, ActionPull, ActionPush,
ActionDelete, ActionCatalog, ActionPolicyManage,
}
for _, a := range actions {
input := PolicyInput{
Subject: "admin-uuid",
AccountType: "human",
Roles: []string{"admin"},
Action: a,
Repository: "myapp",
}
effect, _ := Evaluate(input, rules)
if effect != Allow {
t.Errorf("admin %s: got %s, want allow", a, effect)
}
}
}
func TestDefaultRulesUserContentAccess(t *testing.T) {
rules := DefaultRules()
allowed := []Action{ActionPull, ActionPush, ActionDelete, ActionCatalog}
for _, a := range allowed {
input := PolicyInput{
Subject: "user-uuid",
AccountType: "human",
Roles: []string{"user"},
Action: a,
Repository: "myapp",
}
effect, _ := Evaluate(input, rules)
if effect != Allow {
t.Errorf("user %s: got %s, want allow", a, effect)
}
}
// policy:manage should be denied for regular user.
input := PolicyInput{
Subject: "user-uuid",
AccountType: "human",
Roles: []string{"user"},
Action: ActionPolicyManage,
}
effect, _ := Evaluate(input, rules)
if effect != Deny {
t.Errorf("user policy:manage: got %s, want deny", effect)
}
}
func TestDefaultRulesSystemAccountAccess(t *testing.T) {
rules := DefaultRules()
// System accounts are now allowed for content actions via rule -2.
allowed := []Action{ActionPull, ActionPush, ActionDelete, ActionCatalog}
for _, a := range allowed {
input := PolicyInput{
Subject: "system-uuid",
AccountType: "system",
Action: a,
Repository: "myapp",
}
effect, _ := Evaluate(input, rules)
if effect != Allow {
t.Errorf("system %s: got %s, want allow", a, effect)
}
}
// policy:manage should still be denied for system accounts.
input := PolicyInput{
Subject: "system-uuid",
AccountType: "system",
Action: ActionPolicyManage,
}
effect, _ := Evaluate(input, rules)
if effect != Deny {
t.Errorf("system policy:manage: got %s, want deny", effect)
}
}
func TestDefaultRulesVersionCheckAlwaysAllowed(t *testing.T) {
rules := DefaultRules()
for _, acctType := range []string{"human", "system"} {
input := PolicyInput{
Subject: "any-uuid",
AccountType: acctType,
Action: ActionVersionCheck,
}
effect, _ := Evaluate(input, rules)
if effect != Allow {
t.Errorf("%s version_check: got %s, want allow", acctType, effect)
}
}
}