> ## 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.

# Root Patcher CLI

> Automatically identify and patch vulnerable dependencies across Python, JavaScript, Java, and Go projects using the rootio_patcher CLI.

The Root Patcher CLI (`rootio_patcher`) scans your installed packages, queries Root's remediation API for available patches, and applies Root-fixed packages to your project - automatically.

## When to Use the Patcher

There are two ways to consume Root-patched packages:

| Approach                           | Best for                                                                                                                  |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| **Registry proxy** (`pkg.root.io`) | New projects, CI/CD pipelines, clean installs - point your package manager at Root's registry and packages arrive patched |
| **Patcher CLI**                    | Existing environments, one-shot remediation, or projects where changing global registry config isn't practical            |

For Maven specifically, the patcher is the recommended approach - it resolves transitive dependencies and directly updates your `pom.xml` rather than requiring a full registry mirror configuration.

***

## Installation

### Linux (x86\_64)

```bash theme={null}
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/
```

### macOS (Apple Silicon - M1/M2/M3)

```bash theme={null}
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/
```

### macOS (Intel)

```bash theme={null}
curl -sL https://github.com/rootio-avr/rootio_patcher/releases/latest/download/rootio_patcher_darwin_x86_64.tar.gz | tar xz
chmod +x rootio_patcher
sudo mv rootio_patcher /usr/local/bin/
```

### Windows (PowerShell)

```powershell theme={null}
Invoke-WebRequest -Uri "https://github.com/rootio-avr/rootio_patcher/releases/latest/download/rootio_patcher_windows_x86_64.zip" -OutFile "rootio_patcher.zip"
Expand-Archive -Path rootio_patcher.zip -DestinationPath .
# Add rootio_patcher.exe to your PATH or run it directly
```

### Verify

```bash theme={null}
rootio_patcher --help
```

***

## Configuration

| Variable         | Required           | Default               | Description                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| ---------------- | ------------------ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ROOTIO_API_KEY` | For pip apply only | -                     | Your Root API key. **Not required** for dry-run — the analyze API is public. Required for the **Python** subcommand when running with `--dry-run=false`, because the patcher itself reinstalls packages from `pkg.root.io`. **Not required** by the patcher for the **npm**, **Maven**, or **Go** subcommands — those rewrite your manifest and rely on your package manager's existing `pkg.root.io` registry auth to pull the patched packages. |
| `ROOTIO_API_URL` | No                 | `https://api.root.io` | Override Root API endpoint                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `ROOTIO_PKG_URL` | No                 | `https://pkg.root.io` | Override Root package registry                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `LOG_LEVEL`      | No                 | `info`                | `debug`, `info`, `warn`, or `error`                                                                                                                                                                                                                                                                                                                                                                                                               |

```bash theme={null}
# Needed only for `rootio_patcher pip remediate --dry-run=false`
export ROOTIO_API_KEY="your-api-key-here"
```

<Note>
  **Free discovery, subscription to apply.** Root's `/v3/analyze/*` endpoints are public, so dry-run discovery has no credential requirements — anyone can run `rootio_patcher` against their project to see which packages have Root-patched fixes and which CVEs they resolve. Applying those patches still requires a Root subscription, because the patched packages are served from `pkg.root.io`, which is authenticated.

  Where the credential lives differs by ecosystem:

  * **Python**: the patcher does the `pip install` itself, so it needs `ROOTIO_API_KEY` set in its environment.
  * **npm / Maven / Go**: the patcher only rewrites your manifest. Authentication to `pkg.root.io` is handled by your package manager's own config (`.npmrc`, Maven `settings.xml`, or `GOPROXY`) when you run `npm install`, `mvn install`, or `go build ./...` after — see the ecosystem sections below.

  To get your API key, go to **Settings → Token Management** in the Root platform and click **Generate API Token**.
</Note>

***

## Dry-Run Mode

All commands run in dry-run mode by default - they preview what would change without modifying anything. This is recommended before applying patches for the first time.

Dry-run uses Root's **public analyze API** and **does not require `ROOTIO_API_KEY`** for any ecosystem - you can run it with no Root account at all to discover whether your dependencies have Root patches available.

```bash theme={null}
# Preview what would be patched - no API key needed
rootio_patcher pip remediate

# Apply patches (Python: patcher needs ROOTIO_API_KEY because it runs pip install)
export ROOTIO_API_KEY="your-api-key-here"
rootio_patcher pip remediate --dry-run=false
```

