Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,18 @@ jc setup # Walk through first-time configuration

The wizard guides you through profile selection, authentication (API key or service account), organization ID, output format, color, and list limit. On re-run, existing settings are shown — press Enter to keep current values. Each step saves immediately, so partial completion (Ctrl-C) preserves progress.

### Audit

```bash
jc audit # All checks, grouped by category
jc audit --category security # Security checks only
jc audit --severity high # High/critical findings only
jc audit --output json # For skills + CI pipelines
jc audit --exit-code --threshold high # CI gate: non-zero on high+ findings
```

A composable cross-resource health check registry. Each finding carries a severity (`info` → `critical`), a `resource_ref` like `admin:alice@acme.com`, and a `remediation_hint` that names the exact `jc` command to fix it. Categories: `security`, `compliance`, `hygiene`, `identity`. Backs the `jc-security-audit` and `jc-compliance-check` skills. Full check reference: [docs/AUDIT.md](docs/AUDIT.md).

### Interactive TUI

```bash
Expand Down
4 changes: 4 additions & 0 deletions cmd/sitegen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ var categories = []category{
Name: "Setup",
Commands: []string{"jc auth", "jc config"},
},
{
Name: "Diagnostics",
Commands: []string{"jc audit", "jc doctor"},
},
}

type enrichedCommand struct {
Expand Down
162 changes: 162 additions & 0 deletions docs/AUDIT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# `jc audit` — check reference

`jc audit` runs a battery of cross-resource health checks against the
configured JumpCloud org. Each check is severity-tagged (`info`, `low`,
`medium`, `high`, `critical`) and ships with a `remediation_hint` that
names the exact `jc` command to fix it. Output formats:

- Default human (grouped by category, severity-glyph prefix)
- `--output json` — wrapper object with `results`, `findings`, `warnings`
- `--output ndjson` — one finding per line, for streaming pipelines
- `--output table` / `--output csv` — tabular, fields:
`severity, category, check_id, resource_ref, title`

For CI gating, pair `--exit-code` with `--threshold high` (or any other
severity). Non-zero exit when any finding meets or exceeds the threshold.

```bash
jc audit # everything, human-readable
jc audit --category security # security checks only
jc audit --severity high # high/critical findings only
jc audit --output json # machine-readable for skills
jc audit --exit-code --threshold high # CI gate: fail on high+ findings
```

The check registry lives in `internal/audit/checks.go`. Adding a new
check is one `Register` call from `init()` — the CLI surface, JSON shape,
sidebar showcase entry, and skill prompts all surface it automatically.

## Security

### `admins-without-mfa` — CRITICAL

Admin accounts without `enableMultiFactor` AND `totpEnrolled` both true.
Admin accounts are the highest-value target in any directory; missing
MFA on even one admin is a single-step compromise path to org-wide
takeover.

**Remediation:** Admin Portal → Administrators → edit → Enable
Multi-Factor Authentication. No automatable API for this — JumpCloud
requires the admin to enroll via the portal.

### `users-without-mfa` — HIGH

Active (not suspended, not locked) users without an enrolled MFA factor
(`totp_enabled=false` AND `mfa.configured=false`). Scopes to active
users only: a suspended/locked account isn't a live attack surface.

**Remediation:** Enforce MFA via an auth policy on the user's groups
(`jc auth-policies create`), or have the user enroll via the JumpCloud
user portal.

### `suspended-not-locked` — MEDIUM

Users where `suspended=true` but `account_locked=false`. Suspension
prevents new login but doesn't necessarily invalidate active sessions
or refresh tokens; locking forces re-auth on every gate.

**Remediation:** `jc users lock <username>`.

### `iplists-empty` — LOW

IP lists with zero IP entries. An empty IP list referenced by an auth
policy fails open or closed depending on policy semantics — both are
footguns: in fail-open you've eliminated the gate; in fail-closed
you've locked the user base out of the gated resource.

**Remediation:** Populate (`jc iplists update`) or delete
(`jc iplists delete`).

## Compliance

### `mfa-adoption-rate` — scales by adoption

Org-wide MFA adoption among active users. Severity scales:

| Adoption | Severity |
|----------|----------|
| <50% | CRITICAL |
| <80% | HIGH |
| <95% | MEDIUM |
| ≥95% | silent (no finding) |

The 95% threshold matches the bar in SOC 2 and ISO 27001 audit
frameworks for "material control gap."

**Remediation:** Enforce MFA via auth policies covering user groups.

### `admin-mfa-coverage` — CRITICAL

Admin MFA adoption with a hard 100% target. Reported as a single
finding when adoption is below 100%; pair with `admins-without-mfa` for
the per-admin list.

### `password-age` — MEDIUM

Active users with `password_date` older than 90 days. 90 days mirrors
the common compliance bar (HIPAA, PCI DSS).

If your compliance framework has moved off mandatory rotation (NIST SP
800-63B recommends against forced rotation absent compromise), filter
this check out with `--severity high`.

### `fde-coverage` — scales by coverage

Full-disk encryption coverage across managed macOS and Windows devices.
Linux / iOS / etc. are excluded (no comparable FDE telemetry via the
JumpCloud API).

| Coverage | Severity |
|----------|----------|
| <50% | CRITICAL |
| <90% | HIGH |
| <100% | MEDIUM |
| 100% | silent |

**Remediation:** Push the JumpCloud FDE policy to unencrypted devices.
FileVault / BitLocker keys are escrowed to JumpCloud for recovery.

## Hygiene

### `stale-devices` — MEDIUM

Devices with `lastContact` more than 30 days ago. Either the device is
decommissioned (delete to reclaim the license) or the agent has
crashed (investigate). Stale devices count toward your license while
contributing no telemetry.

**Remediation:** `jc devices delete <id>` (if decommissioned) or
`jc devices get <id>` to investigate agent state.

### `auth-policies-disabled` — LOW

Authentication policies in the disabled state. Disabled policies are
dead code — silent until a future operator wonders why traffic isn't
being gated.

**Remediation:** Re-enable (`jc auth-policies enable <name>`) or delete
(`jc auth-policies delete <name>`).

## Identity

### `recently-created-admins` — INFO

Admin accounts created in the last 14 days. Newly-created admins are
both a legitimate onboarding signal AND a common post-compromise
persistence mechanism — surface them for cross-check against IAM
tickets, Slack approvals, or a CMDB.

This is INFO severity, not LOW: a legitimate new admin shouldn't
contribute to a hygiene score, but every new admin should be **seen**.

## Roadmap

Checks deferred for v1 because they require per-resource follow-up
calls (N+1 patterns that hurt at scale):

- `empty-user-groups` / `empty-system-groups` — needs `/usergroups/{id}/members`
- `suspended-users-with-ssh-keys` — needs `/systemusers/{id}/sshkeys`
- `policies-without-scope` — needs the graph traversal

Filed under cleanup follow-ups once we have a batched member-count
endpoint or sustained-load benchmarks justifying the fan-out cost.
54 changes: 53 additions & 1 deletion docs/site/commands.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"Integrations",
"Org \u0026 Lifecycle",
"AI \u0026 Automation",
"Setup"
"Setup",
"Diagnostics"
],
"commands": [
{
Expand All @@ -25,6 +26,57 @@
"switch"
]
},
{
"path": "jc audit",
"description": "Run cross-resource health checks (security, compliance, hygiene, identity)",
"long": "A composable check registry that audits the entire org in one pass — admins without MFA, MFA adoption rate, FDE coverage, stale devices, disabled auth policies, suspicious admin lifecycle events, and more. Each finding is severity-tagged (info → critical), tagged with a `resource_ref` for downstream grouping, and ships with a `remediation_hint` that names the exact `jc` command to fix it. Use `--category security|compliance|hygiene|identity` to scope, `--severity high` to filter to actionable findings, and `--exit-code --threshold high` to gate CI pipelines. The same primitive powers the `jc-security-audit` and `jc-compliance-check` skills (which now interpret structured findings rather than scripting raw queries). Adding a new check is one Register call in `internal/audit/checks.go` — the registry, CLI surface, JSON shape, and skill prompts all update automatically.",
"category": "Diagnostics",
"subcommands": [
"verify"
],
"flags": [
{
"name": "category",
"type": "string[]",
"description": "Restrict to one or more categories: security, compliance, hygiene, identity"
},
{
"name": "severity",
"type": "string",
"description": "Show only findings at or above this severity (info, low, medium, high, critical)"
},
{
"name": "threshold",
"type": "string",
"default": "high",
"description": "Severity threshold used by --exit-code"
},
{
"name": "exit-code",
"type": "bool",
"description": "Exit with code 1 if any finding meets or exceeds --threshold (for CI gating)"
}
]
},
{
"path": "jc doctor",
"description": "No-auth diagnostic — env, config, auth resolution, API connectivity",
"long": "A pre-flight check for any environment where `jc` is about to run. Reports the active profile, credential source (flag / env / keychain / config), fingerprint of the resolved key, config file location, and runs a single read-only probe against the JumpCloud API to confirm the credentials actually authenticate. Works without auth (skips the API probe gracefully) so it's safe to run in a Dockerfile build step or fresh-clone sanity check. Useful as the first command in a runbook or on-call playbook — when something's wrong with `jc`, this is the fastest path to the cause.",
"category": "Diagnostics",
"flags": [
{
"name": "probe-timeout",
"type": "duration",
"default": "5s",
"description": "Timeout for the live API probe"
},
{
"name": "skip-probe",
"type": "bool",
"description": "Skip the live API probe (no network)"
}
]
},
{
"path": "jc config",
"description": "Configuration management",
Expand Down
28 changes: 28 additions & 0 deletions docs/site/llms-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,34 @@ View and update jc CLI configuration — default output format, color/pager beha

**Subcommands:** `view`, `set`

### Diagnostics

#### `jc audit`

Run cross-resource health checks (security, compliance, hygiene, identity)

A composable check registry that audits the entire org in one pass — admins without MFA, MFA adoption rate, FDE coverage, stale devices, disabled auth policies, suspicious admin lifecycle events, and more. Each finding is severity-tagged (info → critical), tagged with a `resource_ref` for downstream grouping, and ships with a `remediation_hint` that names the exact `jc` command to fix it. Use `--category security|compliance|hygiene|identity` to scope, `--severity high` to filter to actionable findings, and `--exit-code --threshold high` to gate CI pipelines. The same primitive powers the `jc-security-audit` and `jc-compliance-check` skills (which now interpret structured findings rather than scripting raw queries). Adding a new check is one Register call in `internal/audit/checks.go` — the registry, CLI surface, JSON shape, and skill prompts all update automatically.

**Subcommands:** `verify`

**Flags:**

- `--category` `<string[]>` — Restrict to one or more categories: security, compliance, hygiene, identity
- `--severity` `<string>` — Show only findings at or above this severity (info, low, medium, high, critical)
- `--threshold` `<string>` (default `high`) — Severity threshold used by --exit-code
- `--exit-code` `<bool>` — Exit with code 1 if any finding meets or exceeds --threshold (for CI gating)

#### `jc doctor`

No-auth diagnostic — env, config, auth resolution, API connectivity

A pre-flight check for any environment where `jc` is about to run. Reports the active profile, credential source (flag / env / keychain / config), fingerprint of the resolved key, config file location, and runs a single read-only probe against the JumpCloud API to confirm the credentials actually authenticate. Works without auth (skips the API probe gracefully) so it's safe to run in a Dockerfile build step or fresh-clone sanity check. Useful as the first command in a runbook or on-call playbook — when something's wrong with `jc`, this is the fastest path to the cause.

**Flags:**

- `--probe-timeout` `<duration>` (default `5s`) — Timeout for the live API probe
- `--skip-probe` `<bool>` — Skip the live API probe (no network)

## Resource types

Every resource has a JSON schema available via `jc schema <resource>`:
Expand Down
5 changes: 5 additions & 0 deletions docs/site/llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ The jc CLI is a Go-based command-line tool for JumpCloud — managing users, dev
- `jc auth` — Authentication commands
- `jc config` — Configuration management

### Diagnostics

- `jc audit` — Run cross-resource health checks (security, compliance, hygiene, identity)
- `jc doctor` — No-auth diagnostic — env, config, auth resolution, API connectivity

## See also

- [Full reference](llms-full.txt)
Expand Down
Loading
Loading