generated from coulomb/repo-seed
189 lines
5.4 KiB
Go
189 lines
5.4 KiB
Go
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)
|
|
|
|
if metadata.Caring.Profile != api.CaringProfileCaring040RC2 {
|
|
t.Fatalf("metadata.Caring.Profile = %q; want %q", metadata.Caring.Profile, api.CaringProfileCaring040RC2)
|
|
}
|
|
if len(metadata.Caring.Capabilities) != 1 || metadata.Caring.Capabilities[0] != api.CapabilityView {
|
|
t.Errorf("metadata.Caring.Capabilities = %v; want [View]", metadata.Caring.Capabilities)
|
|
}
|
|
if len(metadata.Caring.Restrictions) != 1 || metadata.Caring.Restrictions[0] != api.RestrictionExportBlocked {
|
|
t.Errorf("metadata.Caring.Restrictions = %v; want [ExportBlocked]", metadata.Caring.Restrictions)
|
|
}
|
|
}
|
|
|
|
func TestPolicyFixtureParses(t *testing.T) {
|
|
var fixture api.PolicyFixture
|
|
loadYAML(t, filepath.Join("..", "..", "examples", "caring", "policy_fixture.yaml"), &fixture)
|
|
|
|
if fixture.Expect.Effect != api.DecisionEffectAllow {
|
|
t.Errorf("fixture.Expect.Effect = %q; want allow", fixture.Expect.Effect)
|
|
}
|
|
if fixture.Request.CaringContext == nil {
|
|
t.Fatal("fixture.Request.CaringContext is nil")
|
|
}
|
|
}
|
|
|
|
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()
|
|
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
t.Fatalf("read %s: %v", path, err)
|
|
}
|
|
if err := yaml.Unmarshal(data, out); err != nil {
|
|
t.Fatalf("unmarshal %s: %v", path, err)
|
|
}
|
|
}
|