feat: jc audit — cross-resource health checks (security/compliance/hygiene/identity)#47
Merged
Merged
Conversation
…giene/identity)
A composable check registry that audits the whole org in one pass:
admins without MFA, MFA adoption rate, FDE coverage, stale devices,
disabled auth policies, suspicious admin lifecycle events, and more.
11 checks across 4 categories; adding a new check is one Register call
from init().
Each finding carries severity (info → critical), a resource_ref like
`admin:alice@acme.com`, and a remediation_hint that names the exact
`jc` command to fix it. The same primitive backs the jc-security-audit
and jc-compliance-check skills — they no longer script raw queries,
just `jc audit --category X --output json` and interpret the structured
findings.
CLI surface:
jc audit # everything, grouped human output
jc audit --category security # security checks only
jc audit --severity high # high/critical findings only
jc audit --output {json,ndjson,table,csv,human,yaml}
jc audit --exit-code --threshold high # CI gate, exits 1 on threshold
The parent `audit` command now runs the health checks on bare
invocation; `audit verify` (KLA-411 MCP signed-log verification)
remains as a sibling subcommand.
Package layout:
internal/audit/audit.go — types, registry, runner, sort + filter
internal/audit/data.go — parallel Fetcher + shared Data bundle
internal/audit/checks.go — all 11 checks in one file for discoverability
internal/cmd/audit.go — Cobra command + clientFetcher adapter +
human/json/ndjson/tabular renderers
Tests cover: severity ordering, category/severity filter, sort stability,
context cancellation, exit-code derivation, per-check positive/negative
cases, fetch parallel-soft-failure semantics. Stubbed Fetcher keeps
audit_test free of network deps.
Smoke-tested live against the configured org: surfaced 2 admins without
MFA, 2 active users without MFA, 5 stale devices, low FDE coverage, and
an old disabled auth policy — exit codes wire correctly with
--threshold.
Also adds `jc audit` + `jc doctor` to the showcase site (the hand-curated
schema manifest had drifted from the actual command set) under a new
"Diagnostics" sidebar category. Adds `duration` to the schema flag-type
whitelist so jc doctor's --probe-timeout 5s validates.
docs/AUDIT.md ships a per-check reference: what it checks, why it
matters, severity scaling, and roadmap notes for the N+1 checks
(empty-groups, ssh-keys-on-suspended) deferred to a future PR.
Closes KLA-443
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Reviewed by Cursor Bugbot for commit 5277379. Configure here.
Bugbot review on PR #47 caught two related gaps in how per-check Errors (returned when a check's required data wasn't fetched) flow through the surface: 1. Human output printed "OK — N checks ran clean" when totalFindings was zero, even if half the checks had Error set. The summary bailed before rendering the [ERR] lines, so a partial fetch looked like an all-clear. 2. --exit-code only consulted findings ≥ threshold, so a check that failed to run (count: 0 findings) couldn't trigger the exit. A CI gate where "every check errored" reports the same exit code as "everything is healthy" is a lie the next time a sub-fetch flakes. Fixes: - New audit.AnyCheckError helper (mirrors AnyFindingAtLeast). - runAuditHealth: --exit-code now also fails on AnyCheckError with a distinct error message so the operator can tell findings-failure apart from execution-failure. - writeAuditHuman: count check errors alongside findings, walk the full result set when either is non-zero, and include error count in the summary line ("12 findings across 11 checks (1 check error)."). - TestAnyCheckError regression guard pins the new behavior. Refs KLA-443, addresses Bugbot review on PR #47 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jtaylorjc
approved these changes
Jun 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
A composable check registry that audits the whole org in one pass. 11 checks across 4 categories, each emitting severity-tagged findings with structured
resource_refand remediation hints. The same primitive backsjc-security-auditandjc-compliance-checkskills, which now interpret structured JSON instead of scripting raw queries.What's included
internal/audit/(new package)audit.go— Severity, Category, Finding, CheckResult, AuditCheck types + registry + Run loop + sort/filter helpersdata.go— parallel Fetcher interface + shared Data bundle (best-effort: sub-fetch failures become warnings, only all-fail returns an error)checks.go— all 11 checks in one file for catalog discoverabilityaudit_test.go— registry, runner, per-check, fetch semanticsinternal/cmd/audit.go— parentauditcommand now runs health checks on bare invoke;audit verify(KLA-411 MCP signed-log) remains as sibling subcommand. IncludesclientFetcheradapter mapping v1/v2 to the Fetcher interface, and renderers for human/json/ndjson/table/csv.jc-security-audit+jc-compliance-checkrewritten to invokejc audit --category X --output jsonand layer interpretation on top of structured findings instead of bash-scripted queries.jc audit+jc doctorto the manifest (both were missing from the hand-curated catalog), new "Diagnostics" sidebar category,durationflag-type added to the whitelist (jc doctor's--probe-timeout 5s).docs/AUDIT.md— per-check reference: what it checks, why, severity scaling, roadmap notes.The 11 checks
admins-without-mfausers-without-mfasuspended-not-lockediplists-emptymfa-adoption-rate<50%CRITICAL →<95%MEDIUM → silent above)admin-mfa-coveragepassword-agefde-coverage<50%CRITICAL →<90%HIGH → MEDIUM)stale-devicesauth-policies-disabledrecently-created-adminsDeferred (N+1 fetch patterns):
empty-groups,suspended-users-with-ssh-keys,policies-without-scope. Documented indocs/AUDIT.mdroadmap section.CLI surface
Test plan
go test ./...— full sweep green (incl. new audit package + schema)go vet ./...cleanmake verify-siteclean--threshold critical --severity criticalexits 1;--threshold critical --category hygiene(no criticals there) exits 0audit verify(existing KLA-411 subcommand) still resolves correctlyCloses KLA-443
🤖 Generated with Claude Code
Note
Medium Risk
Read-only org-wide API listing and security/compliance interpretation can mis-rank risk or fail CI gates if sub-fetches degrade; exit-code behavior was tightened to treat check errors as failures.
Overview
jc auditis now the primary entry point for org-wide health checks (security, compliance, hygiene, identity), not only MCP signed-log tooling. A barejc auditruns a registered battery of checks after a single parallel JumpCloud list fetch;jc audit verifyis unchanged for MCP manifest verification.The new
internal/auditpackage defines severities, categories, structured findings (resource_ref,remediation_hint), a check registry (11 checks in v1), and a runner with category/severity filters plus helpers for CI exit policy. The CLI wires v1/v2clientFetcher, renders human/json/ndjson/table/csv/yaml, and--exit-code --thresholdfails on threshold findings or check errors so partial API failures cannot pass a gate.jc-security-auditandjc-compliance-checkskills now calljc auditwith JSON output instead of hand-rolled list queries. README,docs/AUDIT.md, schema, and the site manifest add a Diagnostics category documentingjc auditandjc doctor.Reviewed by Cursor Bugbot for commit 5a3c381. Bugbot is set up for automated code reviews on this repo. Configure here.