This document provides key information about the ComplianceAsCode/content project structure, conventions, and implementation details that are important for working with the codebase.
ComplianceAsCode uses custom Jinja2 delimiters with an extra { and } to avoid conflicts with other template systems:
| Purpose | Standard Jinja2 | ComplianceAsCode |
|---|---|---|
| Variable expansion | {{ variable }} |
{{{ variable }}} |
| Control structures | {% if condition %} |
{{% if condition %}} |
| Comments | {# comment #} |
{{# comment #}} |
Variable expansion:
description: '{{{ ocil_package("audit") }}}'
fixtext: '{{{ package_install("audit") }}}'
srg_requirement: '{{{ srg_requirement_package_installed("audit") }}}'Control structures:
{{% if product in ["rhel8", "rhel9"] %}}
platforms:
- multi_platform_rhel
{{% endif %}}Macro definitions:
{{% macro openshift_cluster_setting(endpoint, suppress) -%}}
This rule's check operates on the cluster configuration dump.
{{%- endmacro %}}Macros are defined in shared/macros/ directory:
01-general.jinja- General-purpose macros10-ansible.jinja- Ansible-specific macros10-bash.jinja- Bash remediation macros10-ocil.jinja- OCIL (manual check) macros10-oval.jinja- OVAL check macros
Use Jinja2 macros in:
- Rules (descriptions, checks, remediations)
- Build scripts (internal use)
Do NOT use Jinja2 macros in:
- Control files (except
srg_ctrandsrg_gpos) - Variable files
- Profile files
| Directory | Description |
|---|---|
linux_os |
Security content for Linux operating systems |
applications |
Security content for applications (OpenShift, OpenStack) |
shared |
Templates, Jinja macros, remediation functions |
products |
Per-product directories with product-specific info and profiles |
ssg |
Python module used by build scripts |
build-scripts |
Scripts used by the build system |
docs |
User and Developer documentation |
tests |
Test suite for content validation |
components |
Component files mapping OS components to rules |
Benchmarks are directories containing a benchmark.yml file:
- Linux OS Benchmark:
/linux_os/guide - Applications Benchmark:
/applications - Firefox Benchmark:
/products/firefox/guide
Products specify which benchmark they use via benchmark_root in their product.yml file.
Each rule is a directory with the rule ID as its name, containing:
rule.yml- Main rule definitionoval/- OVAL checks (optional)bash/- Bash remediation (optional)ansible/- Ansible remediation (optional)tests/- Test scenarios (optional)
documentation_complete: true
title: 'Rule Title'
description: |-
Multi-line description of what the rule checks.
Can contain Jinja2 macros: {{{ complete_ocil_entry_file_permissions(file="/etc/hosts", perms="-rw-r--r--") }}}
rationale: |-
Explanation of why this rule is important.
severity: medium # low, medium, high, or unknown
identifiers:
cce@rhel8: CCE-12345-6
cce@rhel9: CCE-67890-1
references:
nist: CM-6(a)
disa: CCI-000366
stigid@rhel8: RHEL-08-010010
platform: machine # or 'container', 'multi_platform_all', etc.
ocil_clause: 'the configuration does not match'
ocil: |-
To check, run the following command...
fixtext: |-
To fix this, run {{{ package_install("package-name") }}}documentation_complete: Must betruefor the rule to be includedseverity: Must below,medium,high, orunknownplatform: Defines where the rule applies (machine, container, etc.)identifiers: Product-specific identifiers using@notationreferences: Compliance framework references
Products are NOT directly specified in rule files. Instead, product applicability is determined by:
-
Identifiers and References: Using
@notationidentifiers: cce@rhel8: CCE-12345-6 cce@rhel9: CCE-67890-1 stigid@ol8: OL08-010010 references: stigid@rhel9: RHEL-09-255030
-
Profiles: Products include rules in their profiles
-
Platform Applicability: Using platform/CPE checks
To determine which products a rule applies to, check:
- Parse
identifiersfor keys with@(e.g.,cce@rhel8→ rhel8) - Parse
referencesfor keys with@(e.g.,stigid@ol8→ ol8) - Check which product profiles include the rule
products/rhel9/
├── product.yml # Product definition
├── profiles/ # Product-specific profiles
│ ├── cis.profile
│ ├── ospp.profile
│ └── ...
└── transforms/ # Product-specific XSLT transforms
product: rhel9
full_name: Red Hat Enterprise Linux 9
type: platform
benchmark_id: RHEL-9
benchmark_root: "../../linux_os/guide"
profiles_root: "./profiles"
pkg_manager: "dnf"
init_system: "systemd"- Compile: Resolve rules, profiles, groups to product-specific form
- Template: Generate checks and remediations from templates
- Combine: Merge OVAL checks into single document
- Link: Link OVAL checks to XCCDF rules
- Compose: Create SCAP data stream
compile_all.py- Resolves content to product-specific formbuild_templated_content.py- Generates templated contentcombine_ovals.py- Combines OVAL checksbuild_xccdf.py- Generates XCCDF, OVAL, OCIL documentscompose_ds.py- Creates SCAP data stream
Jinja2 macros are expanded at build time by the SSG build system. The custom delimiters {{{ }}} and {{% %}} are processed by Python scripts in build-scripts/ using the ssg module.
- Developer Documentation:
/docs/manual/developer/ - Architecture Decisions:
/docs/adr/ - Template Reference:
/docs/templates/template_reference.md - Style Guide:
/docs/manual/developer/04_style_guide.md
- YAML Parsing: Use
yaml.load(..., Loader=yaml.FullLoader)to handle Jinja2 templates in YAML files - Product Extraction: Parse identifiers/references with
@notation to determine applicable products - Template Awareness: Recognize that
{{{ }}}and{{% %}}are Jinja2 macros, not invalid YAML - Build-Time vs Run-Time: Macros are expanded at build time, not at scan time
- No Direct Products Field: Rules don't have a
products:field - infer from identifiers and profile inclusion
This reference is based on the ComplianceAsCode/content project structure as of January 2025. For the most up-to-date information, always refer to the official documentation in the content repository.