Writing Policies¶
This guide walks through creating custom Cedar policies for PipelineConductor.
Getting Started¶
1. Create a Policy Directory¶
2. Create a Policy File¶
Create policies/go/versions.cedar:
// Require supported Go versions
forbid(
principal,
action == Action::"merge",
resource
)
when {
context.goVersions.containsAny(["1.18", "1.19", "1.20"])
};
3. Validate the Policy¶
4. Test with a Scan¶
Policy Patterns¶
Require Something¶
Use forbid when a required condition is missing:
// Require CI workflow
forbid(
principal,
action == Action::"merge",
resource
)
when {
context.hasWorkflow == false
};
Block Something¶
Use forbid when a condition should prevent action:
// Block repos with vulnerabilities
forbid(
principal,
action == Action::"merge",
resource
)
when {
context.hasVulnerabilities == true
};
Allow with Conditions¶
Use permit to explicitly allow when conditions are met:
// Allow merge when using dependency automation
permit(
principal,
action == Action::"merge",
resource
)
when {
(context.hasRenovate == true || context.hasDependabot == true) &&
context.hasVulnerabilities == false
};
Tiered Requirements¶
Create multiple policies for graduated enforcement:
// Strict: Require all platforms
permit(
principal,
action == Action::"build",
resource
)
when {
context.osMatrix.containsAll(["ubuntu-latest", "macos-latest", "windows-latest"])
};
// Relaxed: Allow Linux-only for legacy
permit(
principal,
action == Action::"build",
resource
)
when {
context.osMatrix.contains("ubuntu-latest") &&
context.topics.contains("legacy")
};
Organization-Specific Policies¶
By Organization¶
// Stricter rules for production org
forbid(
principal,
action == Action::"deploy",
resource
)
when {
context.repoOrg == "production-org" &&
context.branchProtectionEnabled == false
};
By Topic¶
// Require security scanning for public repos
forbid(
principal,
action == Action::"release",
resource
)
when {
context.topics.contains("public") &&
context.hasVulnerabilities == true
};
By Language¶
// Go-specific requirements
forbid(
principal,
action == Action::"merge",
resource
)
when {
context.languages.contains("Go") &&
context.hasGoMod == false
};
Policy File Organization¶
Recommended structure:
policies/
├── common/
│ └── security.cedar # Cross-language security
├── go/
│ ├── merge.cedar # Go merge requirements
│ ├── versions.cedar # Go version enforcement
│ └── matrix.cedar # OS matrix requirements
├── python/
│ └── versions.cedar # Python version enforcement
└── dependencies/
├── age.cedar # Dependency freshness
└── vulnerabilities.cedar # Security scanning
Testing Policies¶
Validate Syntax¶
Dry Run¶
Test against your repos without taking action:
Incremental Testing¶
- Start with permissive policies
- Review violations in reports
- Gradually tighten requirements
Common Mistakes¶
Forgetting the Semicolon¶
// Wrong - missing semicolon
forbid(principal, action, resource)
when { context.hasWorkflow == false }
// Correct
forbid(principal, action, resource)
when { context.hasWorkflow == false };
Wrong Comparison Operator¶
// Wrong - assignment instead of comparison
when { context.hasWorkflow = false };
// Correct
when { context.hasWorkflow == false };
Invalid Context Variable¶
// Wrong - typo in variable name
when { context.hasWorkFlow == false };
// Correct
when { context.hasWorkflow == false };
Debugging Policies¶
Enable Verbose Mode¶
Check Policy Loading¶
Review Violations¶
The report shows which policies triggered violations:
{
"violations": [
{
"policy": "go/versions",
"rule": "supported-versions",
"message": "Go version 1.18 not in allowed versions",
"severity": "medium"
}
]
}
See Also¶
- Cedar Syntax - Language reference
- Examples - Complete policy examples
- Built-in Policies - Default policies