👋 Welcome to the runZero Custom Integration library!
runZero is a total attack surface and exposure management platform that combines active scanning, passive discovery, and API integrations to deliver complete visibility into managed and unmanaged assets across IT, OT, IoT, cloud, mobile, and remote environments. runZero can be used as a hosted service (SaaS) or managed on-premise. The runZero stack consists of one more Consoles, linked Explorers that run as light-weight services on network points-of-presence, and a command-line tool that can be used for offline data collection. runZero can be managed through the web interface, via API, or for self-hosted customers, on the command line.
If you are not a runZero user today, sign up for a trial that can be converted to our free Community Edition.
This repository includes custom integrations that run in the context of a runZero Explorer. These integrations are written in Starlark, a language similar to Python.
To create a custom integration within runZero, you will need a user account with superuser privileges.
You can find detailed documentation about Starlark-based integrations on the runZero help portal.
If you need help setting up a custom integration, you can create an issue on this GitHub repo, and our team will work with you. If you have a Customer Success Engineer, you can also work with them directly.
- Absolute Secure Endpoint
- AdGuard Home
- Akamai Guardicore Centra
- Asimily
- Automox
- Bitdefender GravityZone
- Bitsight
- BMC Helix Discovery
- Carbon Black
- Checkmk Raw Edition
- Cisco ISE
- Cisco Secure Endpoint
- Cortex XDR
- CyberArk EPM
- Cybereason
- Cyberint
- Cyberwatch
- Device42
- Digital Ocean
- Drata
- EfficientIP SOLIDserver
- exe.dev
- ExtraHop Reveal(x)
- Extreme Networks CloudIQ
- Fleet (osquery)
- Foreman
- Forescout CounterACT
- Forescout eyeInspect
- Frontline VM
- Ghost Security
- GLPI
- Greenbone (GMP) Import
- Halcyon
- HCL BigFix
- Home Assistant
- HPE Aruba ClearPass
- Icinga 2
- Illumio Core
- Infoblox NIOS
- iTop
- Ivanti Neurons
- JAMF
- JumpCloud
- Kandji
- Kenna Security
- Kubernetes
- Lansweeper
- LibreNMS
- LimaCharlie
- Linux via SSH
- ManageEngine Endpoint Central
- Maze
- Microsoft SQL Server databases
- Microsoft WSUS
- MikroTik RouterOS
- Miradore
- Mosyle
- Nautobot
- Netdata
- Netdisco
- Netskope
- Nexthink
- NinjaOne
- Nozomi Networks
- ntopng
- Nutanix Prism
- OCS Inventory NG
- Open-AudIT Community
- OpenNMS Horizon
- OpenWrt
- OPNsense
- Palo Alto Networks Device Security
- pfSense
- phpIPAM
- Pi-hole
- Portainer / Docker Engine
- Proxmox
- PuppetDB
- Quest KACE SMA
- Red Hat Insights
- SAP LeanIX
- Scale Computing
- Slurp'it
- Snipe-IT
- Snow License Manager
- SolarWinds Information Service
- Sophos Central
- Stairwell
- Synology DSM
- Tactical RMM
- Tailscale
- TP-Link Omada
- Trellix ePolicy Orchestrator
- Trend Micro Vision One
- TrueNAS
- Ubiquiti UniFi Network
- Ubiquiti UniFi Protect
- Ubiquiti UniFi Site Manager
- Unraid
- Uptycs
- Wazuh
- Windows SMB shares
- Windows WMI
- Workspace ONE UEM
- Zabbix
- Sample README.md for contributing
- Sample script that shows how to use all of the supported libraries
- Embedded
CONFIGmetadata in each script that gives context on the integration for automations to reference
This repository includes the /create-custom-integration skill. Invoke it with
a vendor documentation link and a short statement of the data to import:
/create-custom-integration https://vendor.example/api/docs -- import managed devices, network interfaces, OS details, and installed software
The workflow blocks implementation until it identifies whether the vendor's foreign ID is stable, unique in a documented scope, and one-to-one with the asset being imported. It does not permit random ID fallbacks that would create duplicate assets on later polls.
Asset reconciliation is configurable per integration. runZero does not
automatically choose or rewrite a custom integration's identity policy; the
script author selects matchBehavior when the default is not appropriate.
Every ImportAsset you return needs an id value. runZero uses that
foreign id as the primary key when correlating subsequent runs of the
same integration with the asset graph, so the value you choose has a
direct impact on whether records merge cleanly, fork into duplicates,
or collapse two unrelated devices into one.
A good foreign id is:
- Stable across runs. The same physical asset should produce the same id every time the script runs. Tomorrow's poll must agree with today's poll, even across reboots, IP changes, agent reinstalls, hostname renames, etc.
- Unique across the dataset. Two distinct assets must never share
the same id. If the upstream API recycles ids when devices are
decommissioned, namespace them (e.g.
vendor-{tenant}-{id}). - Opaque. Prefer vendor-issued UUIDs, serial numbers, or hardware ids over derived values like hostnames or IPs (those drift).
If the upstream source does not expose anything that meets both
criteria, that is the signal to relax matching (see below) — do
not invent a random id with new_uuid() per run, because the
same device will appear as a new asset on every poll.
CONFIG accepts an optional top-level matchBehavior string, declared
once for the whole integration and placed after minVersion:
CONFIG = {
"id": "runzero-example",
...
"minVersion": "5.1.0",
# Say WHY the default is wrong for this source. The reasoning is the
# part a future reader cannot reconstruct from the flags.
"matchBehavior": "no-id-match no-id-break",
"params": [...],
}It is not a field on ImportAsset — the merge path needs the behavior
before it has an asset, so the value is read from CONFIG and applies to
every record the script emits. Passing matchBehavior= to ImportAsset
fails validation. An absent or empty value means the default.
That default matches and breaks on all four dimensions (id, MAC, IP, name) which is correct when the integration owns a strong id. When the id is weak or absent, use one of the knobs below to tell the cruncher which dimensions are unreliable for matching (finding the right existing asset to merge into) and which are unreliable for breaking (refusing a merge that would otherwise happen because one dimension conflicts).
Flags:
| Flag | Effect |
|---|---|
no-id-match |
Do not use the foreign id to find candidate assets to merge with. |
no-id-break |
Allow a merge even when the foreign id differs from the existing asset. |
no-mac-match |
Do not use MAC addresses to find merge candidates. |
no-mac-break |
Allow a merge even when MAC addresses conflict. |
no-ip-match |
Do not use IP addresses to find merge candidates. |
no-ip-break |
Allow a merge even when IP addresses conflict. |
no-name-match |
Do not use hostnames to find merge candidates. |
no-name-break |
Allow a merge even when hostnames conflict. |
Combine flags with spaces. Recommended presets:
-
Strong, stable foreign id (most cloud / EDR / MDM APIs): leave
matchBehaviorunset. The default uses every signal. -
Strong id, but the source also reports churny MAC/IP/hostnames (e.g. ephemeral cloud workloads, VPN clients):
"matchBehavior": "no-mac-break no-ip-break no-name-break",
Keeps id-based merging authoritative, but stops drift in the other dimensions from blocking a legitimate merge.
-
No stable id at all (the source only emits per-run / ephemeral ids):
"matchBehavior": "no-id-match no-id-break",
Falls back to MAC / IP / name matching. Pair this with a deterministic key derived from the record's own stable attributes, such as
id="vendor:" + scope + ":" + mac, so the same device yields the same id on every run. Never usenew_uuid()or any other random value as an id: a fresh id each run defeats reconciliation, and thecreate-custom-integrationskill forbids it. If a record has no attribute stable enough to derive a key from, skip the record and log the field that was missing. -
Two-stage enrichment where one integration owns "identity" and another only contributes attributes: use
no-id-match no-id-breakon the enrichment-only integration so it always merges into the primary asset by MAC/IP/name rather than creating a parallel record.
A short rule of thumb: if the upstream id is not both stable and
unique, you must relax id matching. If MAC / IP / hostname are
known to be unreliable for this data source, relax the corresponding
-break flags so a conflict on those fields doesn't fragment one
real asset into many.
We welcome contributions to this repository! Whether you're fixing a bug, adding a new feature, or improving documentation, your efforts make a difference. To ensure a smooth process, please follow these guidelines:
-
Fork the Repository: Start by forking this repository to your GitHub account.
-
Create a Branch: Create a feature branch for your changes. Use a descriptive name like
feature/new-integrationorfix/bug-description. -
Make Your Changes: Implement your changes and test thoroughly. Ensure your code adheres to our coding standards and is well-documented.
-
Commit Your Changes: Write clear and concise commit messages that describe what you changed and why.
-
Open a Pull Request (PR):
- Go to the original repository and open a pull request from your fork.
- Provide a detailed description of your changes, including the problem your contribution solves and how it was tested.
-
Code Review: Collaborate with the maintainers during the review process. Be open to feedback and iterate on your changes if necessary.
-
Merge: Once approved, your PR will be merged by a maintainer.
External tools such as Gemini CLI, OpenAI Codex, and Claude Code can help draft integrations. runZero does not run an LLM in the Console, Explorer, or integration sandbox. These tools produce source that must pass the same review and validation as hand-written .star files.
There is an AGENTS.md file to give your LLM of choice best practices and guidance will building the integrations.
Existing v1 integrations remain supported. See the v1 to v2 migration guide when moving metadata into CONFIG, adopting standard helpers, streaming assets, or tuning match behavior.
This repository is licensed under the MIT License. By contributing to this project, you agree that your contributions will be licensed under the same terms.