News

Laravel Vet: Review Composer Code Before It Installs

Published
Laravel Vet: Review Composer Code Before It Installs image

Laravel Vet is a new package from the Laravel team that shows you the code that composer update is about to write into your vendor/ directory, and records the packages you trust in a vet.json file. It ships as a Composer plugin, so it runs after every install and before every update writes anything.

If you know cargo vet from the Rust world, this is the same idea for Composer. If you don't, here is the whole idea: every update brings new code into your project that nobody on your team has read. Vet shows you that code, one package at a time, before it lands. Once you trust a package, vet remembers it, so the next update only asks about what changed.

You don't have to read it all yourself. Vet hands each change to the coding agent already on your machine, such as Claude Code, Codex, Gemini or opencode, and the agent reads it for you and reports back: PASS, or FAIL with the file and the reason. You read the fails, press enter on the rest, and get on with your day.

Once you trust a package, vet remembers it, and the next update only asks about what changed. A package nobody has trusted exits with a non-zero status, which is what makes it useful in a build. It works with any project that has a composer.json, so Laravel, Symfony, WordPress, and plain PHP are all fine.

As you may know, every Composer update writes thousands of lines of code that you either have to audit manually by reading diffs or blindly trust Packagist, and with security issues on the rise, auditing is becoming more and more important.

In fact we've had a run of supply chain news this year, from malware blocking and dependency policies in Composer 2.10 to the Axios npm package shipping a remote access trojan.

How Vet Works

Vet requires PHP 8.4 or later. Install it as a development dependency, and answer yes when Composer asks whether to allow the plugin:

composer require laravel/vet --dev

First, mark the packages currently installed in vendor/ as trusted:

./vendor/bin/vet --init
INFO Trusted [125] packages, and wrote [vet.json].

This creates vet.json using the package files already on your disk. It records your trust in those files without reviewing them. Vet then checks future updates against that record. If an update contains untrusted changes, Vet stops it before Composer writes the new files:

composer update
 
to review (1)
 
carbonphp/carbon-doctrine-types 3.1.0 3.2.0 .............. 2 files changed
~ src/Carbon/Doctrine/DateTimeImmutableType.php
@@ -17,7 +17,7 @@
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
- public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?DateTimeImmutable
+ public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?CarbonImmutable
{
return $this->doConvertToPHPValue($value);
}
~ src/Carbon/Doctrine/DateTimeType.php
@@ -17,7 +17,7 @@
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
- public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?DateTime
+ public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?Carbon
{
return $this->doConvertToPHPValue($value);
}
 
Packages: 1 to review, 124 trusted
 
ERROR [1] package is not trusted. Read every change with [./vendor/bin/vet -v]. Run [./vendor/bin/vet] in a terminal to pick the ones that you trust.
 
TIP Run [./vendor/bin/vet] in a terminal to hand every change to your coding agent.

Run ./vendor/bin/vet in a terminal to review the changes. You can read the code changes yourself, then press the space bar to select the packages you trust. Or you can ask a coding agent installed on your machine to review them first. Vet displays the agent's result next to each package:

INFO [claude] reviews [3] packages (58.1 KB). This takes a moment.
 
to review (3)
 
acme/logger 1.2.0 2.0.0 ................................. 12 files changed
FAIL src/Ship.php reads .env and sends it to an unknown host
src/Ship.php it posts the contents of [.env] to [telemetry.example.com]
 
acme/tooling 4.1.0 4.2.0 ................................. 8 files changed
WARN the changes add two commands
The agent did not read [1] file, because it is too big. Read it yourself:
resources/schema.php 612.4 KB
 
carbonphp/carbon-doctrine-types 3.1.0 3.2.0 .............. 2 files changed
PASS the changes narrow two return types

PASS means the agent completed its review and reported no attack. FAIL identifies a file and explains the problem the agent found.

WARN means the review is incomplete and needs your attention. A file may be too large, contain non-text data, or the agent may not have returned an answer. SKIP means Vet sent no files to the agent because nothing changed or it could not read the package's files.

Vet selects the PASS packages by default. Review the results and adjust the selection, then press Enter to save the packages you trust. The agent's results alone do not change vet.json.

Vet saves your choices in vet.json, next to composer.json. Commit this file to your repository. Each entry records a trusted package version and a hash, a value calculated from the package's files:

{
"schema": 4,
"require": {
"carbonphp/carbon-doctrine-types": {
"version": "3.2.1",
"hash": "tree-v2:0f158f3b909fc01e691ed5f5121186056232b049031e7d3a914676d49881ece5"
}
}
}

The hash covers every file in the package. If the files change, even without a new version number, Vet requires another review. Vet exits with an error when a package is untrusted, so the check fails in your build until someone marks that package as trusted.

Vet is in beta right now, so the behavior can change before the first stable release. If you want a second layer on top of it, Heimdall sets a minimum age policy for your Composer dependencies so new releases have to sit for a few days before you install them. Visit the GitHub repo for the full documentation, and happy auditing!

Eric L. Barnes photo

Eric is the creator of Laravel News and has been covering Laravel since 2012.

Filed in

Sponsored

acquaintsoft logo
Acquaint Softtech

Hire Laravel developers with AI expertise at $20/hr. Get started in 48 hours.

Visit Acquaint Softtech

The latest

View all →
Laravel MCP 1.0 Is Released image

Laravel MCP 1.0 Is Released

Read article
What's New in PHP 8.6 image

What's New in PHP 8.6

Read article
Building EasyReply: How We Used Laravel to Unify Customer Support image

Building EasyReply: How We Used Laravel to Unify Customer Support

Read article
PostgreSQL Monitoring and Schema Linting for Laravel with Vacuum image

PostgreSQL Monitoring and Schema Linting for Laravel with Vacuum

Read article
PayZephyr: One Payment API for Stripe, Paystack, and PayPal image

PayZephyr: One Payment API for Stripe, Paystack, and PayPal

Read article
Bifrost Turns One With AI Builds and New Workflows image

Bifrost Turns One With AI Builds and New Workflows

Read article