Laravel Agent

NoDisrupt can tell from the outside that a site is a Laravel application, but it cannot tell which version of Laravel or which Composer packages it is running - a Laravel app exposes no version header, generator tag or feed. And on managed hosting such as Laravel Cloud, Vapor or Forge there is no server to install the host agent on.

The Laravel agent closes that gap. It is a small Composer package that runs inside your app, reads what Composer actually installed, and reports the package list to NoDisrupt - once shortly after the app starts, and then daily. Each package is matched against known vulnerability advisories, and anything affected shows up on the monitor's vulnerabilities view. No host access is required.

How it works

  • NoDisrupt's remote check fingerprints the site as Laravel (passively, from the response it already fetches) and creates one unversioned Laravel component.
  • The agent supplies the detail the outside world cannot see: the name and resolved version of every installed Composer package.
  • It sends that inventory shortly after the app boots and then on your app's own scheduler, so there is no inbound connection to open and no credentials for NoDisrupt to hold.

Requirements

  • Laravel 10, 11, 12 or 13, on PHP 8.1 or newer.
  • The app's scheduler running - php artisan schedule:run every minute, or your platform's scheduler. On Laravel Cloud and Vapor this is on by default.
  • Outbound HTTPS access to api.production.nodisrupt.com.

Install

composer require nodisrupt/laravel-agent

The package self-registers through Laravel's package discovery - there is no service provider to add by hand.

Next, generate a key in NoDisrupt under Monitor -> Vulnerabilities -> Add the package, and set the two values it gives you in your environment:

NODISRUPT_KEY=your-key
NODISRUPT_MONITOR_ID=your-monitor-id
Warning

NODISRUPT_KEY is a live credential. On Laravel Cloud, Vapor or Forge, set it in the platform's environment settings - don't commit it to your repository or bake it into a Docker image.

That is the whole setup. The agent reports on its own shortly after the app next serves a request (so a fresh install or deploy shows up in seconds), and then daily; nothing else needs wiring up. The boot report runs after the response is sent, so it never slows a request, and is throttled to at most once per deploy.

Report now

You do not normally need to - installing or deploying triggers the first report. To send one immediately, to confirm the setup or after changing dependencies, run:

php artisan nodisrupt:report-inventory

A successful run prints NoDisrupt: dependency inventory reported. If the key or monitor id is missing it prints a warning instead and sends nothing (see Troubleshooting).

Configuration

The defaults suit most apps. To change the reporting cadence, publish the config file:

php artisan vendor:publish --tag=nodisrupt-config

This writes config/nodisrupt.php, which reads the following environment values:

  • NODISRUPT_KEY - the per-monitor credential minted in NoDisrupt. Required.
  • NODISRUPT_MONITOR_ID - the id of the monitor the inventory is attached to. Required.
  • NODISRUPT_API_BASE - the API endpoint the agent reports to. Defaults to https://api.production.nodisrupt.com.
  • NODISRUPT_SCHEDULE - how often the scheduled report runs: hourly, twiceDaily, daily or weekly. Defaults to daily; an unrecognised value falls back to daily so a typo can't silently stop reporting.
  • NODISRUPT_REPORT_ON_BOOT - whether to also report shortly after the app boots (throttled to at most once per deploy). Defaults to true; set it false to rely on the schedule alone. Uses your cache store for the throttle.
Tip

Daily is the right cadence for almost everyone - a dependency list only changes when you deploy. Reach for hourly only if you deploy many times a day and want new packages matched sooner.

What it sends

On each run the agent reads Composer's runtime InstalledVersions and posts the name and resolved version of every installed package, with development dependencies flagged. Versions are normalised (a leading v is stripped) and the list is de-duplicated and sorted.

That is all it sends. No source code, no environment variables, no secrets - only the package-and-version list needed to match against advisories.

It is a single POST to NODISRUPT_API_BASE/v1/agent/inventory, authenticated with the key in an X-Agent-Authorization header:

{
  "monitorId": 4821,
  "ecosystem": "composer",
  "packages": [
    { "name": "laravel/framework", "version": "11.9.2", "dev": false },
    { "name": "guzzlehttp/guzzle", "version": "7.8.1", "dev": false },
    { "name": "phpunit/phpunit", "version": "11.2.5", "dev": true }
  ]
}

Troubleshooting

"inventory not reported" when you run the command

The key or monitor id isn't set, or isn't visible to the process running the command. Confirm NODISRUPT_KEY and NODISRUPT_MONITOR_ID are present in the environment - on Laravel Cloud, Vapor or Forge, set them in the platform's dashboard and redeploy so the running app picks them up.

No data appears after installing

The scheduled report only runs if the app's scheduler is running. Check the command is registered with php artisan schedule:list - you should see nodisrupt:report-inventory - and that php artisan schedule:run is wired to cron (or that your platform's scheduler is enabled). To confirm the agent itself works, run php artisan nodisrupt:report-inventory by hand.

The report sends but the monitor shows nothing matched

That is the healthy case - it means none of your installed packages match a known advisory. New advisories are matched against your latest reported inventory as they are published, so a clean result today can change without you reporting again.

Uninstall

Remove the package and delete the two environment values:

composer remove nodisrupt/laravel-agent

The remote Laravel fingerprint stays in place; only the Composer inventory stops being reported.