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:
- Results: currently matching resources.
- Accepted: results you have acknowledged as acceptable risk.
- 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
- Expand the rule and select one or more rows in the Results tab.
- Click Accept.
- Pick Until a date or Permanent.
- Add a reason (required for audit trail).
- 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.
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, andREMOVEare rejected. - A
LIMITclause is required. - Every returned column needs an explicit
ASalias; those aliases are what the next step binds to.
3. Output fields
Declare each field your RETURN clause produces:
- Name: must match the
ASalias exactly. - Type:
string,number, orboolean. - Optional: check this if the field can be
nullon 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 500Module: 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 200Module: 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 500Module: 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.
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.