Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
a80d7de
Add Debian 13 product skeleton based on Debian 12
israel-villar Mar 29, 2026
e4fa427
Add Debian 13 CIS policy and product skeleton
israel-villar Mar 29, 2026
1b56513
Align Debian 13 AppArmor controls with CIS benchmark
israel-villar Mar 29, 2026
d42191b
Align Debian 13 CIS warning banner controls with benchmark
israel-villar Mar 30, 2026
d69bfca
Align Debian 13 CIS GDM controls with benchmark
israel-villar Mar 30, 2026
abbda50
Align section 2.4 with CIS Debian 13 (cron access, cron.yearly, title…
israel-villar Mar 30, 2026
9bf74d8
CIS Debian 13: fix section 2.4
israel-villar Mar 30, 2026
87ea223
Align section 3.3 with CIS Debian 13
israel-villar Mar 31, 2026
d8d3afb
Align section 4 with CIS Debian 13
israel-villar Mar 31, 2026
52b0b1f
Align section 5 with CIS Debian 13
israel-villar Mar 31, 2026
b1a12d3
Add CIS Debian 13 6.x & 7.x profile mappings
israel-villar Apr 5, 2026
4a42a02
Refine CIS Debian 13 profile mappings
israel-villar Apr 26, 2026
d517160
Fix CIS Debian 13 control mappings and consistency
israel-villar Apr 26, 2026
50505cb
Fix CIS Debian 13 section 1.x control statuses and levels
israel-villar May 3, 2026
0996e5c
Fix CIS Debian 13 section 2.x and 3.x controls
israel-villar May 3, 2026
aa59a04
Add CIS Debian 13 APT repository controls
israel-villar May 7, 2026
be0090c
Fix CIS Debian 13 product metadata and profile versions
israel-villar May 15, 2026
4ed1bcc
Disable irrelevant CI jobs in fork
israel-villar May 15, 2026
2e82a6e
Fix sshd_enable_warning_banner_net crash on Debian products
israel-villar May 23, 2026
9f69bac
Add CIS Debian 13 Level 1 Server profile adapted for ULPGC
israel-villar May 23, 2026
b5934be
Add sysctl var and CIS Debian 12 ULPGC profile
israel-villar May 23, 2026
1a8f09a
Fix AppArmor SCE checks and enable Debian support
israel-villar May 24, 2026
596f386
Remove redundant debian13 from SCE platform list
israel-villar May 24, 2026
e17518b
Fix grub2_uefi_password OVAL check for Debian products
israel-villar May 26, 2026
401ac5a
Add kea service disable rules for CIS Debian 13 control 2.1.3
israel-villar May 26, 2026
c81c9b0
Add debian13 package name override for bind9 rules
israel-villar May 26, 2026
cc524ba
Fix package and service names for Debian 13 in CIS 2.1 controls
israel-villar May 26, 2026
56f6a66
Add debian13 package name override for rsh rule
israel-villar May 26, 2026
9548f6f
Add debian13 service name override for chronyd_disabled rule
israel-villar May 26, 2026
1ea773c
Add debian13 package name override for gdm rule
israel-villar May 26, 2026
4efd733
Extend guard_var template to Debian for timesyncd/chronyd disabled rules
israel-villar May 26, 2026
cd1240b
Add fallback to remove nullok directly from PAM common-* files
israel-villar May 26, 2026
623eeea
Switch ULPGC profile to chrony and fix Debian chrony rules
israel-villar May 26, 2026
6074f81
Fix chrony/timesyncd rules for Debian and update ULPGC profile
israel-villar May 28, 2026
18c9fc1
Add ulpgc NTP option and fix profile variable syntax
israel-villar May 28, 2026
c03fad8
Add syslog-ng rules and switch ULPGC profile from rsyslog to syslog-ng
israel-villar May 28, 2026
eb2b922
Enable sysctl drop-in file remediation for Debian 13
israel-villar May 28, 2026
dd4f049
Add rule to ensure /etc/sysctl.d/99-sysctl.conf symlink exists on Deb…
israel-villar May 28, 2026
9fee258
Fix syslogng_filecreatemode OVAL: replace arithmetic with direct rege…
israel-villar May 28, 2026
92d9973
Add Debian 13 UFW default policy rules and remediations for CIS 4.1
israel-villar May 29, 2026
48695a0
Review and fix Debian 13 CIS section 5.3 PAM controls
israel-villar Jun 3, 2026
c7d473d
Add mlkem768x25519-sha256 to Debian 13 SSH KEX algorithms
israel-villar Jun 3, 2026
075685f
Replace SCE checks with OVAL for AppArmor and UFW rules on Debian 13
israel-villar Jun 3, 2026
44afdbf
Allow SHA512 or YESCRYPT for password hashing in CIS Debian 13 profile
israel-villar Jun 3, 2026
8c5e22f
Fix sysctl_conf_symlink OVAL: use at_least_one_exists to get fail not…
israel-villar Jun 3, 2026
143b6fe
Write sysctl settings to /etc/sysctl.conf on Debian 13
israel-villar Jun 3, 2026
0d01474
Fix sysctl_conf_symlink OVAL: use unix:file_test instead of symlink_test
israel-villar Jun 3, 2026
3c351e1
Fix sysctl_conf_symlink OVAL: remove invalid follow_symlinks behavior
israel-villar Jun 3, 2026
c5f6a58
Add bash remediation for sshd_limit_user_access via AllowGroups variable
israel-villar Jun 3, 2026
88706a5
Add sshd_set_allow_groups rule for CIS 5.1.4 remediation in ULPGC pro…
israel-villar Jun 3, 2026
2afa1e6
Add sysctl_apply_after_network rule for CIS 3.3.1.16 and 3.3.1.17 on …
israel-villar Jun 4, 2026
e2890c6
Fix sysctl_apply_after_network: use network-online.target instead of …
israel-villar Jun 4, 2026
c73f176
Remove leftover bash/shared.sh from sshd_limit_user_access
israel-villar Jun 4, 2026
14a9228
Add upstream note to AppArmor 1.3.1.3 control
israel-villar Jun 4, 2026
0def094
Fix product.yml: add components_root, remove duplicate reference_uris
israel-villar Jun 4, 2026
571241f
Remove sysctl_apply_after_network rule: causes systemd boot cycle
israel-villar Jun 4, 2026
afe93ce
Add sysctl_reapply_after_network rule for Debian 13
israel-villar Jun 4, 2026
2b85cda
Map Debian 13 CIS rules to component files
israel-villar Jun 4, 2026
1d47c1d
Fix accounts_password bash template: skip pam-auth-update on Debian 13
israel-villar Jun 4, 2026
fb09361
Fix accounts_password_pam_pwquality_enabled bash: skip pam-auth-updat…
israel-villar Jun 5, 2026
9a4d724
Fix log file permission rules for Debian: align with CIS Debian 13 6.…
israel-villar Jun 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/gate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ concurrency:
jobs:
validate-sle:
name: Build, Test on SLE Latest (Container)
if: github.repository == 'ComplianceAsCode/content'
runs-on: ubuntu-latest
container:
image: registry.suse.com/bci/bci-base:latest
Expand Down Expand Up @@ -42,6 +43,7 @@ jobs:

validate-suse:
name: Build, Test on OpenSUSE Leap 15 (Container)
if: github.repository == 'ComplianceAsCode/content'
runs-on: ubuntu-latest
container:
image: opensuse/leap:15
Expand Down Expand Up @@ -85,6 +87,7 @@ jobs:

validate-ubuntu-22-04:
name: Build, Test on Ubuntu 22.04
if: github.repository == 'ComplianceAsCode/content'
runs-on: ubuntu-22.04
steps:
- name: Install Deps
Expand All @@ -104,6 +107,7 @@ jobs:

validate-ubuntu-24-04:
name: Build, Test on Ubuntu 24.04
if: github.repository == 'ComplianceAsCode/content'
runs-on: ubuntu-24.04
steps:
- name: Install Deps
Expand All @@ -123,6 +127,7 @@ jobs:

validate-fedora-rawhide:
name: Build, Test on Fedora Rawhide (Container)
if: github.repository == 'ComplianceAsCode/content'
runs-on: ubuntu-latest
container:
image: registry.fedoraproject.org/fedora:rawhide
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/gate_fedora.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ concurrency:
jobs:
validate-fedora:
name: Build, Test on Fedora Latest (Container)
if: github.repository == 'ComplianceAsCode/content'
runs-on: ubuntu-latest
container:
image: fedora:latest
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/gate_thin_ds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ concurrency:
jobs:
build-and-test-thin-ds:
name: Build, Test on Fedora Latest (Container)
if: github.repository == 'ComplianceAsCode/content'
runs-on: ubuntu-latest
container:
image: fedora:latest
Expand Down
247 changes: 247 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

This repository produces SCAP data streams, Ansible playbooks, Bash scripts, and other artifacts for compliance scanning and remediation. Each supported OS or platform is a **product** (subdirectory under `products/`). The core Python library that drives the build system lives in `ssg/`.

## Build Commands

```bash
# Build a single product (full build including guides and tables)
./build_product rhel9

# Build data stream only (faster — skips guides and tables)
./build_product rhel9 --datastream-only

# Build targeting a single rule (fastest — for development)
./build_product rhel9 --datastream-only --rule-id accounts_password_minlen_login_defs

# Build output: build/ssg-<product>-ds.xml
```

## Linting and Testing

```bash
# Lint Python code
ruff check ssg utils tests build-scripts

# Lint YAML files
yamllint -c .yamllint <file>

# Auto-fix YAML lint issues
yamlfix -c yamlfix.toml <file>

# Run Python unit tests
python -m pytest tests/unit/ssg-module/

# Run utils that import ssg/ — must set PYTHONPATH first
PYTHONPATH=. python utils/controleval.py --help
PYTHONPATH=. python utils/find_duplicates.py --help
```

Python style: PEP 8 with a 99-character line limit. YAML style: 4-space indentation for new files (some older files use 2-space), `.yml` extension, one blank line between sections.

## Repository Structure

```
applications/openshift/ # OCP4/Kubernetes rules, organized by component (api-server/, kubelet/, etcd/, …)
linux_os/guide/ # Linux rules organized by area (system/, services/, auditing/, …)
controls/ # Compliance framework mappings (CIS, STIG, SRG, NIST, …)
products/ # Product definitions, profiles, and product-specific controls
shared/templates/ # ~40 reusable check/remediation templates
shared/macros/ # Jinja2 macro files for OVAL, Ansible, Bash generation
components/ # Component definitions mapping rules to packages (e.g., audit.yml)
ssg/ # Python library used by build-scripts/ and utils/
build-scripts/ # CMake-invoked scripts that assemble the build artifacts
utils/ # Developer utilities (controleval, find_duplicates, compare_ds, …)
```

## Discovering Rule Directories

- **OCP4/Kubernetes rules**: `applications/openshift/<component>/`, where the rule ID prefix matches the component name with hyphens → underscores (e.g., `api-server/` → `api_server_` prefix).
- **Linux rules**: `linux_os/guide/<area>/`, e.g., `system/accounts/`, `services/ssh/`, `auditing/`.
- Each rule lives in its own directory; the **directory name is the rule ID**. It contains `rule.yml` and optionally `tests/`.
- Each category directory contains a `group.yml` describing the group. Rules must belong to a group that covers the same software or service.

## Rule Format (`rule.yml`)

Sections **must appear in this order** when present:

```yaml
documentation_complete: true # Must be true to be built

title: 'Title Case Short Title' # One line; must match directory name

description: |- # HTML-Like: supports <b>, <pre>, <code>, <tt>, <ul>, <li>
rationale: |-
severity: medium # low | medium | high | unknown

identifiers: # Keys alphabetical order
cce@rhel9: CCE-XXXXX-X

references: # Keys alphabetical order
cis@rhel9: 1.2.3
nist: CM-6,CM-6(1)
stigid@rhel9: RHEL-09-XXXXXX

platform: machine # Use platform (not platforms) for new rules

ocil_clause: 'the value is not set'
ocil: |- # Manual check instructions (HTML-Like)

fixtext: |- # STIG fix instructions (HTML-Like)
checktext: |- # STIG check instructions (HTML-Like)
srg_requirement: '...'

warnings:
- general: |-

conflicts:
- some_rule_id
requires:
- other_rule_id

template:
name: <template_name>
vars: ...
```

One rule = one configuration change. Create a variable (`.var` file) when a setting can take multiple valid values.

## Available Templates (`shared/templates/`)

Key templates for Linux: `sysctl`, `file_permissions`, `file_owner`, `file_groupowner`, `shell_lineinfile`, `sshd_lineinfile`, `service_enabled`, `service_disabled`, `package_installed`, `package_removed`, `audit_rules_*`, `kernel_module_disabled`, `grub2_bootloader_argument`, `sudo_defaults_option`, `sebool`, `dconf_ini_file`.

Key templates for OCP4: `yamlfile_value`.

When a template fits, always use it rather than writing custom OVAL/Ansible/Bash checks.

### `yamlfile_value` (primary OCP4 template)

```yaml
template:
name: yamlfile_value
vars:
ocp_data: "true"
filepath: '/apis/...'
yamlpath: '.spec.field'
check_existence: "at_least_one_exists" # optional
entity_check: "at least one" # optional
values:
- value: 'expected'
type: "string" # string | int | boolean
operation: "pattern match" # equals | not equal | pattern match | greater than or equal | less than or equal
```

### Other common templates

```yaml
# sysctl
template:
name: sysctl
vars:
sysctlvar: net.ipv6.conf.all.accept_ra
datatype: int

# file_permissions
template:
name: file_permissions
vars:
filepath: /etc/ssh/sshd_config
filemode: '0600'

# shell_lineinfile
template:
name: shell_lineinfile
vars:
path: /etc/login.defs
parameter: PASS_MIN_LEN
value: '15'

# package_installed / package_removed
template:
name: package_removed
vars:
pkgname: avahi
pkgname@ubuntu2204: avahi-daemon # product-scoped override
```

## Common Jinja2 Macros

```
{{{ full_name }}} → product full name
{{{ xccdf_value("var_name") }}} → XCCDF variable reference
{{{ describe_sysctl_option_value(sysctl="key", value="val") }}}
{{{ complete_ocil_entry_sysctl_option_value(sysctl="key", value="val") }}}
{{{ fixtext_sysctl("key", "value") }}}
{{{ describe_service_disable(service="name") }}}
{{{ describe_service_enable(service="name") }}}
{{{ describe_file_permissions(file="/path", perms="0700") }}}
{{{ fixtext_directory_permissions(file="/path", mode="0600") }}}
{{{ complete_ocil_entry_package_installed("name") }}}
{{{ complete_ocil_entry_package_removed("name") }}}
{{{ fixtext_package_removed("name") }}}
{{{ weblink("https://...") }}}

# OCP4 specific
{{{ openshift_cluster_setting("/api/path") }}}
{{{ openshift_filtered_cluster_setting({'/api/path': jqfilter}) }}}
{{{ openshift_filtered_path('/api/path', jqfilter) }}}
```

## Control File Format

Two layouts exist:

**Single file** (`controls/<id>.yml` or `products/<product>/controls/<id>.yml`):
```yaml
policy: 'Policy Title'
title: 'Full Title'
id: policy_id
version: V1R1
reference_type: stigid # or cis, srg, etc.
product: rhel9
levels:
- id: high
controls:
- id: RHEL-09-211010
levels: [high]
title: '...'
rules: [installed_OS_is_vendor_supported]
status: automated # automated | manual | inherently met | does not meet | pending | not applicable
notes: '...'
```

**Split directory** (`controls/<id>.yml` + `controls/<id>/section-N.yml`): used for large frameworks like CIS. The top-level file holds `policy`, `title`, `id`, `levels`; section files hold nested `controls:` lists.

## Profile Format

`products/<product>/profiles/<name>.profile`:

```yaml
documentation_complete: true
title: 'Profile Title'
description: |-
platform: rhel9
metadata:
version: V2R7
SMEs: [github_username]
selections:
- stig_rhel9:all # all rules from a control file
- specific_rule_id
- '!excluded_rule_id'
- var_name=value
```

## Guidelines for Claude

1. **Always show proposals before making changes.** Present the full content of any new or modified file and wait for explicit approval.
2. **Follow existing patterns.** Before creating a rule, find 2-3 similar existing rules and match their style exactly.
3. **Check for duplicates.** Search before creating a new rule; use `PYTHONPATH=. python utils/find_duplicates.py`.
4. **Use the correct directory.** Find existing rules with the same prefix to locate the right subdirectory.
5. **Preserve formatting.** 4-space YAML indentation for new files; match surrounding file style.
6. **Don't invent references.** Only use CCE, CIS, STIG, SRG, NIST IDs the user provides or that exist in authoritative source documents.
7. **Use templates.** When a shared template covers the requirement, use it instead of writing custom checks.
8. **Rule sections order.** Follow the exact field order listed in the Rule Format section above.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ find_program(XMLLINT_EXECUTABLE NAMES xmllint REQUIRED)
find_program(XSLTPROC_EXECUTABLE NAMES xsltproc REQUIRED)
find_program(YAMLLINT_EXECUTABLE NAMES yamllint)

if(SSG_PRODUCT_FEDORA OR SSG_PRODUCT_RHEL8 OR SSG_PRODUCT_RHEL9 OR SSG_PRODUCT_RHEL10 OR SSG_PRODUCT_UBUNTU2004 OR SSG_PRODUCT_UBUNTU2204 OR SSG_PRODUCT_UBUNTU2404)
if(SSG_PRODUCT_FEDORA OR SSG_PRODUCT_RHEL8 OR SSG_PRODUCT_RHEL9 OR SSG_PRODUCT_RHEL10 OR SSG_PRODUCT_UBUNTU2004 OR SSG_PRODUCT_UBUNTU2204 OR SSG_PRODUCT_UBUNTU2404 OR SSG_PRODUCT_DEBIAN11 OR SSG_PRODUCT_DEBIAN12 OR SSG_PRODUCT_DEBIAN13)
set(SSG_SCE_ENABLED ON)
endif()

Expand Down
Empty file removed build/.gitkeep
Empty file.
1 change: 1 addition & 0 deletions components/apparmor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ rules:
- package_apparmor_installed
- package_apparmor-utils_installed
- package_pam_apparmor_installed
- sysctl_kernel_apparmor_restrict_unprivileged_unconfined
22 changes: 22 additions & 0 deletions components/apt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,26 @@ packages:
- apt
rules:
- apt_conf_disallow_unauthenticated
- apt_disable_weak_dependencies
- apt_sources_list_official
- directory_groupowner_apt_auth_conf_d
- directory_groupowner_apt_sources_list_d
- directory_groupowner_apt_trusted_gpg_d
- directory_groupowner_usr_share_keyrings
- directory_owner_apt_auth_conf_d
- directory_owner_apt_sources_list_d
- directory_owner_apt_trusted_gpg_d
- directory_owner_usr_share_keyrings
- directory_permissions_apt_auth_conf_d
- directory_permissions_apt_sources_list_d
- directory_permissions_apt_trusted_gpg_d
- directory_permissions_usr_share_keyrings
- file_groupowner_apt_auth_conf_d
- file_groupowner_apt_gpg_keys
- file_groupowner_apt_sources_list_d
- file_owner_apt_auth_conf_d
- file_owner_apt_gpg_keys
- file_owner_apt_sources_list_d
- file_permissions_apt_auth_conf_d
- file_permissions_apt_gpg_keys
- file_permissions_apt_sources_list_d
3 changes: 3 additions & 0 deletions components/kea.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ packages:
- kea
rules:
- package_kea_removed
- service_kea_dhcp4_server_disabled
- service_kea_dhcp6_server_disabled
- service_kea_dhcp_ddns_server_disabled
2 changes: 2 additions & 0 deletions components/kernel.yml
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ rules:
- sysctl_net_ipv6_conf_default_forwarding
- sysctl_net_ipv6_conf_default_max_addresses
- sysctl_net_ipv6_conf_default_router_solicitations
- sysctl_conf_symlink_etc_sysctl_d
- sysctl_reapply_after_network
- sysctl_user_max_user_namespaces
- sysctl_user_max_user_namespaces_no_remediation
- sysctl_vm_mmap_min_addr
Expand Down
1 change: 1 addition & 0 deletions components/openssh.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ rules:
- sshd_enable_x11_forwarding
- sshd_limit_user_access
- sshd_print_last_log
- sshd_set_allow_groups
- sshd_rekey_limit
- sshd_set_idle_timeout
- sshd_set_keepalive
Expand Down
2 changes: 2 additions & 0 deletions components/syslog-ng.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ packages:
rules:
- package_syslogng_installed
- service_syslogng_enabled
- syslogng_filecreatemode
- syslogng_nolisten
3 changes: 3 additions & 0 deletions components/ufw.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ rules:
- service_ufw_enabled
- set_ufw_default_rule
- set_ufw_loopback_traffic
- ufw_default_incoming_rule
- ufw_default_outgoing_rule
- ufw_disabled_routed
- ufw_only_required_services
- ufw_rate_limit
- ufw_rules_for_open_ports
Expand Down
Loading