Resolve Rule Variables
DevOps & Securityresolve-rule-variablesResolve Rule Variables is an Agent Skill for devops & security published in the ComplianceAsCode/content repository on GitHub: a SKILL.md instruction file an AI agent can load to do this task.
Resolve XCCDF variable selections for a set of rules. Looks up which variables each rule depends on, reads their .var files, and guides the author to select a value key for each variable. Returns a list of var_name=key selections ready to add to a control file's rules list.
How to use this skill
Bring this guide into your coding agent with a prompt tailored to the tool you use.
- Open your project in Codex.
- Copy and paste the prompt below.
- Review files and risks before approving any action.
Inspect the Agent Skill at https://github.com/ComplianceAsCode/content/blob/HEAD/.claude/skills/resolve-rule-variables/SKILL.md and all supporting files. Report provenance, permissions, scripts, dependencies, and security risks. Propose an exact installation into .agents/skills/resolve-rule-variables, but wait for my approval before writing files or running scripts.
Copying this prompt does not install or run the skill. Review third-party files before use.
Resolve Rule Variables
Given a product and a list of rule IDs that have just been selected for a control mapping, determine which XCCDF variables each rule depends on and interactively collect a value selection for each.
This skill is a sub-skill called by other skills (e.g., assess-nist-control) after rule selection. It can also be invoked directly when an author wants to inspect or change variable selections for rules already in a control file.
Arguments: $ARGUMENTS — format: <product> <rule_id> [<rule_id> ...] [--cis-vars <var=key> [...]]
Examples:
- Used as a sub-skill after rule selection in
assess-nist-controlPhase 3 /resolve-rule-variables rhel9 accounts_password_pam_dcredit accounts_password_pam_minlen/resolve-rule-variables rhel9 accounts_tmout --cis-vars var_accounts_tmout=600
The --cis-vars flag passes pre-existing variable selections from CIS mappings (or other sources) as
default suggestions. Each entry is var_name=key matching the .var file option key.
Phase 1: Load Variable Mapping
-
Parse arguments: Extract
productandrule_idsfrom$ARGUMENTS. Also extract any--cis-varsentries (format:var_name=key). -
Check the mapping file:
ls build/$PRODUCT/rule_variable_mapping.jsonIf the file does not exist:
Note:
build/<product>/rule_variable_mapping.jsonnot found. Build the product first to enable automatic variable detection:./build_product <product> -dProceeding without variable resolution. Add variable selections manually as
var_name=keyentries in the rules list if needed.Stop and return no selections if the file is missing.
-
Look up variables for each rule:
python3 -c " import json, sys, os, glob product = sys.argv[1] rule_ids = sys.argv[2:] with open(f'build/{product}/rule_variable_mapping.json') as f: rule_var_map = json.load(f) # Collect all variables across the selected rules, deduplicating seen_vars = {} for rule_id in rule_ids: for var_name in rule_var_map.get(rule_id, []): if var_name not in seen_vars: seen_vars[var_name] = [] seen_vars[var_name].append(rule_id) # For each variable, find the .var file and read options result = {} for var_name, used_by in seen_vars.items(): var_files = (glob.glob(f'linux_os/**/{var_name}.var', recursive=True) + glob.glob(f'shared/**/{var_name}.var', recursive=True) + glob.glob(f'applications/**/{var_name}.var', recursive=True)) if not var_files: result[var_name] = {'title': var_name, 'type': 'unknown', 'options': {}, 'used_by': used_by} continue import yaml with open(var_files[0]) as f: var_data = yaml.safe_load(f) result[var_name] = { 'title': var_data.get('title', var_name), 'type': var_data.get('type', 'string'), 'options': var_data.get('options', {}), 'used_by': used_by, } print(json.dumps(result, indent=2)) " "$PRODUCT" $RULE_IDSIf no variables are found for any of the rules, output an empty
{}and stop — no variable selections needed. Report: "No variable dependencies found for the selected rules."
Phase 2: Present Variable Selection
For each variable found in Phase 1 (process in alphabetical order):
-
Determine the default key: The default key is the key named
"default"in the options dict. If no key is named"default", look for the key whose value matches the majority/common case. Note the default value for display. -
Check for a CIS pre-selection: If
--cis-varsincluded{var_name}=<key>, pre-mark that option as the suggested default in the question description. -
Ask via
AskUserQuestion:-
Question:
"Select value for \{var_name}` — {title}"` -
Description on the question itself:
"Used by: {rule_id1}, {rule_id2}..." -
Options (limit to 4 total including the "Use default" option; if more keys exist, show the most semantically meaningful ones):
For each key in
options(up to 3 non-default keys):label: the key string (e.g.,1,15_min,never)description:"actual value: {value}"— add"(CIS suggested)"if this key matches the--cis-varsselection, or"(Default)"if this key is the default key
Always add a final option:
label:"Use default (omit variable)"description:"actual value: {default_value} — variable omitted from rules list, scanner uses the .var file default automatically"
Example for
var_password_pam_dcreditwithoptions: {"0": "0", 1: -1, 2: -2, default: -1}:label: "1" description: "actual value: -1 (CIS suggested)" label: "2" description: "actual value: -2" label: "0" description: "actual value: 0" label: "Use default (omit variable)" description: "actual value: -1 — variable omitted from rules list, scanner uses the .var file default automatically"→ If key
1chosen: written asvar_password_pam_dcredit=1→ If "Use default" chosen: variable NOT added to the rules list -
-
Record the selection:
- If a key was chosen: add
{var_name}={key}to the output selections list - If "Use default" was chosen: do not add anything for this variable
- If a key was chosen: add
Phase 3: Report Selections
After all variables are processed, display a summary:
### Variable Selections
| Variable | Key | Actual Value | Status |
|----------|-----|--------------|--------|
| var_password_pam_dcredit | 1 | -1 | selected |
| var_accounts_tmout | default | 900 | omitted (using .var default) |
Return the selections as a list of var_name=key entries. These are ready to be included in the control file's rules: list alongside the rule IDs.
Important Notes
- Key, not value: The
rules:list stores the key from the.varfile'soptionsdict — not the actual value the key resolves to.var_password_pam_dcredit=1means key1, which resolves to actual value-1. - Deduplicate shared variables: If two rules both use
var_accounts_tmout, ask for the value once and apply it once to the rules list. - Variable is mandatory if a rule uses it: Do not finalize a mapping without a variable selection when
rule_variable_mapping.jsonshows the rule requires one. A rule written without its variable produces an incomplete control mapping. - Planned migration: Variable selections are currently written inline in control files alongside rule IDs. The long-term plan is to extract all variable selections into a dedicated per-product file so authors can review and customize values in one place. Until that migration lands, continue writing
var_name=keyinline.
Error Handling
rule_variable_mapping.jsonmissing: Stop and report — build the product first..varfile not found for a variable: Ask the author to enter the key manually viaAskUserQuestionwith an "Other" option. Show the variable name and note the.varfile was not found.- Rule not in
rule_variable_mapping.json: The rule either has no XCCDF variables or was not present in the last build. Treat as having no variables — no warning. - Options dict is empty: Show the variable name as informational. Offer "Use default (omit variable)" as the only option.