Skip to main content

How to Scaffold Controls with the Policy Forge

Create a new security control with validated YAML and pass/fail test fixtures in one command.

Basic usage

make forge \
ID=CTL.IAM.MFA.002 \
NAME="Service Accounts Must Not Have Console Access" \
FIELD=properties.identity.console_access.enabled \
REMEDIATION="Remove console access from service accounts."

With kind discriminator

Most controls need a kind check to scope the predicate. Use --kind:

make forge \
ID=CTL.IAM.MFA.002 \
NAME="Service Accounts Must Not Have Console Access" \
DOMAIN=identity \
SEVERITY=medium \
SCOPE_TAGS=aws,iam \
ASSET_TYPE=aws_iam_user \
KIND=user \
FIELD=properties.identity.console_access.enabled \
OP=eq \
VALUE=true \
REMEDIATION="Remove console access from service accounts."

This generates identity.kind == "user" AND console_access.enabled == true.

With compliance references

make forge \
ID=CTL.S3.NEWCHECK.001 \
NAME="My Check" \
FIELD=properties.storage.access.public_read \
REMEDIATION="Fix it." \
COMPLIANCE="hipaa=164.312(a),cis_aws_v1.4.0=2.1.5"

After generation

# 1. Edit the generated YAML (improve description, remediation)
vim testdata/e2e/e2e-forge-*/controls/*.yaml

# 2. Generate golden expected output
make golden

# 3. Run all E2E tests
make e2e

# 4. Optionally move to built-in controls
cp testdata/e2e/e2e-forge-*-fail/controls/*.yaml controls/s3/mycheck/
make sync-controls && make build && make docs-controls && make readme

What gets validated

The forge runs the generated YAML through UnmarshalControlDefinition + Prepare() before writing. Invalid field paths, unsupported operators, or malformed predicates fail at generation time — not at evaluation time.

Available flags

FlagDefaultDescription
ID(required)Control ID (CTL.S3.NEW.001)
NAME(required)Control name
FIELD(required)Predicate field path
REMEDIATION(required)Remediation action text
DOMAINexposureDomain label
SEVERITYhighSeverity level
SCOPE_TAGSaws,s3Comma-separated scope tags
ASSET_TYPEaws_s3_bucketAsset type for fixtures
KIND(empty)Kind discriminator value
OPeqPredicate operator
VALUEtrueUnsafe value
COMPLIANCE(empty)Compliance refs (key=value,...)
OUTautoOutput base directory