> ## Documentation Index
> Fetch the complete documentation index at: https://docs.root.io/llms.txt
> Use this file to discover all available pages before exploring further.

# PHP - Composer (Beta)

> Configure Composer to use Root Library Catalog for secure PHP packages.

<Note>
  **Beta.** Composer support is actively maintained but may have rough edges. Report issues at [github.com/rootio-avr/rootio\_patcher](https://github.com/rootio-avr/rootio_patcher/issues).
</Note>

Root Library Catalog supports PHP projects managed with Composer. Patched packages are published to `pkg.root.io/composer/` as a Composer repository and consumed via the Root Patcher CLI, which rewrites your `composer.json` and runs `composer update` to apply the patches.

## Prerequisites

The Root Patcher CLI (`rootio_patcher`) is required to analyze your dependencies and apply patches. Install it before configuring your project.

```bash theme={null}
# macOS (Apple Silicon)
curl -sL https://github.com/rootio-avr/rootio_patcher/releases/latest/download/rootio_patcher_darwin_arm64.tar.gz | tar xz
chmod +x rootio_patcher && sudo mv rootio_patcher /usr/local/bin/

# Linux (x86_64)
curl -sL https://github.com/rootio-avr/rootio_patcher/releases/latest/download/rootio_patcher_linux_x86_64.tar.gz | tar xz
chmod +x rootio_patcher && sudo mv rootio_patcher /usr/local/bin/
```

For macOS Intel and Windows, see the [full installation instructions](/rlc/patcher#installation).

Then set your API key:

```bash theme={null}
export ROOTIO_API_KEY="your-api-key-here"
```

<Note>
  **`composer.lock` must exist before running the patcher.** If it is missing, run `composer install` first. The patcher reads exact resolved versions from the lock file to determine what is installed.
</Note>

## How Composer patching works

The patcher uses **pre-install patching**:

1. Reads exact resolved versions from `composer.lock`
2. Queries Root's API for available patches
3. Updates `composer.json` — direct dependencies have their version constraint updated in place; transitive dependencies are explicitly pinned in `require`
4. Adds the Root Composer repository entry (`pkg.root.io/composer/`) permanently to `composer.json`
5. Automatically runs `composer update --with-dependencies <affected-packages>` to download patched versions and update `composer.lock`

The `vendor/` directory is fully populated after the patcher runs — no separate install step needed.

<Note>
  Platform requirements (`php`, `ext-*`) are not patched — they are managed by the OS, not Composer.
</Note>

## Authentication

The patcher passes credentials to Composer via the `COMPOSER_AUTH` environment variable. Set it before running the patcher with `--dry-run=false`:

```bash theme={null}
export COMPOSER_AUTH='{"http-basic":{"pkg.root.io":{"username":"","password":"your-api-key"}}}'
```

<Note>
  **Subsequent `composer install` runs also require `COMPOSER_AUTH`.** Once the patcher adds the `pkg.root.io` repository to `composer.json`, every future `composer install` in CI/CD needs this variable set so Composer can authenticate to fetch patched packages.
</Note>

## Patching your project

### 1. Preview available patches

```bash theme={null}
rootio_patcher composer remediate
```

Example output:

```
=== DRY-RUN MODE ===
The following packages in composer.json would be updated:

1. Package: vendor/package
   Current version: 2.1.0
   Patched version: 2.1.4
   CVEs Fixed: [CVE-2024-12345]

To apply these patches:
  Run: rootio_patcher composer remediate --dry-run=false
  Then ensure COMPOSER_AUTH is configured in your CI/CD environment
```

### 2. Apply patches

```bash theme={null}
export COMPOSER_AUTH='{"http-basic":{"pkg.root.io":{"username":"","password":"your-api-key"}}}'
rootio_patcher composer remediate --dry-run=false
```

The patcher updates `composer.json` and `composer.lock` and populates `vendor/`.

### 3. Commit the changes

```bash theme={null}
git add composer.json composer.lock
git commit -m "Apply Root patches for Composer packages"
```

**Flags:**

| Flag        | Default         | Description                                                                                                                                                         |
| ----------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--dry-run` | `true`          | Preview changes without applying                                                                                                                                    |
| `--file`    | `composer.json` | Path to the target `composer.json`                                                                                                                                  |
| `--ignore`  | -               | Exclude `package@version` from patching (repeatable, comma-separated). Merged with a `.rootioignore` file. See [Ignoring Packages](/rlc/patcher#ignoring-packages). |

## CI/CD Configuration

### GitHub Actions

```yaml theme={null}
- name: Set up PHP
  uses: shivammathur/setup-php@v2
  with:
    php-version: '8.2'

- name: Install dependencies
  run: composer install --no-interaction

- name: Patch vulnerabilities
  env:
    ROOTIO_API_KEY: ${{ secrets.ROOTIO_API_KEY }}
    COMPOSER_AUTH: '{"http-basic":{"pkg.root.io":{"username":"","password":"${{ secrets.ROOTIO_API_KEY }}"}}}'
  run: rootio_patcher composer remediate --dry-run=false

- name: Commit changes
  run: |
    git config user.name "Root.io Patcher"
    git config user.email "bot@root.io"
    git add composer.json composer.lock
    git commit -m "chore: apply Root.io security patches" || echo "No changes"
    git push
```

For subsequent `composer install` runs in other jobs or pipelines, set `COMPOSER_AUTH` as a repository secret and inject it into any step that runs Composer:

```yaml theme={null}
- name: Install dependencies
  env:
    COMPOSER_AUTH: ${{ secrets.COMPOSER_AUTH }}
  run: composer install --no-interaction
```

### GitLab CI

```yaml theme={null}
patch:
  script:
    - composer install --no-interaction
    - rootio_patcher composer remediate --dry-run=false
  variables:
    ROOTIO_API_KEY: $ROOTIO_API_KEY
    COMPOSER_AUTH: '{"http-basic":{"pkg.root.io":{"username":"","password":"$ROOTIO_API_KEY"}}}'
```

### Docker

```dockerfile theme={null}
FROM php:8.2-cli

COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

WORKDIR /app
COPY composer.json composer.lock ./

RUN curl -sL https://github.com/rootio-avr/rootio_patcher/releases/latest/download/rootio_patcher_linux_x86_64.tar.gz | tar xz && \
    chmod +x rootio_patcher && \
    mv rootio_patcher /usr/local/bin/

ARG ROOTIO_API_KEY
ENV ROOTIO_API_KEY=${ROOTIO_API_KEY}
ENV COMPOSER_AUTH='{"http-basic":{"pkg.root.io":{"username":"","password":"'"${ROOTIO_API_KEY}"'"}}}'

RUN composer install --no-interaction && \
    rootio_patcher composer remediate --dry-run=false

COPY . .
CMD ["php", "index.php"]
```

Subsequent `composer install` steps (e.g. in a multi-stage build) require `COMPOSER_AUTH` to authenticate with `pkg.root.io`.

## Troubleshooting

| Issue                                    | Solution                                                                                                       |
| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `composer.lock not found`                | Run `composer install` first to generate the lock file, then re-run the patcher                                |
| `file not found: composer.json`          | Run from your project root, or use `--file=./path/to/composer.json`                                            |
| `composer update` fails after patching   | Ensure `COMPOSER_AUTH` is set with valid credentials for `pkg.root.io`                                         |
| Future `composer install` fails in CI/CD | Add `COMPOSER_AUTH` to your CI/CD secrets — the `pkg.root.io` repository entry is permanent in `composer.json` |
| `401 Unauthorized`                       | Verify your API key is valid and that `COMPOSER_AUTH` is correctly formatted                                   |
