소스 정보
- 저장소
- openshift/cac-content-fork
- 최근 소스 활동
- 2026년 3월 26일 15:13
- 감지된 SKILL.md 언어
- 영어
- 스타
- 6
- 포크
- 6
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/openshift/cac-content-fork --skill create-rule명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SKILL.md 표시 중
Run Automatus tests for a security rule
Interactive control-to-rule mapping session. Walk through unmapped requirements, suggest rules using cross-framework analysis, and write selections to control files.
Map rules to a single control file requirement using cross-framework analysis and rule search.
SOC 직업 분류 기준
| name | create-rule |
| description | Create a new security rule with all required components |
Create a new security rule for ComplianceAsCode. This skill handles both templated and non-templated rules.
Rule ID: $ARGUMENTS
This skill uses mcp__content-mcp__* tools when available (preferred — deterministic, structured results). When the MCP server is not configured, fall back to filesystem-based alternatives noted as Fallback in each step. See .claude/skills/shared/mcp_fallbacks.md for detailed fallback procedures. The skill must complete successfully either way.
Validate rule ID format:
sshd_max_auth_tries, accounts_password_minlenCheck if rule already exists:
Use mcp__content-mcp__search_rules with query=$ARGUMENTS to check if a rule with this ID already exists.
Fallback: Use Glob to search for **/$ARGUMENTS/rule.yml.
Determine rule location:
sshd_* goes under linux_os/guide/services/ssh/ssh_server/)Use AskUserQuestion to ask the user:
Question: "What type of rule do you want to create?"
Options:
If user chose templated rule:
List available templates using mcp__content-mcp__list_templates to get all available templates with their descriptions.
Fallback: Run ls shared/templates/ to list available template directories.
Present available templates from the list obtained in step 1 and help the user select the right one based on their use case.
Ask for template selection using AskUserQuestion
Get template parameter schema using mcp__content-mcp__get_template_schema with template_name=<selected_template> to get the full parameter schema, supported languages, and documentation.
Fallback: Read shared/templates/<template_name>/template.yml or template.py for parameter definitions. Check existing rules using this template for usage examples.
Collect template variables:
Collect the following information using AskUserQuestion or prompts:
Title: Short descriptive title (displayed in scan results)
Description: Detailed description using Jinja2 templating
{{{ sshd_config_file() }}}, {{{ describe_mount(...) }}}Rationale: Why this rule is important for security
Severity: One of low, medium, high, unknown. Default value would be medium.
CCE identifiers: Ask which RHEL products need CCEs (rhel8, rhel9, rhel10)
cce@rhel9: CCE-XXXXX-Xshared/references/cce-redhat-avail.txtrule.yml, remove it from cce-redhat-avail.txt to prevent reuse# Read first available CCE
head -1 shared/references/cce-redhat-avail.txt
# After using a CCE, remove it from the file
sed -i '1d' shared/references/cce-redhat-avail.txt
nist: NIST SP 800-53 controls (e.g., AC-6(2),CM-6(a))srg: DISA SRG IDs (e.g., SRG-OS-000480-GPOS-00227)stigid and cis references are filled in automatically by placing the rule into an appropriate control filePlatform (optional): Platform applicability
platform: machine (not for containers)platform: package[openssh-server]OCIL (optional): OCIL check description
{{{ complete_ocil_entry_sshd_option(...) }}}Use mcp__content-mcp__generate_rule_from_template with:
template_name: The selected template nameparameters: Template variables collected from the userrule_id: $ARGUMENTSproduct: The target productThis generates the rule directory and rule.yml with the template configuration automatically.
Fallback: Create the rule directory and rule.yml manually using Write tool. Include the template: key with name: and vars: based on the selected template.
Use mcp__content-mcp__generate_rule_boilerplate with:
rule_id: $ARGUMENTStitle: The rule titledescription: The rule descriptionseverity: The severity levelproduct: The target productrationale: The rationale (optional)location: The guide path (optional, e.g., linux_os/guide/services/ssh)Fallback: Create the directory structure and all files manually using Write tool, following the skeleton templates below.
This generates the rule directory structure with skeleton files:
<location>/$ARGUMENTS/
├── rule.yml
├── oval/
│ └── shared.xml
├── bash/
│ └── shared.sh
├── ansible/
│ └── shared.yml
└── tests/
├── correct.pass.sh
└── wrong.fail.sh
After MCP generates the boilerplate, customize the generated files:
oval/shared.xml:
<def-group>
<definition class="compliance" id="{{{ rule_id }}}" version="1">
{{{ oval_metadata("{DESCRIPTION}", rule_title=rule_title) }}}
<criteria>
<!-- Add OVAL criteria here -->
</criteria>
</definition>
<!-- Add OVAL tests, objects, and states here -->
</def-group>
Note: rule_id and rule_title are automatically populated during build from the rule.yml.
bash/shared.sh:
# platform = multi_platform_all
# reboot = false
# strategy = configure
# complexity = low
# disruption = low
# Remediation script for $ARGUMENTS
# TODO: Implement remediation
ansible/shared.yml:
# platform = multi_platform_all
# reboot = false
# strategy = configure
# complexity = low
# disruption = low
- name: "{TITLE}"
# TODO: Implement remediation
ansible.builtin.debug:
msg: "Remediation not yet implemented"
tests/correct.pass.sh:
#!/bin/bash
# packages = {REQUIRED_PACKAGES}
# Set up compliant state
# TODO: Configure system to be compliant
tests/wrong.fail.sh:
#!/bin/bash
# packages = {REQUIRED_PACKAGES}
# Set up non-compliant state
# TODO: Configure system to be non-compliant
Every rule must belong to a component. Components are defined in components/*.yml and map rules to their associated packages and groups.
Based on the rule's purpose and location, suggest likely components:
# List all available components
ls components/*.yml | sed 's|components/||;s|\.yml||' | sort
Finding the right component: Search existing component files for rules with a similar prefix to identify the likely component:
# Find which component contains rules with a similar prefix
grep -l '<rule_prefix>' components/*.yml
# Check if suggested component exists
cat components/<component_name>.yml
Use AskUserQuestion with options:
If user selects an existing component:
Read the component file:
cat components/<component_name>.yml
Add the rule ID to the rules: list in alphabetical order:
rules:
- existing_rule_1
- existing_rule_2
- $ARGUMENTS # Add new rule here
- existing_rule_3
If using a template, verify the template is listed in templates: section. If not, add it:
templates:
- existing_template
- {TEMPLATE_NAME} # Add if not present
If no suitable component exists:
Ask for component details:
my-service)Create the component file components/<component_name>.yml:
groups:
- <group_from_rule_hierarchy>
name: <component_name>
packages:
- <package_name>
rules:
- $ARGUMENTS
templates:
- {TEMPLATE_NAME} # If templated rule
Verify the new component:
python3 -c "import yaml; yaml.safe_load(open('components/<component_name>.yml'))"
groups: # Rule groups this component covers (from guide hierarchy)
- service_name
- service_name_server
name: component-name # Matches filename without .yml
packages: # Packages associated with this component
- package-name
- package-name-server
rules: # Rule IDs belonging to this component (alphabetical)
- rule_id_1
- rule_id_2
templates: # Templates used by rules in this component
- template_name
Most profiles in the project reference control files rather than listing rules directly. When adding a rule to a profile that uses a control file, add the rule to the control file instead.
Use mcp__content-mcp__list_profiles with product=<product> to list all available profiles for each target product.
Fallback: Run ls products/<product>/profiles/*.profile to list profiles.
Use AskUserQuestion to ask which profile(s) to add the rule to. Allow multiple selection.
For each selected profile, read it and check if it references a control file:
grep -E "^\s+-\s+\w+:all" products/<product>/profiles/<profile>.profile
Control file reference patterns:
cis_rhel9:all or cis_rhel9:all:l2_server → Control file: products/rhel9/controls/cis_rhel9.ymlstig_rhel9:all → Control file: products/rhel9/controls/stig_rhel9.ymlhipaa:all → Control file: controls/hipaa.yml (shared across products)How to find the control file:
cis_rhel9 from cis_rhel9:all:l2_server)products/<product>/controls/<control_id>.yml firstcontrols/<control_id>.ymlIf the profile references a control file:
Read the control file to understand its structure
Ask user for control placement:
5.2.15 for SSH settings)RHEL-09-123456)Determine the level(s) for the rule:
l1_server, l2_server, l1_workstation, l2_workstationhigh, medium, lowAdd a new control entry to the control file:
For CIS control files:
- id: 5.2.15
title: Ensure SSH MaxAuthTries is set to 4 or less (Automated)
levels:
- l1_server
- l1_workstation
status: automated
rules:
- $ARGUMENTS
For STIG control files:
- id: RHEL-09-123456
levels:
- medium
title: RHEL 9
If the profile lists rules directly (no control file reference):
selections: listProduct-specific (preferred for product-specific benchmarks):
products/rhel8/controls/*.ymlproducts/rhel9/controls/*.ymlproducts/rhel10/controls/*.ymlShared (for cross-product policies):
controls/*.yml| Profile | Control File |
|---|---|
cis.profile (rhel9) | products/rhel9/controls/cis_rhel9.yml |
stig.profile (rhel9) | products/rhel9/controls/stig_rhel9.yml |
hipaa.profile | controls/hipaa.yml |
pci-dss.profile | controls/pcidss_4.yml |
ospp.profile | controls/ospp.yml |
anssi_bp28_*.profile | controls/anssi.yml |
When adding to CIS or STIG control files, reference the corresponding security policy document to find the correct control ID:
security_policies/CIS_Red_Hat_Enterprise_Linux_9_Benchmark_v2.0.0.mdsecurity_policies/Red Hat Enterprise Linux 9 STIG V2R5 - STIG-A-View.mdIMPORTANT: Whenever a rule is added to a profile (whether directly or via control file), the profile stability test data must also be updated.
Profile stability test data is located in tests/data/profile_stability/<product>/<profile>.profile and contains a sorted list of rule IDs, one per line.
Check if stability test file exists:
ls tests/data/profile_stability/<product>/<profile>.profile
If the file exists, add the rule ID in alphabetical order:
# Read current file, add new rule, sort, and write back
(cat tests/data/profile_stability/<product>/<profile>.profile; echo "$ARGUMENTS") | sort -u > /tmp/profile_stability_tmp
mv /tmp/profile_stability_tmp tests/data/profile_stability/<product>/<profile>.profile
If the file doesn't exist, this may be a new profile or a product without stability tests. Check if the product directory exists:
ls tests/data/profile_stability/<product>/
Profile stability test file format:
rule_id_1
rule_id_2
rule_id_3
...
Rules are listed one per line, sorted alphabetically, with no duplicates.
Discover products with stability tests:
ls tests/data/profile_stability/
Verify created files:
ls -la <rule_directory>/
cat <rule_directory>/rule.yml
Validate rule YAML using mcp__content-mcp__validate_rule_yaml with the content of the generated rule.yml. This validates syntax, structure, and reference formats.
Fallback: Validate against the JSON schema:
python3 -c "
import json, yaml, sys
from jsonschema import validate, ValidationError
schema = json.load(open('shared/schemas/rule.json'))
data = yaml.safe_load(open(sys.argv[1]))
try:
validate(instance=data, schema=schema)
print('Valid')
except ValidationError as e:
print(f'Invalid: {e.message}')
" <path_to_rule.yml>
For control files, use mcp__content-mcp__validate_control_file with the control file path.
Fallback: Validate against the control schema:
python3 -c "
import json, yaml, sys
from jsonschema import validate, ValidationError
schema = json.load(open('shared/schemas/control.json'))
data = yaml.safe_load(open(sys.argv[1]))
try:
validate(instance=data, schema=schema)
print('Valid')
except ValidationError as e:
print(f'Invalid: {e.message}')
" <path_to_control.yml>
Verify CCE was removed from available list (if CCE was allocated):
grep "<allocated_cce>" shared/references/cce-redhat-avail.txt # should return nothing
Verify rule is in component:
grep "$ARGUMENTS" components/<component>.yml
Verify profile stability test data (if profile was modified):
grep "$ARGUMENTS" tests/data/profile_stability/<product>/<profile>.profile
Report to user:
ssg/jinja.py) avoid conflicts with YAML/XML curly braces:
{{{ expr }}} (triple braces), NOT {{ expr }}{{% stmt %}}, NOT {% stmt %}{{# comment #}}, NOT {# comment #}{{{ full_name }}}, {{{ describe_service_enable(service="auditd") }}}, {{% if product in ["rhel9"] %}}, {{% set var="value" %}}cce-redhat-avail.txttests/data/profile_stability/<product>/<profile>.profileInsert in the correct position (controls are typically ordered by ID)
stigid and cis references will be automatically populated from the control file/test-rule $ARGUMENTS to test"/test-rule $ARGUMENTS"/build-product <product> to build and /run-tests to validate"