Rules & Compliance

Rules and Compliance

Findings are security and compliance issues detected against your graph. Each finding is the result of a rule (a Cypher query) matching one or more nodes in the inventory that Cartography syncs into Neo4j (cloud accounts, identity, code, devices, ontology). Rules re-run after every sync, so findings reflect the latest snapshot.

Rule status

  • Has findings: the rule matched one or more resources.
  • Pass: the rule ran and matched nothing.
  • Disabled: the rule is turned off and is not evaluated.
  • Error: the last execution failed; check the rule's Cypher.

Working with a rule

Each rule on the Rules page exposes its title, description, tags, first seen, and last match. Click the rule to expand three tabs:

  1. Results: currently matching resources.
  2. Accepted: results you have acknowledged as acceptable risk.
  3. History: resolved results, retained for 48 hours.

Each row shows the resource name, source provider, first and last seen, and the rule-specific output fields. Use the View in Neo4j Browser action on any row to open the underlying query around that resource.

Accept a result

  1. Expand the rule and select one or more rows in the Results tab.
  2. Click Accept.
  3. Pick Until a date or Permanent.
  4. Add a reason (required for audit trail).
  5. Confirm.

Accepted rows move to the Accepted tab. They count toward acceptance, not active findings, until the Until date passes, at which point they re-enter Results automatically.

To revert, open the Accepted tab, select the row(s), and click Unaccept.

tip

Use date-bounded acceptance for known-temporary exceptions (a migration in flight, a vendor remediating). Use permanent acceptance for design decisions, and put the rationale in the reason; auditors read it.

Disable a rule

If a rule does not apply to your environment, click Deactivate on the rule row, choose Until a date or Permanent, and confirm. Disabled rules stay listed at the bottom of the Rules page but do not run.

Filter

The Rules page filters by status, tag, and framework. Filters compose; the URL updates so a filtered view is shareable.

Export

Click Export at the top of the Rules page to download every rule, every active result, and every acceptance as JSON. Use this for offline review or to feed an external GRC tool.

Compliance frameworks

A framework is a curated benchmark whose requirements are mapped to SubImage rules (CIS AWS, CIS GCP, CIS Azure, etc.). Open Compliance to manage them.

  • Enable / disable a framework toggles every rule it owns. Rules disabled this way are restored if the framework is re-enabled.
  • Compliance score = passing assets / total assets across the framework's rules. The score is snapshotted daily.
  • History charts the score over time. Click any point to see the per-rule pass/fail breakdown for that day, useful to attribute a drop to a specific rule.

A rule that belongs to multiple frameworks contributes to each independently.

Notifications

Two notification triggers are tied to findings. Configure them in Settings → Notifications alongside the Slack, email, or webhook destination.

  • First-time enabled: fires the first time a newly enabled rule produces findings. Use this when rolling out a new policy: the alert tells you the rule is detecting something instead of failing silently.
  • Weekly summary: counts of new, resolved, and accepted findings over the past seven days, grouped by tag.

Custom rules

Open Rules to author your own rule. The wizard has four steps.

1. Metadata

  • Name and Description: what the rule checks and why.
  • Tags: comma-separated; use them for filtering and for grouping in the weekly summary.
  • References: URLs to remediation guides or internal runbooks. They surface on the rule detail and in notifications.

2. Facts

A rule has one or more facts. A fact is a Cypher query plus the module it targets (aws, gcp, azure, github, okta, cloudflare, or cross-cloud). Multiple facts let one rule express variants of the same policy. For example, a "public bucket" rule can have one fact for AWS S3 and one for GCS.

For each fact, provide:

  • Name and Description.
  • Module.
  • Cypher query: the detection query.
  • Visual query (optional): a Cypher query returning a path; the UI uses it to render the matched resource on the graph explorer.

Click Test Cypher Query to validate. The validator runs EXPLAIN against Neo4j and a sample fetch.

Query rules:

  • Read-only. CREATE, MERGE, DELETE, SET, and REMOVE are rejected.
  • A LIMIT clause is required.
  • Every returned column needs an explicit AS alias; those aliases are what the next step binds to.

3. Output fields

Declare each field your RETURN clause produces:

  • Name: must match the AS alias exactly.
  • Type: string, number, or boolean.
  • Optional: check this if the field can be null on some matches.

Use the up/down arrows to set the column order on the rule's results table.

4. Review and save

The rule appears in the main Rules list with the custom tag. Editing a rule whose facts changed bumps its version. Deleting a rule removes the rule and all of its findings, accepted or not.

Use cases

Custom compliance policy: every laptop runs Tailscale

You want every managed laptop to be on the tailnet. Devices come from your MDM (Jamf, Kandji, Intune) and Tailscale syncs separately; the ontology Device node unifies them. The rule flags any Device that has no Tailscale representation.

MATCH (d:Device)
WHERE NOT (d)-[:OBSERVED_AS]->(:TailscaleDevice)
RETURN d.id            AS resource_id,
       d.hostname      AS hostname,
       d.serial_number AS serial,
       d.platform      AS platform,
       d.lastupdated   AS last_seen
LIMIT 500

Module: cross-cloud. Output fields: resource_id, hostname, serial, platform, last_seen.

Wire the rule to the First-time enabled notification so the rollout is visible in Slack the moment the first laptop drifts off the tailnet. Querying Device instead of JamfHost or KandjiDevice keeps the rule working if you change MDM.

Post-incident drift tracking: no S3 bucket may become public again

After an incident where a bucket was made public, you want a permanent rule that lights up the moment any bucket is anonymously accessible, and you want the trend over time to detect drift.

MATCH (b:S3Bucket)
WHERE b.anonymous_access = true
   OR b.anonymous_actions = true
RETURN b.id         AS resource_id,
       b.name       AS bucket_name,
       b.region     AS region
LIMIT 200

Module: aws. Output fields: resource_id, bucket_name, region.

When you ship the rule, accept the legitimate exceptions (static-site buckets, public asset CDNs) with a reason and an Until date 90 days out. Anything appearing in Results afterwards is drift. The rule's history tab plus the framework score (if you've added the rule to a framework) make the drift signal trendable.

Migration tracking: Okta → JumpCloud

You are moving identities from Okta to JumpCloud. You want a live punch-list of users who still only exist in Okta, and a history of what has been migrated.

MATCH (u:User)-[:HAS_ACCOUNT]->(:OktaUser)
WHERE NOT (u)-[:HAS_ACCOUNT]->(:JumpCloudUser)
RETURN u.id       AS resource_id,
       u.email    AS email,
       u.fullname AS full_name,
       u.active   AS active
LIMIT 500

Module: cross-cloud. Output fields: resource_id, email, full_name, active.

The Results tab is the punch-list. The History tab is the audit trail of what was migrated. When the count hits zero and stays there, disable the rule.

Programmatic access

Every action above is also exposed via MCP, so an agent can list rules, fetch findings, and read framework scores. The relevant tools are subimageListRules, subimageGetRuleFindings, subimageListFrameworks, and subimageGetFrameworkHistory. Use subimageListRules(view="custom_definitions") for tenant-authored Cypher definitions. See Connect via MCP.

important

Rules query Neo4j directly. If a rule starts erroring after a Cartography upgrade, the most likely cause is a renamed property or label. Open the rule, run Test Cypher Query, and update the fact.