Stop Writing Policy PDFs—Ship Guardrails in Code
If your security policy lives in Confluence, it’s already out of date. Translate rules into automated checks, proofs, and exceptions that fit the way developers actually work.
Policies that don’t execute in the pipeline are just opinions. Ship guardrails, not guidance.Back to all posts
The policy PDF that broke the release
I’ve watched well-meaning teams roll out 40-page “secure coding standards” only to watch developers click past them like EULAs. A fintech I worked with pushed a last-minute PCI DSS update into Confluence on a Friday. Monday’s release died because the only engineer who read it added manual steps no one else did. Two hours of finger-pointing later, we turned the policy into a pre-merge check and the drama vanished.
If the rule isn’t executable where devs work—IDE, pre-commit, CI, and runtime—it’s not a standard. It’s a suggestion.
Translate policy to guardrails developers can feel
Start by mapping human-language policy to concrete checks. Keep it tight—8–12 controls that actually reduce risk.
- Secrets management:
pre-commit
withdetect-secrets
to stop API keys before they hit Git.- CI fails if secrets found in diff; require remediation or redact + rotate.
- Dependency risk (SCA):
- Use
npm audit
/yarn audit
,pip-audit
, ormvn versions
+OWASP Dependency-Check
. - Enforce org-wide blocklist (e.g.,
left-pad
-style abandoned libs) viaRenovate
rules.
- Use
- SAST rules:
semgrep
fast rules in the IDE and pre-commit for taint sinks, unsafe deserialization, and SSRF.- Level up to deep SAST in CI nightly to keep pipelines fast.
- Infrastructure-as-Code:
- Terraform:
Checkov
ortfsec
to catch public S3 buckets, open SGs, and unencrypted EBS. - Kubernetes:
kubeconform
+kubesec
for baseline;Kyverno
orGatekeeper
at admission.
- Terraform:
- Container images:
Trivy
orGrype
in CI; fail on critical CVEs without fixes, warn otherwise with SLA.
- Code review and ownership:
CODEOWNERS
for security-sensitive dirs; enforce 2 reviewers for auth and crypto.
- Logging and PII:
- CI/IDE regex +
pii-detector
rules to block plaintext PII in logs; force structured logging.
- CI/IDE regex +
- Data egress and DLP:
- Stop uploads of prod data to public buckets with organization policies and OPA checks.
The policy lives where developers live: the PR view, not a wiki.
Wire it into the workflow: IDE → pre-commit → CI → runtime
Make the happy path fast and the unsafe path impossible.
- IDE extensions
Semgrep
,ESLint
,Bandit
,Hadolint
. Quick feedback < 500ms.
- Pre-commit hooks
pre-commit
config withdetect-secrets
,semgrep --config p/owasp-top-ten
,black
/eslint
.
- CI gates (fast path)
- Parallel jobs under a 5–7 min budget:
Trivy
image scan,Checkov
IaC,Semgrep
focused rules. - Fail only on: new hardcoded secrets, critical vulns with fixes, critical IaC misconfigs.
- Parallel jobs under a 5–7 min budget:
- Nightly/weekly jobs (deep path)
- Full SAST/DAST, license audits, and SBOM diffs. Open tickets, don’t block builds.
- Registry and admission
- Push to an internal registry (Artifactory/Nexus/GHCR). Block deploys lacking signed attestations.
- Cluster enforces
Kyverno
/Gatekeeper
policies: no:latest
, runAsNonRoot, memory/CPU limits.
The developer experience rule: fast feedback locally, lightweight blocking in CI, hard stops at runtime for anything that slipped through.
Prove it: automated evidence, not screenshots
Auditors don’t want screenshots; they want repeatable proofs. Treat evidence as artifacts.
- SBOMs: Generate with
syft
in CI. Store alongside images. Track diffs across releases. - Attestations: Use
cosign
+in-toto
to sign build provenance (builder, commit, timestamp), SCA report, and policy evaluation. Adopt SLSA levels as your maturity target. - Policy-as-code: Write
Rego
forConftest
/Gatekeeper
to encode rules with rationale and exceptions. - Evidence store: Artifact repository bucket or
rekor
/transparency log. Link evidence to the release tag. - Auditable pipeline: PR → CI run → attestations → deployment stamp. One link per release with proofs.
Example Rego to block public S3 buckets:
package terraform.s3
violation["S3 bucket must not be public"] {
resource := input.resource.aws_s3_bucket[_]
resource.acl == "public-read"
}
And a minimal GitHub Actions step:
- name: IaC Policy Check
run: |
terraform plan -out tf.plan
terraform show -json tf.plan > tf.json
conftest test tf.json --policy policy/terraform
For attestations:
- name: Generate SBOM and Sign
run: |
syft dir:. -o spdx-json > sbom.json
cosign attest --predicate sbom.json --type spdx \
--key $COSIGN_KEY $IMAGE_REF
Keep regulated data safe without killing velocity
You can ship fast and still respect PCI DSS, HIPAA, SOC 2, GDPR. The trick is data discipline and separation.
- Data classification at the code level:
- Tag models/DTOs with
@pii(email)
/@phi
annotations; lint on unsafe sinks. - Block logging of tagged fields via custom
eslint
/semgrep
rules.
- Tag models/DTOs with
- No prod data in dev:
- Synthetic datasets with
Gretel
/Tonic.ai
/Synth
. Seal this with a policy check in CI that rejects imports of live dumps.
- Synthetic datasets with
- Access via brokers, not creds:
- Use short-lived tokens (
Vault
dynamic DB creds) and rotate automatically.
- Use short-lived tokens (
- Crypto defaults:
AWS KMS
/GCP KMS
+Vault Transit
for encryption; enforce TLS and at-rest by policy.
- DLP in CI and logs:
- Scan build logs and artifacts for PII patterns. Fail builds that leak customer data.
- Runtime guards:
- Service mesh (
Istio
) to enforce mTLS and policy; network policies default-deny. Feature flags (LaunchDarkly
) to decouple risky rollouts.
- Service mesh (
Balance comes from a two-lane model: fast lane for low-risk changes with automated proofs; slow lane with extra checks for code touching regulated data. Developers pick the lane in the PR template and policy validates it.
Tooling that actually works together
I’ve seen teams drown in scanners. Pick a thin, composable stack and standardize.
- Local:
pre-commit
,detect-secrets
,semgrep
,eslint
,bandit
. - CI:
Trivy
(images),Checkov
/tfsec
(IaC),Semgrep
(app),Syft
(SBOM),Cosign
(signing). - Control plane:
OPA
+Conftest
for CI;Kyverno
/Gatekeeper
for clusters. - Dependencies:
Renovate
bot with security priority lanes and auto-merge for patch-level updates. - Artifact + evidence: GHCR/Nexus/Artifactory;
rekor
or signed attestations stored next to images. - Dashboards:
DefectDojo
or a lightweight Data Studio/Looker dashboard for MTTR, exceptions, build SLA.
Keep versions pinned and reproducible (containerized tools). Bake these into a reusable CI template for GitHub Actions or GitLab CI so every repo gets the same baseline in one PR.
Make it stick: ownership, metrics, and sane exceptions
Security programs fail on process, not tools. Set clear ownership and feedback loops.
- RACI: App teams own fixing; platform owns the guardrails; security writes policies as code and reviews exceptions.
- Metrics that matter:
- Pipeline P50 and P95 duration with a hard budget (e.g., 7 min P95 for fast path).
- Vulnerability MTTR by severity; SLOs tied to breach risk, not vanity counts.
- Exception TTLs (e.g., 14 days for critical CVEs) and auto-expiry with reminders.
- Change failure rate (DORA) to ensure security didn’t tank reliability.
- Exception workflow:
- PR label
security-exception
requires risk rationale, compensating controls, and expiry date. - Auto-generated ticket with evidence links; Slack bot pings owners 48 hours before expiry.
- PR label
A little ceremony, a lot of automation, and no surprises during audits.
A minimal reference you can copy this week
Drop-in bits for a pilot repo:
CODEOWNERS
# Sensitive areas require security review app/auth/ @security-team @backend-leads infra/ @platform-team
.pre-commit-config.yaml
repos: - repo: https://github.com/Yelp/detect-secrets rev: v1.4.0 hooks: - id: detect-secrets - repo: https://github.com/returntocorp/semgrep rev: v1.80.0 hooks: - id: semgrep args: ["--config", "p/owasp-top-ten", "--error"]
GitHub Actions (excerpt)
name: secure-ci on: [pull_request] jobs: fast-checks: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: pip install checkov trivy-cli conftest syft cosign semgrep - run: semgrep ci --config p/owasp-top-ten - run: checkov -d infra/ - run: trivy fs --exit-code 1 --severity CRITICAL,HIGH . - run: syft dir:. -o spdx-json > sbom.json - run: cosign attest --predicate sbom.json --type spdx --key $COSIGN_KEY $IMAGE
Pilot it in one service that ships weekly. Measure the pain for two sprints, tune thresholds, then templatize across repos.
Key takeaways
- Turn policy statements into executable checks in the IDE, pre-commit, CI, and runtime.
- Automate proofs: SBOMs, vulnerability scans, and signed attestations stored with artifacts.
- Protect regulated data with classification, synthetic data, and strict secrets management.
- Measure friction and risk together: pipeline SLA, MTTR on vulns, exception TTLs.
- Start minimal: one repo, a small ruleset, and a visible exceptions process—iterate weekly.
Implementation checklist
- Define 8–12 policy controls that actually matter (secrets, dependencies, IaC, images, PII).
- Add developer-local checks: `pre-commit` with `detect-secrets` + `semgrep` quick rules.
- Enforce CI gates with `Conftest`, `Trivy`, `Checkov`, and dependency scanning.
- Generate SBOM (`syft`) and sign build artifacts + attestations (`cosign`, `in-toto`).
- Block risky deploys with cluster admission policies (`Kyverno`/`Gatekeeper`).
- Centralize evidence in artifact storage; auto-link to tickets and PRs.
- Set metrics: build time budget, vuln MTTR, exception TTL, change failure rate.
- Pilot in one service, document learnings, then templatize across repos.
Questions we hear from teams
- How do we keep build times from exploding?
- Keep fast-path checks under a 5–7 minute P95 budget by focusing on high-signal rules (secrets, critical CVEs with fixes, critical IaC misconfigs). Push heavy scans (deep SAST/DAST, full license audits) to nightly jobs that create tickets. Track pipeline time as an SLO and enforce it.
- What about legacy monoliths with no tests and shared prod data?
- Start with read-only SBOM and image scanning to understand risk. Add secrets scanning and a dependency bot (Renovate). Introduce a data access broker and synthetic datasets before touching pipelines. Carve out a golden path service as a pilot and backport what works.
- We’re under HIPAA/PCI—do we need specialized tools?
- You need disciplined evidence, not vendor logos. Use SBOMs (Syft), attestations (Cosign/in-toto), policy-as-code (OPA), and strict key/secret management (Vault/KMS). Map controls to your policy matrix and export audit bundles per release.
- How do we handle false positives without killing morale?
- Triage findings by severity and novelty (new vs existing). Allow PR-scoped suppressions with justification and TTL. Tune rules weekly, measure accepted suppressions, and remove noisy checks. Put security engineers on monthly office hours with teams to fix root causes.
- Where do we store proofs for auditors?
- Store signed attestations, SBOMs, scan reports, and policy evaluation results in your artifact repository alongside images. Link them to releases via Git tags and keep a simple dashboard that exports a zip with an audit bundle on demand.
Ready to modernize your codebase?
Let GitPlumbers help you transform AI-generated chaos into clean, scalable applications.