During the CMMC assessment, the Mac side of the environment needed more than a statement that controls were implemented. I needed to show how the macOS baseline connected to managed Macs, what Jamf was reporting, and how we could preserve enough evidence for the assessor without burying everyone in raw exports.

Jamf was central to that conversation because it connected several things that otherwise become hard to explain quickly: the macOS Security Compliance Project baseline, Jamf Compliance, scoped devices, smart groups, benchmark state, and live inventory. For the Mac fleet, Jamf gave me the management-plane view I wanted in front of the assessor. I could walk from the baseline to the managed devices and show how the environment was reporting instead of relying on a disconnected folder of screenshots.

That live view was important during the assessment, but I also needed evidence I could preserve after the conversation. A dashboard is useful while everyone is looking at it. An evidence package needs artifacts that can be opened later, compared against the baseline, and tied back to the assessment record. For Mac compliance, I wanted the Jamf view, the tailored baseline documentation, and a small summary artifact that showed the shape of the failed results without turning the first review into a device-by-device excavation.

Jamf As The Evidence System

The macOS Security Compliance Project gave me the baseline language and the control mapping. Jamf Compliance gave me a way to apply that baseline to the Mac fleet and see how scoped devices were reporting. That combination was the foundation for the Mac evidence story because it connected the written expectation to the managed endpoint population.

The tailored baseline PDF belongs in the evidence package because it explains what was configured and how the benchmark was shaped. Jamf belongs in the evidence conversation because it shows the current reporting state from the platform managing those Macs. Together, they let me talk through the Mac side of CMMC from the management plane rather than asking the assessor to infer everything from static files.

Jamf also provides a native reporting path for compliance benchmark evidence. Jamf documents a workflow using Advanced Computer Search: open Computers > Search Inventory, create a new Advanced Computer Search, use criteria tied to the compliance benchmark or related computer group, choose the fields for the report, and use the Reports tab to download or schedule it. Jamf: Build reports for Jamf Pro compliance benchmarks

I would keep that native Jamf report with the assessment evidence. It is the broad Jamf-generated artifact for the benchmark and device population, and it pairs naturally with the live dashboard review.

Why I Added A Summary Script

The reporting layer I still wanted was smaller and more focused. After showing the benchmark and the live Jamf view, I wanted a quick way to answer how many devices were reporting each failed compliance item. I did not need every inventory field to answer that. I needed a summary that could sit in the evidence package and give the assessor enough information to understand the fleet-level picture.

That is what JAMF Compliance Reports.py produces. The script is read-only, reads Jamf Pro computer inventory, extracts the failed-result Extension Attribute, and writes two CSV files:

compliance_failed_counts.csv
compliance_failed_by_device.csv

The counts file is the high-level artifact:

Item,Count

It shows each failed compliance item and how many devices are reporting it. That is the file I would start with when I want a concise evidence artifact. It gives the assessor a clear summary without handing over too much detail in the first pass.

The by-device file is the drill-down artifact:

ComputerName,Username,FailedItems

If the assessor wants to dig into a number from the summary, I can go to the by-device CSV, the native Jamf report, or the live Jamf dashboard. The summary gives enough context to start the review, and the other artifacts keep the path back to source data intact.

The script lives here: macOS-JAMF-Scripts: Scripts/Security/NIST.

The Failed-Result Extension Attribute

The script default is:

EA_DEFAULT_NAME = "Compliance - Failed Result List"

That generic Extension Attribute still exists in my local Jamf evidence. In the EA usage report I generated on June 17, 2026, Compliance - Failed Result List appears as an Extension Attribute.

For my active CMMC benchmark evidence, the more relevant Extension Attribute is benchmark-specific:

US CMMC 2.0 Level 2 (Enforce) - Failed Result List

That benchmark-specific EA appears in my smart group usage report for the active CMMC groups, including the compliant and non-compliant groups for the baseline and macOS versions. The failed-result EA pattern is still part of the Jamf Compliance and macOS Security Compliance Project workflow, while the exact EA name depends on the benchmark name and how the compliance content was generated.

The compatibility point is --ea-name. For my CMMC Level 2 evidence export, I would run the script against the benchmark-specific EA:

export JAMF_URL="https://yourorg.jamfcloud.com"
export JAMF_CLIENT_ID="your_client_id"
export JAMF_CLIENT_SECRET="your_client_secret"

/usr/local/bin/managed_python3 "JAMF Compliance Reports.py" \
  --ea-name "US CMMC 2.0 Level 2 (Enforce) - Failed Result List" \
  --out-dir "./Reports"

Before running the script in another tenant, I would confirm the failed-result EA name in Jamf and pass the exact value. If the generic EA is the right source, the default works. If the active benchmark has its own failed-result EA, I would use the benchmark-specific name.

Keeping The Export Read-Only

For audit evidence collection, I want the reporting tool to read Jamf and write local CSV files. I do not want it changing the Jamf environment.

The preferred authentication path is OAuth client credentials:

export JAMF_URL="https://yourorg.jamfcloud.com"
export JAMF_CLIENT_ID="your_client_id"
export JAMF_CLIENT_SECRET="your_client_secret"

The script also supports username and password as a fallback:

export JAMF_URL="https://yourorg.jamfcloud.com"
export JAMF_USER="jamf_api_reader"
export JAMF_PASSWORD="••••••••"

For this report, the API role should be limited to inventory read access and the authentication endpoints. The script authenticates, reads computer inventory, extracts the failed-result EA, normalizes the values, and writes the CSV outputs.

The inventory request asks for the sections required for the report:

params = {
    "section": "EXTENSION_ATTRIBUTES,GENERAL,USER_AND_LOCATION",
    "page": page,
    "page-size": page_size,
    "sort": "id:asc",
}
r = client.get("/api/v1/computers-inventory", params=params)

