# 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" }