For `--dry-run=false`, see the per-ecosystem sections — the patcher itself only needs `ROOTIO_API_KEY` for **pip**, since it does the install. For **npm** and **Maven** the patcher only rewrites your manifest, and the auth to `pkg.root.io` is handled by your package manager when you run `npm install` / `mvn install` afterwards.

Dry-run output shows the exact commands that would be run and which CVEs each patch resolves:

```
=== DRY-RUN MODE ===
The following operations would be performed:

1. Package: requests @ 2.25.1
   Patch (Aliased): rootio-requests @ 2.25.1+root.io.1
   CVEs Fixed: [CVE-2023-32681]
   Commands:
     pip uninstall -y requests
     pip install --no-deps --index-url https://root:<key>@pkg.root.io/pypi/simple/ rootio-requests==2.25.1+root.io.1

To apply these patches, run with --dry-run=false
```

***

## Python - pip

The patcher uses **post-install patching**: it reads your current environment with `pip list`, queries Root's public analyze API for available patches, then uninstalls vulnerable packages and reinstalls Root-patched versions.

Because the patcher runs `pip install` itself against `pkg.root.io`, applying patches requires `ROOTIO_API_KEY` to be set in the patcher's environment. Dry-run does not.

```bash theme={null}
# Preview - no key needed
rootio_patcher pip remediate

# Apply - patcher needs ROOTIO_API_KEY to install from pkg.root.io
export ROOTIO_API_KEY="your-api-key-here"
rootio_patcher pip remediate --dry-run=false
```

**Flags:**

| Flag            | Default  | Description                                                 |
| --------------- | -------- | ----------------------------------------------------------- |
| `--dry-run`     | `true`   | Preview changes without applying                            |
| `--python-path` | `python` | Path to a specific Python interpreter                       |
| `--use-alias`   | `true`   | Install under Root's aliased name (e.g., `rootio-requests`) |

To patch a specific virtual environment:

```bash theme={null}
rootio_patcher pip remediate --python-path=./venv/bin/python --dry-run=false
```

***

## JavaScript - npm, yarn, pnpm

The patcher uses **pre-install patching**: it reads your lock file, queries Root's public analyze API, then injects `overrides` or `resolutions` into your `package.json`. You run your package manager's install command afterward to apply the changes.

The patcher itself does **not** need `ROOTIO_API_KEY` - it only rewrites your manifest. The patched packages are pulled in by the subsequent `npm install` (or `yarn` / `pnpm`), which authenticates to `pkg.root.io` via your `.npmrc` - see [JavaScript registry setup](/rlc/javascript) for configuring that auth.

```bash theme={null}
# npm (default) - no ROOTIO_API_KEY needed
rootio_patcher npm remediate --dry-run=false

# yarn
rootio_patcher npm remediate --package-manager=yarn --dry-run=false

# pnpm
rootio_patcher npm remediate --package-manager=pnpm --dry-run=false
```

After running the patcher, run your package manager's install command (this is the step that needs `pkg.root.io` auth in your `.npmrc`):

```bash theme={null}
npm install      # or yarn install / pnpm install
```

**Flags:**

| Flag                | Default | Options               | Description                      |
| ------------------- | ------- | --------------------- | -------------------------------- |
| `--dry-run`         | `true`  | -                     | Preview changes without applying |
| `--package-manager` | `npm`   | `npm`, `yarn`, `pnpm` | Which package manager to target  |

The patcher injects entries in the format `npm:@rootio/<package>@<version>` into the appropriate override field for your package manager:

| Package manager | Field updated    |
| --------------- | ---------------- |
| npm             | `overrides`      |
| pnpm            | `pnpm.overrides` |
| Yarn 1          | `resolutions`    |
| Yarn 2+ (Berry) | `resolutions`    |

***

## Java - Maven

The patcher uses **pre-install patching**: it reads your `pom.xml` (and any multi-module submodules), queries Root's public analyze API, then rewrites dependency `groupId` and `version` values to use Root-patched equivalents. It also adds `<exclusions>` to prevent transitive re-introduction of vulnerable versions.

The patcher itself does **not** need `ROOTIO_API_KEY` - it only rewrites your `pom.xml`. The patched artifacts are pulled in by the subsequent `mvn` build, which authenticates to `pkg.root.io` via your Maven `settings.xml` - see [Maven registry setup](/rlc/java) for configuring that auth.

