tutorial

How to Monitor mix_audit with Vigilmon

mix_audit scans Elixir projects for Hex dependencies with known CVEs. Learn how to integrate mix_audit into your CI pipeline and use Vigilmon heartbeats to ensure your vulnerability scans never silently stop running.

mix_audit is a Mix task that audits Hex packages in your Elixir project against the Elixir security advisories database, flagging dependencies with known CVEs or vulnerabilities. It is a critical line of defence in your CI pipeline — but like any scheduled or CI-triggered process, it can stop running silently: a broken CI configuration, a skipped pipeline step, or a task that always exits zero even when the advisory database is unreachable. Vigilmon lets you verify that your security scans are actually completing, so you never discover a vulnerability gap after a breach.

What You'll Set Up

  • Cron heartbeat confirming mix_audit runs complete successfully on your scheduled cadence
  • CI pipeline health check via Vigilmon HTTP monitor
  • Alert routing so security failures reach the right people
  • SSL certificate monitoring for the advisory database endpoint

Prerequisites

  • Elixir 1.14+ with mix_audit in your mix.exs dev/test dependencies
  • A CI system (GitHub Actions, GitLab CI, or similar)
  • A free Vigilmon account

Step 1: Add mix_audit to Your Project

# mix.exs
defp deps do
  [
    {:mix_audit, "~> 2.1", only: [:dev, :test], runtime: false},
    # ... other deps
  ]
end
mix deps.get
mix deps.audit

A passing audit exits 0; a failing audit (dependencies with known CVEs) exits non-zero. Run it as part of your standard CI check:

# Verify it works
mix deps.audit
# No vulnerable packages found

Step 2: Set Up a Vigilmon Cron Heartbeat for Your Audit Schedule

The critical gap in most security tooling is that nobody notices when the scan stops running. CI pipelines get disabled, scheduled jobs get removed, and months pass without audits. A Vigilmon heartbeat closes that gap.

