WAF++ WAF++
Back to WAF++ Homepage

WAF++ PASS – CLI Reference

wafpass is the official CLI tool of the WAF++ Framework. It reads the machine-readable YAML controls and automatically checks Terraform configurations against the defined assertions.

Installation

pip install wafpass

Check version:

wafpass --version

Prerequisites

  • Python 3.10+

  • Terraform configuration as .tf files (HCL2)

  • WAF++ YAML controls (by default from the controls/ directory)


Commands

wafpass check

The only command in the current version. Checks Terraform files against WAF++ controls.

wafpass check <PATH> [OPTIONS]

Arguments

Argument Description

PATH

Path to a Terraform directory or a single .tf file. Must exist.

Options

Option Default Description

--controls-dir PATH

controls/

Path to the directory containing the WAF++ YAML control files.

--pillar NAME

(all)

Load only controls for a specific pillar. Allowed values: cost, sovereign, security, reliability, operations, architecture, governance.

--controls ID,ID,…​

(all)

Comma-separated list of control IDs to check. Example: WAF-COST-010,WAF-SOV-020

--severity LEVEL

(all)

Minimum severity level for evaluation. Allowed values: low, medium, high, critical. Checks below the threshold are skipped.

--verbose / -v

false

Output all results, including PASSes. Default: only FAILs and SKIPs are displayed.

--summary

false

Output only the summary table, no per-control details.

--fail-on MODE

fail

Condition for exit code 1 (error).
fail – on at least one FAIL
skip – on at least one FAIL or SKIP
any – same as skip

--output FORMAT

console

Output format. Currently only console supported. More formats planned.

--version / -V

Print version and exit.


Exit Codes

Code Meaning

0

All checks passed (according to --fail-on condition).

1

At least one FAIL (or SKIP with --fail-on skip/any).

2

Error loading controls or parsing Terraform files.


Output Format

Default (FAILs only)

 WAF++ PASS — Terraform Compliance Check
 Path: ./infrastructure/   Controls: 12

 WAF-SOV-010  Data Residency Policy            critical   FAIL
   ✗ aws_db_instance.main
     → Tag 'data-residency' not found in 'tags'.
   ✗ aws_elasticache_cluster.session
     → Tag 'data-class' not found in 'tags'.

 WAF-COST-010  Cost Allocation Tagging         high       FAIL
   ✗ aws_instance.web
     → Key 'cost-center' not found in 'tags'.
     → Key 'owner' not found in 'tags'.

 WAF-COST-040  Retention Lifecycle             medium     FAIL
   ✗ aws_cloudwatch_log_group.debug_logs
     → 'retention_in_days' is 0, must be >= 1.

────────────────────────────────────────────────────────────
 Summary
┌──────────────┬───────┬──────┬──────┬──────┐
│ Pillar       │ Total │ PASS │ FAIL │ SKIP │
├──────────────┼───────┼──────┼──────┼──────┤
│ cost         │     6 │    4 │    2 │    0 │
│ sovereign    │     6 │    4 │    1 │    1 │
├──────────────┼───────┼──────┼──────┼──────┤
│ TOTAL        │    12 │    8 │    3 │    1 │
└──────────────┴───────┴──────┴──────┴──────┘

Verbose (--verbose)

With --verbose, PASSes and remediation hints are additionally output:

 WAF-SOV-020  Region Pinning                  high       PASS
   ✓ provider.aws — 'region' is not empty.

 WAF-SOV-010  Data Residency Policy            critical   FAIL
   ✗ aws_db_instance.main
     → Tag 'data-residency' not found in 'tags'.
     Remediation: Add 'data-residency' and 'data-class' tags to all data resources.

SKIP Status

A check receives SKIP when:

  • No matching Terraform resources were found in scope

  • The check uses assertion operators that cannot be evaluated automatically (e.g. json_not_contains_pattern, region_in_arn_matches)

SKIP is not an error — it means the check should be verified manually.


Assertion Operators

The following table lists all operators that can be used in WAF++ YAML controls:

Automatically evaluable

Operator Description Example Use Case

attribute_exists

Attribute exists and is not null

enable_key_rotation present?

attribute_exists_or_fallback

Primary or fallback attribute exists

kms_key_id or kms_master_key_id

not_empty

Attribute exists and is not empty ("", [], {})

Region not empty?

equals

Attribute value == expected value

budget_type == "COST"

not_equals

Attribute value != expected value

policy_arn != AdministratorAccess

in

Attribute value is in the allowed list

sse_algorithm in ["aws:kms"]

not_in

Attribute value is not in the forbidden list

engine not_in ["mysql4"]

is_true

Attribute is true (also as string)

is_multi_region_trail = true

is_false

Attribute is false

publicly_accessible = false

greater_than_or_equal

Numeric value >= threshold

backup_retention_period >= 7

less_than_or_equal

Numeric value ⇐ threshold

retention_in_days ⇐ 365

matches

Attribute value matches regex pattern

name matches "^eu-"

not_matches

Attribute value does not match regex pattern

region not_matches "us-.*"

key_exists

Key exists in a map (e.g. tags)

tags.cost-center present?

block_exists

Terraform block of the specified type exists

aws_budgets_budget present?

has_associated_resource

Another resource references this block

VPC has flow log or endpoint?

not_contains

Attribute value does not contain the substring

String contains no unwanted patterns

Automatically skipped (SKIP)

These operators require runtime information or cross-resource analysis that goes beyond static HCL evaluation:

Operator Reason for SKIP

json_not_contains_pattern

Requires JSON parsing of the IAM policy string at runtime

region_in_arn_matches

ARN contains account ID and region, which are only known after terraform plan

in_variable

Variable values are only fully resolvable after terraform apply

has_associated_metric_filter

Requires cross-resource lookup between CloudWatch Log Group and Metric Filter

references_cloudtrail_bucket

Requires cross-resource resolution of S3 bucket references

not_equals_with_sibling

Requires knowledge of a sibling attribute

not_all_true_with

Multi-attribute condition

attribute_exists_on_all_providers

Multiple provider blocks must be evaluated together

attribute_exists_if

Conditional assertion depending on another attribute value


Examples

Full check of all controls

wafpass check ./infrastructure/

Sovereign controls only, critical severity

wafpass check ./infrastructure/ --pillar sovereign --severity critical

Check individual controls

wafpass check ./infrastructure/ --controls WAF-COST-010,WAF-COST-020,WAF-SOV-010

Output summary only

wafpass check ./infrastructure/ --summary

Custom controls directory

wafpass check ./infrastructure/ --controls-dir /path/to/custom-controls/

CI/CD: Only critical as blocking

wafpass check ./infrastructure/ --fail-on critical

CI/CD: Treat SKIPs as errors too

wafpass check ./infrastructure/ --fail-on skip

CI/CD Integration

GitHub Actions

name: WAF++ Compliance

on:
  push:
    branches: [main]
  pull_request:
    paths:
      - 'infrastructure/**'

jobs:
  wafpass:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - name: Install wafpass
        run: pip install wafpass

      - name: Copy WAF++ controls
        run: cp -r path/to/wafpp-controls/ controls/

      - name: Run WAF++ PASS
        run: |
          wafpass check infrastructure/ \
            --pillar cost,sovereign \
            --severity high \
            --fail-on critical \
            --verbose

GitLab CI

wafpass:
  stage: validate
  image: python:3.12-slim
  script:
    - pip install wafpass
    - wafpass check infrastructure/ --fail-on critical
  rules:
    - changes:
        - infrastructure/**/*.tf

Pre-commit Hook

#!/bin/bash
# .git/hooks/pre-commit

wafpass check ./infrastructure/ --fail-on critical --severity critical,high
if [ $? -ne 0 ]; then
  echo "WAF++ PASS: Critical compliance findings. Commit aborted."
  exit 1
fi

Controls Directory

wafpass expects YAML files in the format WAF-*.yml in the controls directory. By default it looks in the controls/ subdirectory relative to the working directory.

Each YAML file corresponds to one control. The complete schema documentation is available at Control Schema Reference.


Further Reading