```bash theme={null}
# Preview - no ROOTIO_API_KEY needed
rootio_patcher maven remediate

# Apply - still no key needed by the patcher itself
rootio_patcher maven remediate --dry-run=false

# Specify a pom.xml path
rootio_patcher maven remediate --file=path/to/pom.xml --dry-run=false
```

After running the patcher, rebuild (this is the step that needs `pkg.root.io` auth in your Maven `settings.xml`):

```bash theme={null}
mvn clean install
```

**Flags:**

| Flag        | Default   | Description                      |
| ----------- | --------- | -------------------------------- |
| `--dry-run` | `true`    | Preview changes without applying |
| `--file`    | `pom.xml` | Path to the target `pom.xml`     |

<Note>
  For multi-module Maven projects, run the patcher from the root of the project. It will discover all submodule `pom.xml` files automatically.
</Note>

***

## Go - Go modules

The patcher uses **pre-build patching**: it reads your `go.mod`, queries Root's public analyze API, then adds `replace` directives pointing to Root-patched module aliases. After writing `go.mod`, the patcher automatically runs `go mod tidy` (and `go mod vendor` if a vendor directory is present).

The patcher itself does **not** need `ROOTIO_API_KEY` - it only rewrites your `go.mod`. The patched modules are downloaded when `go mod tidy` runs (automatically) and when you build, which authenticates to `pkg.root.io` via your `GOPROXY` configuration.

<Note>
  Only modules with pinned semver versions (e.g. `v1.2.3`) are analyzed. Modules using pseudo-versions (e.g. `v0.0.0-20230101123456-abcdef012345`) are skipped. If you have vulnerable pseudo-versioned dependencies, upgrade them to a pinned release first.
</Note>

```bash theme={null}
# Preview - no ROOTIO_API_KEY needed
rootio_patcher go remediate

# Apply - no key needed by the patcher itself; GOPROXY must be configured for go mod tidy to reach pkg.root.io
rootio_patcher go remediate --dry-run=false

# Specify a go.mod path
rootio_patcher go remediate --go-mod=./submodule/go.mod --dry-run=false
```

After running the patcher, build your project (this is the step that needs `GOPROXY` to include `pkg.root.io`):

```bash theme={null}
go build ./...
```

**Flags:**

| Flag        | Default  | Description                      |
| ----------- | -------- | -------------------------------- |
| `--dry-run` | `true`   | Preview changes without applying |
| `--go-mod`  | `go.mod` | Path to the target `go.mod`      |

Dry-run output shows the exact `replace` directives that would be added and which CVEs each patch resolves:

```
=== DRY-RUN MODE ===
The following replace directives would be added to go.mod:

1. replace golang.org/x/net v0.17.0 => rootio/golang.org/x/net v0.17.1
   CVEs Fixed: [CVE-2024-12345]

2. replace github.com/golang-jwt/jwt/v4 v4.5.0 => rootio/github.com/golang-jwt/jwt/v4 v4.5.1
   CVEs Fixed: [CVE-2024-67890]

To apply these patches:
  1. Run: rootio_patcher go remediate --dry-run=false
  2. Then run: go build ./...
```

***

## Vulnerability Gate

Running `rootio_patcher` in dry-run mode (the default) is non-destructive — it checks for available patches and exits with a code that indicates the result. Use this to fail a pipeline or trigger an alert without touching any files.

| Exit code | Meaning                                           |
| --------- | ------------------------------------------------- |
| `0`       | No patches needed — all packages are up to date   |
| `1`       | Error (bad config, API failure, unexpected panic) |
| `2`       | Patches are available — action required           |

```bash theme={null}
rootio_patcher npm remediate   # --dry-run=true is the default
case $? in
  0) echo "All packages are up to date." ;;
  2) echo "Patches available — please remediate." ; exit 1 ;;
  *) echo "Unexpected error." ; exit 1 ;;
esac
```

***

## CI/CD

Dry-run discovery has no credential requirements. For apply, the credential lives in different places depending on ecosystem - on the patcher for pip, on the package manager step for npm and Maven.

### GitHub Action

A reusable composite action runs the vulnerability gate — it calls `rootio_patcher` in dry-run mode and **fails the job** if patches are available. No files are modified.

```yaml theme={null}
- uses: rootio-avr/rootio_patcher/.github/actions/rootio-patch@main
  with:
    api-key: ${{ secrets.ROOTIO_API_KEY }}
    ecosystem: npm   # pip | npm | maven
```

**Inputs:**

| Input               | Required | Default   | Description                                        |
| ------------------- | -------- | --------- | -------------------------------------------------- |
| `api-key`           | Yes      | —         | Root.io API key                                    |
| `ecosystem`         | Yes      | —         | `pip`, `npm`, or `maven`                           |
| `working-directory` | No       | `.`       | Repo subdirectory to run in (e.g. `services/api`)  |
| `package-manager`   | No       | `npm`     | *(npm)* `npm`, `yarn`, or `pnpm`                   |
| `directory`         | No       | `.`       | *(npm)* Project directory containing the lock file |
| `python-path`       | No       | `python`  | *(pip)* Path to Python interpreter                 |
| `use-alias`         | No       | `true`    | *(pip)* Use Root.io aliased packages               |
| `file`              | No       | `pom.xml` | *(maven)* Path to `pom.xml`                        |

Advanced settings (`ROOTIO_API_URL`, `ROOTIO_PKG_URL`, `ROOTIO_PIP_INDEX_URL`, `LOG_LEVEL`) are not inputs — pass them as environment variables on the calling step:

```yaml theme={null}
- uses: rootio-avr/rootio_patcher/.github/actions/rootio-patch@main
  env:
    ROOTIO_PIP_INDEX_URL: https://my-private-index.example.com/simple/
  with:
    api-key: ${{ secrets.ROOTIO_API_KEY }}
    ecosystem: pip
```

**Outputs:**

| Output              | Description                                                           |
| ------------------- | --------------------------------------------------------------------- |
| `patches-available` | `"true"` if patches were found, `"false"` if everything is up to date |

#### Block a PR if vulnerabilities exist

```yaml theme={null}
name: Security Check

on: [pull_request]

jobs:
  vuln-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: rootio-avr/rootio_patcher/.github/actions/rootio-patch@main
        with:
          api-key: ${{ secrets.ROOTIO_API_KEY }}
          ecosystem: npm
          package-manager: npm
```

#### Warn without blocking

```yaml theme={null}
- uses: rootio-avr/rootio_patcher/.github/actions/rootio-patch@main
  id: vuln-check
  continue-on-error: true
  with:
    api-key: ${{ secrets.ROOTIO_API_KEY }}
    ecosystem: npm
- if: steps.vuln-check.outputs.patches-available == 'true'
  run: echo "Patches available — consider remediating soon."
```

### Apply patches in CI

To remediate (not just check), run the patcher with `--dry-run=false` and commit the result:

**Dry-run discovery** (any ecosystem, no Root subscription needed):

```yaml theme={null}
- name: Discover available Root patches
  run: rootio_patcher pip remediate
```

**Apply - Python (pip)**: the patcher does the install, so it needs `ROOTIO_API_KEY`:

```yaml theme={null}
- name: Patch vulnerable dependencies
  run: rootio_patcher pip remediate --dry-run=false
  env:
    ROOTIO_API_KEY: ${{ secrets.ROOTIO_API_KEY }}
```

**Apply - npm**: the patcher rewrites `package.json` with no key; the following `npm install` authenticates to `pkg.root.io` via your `.npmrc` (which can use `${ROOTIO_API_KEY}` for the registry token):

```yaml theme={null}
- name: Patch and install
  run: |
    rootio_patcher npm remediate --package-manager=npm --dry-run=false
    npm install
  env:
    ROOTIO_API_KEY: ${{ secrets.ROOTIO_API_KEY }}
```

**Apply - Maven**: same shape — the patcher edits `pom.xml` with no key; the subsequent `mvn` step authenticates via your `settings.xml`.

**Apply - Go**: the patcher rewrites `go.mod` and auto-runs `go mod tidy`. Configure `GOPROXY` to include `pkg.root.io` so the module proxy can authenticate when fetching patched modules:

```yaml theme={null}
- name: Patch and build
  run: |
    rootio_patcher go remediate --dry-run=false
    go build ./...
  env:
    GOPROXY: "https://${{ secrets.ROOTIO_API_KEY }}@pkg.root.io/go,direct"
```

***

## Source

`rootio_patcher` is open source under the Apache 2.0 license: [github.com/rootio-avr/rootio\_patcher](https://github.com/rootio-avr/rootio_patcher)
