Composer packages
Installing
To install packages, use composer require to include the package and resolve dependencies.
- Ahoy
- Docker Compose
ahoy composer require drupal/devel
docker compose exec cli composer require drupal/devel
By default, stable releases are installed. If you need a non-stable version (e.g., alpha, beta, RC), specify the version constraint explicitly:
- Ahoy
- Docker Compose
ahoy composer require drupal/devel:^1.0.0@beta
docker compose exec cli composer require drupal/devel:^1.0.0@beta
Make sure that the minimum-stability setting in composer.json is set to
the version constraint you need. For example, to allow alpha, beta, and RC versions:
{
"minimum-stability": "beta"
}
Adding JavaScript/CSS libraries (npm packages)
To install JavaScript or CSS libraries as Drupal libraries with Composer,
they must be defined as inline Composer packages.
The package type for inline packages must be drupal-library, as Drupal
treats these as libraries and places them into the web/libraries/ directory
where it expects all libraries to reside.
Do not use Asset Packagist to install front-end libraries. Unlike Drupal.org, which maintains the distribution of Composer packages with established security policies, Asset Packagist is a third-party service that lacks the safeguards needed to protect against supply chain attacks. Instead, define packages as inline Composer packages as shown below.
-
Define the package in
composer.jsonunder therepositoriessection:{"repositories": [{"type": "package","package": {"name": "gdsmith/jquery.easing","type": "drupal-library","version": "1.4.1","source": {"type": "git","url": "https://github.com/gdsmith/jquery.easing","reference": "1.4.1"}}}]} -
Require the package using Composer:
- Ahoy
- Docker Compose
ahoy composer require gdsmith/jquery.easing
docker compose exec cli composer require gdsmith/jquery.easing
Updating
To update all dependencies:
- Ahoy
- Docker Compose
ahoy composer update
docker compose exec cli composer update
If your project uses patches to modify dependencies, the update may fail if the patches are not compatible with the new versions of the dependencies.
A common solution is to remove the patches temporarily, run the update, and then reapply the patches one by one.
To update a specific package and its dependencies:
- Ahoy
- Docker Compose
ahoy composer update vendor/package-name --with-dependencies
docker compose exec cli composer update vendor/package-name --with-dependencies
For updating Drupal core, use:
- Ahoy
- Docker Compose
ahoy composer update "drupal/core-*" --with-dependencies
docker compose exec cli composer update "drupal/core-*" --with-dependencies
After updating core, review changes with git diff, especially modified scaffolding files like .htaccess, and commit them in a single commit.
Overriding paths
To override package installation paths, modify composer.json:
{
"extra": {
"installer-paths": {
"web/libraries/jquery-easing": [
"gdsmith/jquery.easing"
],
"web/libraries/{$name}": [
"type:drupal-library"
]
}
}
}
The first entry overrides the path for a specific package, placing it into a
custom directory name. The second entry is a catch-all that routes all
drupal-library type packages to web/libraries/{$name} by default.
Patching
Vortex uses cweagans/composer-patches v2.x for applying patches to Composer dependencies. Version 2.x uses git-based patching with git apply for better cross-platform consistency.
For official documentation, visit: Composer Patches Recommended Workflows
Understanding patches.lock.json
Composer Patches v2.x automatically generates a patches.lock.json file that contains:
- Patch metadata (URLs, descriptions, target packages)
- SHA-256 checksums for patch verification
This file must be committed to version control (like composer.lock).
Benefits:
- Ensures reproducible builds across teams and CI/CD environments
- Verifies patch integrity with checksums
- Prevents "works on my machine" issues with patches
- Makes the patch state explicit and trackable
Adding a new patch
-
Define the patch in
composer.jsonunderextra.patches:"extra": {"patches": {"drupal/foobar": {"Fix for issue #123": "https://www.drupal.org/files/issues/fix-123.patch"}}} -
Regenerate
patches.lock.json:
- Ahoy
- Docker Compose
ahoy composer patches-relock
docker compose exec cli composer patches-relock
- Remove and reinstall patched packages:
- Ahoy
- Docker Compose
ahoy composer patches-repatch
docker compose exec cli composer patches-repatch
composer patches-repatch removes patched dependencies from vendor/ and reinstalls them. Ensure you have no unsaved changes in those directories.
- Update
composer.lock:
- Ahoy
- Docker Compose
ahoy composer update --lock
docker compose exec cli composer update --lock
Removing a patch
-
Delete the patch definition from
composer.json -
Regenerate
patches.lock.json:
- Ahoy
- Docker Compose
ahoy composer patches-relock
docker compose exec cli composer patches-relock
- Manually delete the affected dependency:
- Ahoy
- Docker Compose
ahoy cli rm -rf vendor/drupal/foobar
docker compose exec cli rm -rf vendor/drupal/foobar
- Reinstall without the patch:
- Ahoy
- Docker Compose
ahoy composer patches-repatch
docker compose exec cli composer patches-repatch
- Update
composer.lock:
- Ahoy
- Docker Compose
ahoy composer update --lock
docker compose exec cli composer update --lock
Security auditing
Composer 2.10.0 introduced a unified config.policy setting that controls both security auditing (reporting known security vulnerabilities and abandoned packages) and version blocking (refusing to install or update affected packages). Vortex uses it to keep vulnerabilities visible without blocking day-to-day dependency work.
Configuration options
Configure the policy in your composer.json under the config section:
{
"config": {
"policy": {
"advisories": {
"block": false,
"audit": "fail"
},
"abandoned": {
"audit": "report"
}
}
}
}
Vortex sets the following values:
advisories.blocktofalse: security advisories do not blockcomposer install,composer update, orcomposer require, so builds and deployments stay reproducible even when a new advisory is published upstream against an existing dependency. (Composer's own default istrue.)advisories.audittofail: thecomposer auditcommand still fails when an advisory is found, keeping vulnerabilities visible locally and in CI.abandoned.audittoreport: abandoned packages are reported as warnings but do not fail the audit. (Composer's own default isfail.)
Each section accepts block (refuse affected versions during composer update/require/remove), audit (ignore, report, or fail for the composer audit command), and ignore/ignore-id/ignore-severity for assessed exceptions.
config.policy requires Composer 2.10 or newer, which ships in the Vortex container images. On older Composer versions, use the legacy config.audit keys (block-insecure, abandoned) instead - they continue to work as a fallback.
Why advisories do not block installation
Coupling installation to advisory publication makes builds non-deterministic: a newly published advisory against an already-installed dependency can fail every build - including work unrelated to security - until the advisory is assessed and ignored. Vortex decouples the two by setting advisories.block to false while keeping advisories.audit at fail, so installs and updates remain reproducible while vulnerabilities are still surfaced by composer audit and the CI lint job.
If your project requires installation to hard-stop on advisories - for example, a production site with strict supply-chain controls - set advisories.block to true.
Ignoring specific advisories
When you've assessed an advisory and determined it doesn't affect your project, add it to the ignore-id list with a reason:
{
"config": {
"policy": {
"advisories": {
"ignore-id": {
"CVE-2024-1234": "Component is not used in our implementation.",
"GHSA-xxxx-yyyy-zzzz": "Patched via custom security fix."
}
}
}
}
}
Record the reason for each ignored advisory in your Git commit message. This helps your team understand why a vulnerability was deemed acceptable and makes the decision easy to review later.
Running audit command
Check your dependencies for security issues manually:
- Ahoy
- Docker Compose
# Audit all installed packages
ahoy composer audit
# Audit only production dependencies (exclude dev)
ahoy composer audit --no-dev
# Audit packages from lock file (faster)
ahoy composer audit --locked
# Control abandoned package behavior
ahoy composer audit --abandoned=ignore # Skip abandoned packages
ahoy composer audit --abandoned=report # Show but don't fail
# Audit all installed packages
docker compose exec cli composer audit
# Audit only production dependencies (exclude dev)
docker compose exec cli composer audit --no-dev
# Audit packages from lock file (faster)
docker compose exec cli composer audit --locked
# Control abandoned package behavior
docker compose exec cli composer audit --abandoned=ignore # Skip abandoned packages
docker compose exec cli composer audit --abandoned=report # Show but don't fail
CI/CD integration
Vortex runs composer audit as part of the CI lint job. Because advisories.audit is fail, the audit reports vulnerabilities and the lint job fails when any are found - even though installs and updates are not blocked.
By default that failure gates the build. Set the repository variable VORTEX_CI_COMPOSER_AUDIT_IGNORE_FAILURE to 1 to make the audit step run and report without failing the build - useful as a one-off bypass while a known advisory is being addressed.