Files
git.stella-ops.org/policies/secret-detection.rego
2026-01-08 08:38:27 +02:00

117 lines
3.7 KiB
Rego

# Secret Detection Policy - OPA Rego
# Sprint: SPRINT_20260104_004_POLICY - Task PSD-010
#
# This Rego policy provides advanced logic for secret detection gates.
# Use this for complex organizations that need conditional logic based on
# environment, image source, or team ownership.
#
# Input schema (from ScanResult):
# input.secrets.findings[] - Array of SecretFinding objects
# input.secrets.bundle.version - Bundle version used for detection
# input.secrets.maskApplied - Whether masking was applied
# input.image.name - Full image name
# input.image.registry - Registry domain
# input.environment - Deployment environment (dev/staging/prod)
package stella.policy.secrets
import future.keywords.contains
import future.keywords.if
import future.keywords.in
default deny := []
default warn := []
# Block any critical secrets in production
deny contains msg if {
input.environment == "production"
finding := input.secrets.findings[_]
finding.severity == "critical"
msg := sprintf(
"BLOCKED: Critical secret '%s' detected in production image %s. Rule: %s",
[finding.ruleId, input.image.name, finding.ruleName]
)
}
# Block high-severity secrets with high confidence in all environments
deny contains msg if {
finding := input.secrets.findings[_]
finding.severity == "high"
finding.confidence == "high"
msg := sprintf(
"BLOCKED: High-confidence secret '%s' detected in %s. File: %s",
[finding.ruleName, input.image.name, finding.filePath]
)
}
# Allow low-confidence findings in dev, but block in prod/staging
deny contains msg if {
input.environment in {"production", "staging"}
finding := input.secrets.findings[_]
finding.severity in {"high", "critical"}
finding.confidence == "low"
msg := sprintf(
"BLOCKED: Low-confidence secret finding requires review before %s deployment. Rule: %s",
[input.environment, finding.ruleName]
)
}
# Warn on medium severity secrets in any environment
warn contains msg if {
finding := input.secrets.findings[_]
finding.severity == "medium"
msg := sprintf(
"WARNING: Medium-severity secret '%s' in %s. Consider adding to exceptions if legitimate.",
[finding.ruleName, finding.filePath]
)
}
# Warn if secret count exceeds threshold (potential bulk exposure)
warn contains msg if {
count(input.secrets.findings) > 10
msg := sprintf(
"WARNING: High number of secrets detected (%d findings). Review for bulk credential exposure.",
[count(input.secrets.findings)]
)
}
# Block export without masking
deny contains msg if {
input.context == "export"
not input.secrets.maskApplied
msg := "BLOCKED: Secrets must be masked before export. Enable masking in revelation policy."
}
# Require bundle signature verification
deny contains msg if {
input.environment == "production"
not input.secrets.bundle.verified
msg := sprintf(
"BLOCKED: Secret detection bundle '%s' signature verification failed.",
[input.secrets.bundle.id]
)
}
# Warn on outdated bundle in production
warn contains msg if {
input.environment == "production"
input.secrets.bundle.ageHours > 168 # 7 days
msg := sprintf(
"WARNING: Secret detection bundle is over 7 days old (version: %s). Update for latest rules.",
[input.secrets.bundle.version]
)
}
# Allowlist: Skip checks for internal base images
skip_secret_checks if {
startswith(input.image.registry, "internal.registry.")
input.image.isBaseImage
}
# Allowlist: Skip low-severity in dev environment
skip_warning[finding.id] if {
input.environment == "development"
finding := input.secrets.findings[_]
finding.severity == "low"
}