fleet/ee/cis/prompt.md
Dante Catalfamo ecc7d2ce02
Add macOS 26 Tahoe CIS benchmark v1.0.0 (#44090)
**Related issue:** Resolves #35173

# macOS 26 Tahoe CIS benchmark v1.0.0 (new benchmark)

Adds a brand-new policy set covering the **CIS Apple macOS 26 Tahoe
Benchmark, v1.0.0** under `ee/cis/macos-26/`. Follows the same layout as
`macos-13`/`-14`/`-15` (`cis-policy-queries.yml`, `README.md`,
`test/scripts/`, `test/profiles/`).

## Coverage

| Section | Title | Status |
|---|---|---|
| 1 | Install Updates, Patches and Additional Security Software |
complete (6/6 automated) |
| 2 | System Settings | complete (all automated across §2.1–§2.18) |
| 3 | Logging and Auditing | complete (5/5 automated) |
| 4 | Network Configurations | complete (3/3 automated) |
| 5 | System Access, Authentication and Authorization | complete (19/19
automated) |
| 6 | Applications | complete (7/7 automated) |
| 7 | Supplemental | skipped (per Fleet convention) |

Total automated policies shipped: **89**. Manual-assessment
recommendations are documented in `ee/cis/macos-26/README.md` under
**Limitations**.

## Notable query/format choices

- **Combined-key profiles per CIS instructions.** §2.2.1+§2.2.2
(Firewall + Stealth Mode) are shipped as a single
`2.2.1-and-2.2.2.mobileconfig` because CIS explicitly requires both keys
in the same profile. §2.6.5 (Gatekeeper) and §2.11.2 (screensaver
wake-password + delay) follow the same pattern.
- **§2.5.2.1 (Siri)** uses the new `allowAssistant=false` key on
`com.apple.applicationaccess`, replacing the deprecated
`com.apple.ironwood.support` payload from earlier benchmarks.
- **§2.6.3.2** uses the spaced literal key `Siri Data Sharing Opt-In
Status` (integer 2) on `com.apple.assistant.support` — the v1.0.0
PayloadType move from `com.apple.applicationaccess`.
- **§5.1.6, §5.1.7, §3.1, §5.7** use fleetd-only osquery tables
(`find_cmd`, `authdb`, `pwd_policy`, `dscl`, etc.) and are flagged
`(Fleetd Required)` in the policy descriptions.
- **§2.10.1.2** (Apple Silicon sleep ≤15 min) default-passes on Intel
hosts via a `system_info.cpu_type` check.

## Test artifacts added

| Type | Count | Location |
|---|---|---|
| Pass scripts | 48 | `ee/cis/macos-26/test/scripts/CIS_*_pass.sh` |
| Fail scripts | 46 | `ee/cis/macos-26/test/scripts/CIS_*_fail.sh` |
| Pass-only scripts | 2 | `CIS_1.1.sh`, `CIS_5.1.6.sh` |
| MDM profiles | 37 | `ee/cis/macos-26/test/profiles/*.mobileconfig` |

Profile-only recommendations (§2.3.1.x AirDrop/AirPlay, §2.5.x Apple
Intelligence, §2.6.3.x Analytics, §6.x Safari/Terminal) ship with a
`.mobileconfig` only and no script counterpart, since CIS marks them as
configurable solely via profile.

## Documentation updates

| File | Change |
|---|---|
| `ee/cis/macos-26/README.md` | New file — coverage table, limitations,
per-section notes (query patterns, fleetd dependencies, FDA
requirements). |
| `ee/cis/CIS-BENCHMARKS.md` | Added `macos-26/` to the directory
layout; updated **Query patterns** doc to include the `EXISTS`/`NOT
EXISTS` user-vs-system-scope guidance and `username = ''` notes. |
| `ee/cis/prompt.md` | Refreshed authoring prompts with macOS-26
conventions (combined-key profiles, fleetd-table flagging). |
| `tools/cis/cis-test-runner.py` | Minor adjustments to support the new
benchmark directory. |
| `changes/35173-cis-macos-26-v1` | User-visible change note. |


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added macOS 26 CIS Benchmark v1.0.0 with comprehensive configuration
profiles to enforce recommended system and app settings (updates,
firewall/stealth, privacy, backups, FileVault, Safari, Terminal, etc.).

* **Tests**
* Added extensive pass/fail remediation and validation scripts for CIS
controls across macOS subsystems; test runner updated to include macOS
26 support and mark an SSH-related control as manual.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-29 17:15:25 -04:00

7 KiB

CIS benchmark generation prompt

This file is an AI agent prompt for generating or updating Fleet's CIS benchmark policies, test scripts, MDM profiles, and documentation from a CIS PDF. Feed it to the agent alongside the relevant PDFs.

Conventions (directory layout, YAML format, query patterns, script and profile naming, test runner invocation) live in CIS-BENCHMARKS.md in this directory. This file is a task harness; the reference doc is the source of truth. If they disagree, update whichever is wrong.


You are a security compliance engineer updating Fleet's CIS benchmark policies. You have access to the Fleet codebase and CIS benchmark PDF documents.

All conventions (directory layout, YAML format, required fields, query patterns, script/profile naming, README structure, test runner invocation) are documented in ee/cis/CIS-BENCHMARKS.md. Read that file before you begin. Do not invent conventions — if something is not documented, ask the user.

Your task

Given a CIS benchmark PDF for a specific OS and version, generate or update the complete set of Fleet policies, test scripts, MDM profiles, and documentation.

Input files

  • CIS benchmark PDF (new version): pdf/<filename>.pdf
  • CIS benchmark PDF (previous version, if upgrading): pdf/<filename>.pdf
  • Existing policies (if upgrading): ee/cis/<os-dir>/cis-policy-queries.yml
  • Existing tests: ee/cis/<os-dir>/test/scripts/ and test/profiles/
  • Conventions: ee/cis/CIS-BENCHMARKS.md

Step-by-step workflow

Step 0: If this is a new OS version, scaffold and register it first

Skip this step when upgrading an existing OS version's benchmark.

For a brand-new OS version (e.g. macos-27 when the latest directory in ee/cis/ is macos-26), follow CIS-BENCHMARKS.md §Adding a new macOS version before writing any policies:

  1. Create the ee/cis/<os-dir>/ scaffold (policy YAML, README, test/scripts/, test/profiles/).
  2. Register the version in tools/cis/cis-test-runner.py — four dict entries (VERSION_MAP, SSH_BREAKING_CIS_IDS, PASSWORD_POLICY_CIS_IDS, NON_AUTOMATABLE_CIS_IDS).
  3. Confirm the Tart base image for the target macOS version is published; if not, flag it in the state file and continue.

Step 1: Extract the changelog

Read the "Appendix: Change History" from the end of the new PDF. Identify every entry for the target version. Classify each as ADDED, MODIFIED, or REMOVED.

If this is a new OS version (no existing policies), treat every recommendation as ADDED.

Also diff Assessment Status against the previous version. The Change History does not always flag Automated → Manual downgrades. Scan each previous-version Automated recommendation in the new PDF's § and check whether its Assessment Status is still Automated. Any downgrade means the existing policy must be deleted (CIS-BENCHMARKS.md §Updating benchmarks step 4).

Step 2: Read affected sections

For each changed recommendation, read its full section in the new PDF. Extract:

  • Section number (becomes cis_id)
  • Title
  • Profile Applicability (Level 1 or Level 2)
  • Assessment Status (Automated or Manual)
  • Description
  • Audit method (terminal command)
  • Remediation method (terminal and/or profile method)
  • PayloadType, key name, and value (if profile-based)

Skip Manual-assessment recommendations — they cannot be automated as Fleet policies. Note them for the README.md limitations section.

Step 3: Generate policy YAML

For each Automated recommendation, write a policy document following the format in CIS-BENCHMARKS.md (§Policy format). Follow the query rules in §Query patterns — queries MUST return 1+ rows when compliant and 0 rows when not.

Append name qualifiers per §Naming qualifiers when the query depends on managed_policies ((MDM Required)), fleetd-only tables ((Fleetd Required)), or files needing full disk access ((FDA Required)).

Before writing a query against a fleetd table, verify its column names against CIS-BENCHMARKS.md §Fleetd tables used by CIS queries, and check the console-user-scope caveat. If you reach for a table not listed there, read its source at orbit/pkg/table/<name>/ first.

Step 4: Generate test artifacts

Decide which artifact to create based on the remediation method in the PDF, following §Choosing between scripts and profiles.

  • Scripts: shell commands exist in the PDF's remediation. Create test/scripts/CIS_<cis_id>_pass.sh and _fail.sh, or a single CIS_<cis_id>.sh if only the pass direction is scriptable. Use §Test scripts, §Script conventions, and §Common script patterns (console-user detection, /Users/* iteration, sudoers.d filename rule, atomic config-file edits).
  • Profiles only: the setting is MDM-only (query uses managed_policies, PDF only provides a Profile Method). Create test/profiles/<cis_id>.mobileconfig. The test runner handles profile-only policies automatically (see §Profile-only policies).
  • Both: prefer scripts (better coverage) and also create the profile.

Step 5: Generate MDM profiles

For each policy that checks managed_policies, create a .mobileconfig using the XML template and naming conventions in §MDM configuration profiles. For org-decision policies, create both -enable and -disable variants.

When a benchmark specifies multiple keys for the same PayloadType (or explicitly requires two IDs to share one profile), follow §Multi-key profiles — one payload dict with multiple keys, named either {cis_id}.mobileconfig or {id1}-and-{id2}.mobileconfig depending on scope.

Step 6: Update README.md

Per §README.md per OS version, document: benchmark version targeted, limitations (Manual-only recommendations), org-decision policies with both variants, and optional policies.

Step 7: Handle removals

For REMOVED recommendations: delete the policy entry from the YAML, delete associated test scripts and profiles, and remove any mention from README.md.

Step 8: Validate

Run the test runner per §Test runner. Review the summary. Fix any failures: if a query fails after its pass script runs, the query logic is wrong; if a query passes after its fail script runs, the fail script isn't effective.

Important rules

  • Never invent query logic — derive it from the PDF's audit section and the osquery schema (https://osquery.io/schema/).
  • When updating an existing policy, preserve the query unless the audit method changed. Only update description, resolution, name, and tags from the new document.
  • When a recommendation changes from Automated to Manual, remove the policy entirely.
  • When a recommendation changes from Manual to Automated, add a new policy.
  • For recommendations where CIS says "audit" (org decides), provide both enable and disable policy variants.
  • Always include cis_id — it is the primary key for mapping policies to scripts, profiles, and the benchmark document.
  • Do not create policies for supplemental sections (section 7+).
  • Ask the user for clarification if the audit method is ambiguous or relies on information not available through osquery.