Checkpoint: password reset, rule expiry, migrations
- Self-service and admin password-change endpoints
(PUT /v1/auth/password, PUT /v1/accounts/{id}/password)
- Policy rule time-scoped expiry (not_before / expires_at)
with migration 000006 and engine filtering
- golang-migrate integration; embedded SQL migrations
- PolicyRecord fieldalignment lint fix
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ package policy
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// adminInput is a convenience helper for building admin PolicyInputs.
|
||||
@@ -378,3 +379,131 @@ func TestEvaluate_AccountTypeGating(t *testing.T) {
|
||||
t.Error("human account should not match system-only rule")
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Engine.SetRules time-filtering tests ----
|
||||
|
||||
func TestSetRules_SkipsExpiredRule(t *testing.T) {
|
||||
engine := NewEngine()
|
||||
past := time.Now().Add(-1 * time.Hour)
|
||||
|
||||
err := engine.SetRules([]PolicyRecord{
|
||||
{
|
||||
ID: 1,
|
||||
Description: "expired",
|
||||
Priority: 100,
|
||||
RuleJSON: `{"effect":"allow","actions":["accounts:list"]}`,
|
||||
Enabled: true,
|
||||
ExpiresAt: &past,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("SetRules: %v", err)
|
||||
}
|
||||
|
||||
// The expired rule should not be in the cache; evaluation should deny.
|
||||
input := PolicyInput{
|
||||
Subject: "user-uuid",
|
||||
AccountType: "human",
|
||||
Roles: []string{},
|
||||
Action: ActionListAccounts,
|
||||
Resource: Resource{Type: ResourceAccount},
|
||||
}
|
||||
effect, _ := engine.Evaluate(input)
|
||||
if effect != Deny {
|
||||
t.Error("expired rule should not match; expected Deny")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetRules_SkipsNotYetActiveRule(t *testing.T) {
|
||||
engine := NewEngine()
|
||||
future := time.Now().Add(1 * time.Hour)
|
||||
|
||||
err := engine.SetRules([]PolicyRecord{
|
||||
{
|
||||
ID: 2,
|
||||
Description: "not yet active",
|
||||
Priority: 100,
|
||||
RuleJSON: `{"effect":"allow","actions":["accounts:list"]}`,
|
||||
Enabled: true,
|
||||
NotBefore: &future,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("SetRules: %v", err)
|
||||
}
|
||||
|
||||
input := PolicyInput{
|
||||
Subject: "user-uuid",
|
||||
AccountType: "human",
|
||||
Roles: []string{},
|
||||
Action: ActionListAccounts,
|
||||
Resource: Resource{Type: ResourceAccount},
|
||||
}
|
||||
effect, _ := engine.Evaluate(input)
|
||||
if effect != Deny {
|
||||
t.Error("future not_before rule should not match; expected Deny")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetRules_IncludesActiveWindowRule(t *testing.T) {
|
||||
engine := NewEngine()
|
||||
past := time.Now().Add(-1 * time.Hour)
|
||||
future := time.Now().Add(1 * time.Hour)
|
||||
|
||||
err := engine.SetRules([]PolicyRecord{
|
||||
{
|
||||
ID: 3,
|
||||
Description: "currently active",
|
||||
Priority: 100,
|
||||
RuleJSON: `{"effect":"allow","actions":["accounts:list"]}`,
|
||||
Enabled: true,
|
||||
NotBefore: &past,
|
||||
ExpiresAt: &future,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("SetRules: %v", err)
|
||||
}
|
||||
|
||||
input := PolicyInput{
|
||||
Subject: "user-uuid",
|
||||
AccountType: "human",
|
||||
Roles: []string{},
|
||||
Action: ActionListAccounts,
|
||||
Resource: Resource{Type: ResourceAccount},
|
||||
}
|
||||
effect, _ := engine.Evaluate(input)
|
||||
if effect != Allow {
|
||||
t.Error("rule within its active window should match; expected Allow")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetRules_NilTimesAlwaysActive(t *testing.T) {
|
||||
engine := NewEngine()
|
||||
|
||||
err := engine.SetRules([]PolicyRecord{
|
||||
{
|
||||
ID: 4,
|
||||
Description: "no time constraints",
|
||||
Priority: 100,
|
||||
RuleJSON: `{"effect":"allow","actions":["accounts:list"]}`,
|
||||
Enabled: true,
|
||||
// NotBefore and ExpiresAt are both nil.
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("SetRules: %v", err)
|
||||
}
|
||||
|
||||
input := PolicyInput{
|
||||
Subject: "user-uuid",
|
||||
AccountType: "human",
|
||||
Roles: []string{},
|
||||
Action: ActionListAccounts,
|
||||
Resource: Resource{Type: ResourceAccount},
|
||||
}
|
||||
effect, _ := engine.Evaluate(input)
|
||||
if effect != Allow {
|
||||
t.Error("nil time fields mean always active; expected Allow")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user