-
Notifications
You must be signed in to change notification settings - Fork 15
CMDB Data Quality Developer Guide
Six checks with no schema and no rule engine, why a clean check must still render, and why the negative control is the test here.
Shipped as #972.
The user-facing page is CMDB β Data Quality. The foundations are CMDB β Developer Guide; this exists mainly to protect Impact analysis, and Β§2 explains why.
Colour key: ποΈ schema Β· βοΈ engine Β· π API Β· π₯οΈ UI Β· π¨ CSS Β· π i18n Β· π§ͺ tests Β· π docs
| π¨ | File | What it does |
|---|---|---|
| βοΈ | includes/cmdb_audit.php |
the whole feature. cmdbRunAudit() plus one function per check, cmdbAuditResult() (the uniform shape), CMDB_AUDIT_STALE_MONTHS, CMDB_AUDIT_MAX_ITEMS
|
| π | api/cmdb/get_audit.php |
~20 lines. Auth, module access, run, return |
| π₯οΈ | cmdb/audit.php |
the page and its .audit-* styles |
| π₯οΈ | cmdb/audit.js |
CHECK_ORDER, card rendering, the two empty states |
| π₯οΈ | cmdb/includes/header.php |
the nav button ($current_page === 'audit') |
| π₯οΈ | cmdb/help.php |
section 13, which pushed Companies to 14 |
| π |
lang/en/cmdb.php + lang/pt-BR/cmdb.php
|
the audit.* block, nav.audit, help.dataquality_*
|
π No schema change at all. Every check reads columns that already exist. Nothing to verify, nothing to migrate.
The temptation is a general-purpose rule engine β iTop has one, and it is genuinely more powerful. It is also a much bigger feature, and a rule engine with no rules written is worth nothing on day one.
So instead: every check is derived from a declaration the install has already made.
| Check | The declaration it enforces |
|---|---|
required_missing |
a property marked is_required
|
dependency_blank |
a property ticked spreads_impact
|
broken_reference |
an object_ref pointing at a real object |
no_impact_edges |
at least one relationship type set to carry impact |
disconnected |
(none β it is structural) |
stale |
(none β a fixed six-month constant) |
Nobody has to configure anything for the audit to say something useful, and nothing it reports is our opinion about their estate β it is their own stated intent, checked.
π The framing is impact analysis, not tidiness. "Connected to nothing" is not flagged because it looks untidy; it is flagged because such an object can never appear in any blast radius, which makes it invisible to the thing the module is for. That is also why no_impact_edges is rendered first β if nothing carries impact, every other finding is moot, and there is no point tidying dependencies nothing will follow.
A rule builder can be added later without breaking any of this.
The obvious query is no parent, no children, no relationships. On the estate this shipped against, that returns 13 of 39 objects. The real check returns 2.
The difference is object_ref properties. Eleven of those objects are pointed at by β or point at β another object through a typed property. They are connected; the naive query just doesn't look there.
Ticket links deliberately do not rescue an object here. A CI referenced by a ticket is being used, but it still contributes nothing to impact analysis, which is what this check is about.
A check finding nothing is information β "every object reference points at something real" is worth reading. More importantly, hiding passing checks makes a clean result indistinguishable from a check that silently failed to run.
Cards therefore always render, with a green left border and the clean message. no_impact_edges is the one exception to the shape: it is install-level, so it shows OK / ! and a link to settings rather than a list of objects.
CMDB_AUDIT_MAX_ITEMS bounds the rows returned; cmdbAuditResult() sets capped by comparing the true count with the returned rows, and the card renders "showing the first 100 of 412". A truncated list presented as complete is a worse failure than a slow page.
On healthy data five of the six checks return 0. That is indistinguishable from a query with a typo in it, a wrong join, or a WHERE clause that can never be true. Asserting "returns 0 on clean data" proves nothing whatsoever.
The test therefore works by injection: record a baseline, break exactly one thing, assert the relevant count moves by exactly +1 β and assert the other checks did not move.
| Injected | Expected |
|---|---|
| A required property added to a class with existing objects |
required_missing +1, everything else unchanged |
An object_ref value pointing at a non-existent id |
broken_reference +1 |
A property ticked spreads_impact, left blank |
dependency_blank rises |
| A new object with no links |
disconnected +1 |
| β¦then give it a parent |
disconnected β1 β proves the check can clear, not just count |
Backdate updated_datetime 14 months |
stale +1 |
Set every impact_direction to none |
no_impact_edges flips 0 β 1 |
broken_reference cannot be reproduced on a fresh install. freeitsm.sql defines fk_cmdb_op_value_object with ON DELETE SET NULL, so the dangling row simply cannot be inserted. The check exists for Verify-grown installs, which have no CMDB foreign keys (see the foundations guide Β§5). The fixture uses SET FOREIGN_KEY_CHECKS = 0 to reproduce that install's shape. Skipping instead would leave the check unproven on the only installs where it can ever fire β and a skip that describes your data shape is always worth chasing.
Everything runs inside a transaction and rolls back.
- User-defined rules. The iTop equivalent. Additive β the built-ins can stay.
-
Per-class thresholds.
CMDB_AUDIT_STALE_MONTHSis one constant for the whole install; six months is right for a server and absurd for a wall switch. - Trend. Nothing is stored, so there is no "findings are down from last month" β and nothing to chart.
- Fix-it actions. Deliberately read-only for now. The analyst is the one who knows whether a standalone CI is a mistake.
- Exposure through REST v1. The engine is callable; no route yet.
FreeITSM β an open-source IT Service Management platform Β· github.com/edmozley/freeitsm Β· MIT licence
- Installation
- β° Scheduled tasks (cron jobs)
- Architecture
- AI Providers
- Internationalisation (i18n)
- Timezones & Time Handling
- Theming & Dark Mode
- β¨οΈ Command palette (βK)
- π Searching inside tickets
- π Attached documents
- MobileβFriendly
-
Security
- Layer 1 β which modules you can enter
- β³ π§© Module Access Control
- β³ π οΈ Module Access β Developer Guide
- Layer 2 β what you can administer
- β³ π Roles & Permissions
- β³ π οΈ Roles β Developer Guide
- β³ π€ Why capabilities are constants
- Layer 3 β the System module
- β³ π Admin Access Control
- Hardening
- β³ π Security review response 2026-08
- β³ π‘οΈ Security hardening 2026-08
- β³ π οΈ Security hardening 2026-08 β Developer Guide
- β³ π‘οΈ Round three β plain English
- β³ π οΈ Round three β Developer Guide
- Single Sign-On (SSO)
- ποΈ LDAP & Active Directory
- Browser Extension
- API Reference
-
π REST API β how it works
- β³ π« REST API: Tickets
- β³ π» REST API: Assets
- β³ π΄ REST API: Problems
- β³ π REST API: Changes
- β³ π REST API: Knowledge
- β³ β REST API: Tasks
- β³ ποΈ REST API: CMDB
- β³ π REST API: Contracts
- β³ ποΈ REST API: Calendar
- β³ πΏ REST API: Software
- β³ π¦ REST API: Service Status
- β³ βοΈ REST API: Morning Checks
- β³ π REST API: Forms
- β³ βοΈ REST API: Workflow
- β³ πΊοΈ REST API: Network Mapper
- β³ π§ Using the API docs page
- β³ π OpenAPI specification
- β³ β OpenAPI: kept correct
- β³ π οΈ Maintaining the catalogue
- Watchtower
-
Tickets
- β³ Mailbox Authentication
- β³ π€ Email send log
- β³ Basic IMAP mailboxes
- β³ Email rendering & images
- β³ SLA Management
- β³ WhatsApp channel
- β³ π¬ Web chat channel
- β³ π£ Slack channel
- β³ π Linking tickets
- β³ ποΈ Canned responses
- β³ βοΈ Limiting replies to particular senders
- β³ βοΈ Email signatures
- β³ π The public web address
- β³ π Raising a ticket for someone else
- β³ π Merging tickets
- β³ β Splitting tickets
- β³ β Selecting several tickets
- β³ π οΈ Snoozing tickets β Developer Guide
- β³ π₯ Collision detection
- β³ β±οΈ Time tracking
- Problem Management
- Tasks
- Assets
- Knowledge
- Change Management
- Calendar
- Morning Checks
- Reporting
- Software
- Forms
- Contracts
- Service Status
- π Notifications
- π¨ War Room
- Self-Service Portal
- LMS
- Process Mapper
- CMDB
- Network Mapper
- Workflows
- Issue trackers (Jira, Azure DevOps)
- System
-
Overview
- β³ π Progress tracker
- β³ Concepts & vocabulary
- β³ Email routing & mailboxes
- β³ Settings: global vs per-company
- β³ Users & self-service
- β³ Staff cross-company access
- β³ Worked examples
- β³ Pitfalls & gotchas
- β³ Scope: what it's for
- β³ π οΈ Developer Guide (make a module multi-company)
- β³ ποΈ Case study: CMDB (a linked graph)
- β³ π§ͺ Test harness (prove it's isolated)