# pkgradar-cli
PkgRadar's CI gate and static package scanner as a single binary, plus the
GitHub Actions composite that wraps it.
```sh
pkgradar gate --lockfile package-lock.json --fail-on high
```
This repo is the entire installable surface area for the gate. Fork, vendor,
audit, or run it as-is — there's no closed-source path to the binary you run.
## Install
### Prebuilt binaries
Each release tag (`v0.1.0`+) attaches binaries for:
- `pkgradar-x86_64-unknown-linux-gnu.tar.gz`
- `pkgradar-aarch64-unknown-linux-gnu.tar.gz`
- `pkgradar-x86_64-apple-darwin.tar.gz`
- `pkgradar-aarch64-apple-darwin.tar.gz`
```sh
TAG=$(curl -sSfL https://api.github.com/repos/PkgRadar/pkgradar-cli/releases/latest \
| grep '"tag_name"' | head -1 | sed -E 's/.*"tag_name": "([^"]+)".*/\1/')
linux-x86_64) ASSET="pkgradar-x86_64-unknown-linux-gnu.tar.gz" ;;
linux-aarch64) ASSET="pkgradar-aarch64-unknown-linux-gnu.tar.gz" ;;
darwin-x86_64) ASSET="pkgradar-x86_64-apple-darwin.tar.gz" ;;
darwin-arm64) ASSET="pkgradar-aarch64-apple-darwin.tar.gz" ;;
esac
curl -sSfL "https://github.com/PkgRadar/pkgradar-cli/releases/download/${TAG}/${ASSET}" \
| tar -xz
sudo install -m 0755 pkgradar /usr/local/bin/
```
### From crates.io
```sh
cargo install pkgradar --locked
```
### From source
```sh
git clone https://github.com/PkgRadar/pkgradar-cli
cd pkgradar-cli
cargo install --path . --locked
```
## GitHub Actions
The composite action lives at the root of this repo, so you can use it
directly without specifying a subpath:
```yaml
- uses: PkgRadar/pkgradar-cli@v1
with:
token: ${{ secrets.PKGRADAR_TOKEN }}
fail-on: high
# lockfile: pnpm-lock.yaml # optional override; auto-detects otherwise
```
| Input | Required | Default | Meaning |
|-------------|----------|---------|---------------------------------------------------------------------------------------------------------------|
| `token` | yes | — | API token from <https://pkgradar.com/dashboard/keys> |
| `lockfile` | no | auto | Path to a lockfile. Auto-detects npm/pnpm/yarn-classic, pip/pipenv/poetry/uv/pdm in the working dir. |
| `fail-on` | no | `high` | Block on this risk level or worse (`low`, `review`, `high`) |
| `config` | no | — | Path to a `.pkgradar.yml` config file |
| `fail-open` | no | `true` | Exit 0 on transport-level API errors (timeout, 5xx). Set `false` to harden. |
| `version` | no | latest | Pin a specific `pkgradar` CLI version, e.g. `v0.1.0` |
| `base-url` | no | — | Override `https://pkgradar.com` (self-hosted only) |
The action prefers a prebuilt binary from this repo's releases for fast
cold-start (~10s) and falls back to `cargo install` when the runner platform
isn't in the release matrix.
## GitLab CI
A ready-made template is hosted on pkgradar.com:
```yaml
include:
- remote: 'https://pkgradar.com/templates/pkgradar.gitlab-ci.yml'
pkgradar-gate:
extends: .pkgradar-base
stage: test
variables:
PKGRADAR_FAIL_ON: high
```
`PKGRADAR_TOKEN` must be set in Settings → CI/CD → Variables.
## Configure
```sh
export PKGRADAR_TOKEN="rps_..."
export PKGRADAR_BASE_URL="https://pkgradar.com" # optional
```
Or commit a `.pkgradar.yml` at the root of your repo:
```yaml
fail_on: high
timeout_ms: 30000
fail_open: true
allowlist:
- "@types/node@22.5.4" # reviewed and approved internally
watchlist:
- "react@18.3.1"
```
CLI flags override the config file on conflict.
## Commands
### `pkgradar gate`
Asks the gate endpoint whether each spec should be blocked. Exits non-zero
when any spec breaches `--fail-on`. Combine with `--lockfile` to batch every
transitive in one call.
```sh
pkgradar gate lodash@4.17.21 left-pad@1.3.0 --fail-on high
pkgradar gate --lockfile pnpm-lock.yaml --fail-on review
```
### `pkgradar scan`
Returns the full scan report rather than the gate decision. Use this when
you want to see *why* a release would be blocked.
```sh
```
### `pkgradar version`
Prints the binary version and the resolved API endpoint.
## Lockfile support
### npm ecosystem
| `package-lock.json` v1 | Yes |
| `package-lock.json` v2 | Yes |
| `package-lock.json` v3 | Yes |
| `npm-shrinkwrap.json` | Yes |
| `pnpm-lock.yaml` v6+ | Yes |
| `yarn.lock` v1 | Yes |
| `yarn.lock` v2+ (Berry) | No — errors with a hint |
### PyPI ecosystem
| `requirements.txt` | Yes — only fully-pinned (`==`) entries are gated |
| `requirements.lock` (pip-tools) | Yes |
| `constraints.txt` | Yes |
| `Pipfile.lock` | Yes (default + develop sections) |
| `poetry.lock` | Yes |
| `uv.lock` | Yes |
| `pdm.lock` | Yes |
### RubyGems ecosystem
| `Gemfile.lock` | Yes (GEM block, registry-resolved pins; GIT/PATH/PLUGIN sources skipped) |
| `gems.locked` | Yes |
### Cargo (Rust / crates.io) ecosystem
| `Cargo.lock` | Yes (registry+ and sparse+ sources; git+ and workspace crates skipped) |
### Maven (Java / Maven Central) ecosystem
| `pom.xml` | Yes — `<dependency>` blocks with concrete pinned versions; `${prop}` / `[1,2)` ranges skipped, `<dependencyManagement>` ignored |
Maven specs use the `groupId:artifactId@version` shape, e.g.
`com.fasterxml.jackson.core:jackson-databind@2.17.0`.
### NuGet (.NET / nuget.org) ecosystem
| `packages.lock.json` | Yes (PackageReference lockfile; `type: Project` entries skipped) |
| `packages.config` | Yes (legacy XML format) |
| `project.assets.json` | Yes (resolved restore graph; `type: project` entries skipped) |
NuGet specs use `Id@Version`, e.g. `Newtonsoft.Json@13.0.3`. IDs are
case-insensitive on the registry.
### Composer (PHP / Packagist) ecosystem
| `composer.lock` | Yes (`packages` + `packages-dev` arrays; `metapackage` and `dev-*` refs skipped) |
Composer specs use `vendor/name@version`, e.g. `symfony/console@v6.4.1`.
The parser deduplicates by `(ecosystem, name, version)`, normalizes
PyPI names per PEP 503, and skips non-registry refs (`file:`, `link:`,
`workspace:`, `git+`, `github:`, direct URL specs).
## Fail-open behaviour
Network or transport-level errors (timeout, 5xx, DNS) print a warning and
exit 0 by default — security tooling shouldn't take down a deploy pipeline
because PkgRadar had a 30-second blip. Set `fail_open: false` in
`.pkgradar.yml` (or pass `--no-fail-open`) once your gate cadence is stable.
## Exit codes
| `0` | All specs passed the gate. |
| `1` | At least one spec was blocked. |
| `2` | Usage / config error (missing token, bad flag). |
| `3` | Network, TLS, or installer failure. |
## Building locally
```sh
cargo build --release
./target/release/pkgradar --help
cargo test --release
```
The binary is statically linked against `rustls-tls-native-roots`, so it
picks up the host's CA bundle and doesn't link OpenSSL at runtime.
## License
Apache-2.0. See [LICENSE](LICENSE).