Create a heartbeat monitor:

  1. In Vigilmon, click Add MonitorCron Heartbeat.
  2. Set Expected ping interval to match your audit schedule:
    • Daily audits: 1440 minutes (24 hours)
    • Weekly audits: 10080 minutes (7 days)
    • Per-PR audits: set conservatively at 1440 minutes (daily) to catch abandoned pipelines
  3. Copy the heartbeat URL (e.g. https://vigilmon.online/heartbeat/abc123).
  4. Set the VIGILMON_AUDIT_HEARTBEAT_URL environment variable in your CI system.

Step 3: Integrate the Heartbeat Ping Into Your CI Pipeline

GitHub Actions

# .github/workflows/security.yml
name: Security Audit

on:
  schedule:
    - cron: '0 6 * * *'   # daily at 06:00 UTC
  push:
    branches: [main]
  pull_request:

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Elixir
        uses: erlef/setup-beam@v1
        with:
          elixir-version: '1.16'
          otp-version: '26'

      - name: Install dependencies
        run: mix deps.get

      - name: Run mix_audit
        run: mix deps.audit

      - name: Ping Vigilmon heartbeat
        if: success() && github.ref == 'refs/heads/main'
        run: |
          curl -fsS "${{ secrets.VIGILMON_AUDIT_HEARTBEAT_URL }}" > /dev/null

The if: success() condition ensures the heartbeat is only pinged when the audit passes. The github.ref filter ensures only main-branch runs count toward the heartbeat — PR runs verify the code but should not reset the heartbeat timer.

GitLab CI

# .gitlab-ci.yml
security_audit:
  stage: test
  image: elixir:1.16
  only:
    - schedules
    - main
  script:
    - mix local.hex --force
    - mix deps.get
    - mix deps.audit
    - |
      if [ "$CI_PIPELINE_SOURCE" = "schedule" ] || [ "$CI_COMMIT_BRANCH" = "main" ]; then
        curl -fsS "$VIGILMON_AUDIT_HEARTBEAT_URL" > /dev/null
      fi

Step 4: Make mix_audit Failures Actionable in CI

By default, mix deps.audit prints a list of vulnerable packages and exits non-zero. To make output more actionable in CI, use the JSON format and parse it:

# Generate machine-readable output
mix deps.audit --format json > audit_result.json 2>&1 || true

# Check for vulnerabilities
VULN_COUNT=$(jq '.vulnerabilities | length' audit_result.json 2>/dev/null || echo "0")

if [ "$VULN_COUNT" -gt "0" ]; then
  echo "::error ::mix_audit found $VULN_COUNT vulnerable dependencies"
  jq -r '.vulnerabilities[] | "  \(.package)@\(.version): \(.advisory.title)"' audit_result.json
  exit 1
fi

# Only ping heartbeat on clean audit
curl -fsS "$VIGILMON_AUDIT_HEARTBEAT_URL" > /dev/null

This approach gives you both a structured exit code (for CI) and a clear Vigilmon signal (heartbeat only on clean pass). If you want to alert on vulnerabilities even when CI is configured to allow the build to pass, add a second webhook notification step.


Step 5: Add an HTTP Monitor for Your CI Status API

If your CI system exposes a status API (GitHub, GitLab, Buildkite all do), add a Vigilmon HTTP monitor pointing at your pipeline's last-run status. This gives you a second signal beyond the heartbeat:

GitHub Actions via GitHub API:

  1. Click Add MonitorHTTP / HTTPS.
  2. Enter the workflow runs API URL:
    https://api.github.com/repos/YOUR_ORG/YOUR_REPO/actions/workflows/security.yml/runs?per_page=1&branch=main
    
  3. Add an Authorization header with a GitHub personal access token.
  4. Under Response body, enable Contains keyword and enter "completed".
  5. Set Check interval to 60 minutes.

This monitor alerts if no completed run appears in the last hour — a signal that the CI schedule is broken before the heartbeat window has even expired.


Step 6: SSL Certificate Monitoring for the Advisory Database

mix_audit fetches the advisory database from hex.pm's security endpoint. If that endpoint's certificate expires or becomes unreachable, mix deps.audit will fail with a TLS error rather than a clean advisory report. Add certificate monitoring so you know before your CI starts failing with cryptic SSL errors:

  1. Click Add MonitorHTTP / HTTPS.
  2. Enter https://hex.pm.
  3. Enable Monitor SSL certificate.
  4. Set Alert when certificate expires in less than 14 days.
  5. Click Save.

This is an external dependency you don't control — but knowing about it early gives you time to investigate or work around it.


Step 7: Configure Alert Channels

Security alerts warrant their own routing:

  1. Go to Alert Channels in Vigilmon.
  2. Add a dedicated Slack channel for security alerts (e.g. #security-alerts) separate from your general uptime alerts.
  3. Add email to reach the security or platform team directly.
  4. Set Consecutive failures before alert to 1 for the heartbeat monitor — a single missed audit heartbeat is always a real concern.

Use Maintenance windows when you intentionally pause the CI schedule (e.g. over a holiday freeze):

curl -X POST https://vigilmon.online/api/maintenance \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "monitor_id": "audit-heartbeat-id",
    "duration_minutes": 4320,
    "reason": "Holiday CI freeze"
  }'

Handling False Positives: Ignoring Known Advisories

If an advisory applies to a dependency you've assessed and accepted, ignore it rather than disabling the audit entirely:

# mix.exs — ignored advisories
def project do
  [
    # ...
    deps_audit_ignored_advisories: [
      # Advisory ID from https://github.com/dependabot/advisory-database
      "GHSA-xxxx-xxxx-xxxx"
    ]
  ]
end

With explicit ignores in place, mix deps.audit still exits 0 and pings Vigilmon — confirming the scan ran cleanly rather than the advisory list just being empty.


Summary

| Monitor | Target | What It Catches | |---|---|---| | Cron heartbeat | Heartbeat URL after clean audit | Silent CI failure, missed scan schedule, audit errors | | GitHub Actions HTTP | Workflow runs API | Broken CI schedule before heartbeat window expires | | SSL certificate | https://hex.pm | TLS errors causing advisory fetch failures |

mix_audit is only useful when it runs. Vigilmon's heartbeat monitoring ensures you always know when it stops — giving you a continuous guarantee that your dependency vulnerability scanning is active, not just configured.

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →