Skip to content

Conversation

@lcatlett
Copy link
Member

When installing plugins via terminus plugin:install using PHP 8.3 and Composer 2.9.1+, the installation fails due to Composer security advisories even when the user explicitly sets COMPOSER_AUDIT_BLOCK_INSECURE=0.

The issue is that Terminus was not forwarding environment variables (specifically COMPOSER_AUDIT_BLOCK_INSECURE) to the Composer subprocess used during plugin installation. As a result, Composer's security audit system would block installations of plugins with known security advisories in their dependencies, even when users explicitly opted out.

Example Error

Error executing command "composer require ...":
Your requirements could not be resolved to an installable set of packages.

Problem 1
  - Root composer.json requires symfony/process v5.4.40 (exact version match),
    found symfony/process[v5.4.40] but these were not loaded, because they are
    affected by security advisories. To ignore the advisories, add
    ("PKSA-wws7-mr54-jsny") to the audit "ignore" config. To turn the feature
    off entirely, you can set "block-insecure" to false in your "audit" config.

Solution

This PR implements environment variable forwarding in LocalMachineHelper::getProcess() to ensure that:

  1. Composer-related environment variables are automatically forwarded - Including COMPOSER_AUDIT_BLOCK_INSECURE, COMPOSER_ALLOW_SUPERUSER, COMPOSER_MEMORY_LIMIT, etc.
  2. TERMINUS_FORWARD_ENV support - Users can forward additional environment variables via TERMINUS_FORWARD_ENV=VAR1,VAR2
  3. Applies to all commands - The fix is in LocalMachineHelper, so it applies to plugin install, update, and any other command that uses this helper

Key Changes

  • src/Helpers/LocalMachineHelper.php:

    • Modified getProcess() to forward environment variables to subprocesses
    • Added getForwardedEnvironment() method that collects and returns env vars to forward
    • Automatically forwards Composer-related env vars if they are set
    • Supports TERMINUS_FORWARD_ENV for additional variables
  • Test Infrastructure:

    • Added tests/unit_tests/TerminusTestCase.php - Base test case class
    • Added tests/unit_tests/bootstrap.php - Bootstrap for unit tests
    • Added phpunit.unit.xml - Separate PHPUnit config for unit tests
    • Updated composer.json to include unit test scripts and autoload config
  • Tests:

    • Unit tests (tests/unit_tests/Plugins/PluginEnvForwardingTest.php): 5 test cases verifying env forwarding logic
    • Functional test (tests/Functional/PluginManagerCommandsTest.php::testPluginInstallRespectsComposerAuditBlockInsecureEnv): End-to-end test using terminus-build-tools-plugin (which has known security advisories)

Testing

Automated Tests

  • ✅ All unit tests pass (5 tests, 10 assertions)
  • ✅ Functional test verifies end-to-end behavior with a plugin that has security advisories

Manual Validation

To validate the fix manually:

# Set up environment
brew unlink php
brew link php@8.3

# Uninstall plugin if it exists
terminus plugin:uninstall terminus-build-tools-plugin

# Verify versions
php -v  # Should show PHP 8.3
composer --version  # Should show Composer 2.9.1+
terminus --version

# Reload plugins
terminus plugin:reload

# Test the fix - this should now succeed
export COMPOSER_AUDIT_BLOCK_INSECURE=0
terminus plugin:install terminus-build-tools-plugin

Expected Result: Plugin installation succeeds without security advisory blocking errors.

Without the fix: Installation fails with Composer security advisory errors.

Implementation Details

The fix works by:

  1. Collecting environment variables that should be forwarded (Composer vars + TERMINUS_FORWARD_ENV)
  2. Merging them with the current process environment
  3. Setting the merged environment on the Symfony Process object before execution

This ensures that when Composer runs as a subprocess, it sees the same environment variables that the parent Terminus process sees, allowing users to control Composer's behavior via environment variables.

Notes

  • I did not globally disable Composer audit intentionally so that we are only respecting explicit user instructions via environment variables
  • The fix applies to all commands using LocalMachineHelper, not just plugin installation
  • Backward compatible - if no env vars are set, behavior is unchanged

Related

  • Composer 2.9.1+ introduced stricter security audit blocking behavior
  • This fix ensures Terminus respects user overrides for Composer's audit system

…oser subprocess

This fixes a bug where COMPOSER_AUDIT_BLOCK_INSECURE=0 (and other
Composer-related environment variables) were not being forwarded to
Composer subprocesses during plugin installation, causing installations
to fail with security advisory errors even when users explicitly opted
out via environment variables.

Changes:
- Modified LocalMachineHelper::getProcess() to forward environment
  variables to subprocesses
- Added getForwardedEnvironment() method that:
  * Automatically forwards Composer-related environment variables
    (COMPOSER_AUDIT_BLOCK_INSECURE, COMPOSER_ALLOW_SUPERUSER, etc.)
  * Supports TERMINUS_FORWARD_ENV for forwarding additional variables
- Added unit tests (PluginEnvForwardingTest) to verify env forwarding
- Added functional test using terminus-build-tools-plugin (which has
  known security advisories) to verify end-to-end behavior
- Set up unit test infrastructure (TerminusTestCase, phpunit.unit.xml,
  autoload config)

This fix applies to all commands that use LocalMachineHelper, ensuring
consistent behavior across plugin install, update, and other operations.

Fixes: [Issue number if applicable]
Related: Composer 2.9.1+ security audit blocking behavior
@lcatlett lcatlett requested a review from a team as a code owner November 14, 2025 18:50
@greg-1-anderson
Copy link
Member

Security vulnerabilities in Terminus are typically not an issue. Rather than forwarding COMPOSER_AUDIT_BLOCK_INSECURE, should we just disable auditing for Composer plugins?

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.

3 participants