Skip to content

Composer crawler ignores a vendor-dir set in the global Composer config, so scan -g and agent scans report "No packages found" and leave installs unpatched #439

Description

[agent] Found by the scheduled Composer bug-hunt routine (ledger #321).

Summary

Composer resolves vendor-dir through its config cascade: COMPOSER_VENDOR_DIR, then the project's composer.json config.vendor-dir, then the user-level $COMPOSER_HOME/config.json. The socket-patch Composer crawler follows only part of that cascade, so real installs go undiscovered:

  1. Global (-g): get_vendor_paths hardcodes $COMPOSER_HOME/vendor (crates/socket-patch-core/src/crawlers/composer_crawler.rs:52-64). If the global project sets config.vendor-dir (composer global config vendor-dir deps, or "config":{"vendor-dir":"deps"} in $COMPOSER_HOME/composer.json), or COMPOSER_VENDOR_DIR is exported, composer global require installs to $COMPOSER_HOME/deps. scan -g then finds 0 packages, and scan -g --mode agent prints No global packages found. with exit 0.
  2. Local (agent mode): resolve_local_vendor_dir (composer_crawler.rs:473-492) reads COMPOSER_VENDOR_DIR and the project composer.json, but not the user-level $COMPOSER_HOME/config.json. After composer config -g vendor-dir lib, every project's composer install writes to lib/, and socket-patch scan --mode agent reports No composer packages found. (exit 0) while the package stays unpatched.

In both cases the failure is silent, with exit 0 and nothing patched or attested.

Repro (Linux; Composer 2.8.12, mock patch API, local path-repo package acme/[email protected])

# 1. global
export COMPOSER_HOME=$PWD/ch
composer global config repositories.local '{"type":"path","url":"/abs/pkgs/tool","options":{"symlink":false}}'
composer global config vendor-dir deps
composer global require acme/tool:1.0.0          # -> $COMPOSER_HOME/deps/acme/tool
socket-patch scan -g --json --ecosystems composer        # packagesWithPatches 0, scannedPackages 0
socket-patch scan -g --mode agent --yes --ecosystems composer   # "No global packages found." exit 0
socket-patch scan --global-prefix "$COMPOSER_HOME/deps" --json --ecosystems composer   # finds 1 (workaround)

# 2. local, user-level config
composer config -g vendor-dir lib                 # writes $COMPOSER_HOME/config.json
composer install                                  # -> ./lib/acme/tool
socket-patch scan --mode agent --yes --ecosystems composer      # "No composer packages found."

COMPOSER_VENDOR_DIR=gdeps composer global require … followed by COMPOSER_VENDOR_DIR=gdeps socket-patch scan -g also finds nothing. Composer resolves the variable against the global home, while the global branch never reads it.

Expected vs actual

  • Expected: CLI_CONTRACT.md --global: "Operate on globally-installed packages". The crawler's local-mode doc promises COMPOSER_VENDOR_DIR / config.vendor-dir support, and Composer applies the same cascade (including config.json) to the global project and to every local one. The maintainer requirement for -g is that none may be missing.
  • Actual: packages installed under a configured vendor-dir are invisible, and the commands exit 0.

OS × version

OS Composer global vendor-dir → scan -g / apply -g user config.json vendor-dir → local agent scan
Linux (local) 1.10.28, 2.2.30, 2.8.12, 2.10.3 (PHP 8.3) fail (each run twice) fail (2.8.12, twice)
ubuntu-latest 1.10.28, 2.2.30, 2.10.3 fail untested
macos-latest 1.10.28, 2.2.30, 2.10.3 fail untested
windows-latest 1.10.28, 2.2.30, 2.10.3 fail untested

The default vendor/ layout passes everywhere except Windows, where default-home discovery is broken separately (#438).

Probe runs: https://github.com/SocketDev/socket-patch/actions/runs/36823671080 and https://github.com/SocketDev/socket-patch/actions/runs/36827949605

First bad version

Not a regression. It reproduces identically with the v4.0.0 release binary (both cases: 0 scanned).

Suspect code

  • crates/socket-patch-core/src/crawlers/composer_crawler.rs:52-64 (global: composer_home.join("vendor"))
  • crates/socket-patch-core/src/crawlers/composer_crawler.rs:473-492 (local: no $COMPOSER_HOME/config.json layer)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions