Skip to content
Docs

    Monitors, dashboards and detections as code

    11 min read · Updated View as Markdown

    Tracix takes two kinds of content from Git. Detection rules, value lists and YARA rulesets live as plain files in a detection repository. Monitors, visualizations, dashboards and APM service groups are described in tracix.io/v1 JSON bundles. Both are published the same way: validate, then plan, then apply the plan you reviewed.

    What you can automate today

    Detection content runs from any CI system with a scoped API key, or your workspace syncs the repository itself. Monitor and dashboard bundles can't be published with an API key yet: publishing one needs a workspace admin, so bundles have no unattended CI path today.

    How content managed as code behaves

    • Git owns the definition. Each published object gets a stable ID, code:<package>:<kind>:<uid>, and is marked as managed as code.
    • The workspace won't edit it. Editing or deleting a managed definition in the workspace is refused, for admins too. To change one for yourself, duplicate it: the copy is an ordinary object you own.
    • Operational controls stay yours. You can still enable, disable and snooze a managed monitor and change where it notifies, and enable or disable a managed detection rule or YARA ruleset. These settings survive later publishes.
    • A package owns its objects. Everything a repository or bundle publishes belongs to the package it names.

    Integration packages from the catalog install their monitors and dashboards the same way, so those are managed as code too.

    Validate, plan and apply

    StepWhat it doesChanges your workspace
    ValidateCompiles every definition with your workspace's engine and runs the tests that come with themNo
    PlanValidates, then compares with what the workspace runs: each object is a create, update, delete, unchanged or conflict, and the plan gets a plan hashNo
    ApplyPlans again and must reproduce the plan hash you reviewed, then publishesYes
    • Apply refuses a stale plan. If anything changed since the review, apply answers 409 and you plan again.
    • Plans survive a merge. The plan hash covers each object's action, definition and live version, not the commit, so a plan reviewed on a pull request still applies at the merge commit when the content is the same.
    • Apply isn't a transaction. Each write is safe to repeat, but a failure part way leaves the earlier writes in place. Plan again and apply again.
    • Roll back from Git. Revert the commit and apply it. For detection content, only the rules whose definition changes are written.

    Detection repositories

    A detection repository holds plain files, and its Sigma rules stay readable by sigma-cli and pySigma.

    Repository layout
    tracix-detections.yaml    the manifest: package, defaults, overrides
    sigma/**/*.yml|yaml       Sigma rules, verbatim (up to 50 documents per file)
    native/**/*.yml|yaml      native rules: sql, sequence, new_terms, cardinality, watchlist
    lists/**/*.yml|yaml       value lists: name, description, items
    yara/**/*.yar|yara        YARA rulesets, one per file
    tests/**/*.yml|yaml       fixtures: events each rule must or must not match

    Other files, such as a README or CI configuration, are ignored. A repository can keep its detections in a subfolder. It can hold up to 5,000 detection files and 50 MB of content, and publish up to 5,000 objects.

    The manifest

    tracix-detections.yaml at the repository root names the package and tunes the rules. Unknown keys and values that would need converting fail validation, so a typo never becomes a silent default.

    tracix-detections.yaml
    package: acme-soc
    
    defaults:
      intervalSeconds: 60   # how often each rule's monitor runs
      windowMinutes: 5      # how far back each run looks
      rbacFloor: editor     # who sees the published rules: viewer | editor | admin
      license: custom       # for Sigma documents that declare no license
    
    overrides:
      # One rule, by its Sigma id: tuning lives here, not in the Sigma file.
      "0dc16a63-818e-4162-95ea-d8f9e5740ef7":
        severity: high
        exceptions:
          - User: list:service-accounts
        suppress:
          byFields: [host.name]
          windowMinutes: 60
    
      # A glob over repository paths: new network rules start in shadow mode.
      "sigma/network/**":
        stage: test
    
    prune: true
    KeyWhat it sets
    packageRequired. A lowercase name of letters, digits, _, . and -, up to 128 characters
    defaultsstage, enabled, intervalSeconds (15 to 86,400), windowMinutes (1 to 10,080), rbacFloor and license for every rule
    overridesTuning per rule ID, uid, path or glob: stage, severity, risk score, threshold, exceptions, suppression, schedule and investigation guide. Glob keys apply first, in order, and exact keys last
    prunetrue by default: a file removed from the repository plans a delete. With false, removing a file leaves the published object alone
    logsourcesRoutes for Sigma log sources the built-in table doesn't know. In this release, validate checks the block and warns that it isn't applied yet

    Stages

    Every rule runs at a stage. A rule's stage comes from the manifest; without one, a Sigma rule's status decides: experimental and test start in test, stable in production, and deprecated or unsupported documents are errors.

    StageBehavior
    draftOff, with no monitor
    testShadow mode: the rule's monitor runs and records alerts, but nobody is notified or paged and no case is opened
    productionAlerts and notifies as usual

    Promote a rule with a pull request that changes its stage. A rule that doesn't compile is published disabled, with its reasons, never dropped.

    Fixtures

    Files under tests/ hold events a rule must or must not match. Validate and plan run every case against the compiled rule on one synthetic row: nothing is written and nothing alerts.

    tests/proc_creation_whoami.yaml
    rule: 0dc16a63-818e-4162-95ea-d8f9e5740ef7
    cases:
      - name: whoami run by a person
        event:
          Image: 'C:\Windows\System32\whoami.exe'
          User: alice
        expect: match
    
      - name: service account excluded by the exception
        event:
          Image: 'C:\Windows\System32\whoami.exe'
          User: svc_backup
        expect: no_match
        withExceptions: true
    • Sigma and SQL rules run fixtures. Sequence, new terms, cardinality and watchlist rules need several events or history, so their cases report unsupported and the rules are checked by compiling them.
    • A file that names a ruleset holds YARA fixtures: text or base64 samples and the exact set of rules that must match.
    • A file holds up to 100 cases. A failing case makes validate and plan report valid: false, so the CLI exits with 1 before apply.

    Conflicts

    A repository rule whose rule ID matches a rule created in the UI or installed from the Sigma pack plans a conflict. Apply refuses the whole plan until you confirm the replacement with --replace. The older rule is then disabled and linked to the new one, never taken over in place. Value lists can't be replaced: a list name that another list already uses blocks the plan.

    In this release, a repository refuses Sigma correlation and filter documents. Write a correlation as a native sequence or cardinality rule, and a filter as manifest exceptions.

    Run the CLI

    tracix-detections is a single Node.js 20 or later file with no dependencies. Your workspace serves the build that matches its API.

    1. Point it at your workspace

      Set your workspace's address and a CI key with security.read:

      bash
      export TRACIX_URL=https://production-a7k3p2q9.app.tracix.io
      export TRACIX_API_KEY=txk_...
    2. Download the CLI

      bash
      curl -fsS -H "X-API-Key: $TRACIX_API_KEY" \
      "$TRACIX_URL/api/security/detections/cli" -o tracix-detections.mjs

      The response's X-Tracix-Cli-Sha256 header carries the file's SHA-256, so CI can pin a reviewed build.

    3. Validate and plan

      bash
      node tracix-detections.mjs validate .
      node tracix-detections.mjs plan . plan.json

      The plan lists what apply would create, update, delete or replace, and is saved for review.

    4. Apply the reviewed plan

      With a key that carries security.manage:

      bash
      node tracix-detections.mjs apply . plan.json

      More than 200 writes run in the background, and the CLI follows the job to the end.

    CLI reference

    CommandWhat it does
    validate <dir>Compiles every file and runs the fixtures. Read-only
    plan <dir> <plan.json>Validates, compares with the workspace and writes the plan for review
    apply <dir> <plan.json>Applies a reviewed plan. The workspace plans again and must match
    export <package> <outdir>Writes a package's published rules and lists as repository files
    OptionWhat it does
    --replaceplan, apply: confirm replacing rules that share a rule ID with this repository
    --archiveHave the workspace fetch the commit from GitHub or GitLab instead of sending the files
    --revision <sha>The commit the files were taken at. Defaults to the Git HEAD of the folder, with -dirty when it has changes
    --repo <owner/name>Archive mode: the repository
    --package <name>Refuse to run unless the manifest publishes this package
    --no-waitapply: return once a background apply has started
    --forceexport: write into a folder that isn't empty
    --jsonPrint the workspace's JSON instead of tables
    --verboseAlso list unchanged objects and passing fixtures
    Environment variableWhat it sets
    TRACIX_URLYour workspace's address. HTTPS, except for localhost
    TRACIX_API_KEYA CI key: security.read for validate, plan and export, security.manage for apply
    TRACIX_TOKENA bearer token, used instead of TRACIX_API_KEY. Set one or the other
    TRACIX_REPO_CREDENTIALArchive mode: the ID of a GitHub or GitLab credential stored in your workspace
    TRACIX_REPOArchive mode: owner/name, when --repo isn't given
    TRACIX_REVISIONThe revision to publish, when --revision isn't given
    TRACIX_MAX_REQUEST_BYTESRequest size before the CLI batches or switches to archive mode. Default 1,000,000, at most 10,485,760
    TRACIX_TIMEOUT_MSTimeout per request. Default 300,000
    TRACIX_POLL_MSHow often apply checks a background job. Default 2,000
    TRACIX_APPLY_WAIT_MSHow long apply follows a background job. Default 1,800,000

    The CLI exits with 0 on success, 1 for compile errors, failing fixtures, unconfirmed conflicts, a blocked plan or a failed request, and 2 for usage or configuration errors. It sends the key only in a header to TRACIX_URL, refuses redirects and masks the key in everything it prints. A plan is bound to the workspace it was made against, and apply refuses a plan made for another TRACIX_URL.

    Sync a repository from your workspace

    Your workspace can follow a repository without any CI. An admin connects it under Security › Detection rules › Repositories with Connect repository, or with Keep in sync when importing rules from a Git repository, using a GitHub or GitLab credential stored in the workspace.

    SettingOptions
    Repository, branch and folderWhere the detections live
    ModeInterval checks the branch every 15 minutes by default (5 to 1,440). Webhook plans on every push, checked against a webhook signing secret, and still checks hourly in case a delivery was lost. Manual plans only when you select Sync now or Sync to commit
    Apply clean plans automaticallyOff by default. When on, a plan applies by itself only if it has no compile errors, failing fixtures or conflicts

    Every other plan waits for an admin to review it, with a diff per rule, and apply or discard it. To roll back, Sync to commit pins the repository to an earlier commit and plans it.

    Export rules you wrote in the UI

    Security › Detection rules › Export, or Export to git on one rule, turns rules authored in the UI into repository files: a download, or one pull request on a connected GitHub repository (GitLab repositories export as files). After the merge, the next plan shows each exported rule as a conflict that replaces its UI rule; confirm it to hand the rule to Git.

    To get a published package back as files, run node tracix-detections.mjs export <package> <outdir>. Fixtures aren't stored in the workspace, so they aren't exported.

    Monitor and dashboard bundles

    A bundle is one JSON file that describes monitors, visualizations, dashboards and APM service groups.

    operations.json
    {
      "apiVersion": "tracix.io/v1",
      "package": "team-operations",
      "revision": "1.0.0",
      "resources": [
        {
          "kind": "monitor",
          "uid": "service-error-rate",
          "attributes": {
            "name": "Service error rate",
            "description": "Sustained server error ratio above 5 percent.",
            "templateId": "apm.error_rate",
            "enabled": false,
            "condition": "above",
            "thresholds": { "alert": 5, "warn": 2 },
            "windowMinutes": 15,
            "pendingForMinutes": 5,
            "noData": "last_known",
            "sharing": { "visibility": "team", "rbacFloor": "viewer" }
          },
          "tests": [
            { "name": "healthy", "value": 1, "expected": "ok" },
            { "name": "warning", "value": 3, "expected": "warn" },
            { "name": "alert", "value": 6, "expected": "alert" }
          ]
        }
      ]
    }
    FieldRules
    apiVersiontracix.io/v1
    packageA lowercase name of letters, digits, _, . and -, up to 128 characters, starting with a letter or digit
    revisionAny label up to 128 characters, such as a version or a commit
    resources1 to 500 objects
    resources[].kindmonitor, visualization, dashboard or service_group
    resources[].uidThe object's ID within the package, in the same form as package
    resources[].attributesThe object's definition, as the workspace stores it
    resources[].referencesData sources, visualizations or dashboards it depends on. @<uid> refers to an object of that kind in the same bundle
    resources[].testsMonitors only: threshold fixtures
    resources[].statepresent (the default) or absent

    Validation is strict: an unknown field fails, and a monitor value that would have to be converted or clamped fails instead of being adjusted. Detection content can't go in a bundle; it comes from a detection repository.

    Tests

    A value-threshold monitor can carry tests: a name, a numeric value, an optional currentLevel and the expected level (ok, warn or alert). Validation runs the real threshold logic, including recovery. Tests don't replay queries, pending periods, missing data timing, notifications or anomaly learning, so check those with real telemetry in a staging workspace.

    Delete and restore

    Leaving an object out of a bundle never deletes it. To delete one, keep it in the bundle with "state": "absent", plan and apply: the plan shows delete. Set it back to present to restore it. Apply writes visualizations before the dashboards that use them and deletes dashboards first, so delete or update the dashboards that reference a visualization in the same change.

    Publish a bundle

    Workspace admins only, for now

    Your workspace validates, plans, applies and exports bundles only for a signed-in workspace admin. API keys can't publish monitor and dashboard bundles yet, so you can't apply them from unattended CI today.

    An export captures each object's current definition and operational controls. It isn't a backup of your Git file: tests and comments aren't stored in the workspace.

    Next steps