Skip to main content

Rule Structure

Learn the mSCP YAML format for writing custom rules.

Required fields, optional fields, and how they all fit together.

Basic Structure​

Here's what the Rule Builder generates when you create a new rule:

id: os_example_rule
title: Example Custom Rule
discussion: |
This setting _MUST_ be configured for security.
Explain why this rule matters and what risk it mitigates.

references:
nist:
cce:
macos_26: []
macos_15: []
disa:
disa_stig:
macos_26: []
macos_15: []

platforms:
macOS:
'26.0':
benchmarks:
- name: cis_lvl1
'15.0':
benchmarks:
- name: cis_lvl1
enforcement_info:
check:
shell: /usr/bin/defaults read com.example.app Setting
result:
string: 'expected_value'
fix:
shell: /usr/bin/defaults write com.example.app Setting -string 'expected_value'

Required Fields​

🔤id

Unique identifier. mSCP convention is lowercase letters and underscores. The Rule Builder replaces spaces with underscores, and the editor's import accepts letters, digits, dots, dashes, and underscores. MACE reads the ID from the file's content, not its name.

📝title

Human-readable name shown in the UI and documentation.

💬discussion

Explanation of why the rule exists and what it protects against. Use RFC 2119 keywords: MUST, SHOULD, MAY.

🔗references

Compliance framework references. The Rule Builder auto-generates nist.cce and disa.disa_stig based on selected versions.

💻platforms

Platform-specific enforcement info including check and fix commands.

Field Details​

id​

The unique identifier for your rule. The Rule Builder automatically prefixes the ID based on the Category you select:

id: os_chrome_autoupdate_enabled

Category prefixes:

  • os_ - Operating System rules
  • system_settings_ - System Settings rules
  • auth_ - Authentication rules
  • audit_ - Audit rules
  • pwpolicy_ - Password Policy rules
  • icloud_ - iCloud rules
  • settings_ - Settings rules

Requirements:

  • Lowercase letters and underscores by mSCP convention
  • Must be unique across all rules, or MACE treats the file as a modification of the existing rule with that ID
  • Name the file to match: os_chrome_autoupdate_enabled.yaml

title​

Human-readable name:

title: Ensure Chrome Auto-Update is Enabled

discussion​

Multi-line explanation using YAML's | syntax. Use RFC 2119 keywords (MUST, SHOULD, MAY) to indicate requirement levels:

discussion: |
Google Chrome _MUST_ automatically update to ensure
the latest security patches are applied.

Outdated browsers are a common attack vector.

platforms​

The platforms section defines which macOS versions to target and the enforcement commands:

platforms:
macOS:
'15.0':
benchmarks:
- name: cis_lvl1
enforcement_info:
check:
shell: /usr/bin/command_to_check
result:
string: 'expected_value'
fix:
shell: /usr/bin/command_to_fix

check​

The check section verifies compliance:

check:
shell: /usr/bin/defaults read com.apple.screensaver askForPassword
result:
string: '1'

Tips:

  • Use full paths (/usr/bin/defaults, not defaults)
  • Redirect stderr if needed (2>/dev/null)
  • Return a simple, comparable value

result​

The expected output from the check command. Supports multiple types:

📝String
result:
string: 'expected text'
🔢Integer
result:
integer: 1
✓Boolean
result:
boolean: true
🔢ODV (Variable)
result:
integer: $ODV

fix​

The command to remediate non-compliant settings:

fix:
shell: /usr/bin/defaults write com.apple.screensaver askForPassword -bool true

Tips:

  • Make fixes idempotent (safe to run multiple times)
  • Test thoroughly before deploying
  • Use full paths to binaries

Optional Fields​

Additional References​

Beyond what the Rule Builder generates, you can add more compliance framework mappings:

references:
nist:
cce:
macos_15:
- CCE-XXXXX-X
800-53r5: # Optional
- CM-7
- AC-6
disa:
cci: # Optional
- CCI-000381
srg: # Optional
- SRG-OS-000095-GPOS-00049
disa_stig:
macos_15:
- APPL-15-XXXXXX
cis: # Optional
benchmark:
macos_15:
- '2.5.1 (level 1)'
controls_v8:
- '4.1'

odv​

Organization Defined Values allow customization per baseline:

odv:
hint:
datatype: number
description: Maximum failed login attempts before lockout
validation:
min: 1
max: 10
recommended: 5
cis_lvl1: 5
cis_lvl2: 3
stig: 3

ODV datatypes: string, number, boolean

Use $ODV in check/fix scripts to reference the value:

check:
shell: /usr/bin/pwpolicy -getpolicy | grep maxFailedAttempts
result:
integer: $ODV

mobileconfig_info​

For rules enforceable via configuration profile:

mobileconfig_info:
- PayloadType: com.apple.screensaver
PayloadContent:
- askForPassword: true
askForPasswordDelay: 0

ddm_info​

For Declarative Device Management:

ddm_info:
declarationtype: com.apple.configuration.screensaver.settings
ddm_key: AskForPassword
ddm_value: true

benchmarks​

Specify which baselines and severity:

platforms:
macOS:
'15.0':
benchmarks:
- name: cis_lvl1
- name: disa_stig
severity: medium

Severity levels: low, medium, high. The Rule Builder adds severity: medium automatically to STIG and INDIGO benchmarks. iOS and visionOS versions also carry supervised: true or false.

tags​

Categorization tags for filtering and organization:

tags:
- cis_lvl1
- 800-53r5_moderate

Common tags: cis_lvl1, cis_lvl2, disa_stig, 800-53r5_low, 800-53r5_moderate, 800-53r5_high

File Naming​

Save your rule as {id}.yaml:

os_chrome_autoupdate_enabled.yaml

The Rule Builder proposes this name automatically. MACE reads the ID from inside the file, but the editor's Delete and Show in Finder actions look for custom/rules/<id>.yaml, so keep them matching.

Validation​

MACE does minimal validation when loading a custom rule:

✅YAML syntax is valid
✅id and title are present

A file that fails is skipped and the reason is written to the app log; there is no alert in the UI. Two silent cases to watch for: a platforms block that doesn't include the project's platform hides the rule entirely, and a rule that isn't tagged or benchmarked for the project's framework shows as Not Included until you check it.