GENERAL provides the computer name, USER_AND_LOCATION provides the user context, and EXTENSION_ATTRIBUTES provides the failed-result EA. Those fields are enough for the summary and the drill-down CSV.

The parser handles JSON, lists, comma-separated values, semicolon-separated values, pipe-delimited values, and multiline strings. It also handles No baseline set as a special value: the phrase remains visible on the per-device report, while the fleet counts exclude it so the summary is not distorted by scoping noise.

Reviewing The Output

After the script runs, I usually look at the counts first:

(head -n 1 Reports/compliance_failed_counts.csv && \
tail -n +2 Reports/compliance_failed_counts.csv | sort -t, -k2,2nr | head -20) | column -s, -t

Then I spot-check the device file:

(head -n 1 Reports/compliance_failed_by_device.csv && \
tail -n +2 Reports/compliance_failed_by_device.csv | grep -v ',$' | head -15) | column -s, -t

If the CSVs are empty or do not match what I expect from the dashboard, I check the EA name, the API role, and the benchmark scope first. In this workflow, scope is usually the fastest way to create confusing evidence. The report can only summarize what Jamf is actually returning for the devices assigned to the benchmark.

The Evidence Package I Would Keep

For the Mac side of the CMMC assessment, I would keep the evidence package organized around the way the assessor conversation actually works:

  1. Tailored baseline PDF from the macOS Security Compliance Project and Jamf Compliance workflow.
  2. Native Jamf compliance benchmark report or dashboard export.
  3. compliance_failed_counts.csv as the high-level failed-item summary.
  4. compliance_failed_by_device.csv as the drill-down artifact.
  5. Live Jamf dashboard review during the assessment.

That package lets me start with the baseline, move into Jamf as the management system, preserve the broad native Jamf report, and then use the script output as a concise summary of failed items across the fleet. If the assessor wants detail, the evidence trail can move from the count to the device list and then back into Jamf.

Jamf was key because it gave the Mac evidence a real management-plane source. The script helped me preserve one focused slice of that data in a format that was easier to review and easier to keep with the assessment record.

Sources

AI Usage Transparency Report

AI Era · Written during widespread use of AI tools

AI Signal Composition

Rep Tone Struct List Instr
Repetition: 65%
Tone: 65%
Structure: 65%
List: 8%
Instructional: 22%
Emoji: 0%

Score: 0.31 · Moderate AI Influence

Summary

The script generates two CSV files: compliance_failed_counts.csv and compliance_failed_by_device.csv. The counts file shows each failed compliance item and how many devices are reporting it, while the by-device file provides a drill-down artifact for further review.

Related Posts

Setting up Ollama on macOS

Recently, after some bad experiences with OpenAI's ChatGPT and CODEX, I decided to look into and learn more about running local AI models. On its face it was intimidating, but I had seen a lot of people in the MacAdmins community posting examples of macOS setups, which really helped lower the bar for me both in terms of approachability and just making me more aware of the local AI community that exists out there today.

Read more

AI Agent Constraints and Security

I really feel like in this era of AI it's essential to write about and share experiences for others who are leveraging AI, especially now that AI usage seems almost ubiquitous. Specifically, when it comes to AI in development and the rapid growth of AI-driven automations in the IT landscape, I believe there's a need for open discussion and exploration.

Read more

Vibe Coding with Codex: From Fun to Frustration

So there I was, a typically day, a typical weekend. As a ChatGPT customer, I had heard good things about Codex and had not yet tried the platform. To date my experience with agentic coding was simply snippit based support with ChatGPT and Gemeni where I would ask questions, get explanations and support with squashing bugs in a few apps that I work on, for fun, on the side. There were a few core features in one of the apps I built that I wanted to try implementing but the...

Read more

Turn Jamf Compliance Output into Real Audit Evidence

Most teams use Apple’s macOS Security Compliance Project (mSCP) baselines because they scale and they’re repeatable. Jamf’s tooling makes deployment straightforward and the Extension Attribute (EA) output is a convenient place to capture drift. What you don’t automatically get is the artifact an auditor will accept on a specific date—an actual document you can file that shows which endpoints are failing which items, plus a concise roll-up of failure counts you can act on. Smart Groups answer scope; they don’t produce evidence.

Read more

Secure Software, Secure Career: How I Passed the CSSLP

After passing the CISSP earlier this year, I decided to follow it up with the **Certified Secure Software Lifecycle Professional (CSSLP)** certification. For those unfamiliar, CSSLP is an ISC2 certification that focuses specifically on secure software development practices across the full SDLC—from requirements and design to coding, testing, deployment, and maintenance. My goal in pursuing this certification was to further develop my skills in ensuring the security of software throughout its entire lifecycle.

Read more

Good Cybersecurity policies, procedures, guidelines take time. They're not rushed and aren't rubber stamped

Cybersecurity is no longer a luxury or an afterthought—it's an absolute necessity. But how can you tell if the company you work for, as a security professional, truly values cybersecurity? Let's explore some clear indicators that demonstrate a company's commitment to implementing robust security practices in-house. A genuine commitment will be reflected in the organization's policies and procedures, which should be regularly reviewed and updated to address emerging threats.

Read more

Managing Bring Your Own Device (BYOD) for Android with Microsoft Intune

Alright, so today we're going to be talking about the management of bring your own device BYOD for Android devices. There's a lot of information out there for the management of iOS devices and you can do that with pretty much any Apple MDM on the market. We just happen to use Jamf where I work, but you could use anything from Braavos to SimpleMDM to Kanji or JumpCloud. Mosyle is also a great option.

Read more