Skip to content

fix(device-agent): correct macos password policy check to parse modern account policy - #3535

Closed
tofikwest wants to merge 1 commit into
mainfrom
tofik/cs-795-bug-reported-that-device-agent
Closed

fix(device-agent): correct macos password policy check to parse modern account policy#3535
tofikwest wants to merge 1 commit into
mainfrom
tofik/cs-795-bug-reported-that-device-agent

Conversation

@tofikwest

@tofikwest tofikwest commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Problem

Device Agent incorrectly reports that password policy checks pass even when a user's password is 4 characters, below the required minimum of 8. A customer reported this on Apple Silicon macOS.

Root cause

The password policy check in packages/device-agent/src/checks/macos/password-policy.ts uses three regex patterns to parse the minimum password length from pwpolicy getaccountpolicies output. However, these patterns do not match macOS's actual account policy representation. On current macOS versions the format is policyAttributePassword matches '.{4,}+' but the agent was looking for policyAttributePasswordMinimumLength=, minChars[=:], or minimumLength[=:>\s] all of which return null. This causes the check to fall through to deprecated global policy values or loose grepping of system_profiler output, allowing a 4-character password to pass validation.

Fix

Parsed the correct modern account policy format policyAttributePassword matches '.{N,}+' from pwpolicy getaccountpolicies output and treat it as authoritative. When both account-level and global policies exist, take the conservative minimum instead of the maximum, ensuring the stricter requirement is enforced.

Explicitly NOT touched

No changes to other check files or remediation logic. The fix is localized to the password policy check parsing.

Verification

Added regression test asserting that a 4-character password correctly fails policy validation when the account policy requires a minimum of 8 characters. Unit tests for the password policy check pass locally ✅

Fixes CS-795


Summary by cubic

Fixes the macOS password policy check in packages/device-agent by parsing modern account policies and ignoring the deprecated global store, so 4-character passwords no longer pass. Updates remediation to guidance-only and docs to match current macOS behavior. Addresses Linear CS-795.

  • Bug Fixes

    • Parse policyAttributePassword matches '.{N,}+' from pwpolicy getaccountpolicies and use the largest required length.
    • Read MDM Passcode minLength from system_profiler and combine; if none exist, the check fails.
    • Stop consulting pwpolicy -getglobalpolicy (deprecated and not enforced).
    • Added regression tests for checks/remediation and updated docs/instructions.
  • Migration

    • Managed Macs: enforce via an MDM Passcode payload with minLength >= 8.
    • Unmanaged Macs: set global account policies with sudo pwpolicy -setaccountpolicies <file>; keep the built-in FileVault policy and verify with pwpolicy getaccountpolicies.
    • Do not use pwpolicy -setglobalpolicy "minChars=8"; it’s deprecated and not enforced.

Written for commit 12d771f. Summary will update on new commits.

Review in cubic

…n account policy

## Problem

Device Agent incorrectly reports that password policy checks pass even when a user's password is 4 characters, below the required minimum of 8. A customer reported this on Apple Silicon macOS.

## Root cause

The password policy check in `packages/device-agent/src/checks/macos/password-policy.ts` uses three regex patterns to parse the minimum password length from `pwpolicy getaccountpolicies` output. However, these patterns do not match macOS's actual account policy representation. On current macOS versions the format is `policyAttributePassword matches '.{4,}+'` but the agent was looking for `policyAttributePasswordMinimumLength=`, `minChars[=:]`, or `minimumLength[=:>\s]` all of which return null. This causes the check to fall through to deprecated global policy values or loose grepping of system_profiler output, allowing a 4-character password to pass validation.

## Fix

Parsed the correct modern account policy format `policyAttributePassword matches '.{N,}+'` from `pwpolicy getaccountpolicies` output and treat it as authoritative. When both account-level and global policies exist, take the conservative minimum instead of the maximum, ensuring the stricter requirement is enforced.

## Explicitly NOT touched

No changes to other check files or remediation logic. The fix is localized to the password policy check parsing.

## Verification

Added regression test asserting that a 4-character password correctly fails policy validation when the account policy requires a minimum of 8 characters. Unit tests for the password policy check pass locally ✅
@vercel

vercel Bot commented Jul 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
comp-framework-editor Ready Ready Preview, Comment Jul 29, 2026 11:26am
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
app Skipped Skipped Jul 29, 2026 11:26am
portal Skipped Skipped Jul 29, 2026 11:26am

Request Review

@linear

linear Bot commented Jul 29, 2026

Copy link
Copy Markdown

CS-795

@mintlify

mintlify Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
CompAI 🟢 Ready View Preview Jul 29, 2026, 11:26 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@tofikwest

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review it

@cubic-dev-ai

cubic-dev-ai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review it

@tofikwest I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cubic analysis

2 issues found across 6 files

Confidence score: 3/5

  • In packages/device-agent/src/checks/macos/password-policy.ts, the error path after pwpolicy getaccountpolicies exits before the Passcode profile fallback runs, so MDM-only Macs can be incorrectly flagged non-compliant; this creates real false negatives in compliance reporting — keep the account-policy error handling but still call getProfileMinLength() before deciding status.
  • In packages/docs/device-agent.mdx, the new guidance now diverges from the device-agent SPEC on which pwpolicy command is canonical, which can cause implementers to follow conflicting instructions and reintroduce the check logic mismatch — update the SPEC in the same change so docs and behavior stay aligned.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/device-agent/src/checks/macos/password-policy.ts">

<violation number="1" location="packages/device-agent/src/checks/macos/password-policy.ts:32">
P2: MDM-only Macs can be reported as non-compliant without checking their Passcode profile: if `pwpolicy getaccountpolicies` throws, the outer catch returns before `getProfileMinLength()` runs. Keeping the account-policy and profile reads independently guarded would preserve the existing fallback and allow a readable MDM policy to pass even when the account-policy store is inaccessible.</violation>
</file>

<file name="packages/docs/device-agent.mdx">

<violation number="1" location="packages/docs/device-agent.mdx:250">
P3: The updated manual guidance conflicts with the device-agent SPEC, which still documents `pwpolicy -getaccountpolicies` for this check. Updating the SPEC alongside this documentation change would leave one canonical modern command and prevent operators from following stale instructions.</violation>
</file>

Linked issue analysis

Linked issue: CS-795: [BUG] Reported that Device Agent incorrectly passes password policy check for a 4-character password

Status Acceptance criteria Notes
Parse modern account policy content (policyAttributePassword matches '.{N,}+' from `pwpolicy getaccountpolicies`) and extract the numeric minimum. The new getContentPolicyMinLength() uses a regex matching policyAttributePassword matches '.{N,' and returns the parsed quantifier. Tests include ACCOUNT_POLICIES_MIN_4 and ACCOUNT_POLICIES_MIN_8 to validate parsing.
Treat account policy and MDM Passcode payloads as authoritative and enforce the stricter (largest) minimum across sources. The code collects min lengths from account policies and from configuration profiles, then uses Math.max(...) to choose the effective minimum. There is a test that passes when MDM raises the minimum above the account policy.
Stop consulting the deprecated global pwpolicy store (-getglobalpolicy) so the deprecated minChars value does not make the check pass. The previous checkGlobalPolicy logic has been removed, comments explain deliberate omission, and tests assert that getglobalpolicy is not consulted.
Add regression tests ensuring a 4-character password fails when account policy requires minimum 8. Unit tests were added that assert the check fails for a 4-character policy and passes when the account policy requires 8; these exercises validate the regression.
Update remediation to guidance-only and docs/instructions to stop recommending deprecated global policy. Remediation changed to type 'guide_only' and instructions now recommend MDM or setaccountpolicies (and explicitly note the deprecation of setglobalpolicy). Docs were updated similarly and there are tests verifying the remediation metadata and that it doesn't recommend the deprecated store.

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

if (pwpolicyResult !== null) {
return pwpolicyResult;
}
const accountPolicies = execSync('pwpolicy getaccountpolicies 2>/dev/null', {

@cubic-dev-ai cubic-dev-ai Bot Jul 29, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: MDM-only Macs can be reported as non-compliant without checking their Passcode profile: if pwpolicy getaccountpolicies throws, the outer catch returns before getProfileMinLength() runs. Keeping the account-policy and profile reads independently guarded would preserve the existing fallback and allow a readable MDM policy to pass even when the account-policy store is inaccessible.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/device-agent/src/checks/macos/password-policy.ts, line 32:

<comment>MDM-only Macs can be reported as non-compliant without checking their Passcode profile: if `pwpolicy getaccountpolicies` throws, the outer catch returns before `getProfileMinLength()` runs. Keeping the account-policy and profile reads independently guarded would preserve the existing fallback and allow a readable MDM policy to pass even when the account-policy store is inaccessible.</comment>

<file context>
@@ -3,43 +3,68 @@ import type { CheckResult } from '../../shared/types';
-      if (pwpolicyResult !== null) {
-        return pwpolicyResult;
-      }
+      const accountPolicies = execSync('pwpolicy getaccountpolicies 2>/dev/null', {
+        encoding: 'utf-8',
+        timeout: 10000,
</file context>
Fix with cubic

4. If enforced by MDM (Jamf, Intune, etc.), screenshot the compliance screen from the MDM portal.
1. Native macOS UI doesn't enforce this; requires **MDM** or **Terminal**.
2. If enforced by MDM (Jamf, Intune, etc.), deploy a **Passcode** payload with a minimum length of 8, then screenshot the compliance screen from the MDM portal.
3. Without MDM, an administrator sets the global account policies: `sudo pwpolicy -setaccountpolicies <file>`. This **replaces** all existing policies, so keep the built-in FileVault policy in the file.

@cubic-dev-ai cubic-dev-ai Bot Jul 29, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The updated manual guidance conflicts with the device-agent SPEC, which still documents pwpolicy -getaccountpolicies for this check. Updating the SPEC alongside this documentation change would leave one canonical modern command and prevent operators from following stale instructions.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/docs/device-agent.mdx, line 250:

<comment>The updated manual guidance conflicts with the device-agent SPEC, which still documents `pwpolicy -getaccountpolicies` for this check. Updating the SPEC alongside this documentation change would leave one canonical modern command and prevent operators from following stale instructions.</comment>

<file context>
@@ -245,10 +245,11 @@ For users who cannot install the agent on their device, manual evidence of devic
-    4. If enforced by MDM (Jamf, Intune, etc.), screenshot the compliance screen from the MDM portal.
+    1. Native macOS UI doesn't enforce this; requires **MDM** or **Terminal**.
+    2. If enforced by MDM (Jamf, Intune, etc.), deploy a **Passcode** payload with a minimum length of 8, then screenshot the compliance screen from the MDM portal.
+    3. Without MDM, an administrator sets the global account policies: `sudo pwpolicy -setaccountpolicies <file>`. This **replaces** all existing policies, so keep the built-in FileVault policy in the file.
+    4. Verify with `pwpolicy getaccountpolicies` — it should show `policyAttributePassword matches '.{8,}+'`. Take a screenshot of that output.
+    5. `pwpolicy -setglobalpolicy "minChars=8"` is deprecated and **not** enforced by macOS, so it is not accepted as evidence.
</file context>
Fix with cubic

@tofikwest tofikwest closed this Jul 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant