Implement policy package loader
Some checks failed
CI / Build and Test (push) Has been cancelled
CI / Lint (push) Has been cancelled

This commit is contained in:
2026-05-17 05:30:40 +02:00
parent 2cce434d47
commit 550d096cb2
9 changed files with 1170 additions and 7 deletions

View File

@@ -1,15 +1,96 @@
package policy_test
import (
"context"
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"
"gopkg.in/yaml.v3"
"github.com/netkingdom/flex-auth/internal/policy"
"github.com/netkingdom/flex-auth/pkg/api"
)
func TestLoadPolicyPackageMarkdownValidates(t *testing.T) {
pkg, err := policy.LoadAndValidateFile(context.Background(), filepath.Join("..", "..", "examples", "caring", "policy_package.md"))
if err != nil {
t.Fatalf("LoadAndValidateFile: %v", err)
}
if !pkg.Valid {
t.Fatalf("pkg.Valid = false\n%s", formatValidation(pkg.Validation))
}
if pkg.Metadata.Caring.Profile != api.CaringProfileCaring040RC2 {
t.Fatalf("metadata.Caring.Profile = %q; want %q", pkg.Metadata.Caring.Profile, api.CaringProfileCaring040RC2)
}
if pkg.Metadata.Namespace != "markitect:document" {
t.Errorf("metadata.Namespace = %q; want markitect:document", pkg.Metadata.Namespace)
}
if !strings.HasPrefix(pkg.RegoModule, "package flexauth.markitect.documents") {
t.Errorf("RegoModule prefix = %q; want flexauth.markitect.documents package", pkg.RegoModule[:min(len(pkg.RegoModule), 80)])
}
if len(pkg.RuleBlocks) != 1 || len(pkg.TestBlocks) != 1 || len(pkg.Fixtures) != 2 {
t.Fatalf("blocks/fixtures = rules:%d tests:%d fixtures:%d; want 1/1/2", len(pkg.RuleBlocks), len(pkg.TestBlocks), len(pkg.Fixtures))
}
if len(pkg.Validation.Tests) != 2 {
t.Fatalf("Validation.Tests len = %d; want 2", len(pkg.Validation.Tests))
}
for _, test := range pkg.Validation.Tests {
if !test.Passed {
t.Fatalf("test %s failed: %s", test.Name, test.Error)
}
}
for _, fixture := range pkg.Validation.Fixtures {
if !fixture.Passed {
t.Fatalf("fixture %s failed: %s\nactual: %+v", fixture.ID, fixture.Error, fixture.Actual)
}
}
}
func TestCaringFindingsAreAdvisoryUntilEnforced(t *testing.T) {
doc := inlinePolicy(false, "allow")
pkg, err := policy.Load([]byte(doc), "inline-policy.md")
if err != nil {
t.Fatalf("Load: %v", err)
}
result := pkg.Validate(context.Background())
if !result.Valid {
t.Fatalf("result.Valid = false without CARING enforcement\n%s", formatValidation(result))
}
if len(result.CaringFindings) == 0 {
t.Fatal("expected advisory CARING findings for missing metadata dimensions")
}
enforced := strings.Replace(doc, "enforce: false", "enforce: true", 1)
pkg, err = policy.Load([]byte(enforced), "inline-policy.md")
if err != nil {
t.Fatalf("Load enforced: %v", err)
}
result = pkg.Validate(context.Background())
if result.Valid {
t.Fatalf("result.Valid = true with CARING enforcement; want invalid\n%s", formatValidation(result))
}
}
func TestFixtureMismatchInvalidatesPackage(t *testing.T) {
pkg, err := policy.Load([]byte(inlinePolicy(false, "deny")), "inline-policy.md")
if err != nil {
t.Fatalf("Load: %v", err)
}
result := pkg.Validate(context.Background())
if result.Valid {
t.Fatalf("result.Valid = true; want fixture mismatch to invalidate package\n%s", formatValidation(result))
}
if len(result.Fixtures) != 1 || result.Fixtures[0].Passed {
t.Fatalf("fixture result = %+v; want one failed fixture", result.Fixtures)
}
}
func TestPolicyPackageMetadataParses(t *testing.T) {
var metadata api.PolicyPackageMetadata
loadYAML(t, filepath.Join("..", "..", "examples", "caring", "policy_package.yaml"), &metadata)
@@ -37,6 +118,63 @@ func TestPolicyFixtureParses(t *testing.T) {
}
}
func inlinePolicy(enforce bool, expectedEffect string) string {
enforceValue := "false"
if enforce {
enforceValue = "true"
}
fence := "```"
doc := strings.ReplaceAll(`---
id: inline.allow
version: v1
package: flexauth.inline
caring:
profile: caring-0.4.0-rc2
enforce: ENFORCE
---
# Inline Policy
`+fence+`rego
default decision := {"effect": "allow", "reason": "ok"}
`+fence+`
`+fence+`rego test
package flexauth.inline_test
import future.keywords.if
import data.flexauth.inline
test_allow if {
inline.decision.effect == "allow"
}
`+fence+`
`+fence+`yaml fixture
id: fixture:inline
request:
subject:
id: user:alice
action: read
resource:
id: document:inline
expect:
effect: EXPECTED
reason: ok
`+fence+`
`, "ENFORCE", enforceValue)
return strings.ReplaceAll(doc, "EXPECTED", expectedEffect)
}
func formatValidation(result policy.ValidationResult) string {
data, err := json.MarshalIndent(result, "", " ")
if err != nil {
return err.Error()
}
return string(data)
}
func loadYAML(t *testing.T, path string, out any) {
t.Helper()