Skip to content

Add Composer scanner for PHP projects - #38

Merged
gr-markin merged 9 commits into
mainfrom
feature/composer-scan
Oct 1, 2026
Merged

gr-markin merged 9 commits into
mainfrom
feature/composer-scan

Conversation

@jthDEV

@jthDEV jthDEV commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Why

PHP support used to live in the standalone Composer plugin eacg-gmbh/ecs-composer, which posted scans directly to the ECS API. Since ts-scan became the entry point for all ecosystems, that plugin is no longer usable. This brings PHP back as a regular ts-scan scanner, so Composer projects flow through the same scan → check / analyse / upload paths as every other ecosystem.

What

A new ComposerScanner in src/ts_scan/pm/composer.py:

  • detects a project by its composer.json and resolves the dependency graph from composer.lock — a committed lockfile needs neither a Composer installation nor network access
  • without a lockfile, runs composer update --no-install --no-scripts; if that fails or Composer is missing, falls back to the requirements declared in composer.json (reported without resolved versions) instead of aborting the scan
  • resolves provide / replace, so virtual requirements such as psr/log-implementation attach to the package that satisfies them
  • carries over dist.shasum, source.reference, licenses, homepage and description, and warns about abandoned packages
  • records vendor/<vendor>/<package> as package_files, so the in-depth analysis picks up installed sources
  • guards against cyclic requirements and attaches each package once, even when several requirements resolve to it

Carried over from ecs-composer

  • the component key composer:vendor/name, so existing TrustSource components keep matching
  • the platform package table from PlatformPackage.php — php / ext-* → PHP-3.01, composer-plugin-api / composer-runtime-api → MIT, including their homepage and repository URLs

Identity

Dependencies export as spec conformant purls, e.g. pkg:composer/monolog/monolog@3.5.0. The module id deliberately carries no version (composer:acme/inventory-app), so module level mutes and exemptions survive version bumps.

Options

Option Effect
--composer:includeDevDependencies include require-dev and packages-dev
--composer:includePlatformPackages include php, ext-*, lib-*, composer-* with their licenses
--composer:enableMetadataRetrieval enrich packages from the Packagist registry

plus the inherited --composer:ignore, --composer:executable and --composer:forward.

Tests

examples/composer/ ships a committed lockfile covering transitive requirements, provide, an abandoned package, dev dependencies and platform requirements. tests/test_composer.py adds 12 regression tests; the full suite is green (52 passed).

Limitations

  • PHP and Composer are not installed on the machine this was developed on, so the lockfile generation path is covered by a mocked executable only, not against a real Composer run. Worth one manual check against a real project before release.
  • Platform packages carry their declared constraint (>=8.1), not a resolved runtime version — the lockfile does not contain one, and the scanning machine's PHP version would be misleading.
  • pkg:composer/php is a pragmatic purl; purl has no PHP runtime type. It intentionally does not match anything on Packagist.

Note for reviewers

feature/cocoapods-scan and feature/swift-package-manager-scan touch the same three lines (scanner registry, README ecosystem list, CHANGELOG) and will need a rebase after this lands.

🤖 Generated with Claude Code

Restores PHP support that was previously covered by the standalone
eacg-gmbh/ecs-composer Composer plugin, this time as a regular ts-scan
package manager scanner.

The scanner detects a project by its composer.json and resolves the
dependency graph from composer.lock, so a committed lockfile needs
neither a Composer installation nor network access. Without a lockfile
ts-scan runs "composer update --no-install" and falls back to the
requirements declared in composer.json if that is not possible.

Carried over from ecs-composer:
  * the component key "composer:vendor/name", so existing TrustSource
    components keep matching
  * the platform package metadata (php, ext-*, composer-*) including
    their well-known licenses

Dependencies are exported with spec conformant purls of the form
pkg:composer/vendor/name@version. The module id deliberately carries no
version, so module level mutes survive version bumps.

New options:
  * --composer:includeDevDependencies
  * --composer:includePlatformPackages
  * --composer:enableMetadataRetrieval

Includes an example project with a committed lockfile and regression
tests covering transitive requirements, provide/replace resolution,
abandoned packages, cyclic requirements and the lockfile fallbacks.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@github-advanced-security github-advanced-security AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bandit found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

This was referenced Sep 22, 2026
@gr-markin

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Copilot AI and others added 8 commits September 28, 2026 12:11
Co-authored-by: gr-markin <2349286+gr-markin@users.noreply.github.com>
Co-authored-by: gr-markin <2349286+gr-markin@users.noreply.github.com>
Co-authored-by: gr-markin <2349286+gr-markin@users.noreply.github.com>
Co-authored-by: gr-markin <2349286+gr-markin@users.noreply.github.com>
Co-authored-by: gr-markin <2349286+gr-markin@users.noreply.github.com>
Co-authored-by: gr-markin <2349286+gr-markin@users.noreply.github.com>
Co-authored-by: gr-markin <2349286+gr-markin@users.noreply.github.com>
Co-authored-by: gr-markin <2349286+gr-markin@users.noreply.github.com>

Copilot AI commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Resolved and pushed in 410a8f4. I merged main, fixed all conflict markers in CHANGELOG.md, README.md, and src/ts_scan/__init__.py, and validated with targeted scanner tests.

@gr-markin
gr-markin merged commit 836b7b0 into main Oct 1, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants