Package Scanner
The Package Scanner is a cross-platform CLI for scanning dependency manifests and uploading package inventory to ShieldedStack. It is useful for seeding existing repositories, scanning projects that do not restore through the proxy, and adding scheduled CI inventory checks.
Scanner uploads are sent to the package proxy at <proxy-url>/scans. For on-prem deployments, always configure the scanner with your deployed proxy URL.
Install
Section titled “Install”Binaries are published for five platforms, always at the same URL for the current release:
| Platform | File |
|---|---|
| Linux (x64) | package-scanner-linux-amd64 |
| Linux (ARM64) | package-scanner-linux-arm64 |
| macOS (Intel) | package-scanner-darwin-amd64 |
| macOS (Apple Silicon) | package-scanner-darwin-arm64 |
| Windows (x64) | package-scanner-windows-amd64.exe |
Each is served from https://tools.shieldedstack.com/u/<file>, and SHA256 checksums for all five are
published together at https://tools.shieldedstack.com/r/checksums.txt.
Verify the download before you run it. The steps below do that, substituting the file for your platform.
curl -LO https://tools.shieldedstack.com/u/package-scanner-linux-amd64curl -L -o checksums.txt https://tools.shieldedstack.com/r/checksums.txtgrep package-scanner-linux-amd64 checksums.txt | sha256sum -c -sha256sum prints OK when the file matches. If it does not, stop and do not run the binary.
Then put it on your PATH:
install -m 755 package-scanner-linux-amd64 ~/.local/bin/package-scannerUse package-scanner-linux-arm64 on ARM64 machines.
curl -LO https://tools.shieldedstack.com/u/package-scanner-darwin-arm64curl -L -o checksums.txt https://tools.shieldedstack.com/r/checksums.txtgrep package-scanner-darwin-arm64 checksums.txt | shasum -a 256 -c - \ && install -m 755 package-scanner-darwin-arm64 ~/.local/bin/package-scannerUse package-scanner-darwin-amd64 on Intel machines.
Windows
Section titled “Windows”Invoke-WebRequest https://tools.shieldedstack.com/u/package-scanner-windows-amd64.exe -OutFile package-scanner.exe(Get-FileHash .\package-scanner.exe -Algorithm SHA256).Hash.ToLower()Compare the printed hash against the package-scanner-windows-amd64.exe line in
https://tools.shieldedstack.com/r/checksums.txt, then move the executable somewhere on your PATH.
Pinning a build
Section titled “Pinning a build”The download URLs always serve the current release, so an unpinned CI job picks up a new binary whenever one ships. Record the checksum you verified and check it on every run, as the GitHub Actions example does. The job then fails loudly when the binary changes rather than quietly running a different one.
Deployment URL
Section titled “Deployment URL”<proxy-url> is the base URL of the package proxy, without a trailing slash. Pass it with
--proxy-url <proxy-url>, or set SHIELDEDSTACK_PROXY_URL in the environment.
Features
Section titled “Features”- Multi-ecosystem support: npm, NuGet, pip, Go, Maven, Cargo, RubyGems, Dart.
- Manifest-only scanning: Fast scans without dependency resolution.
- Concurrent processing: Parallel manifest parsing.
- Batch uploads: Efficient bulk submission to ShieldedStack.
- Retry logic: Automatic retries with exponential backoff.
- Rate limiting: Respects API rate limits.
- Dry-run mode: Preview findings without uploading.
- CI/CD ready: Non-interactive execution with clear exit codes.
Supported Manifests
Section titled “Supported Manifests”package-lock.jsonv2/v3.package.jsonfallback.
packages.lock.json.*.csproj/*.fsprojusing PackageReference.packages.config.
requirements.txt.Pipfile.lock.poetry.lock.
go.mod.
pom.xml.
Cargo.lock.
RubyGems
Section titled “RubyGems”Gemfile.lock.
pubspec.lock.
Basic Usage
Section titled “Basic Usage”package-scanner --api-key YOUR_API_KEY --proxy-url <proxy-url> /path/to/projectEnvironment Variables
Section titled “Environment Variables”export SHIELDEDSTACK_API_KEY=your_api_keyexport SHIELDEDSTACK_PROXY_URL=<proxy-url>package-scanner /path/to/projectWith the default HTTP endpoint, this looks like:
export SHIELDEDSTACK_PROXY_URL=http://<host>:3003package-scanner --api-key YOUR_API_KEY .Dry Run
Section titled “Dry Run”Preview findings without uploading:
package-scanner --dry-run --api-key YOUR_API_KEY --proxy-url <proxy-url> .Exclude Directories
Section titled “Exclude Directories”package-scanner --api-key YOUR_API_KEY --proxy-url <proxy-url> --exclude "test,examples" .CI/CD Integration
Section titled “CI/CD Integration”GitHub Actions
Section titled “GitHub Actions”name: Scan Dependencies
on: schedule: - cron: '0 0 * * *' push: branches: [main]
jobs: scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Download Package Scanner env: SCANNER_SHA256: ${{ vars.SCANNER_SHA256 }} run: | curl -L https://tools.shieldedstack.com/u/package-scanner-linux-amd64 -o scanner echo "${SCANNER_SHA256} scanner" | sha256sum -c - chmod +x scanner
- name: Scan Dependencies env: SHIELDEDSTACK_API_KEY: ${{ secrets.SHIELDEDSTACK_API_KEY }} SHIELDEDSTACK_PROXY_URL: ${{ vars.SHIELDEDSTACK_PROXY_URL }} run: ./scanner --no-color .Azure DevOps
Section titled “Azure DevOps”trigger: - main
pool: vmImage: 'ubuntu-latest'
steps:- script: | curl -L https://tools.shieldedstack.com/u/package-scanner-linux-amd64 -o scanner chmod +x scanner displayName: 'Download Package Scanner'
- script: ./scanner --no-color . env: SHIELDEDSTACK_API_KEY: $(ShieldedStackApiKey) SHIELDEDSTACK_PROXY_URL: $(ShieldedStackProxyUrl) displayName: 'Scan Dependencies'GitLab CI
Section titled “GitLab CI”scan-dependencies: image: alpine:latest before_script: - apk add --no-cache curl - curl -L https://tools.shieldedstack.com/u/package-scanner-linux-amd64 -o scanner - chmod +x scanner script: - ./scanner --no-color . variables: SHIELDEDSTACK_PROXY_URL: "<proxy-url>" only: - mainStore SHIELDEDSTACK_API_KEY as a protected CI secret. Store SHIELDEDSTACK_PROXY_URL as a variable or secret depending on your internal policy.
Flags Reference
Section titled “Flags Reference”| Flag | Environment Variable | Description |
|---|---|---|
--api-key |
SHIELDEDSTACK_API_KEY |
ShieldedStack API key. Required for uploads. |
--proxy-url |
SHIELDEDSTACK_PROXY_URL |
Package proxy base URL. Set this for on-prem deployments. |
--include |
- | Include glob patterns. |
--exclude |
- | Additional exclude patterns. |
--dry-run |
- | Print findings without uploading. |
--output-json |
- | Write results to JSON file. |
--format |
- | Output format: text or json. |
--no-color |
- | Disable colored output. |
--concurrency |
- | Worker pool size. |
Do not rely on the scanner binary’s built-in proxy URL default for on-prem deployments. Set SHIELDEDSTACK_PROXY_URL or pass --proxy-url explicitly.
Default Excludes
Section titled “Default Excludes”The scanner automatically excludes these directories:
node_modulesbinobj.venv/venv.git__pycache__.pytest_cache.mypy_cache
Exit Codes
Section titled “Exit Codes”0: Success; all packages uploaded.1: Upload errors such as network, auth, or rate-limit failures.2: Scan failures such as manifest parsing errors.
Monorepo Support
Section titled “Monorepo Support”For monorepos with multiple projects or workspaces, run the scanner multiple times with different API keys and target directories:
# Frontend projectpackage-scanner --api-key FRONTEND_KEY --proxy-url <proxy-url> ./frontend
# Backend projectpackage-scanner --api-key BACKEND_KEY --proxy-url <proxy-url> ./backendTroubleshooting
Section titled “Troubleshooting”Authentication Errors
Section titled “Authentication Errors”Verify your API key is correct, has not expired, and belongs to the workspace you expect:
package-scanner --dry-run --api-key YOUR_API_KEY --proxy-url <proxy-url> .Then run without --dry-run to test upload authentication.
Uploads Go to the Wrong Host
Section titled “Uploads Go to the Wrong Host”Confirm the active proxy URL:
printf '%s\n' "$SHIELDEDSTACK_PROXY_URL"The scanner posts inventory to <proxy-url>/scans.
Rate Limiting
Section titled “Rate Limiting”If you hit rate limits with 429 responses, the scanner automatically retries with backoff. Current limit: 5,000 packages/hour per API key.
Parsing Errors
Section titled “Parsing Errors”Use JSON output to see which manifests fail to parse:
package-scanner --format json --api-key YOUR_API_KEY --proxy-url <proxy-url> . 2>&1 | tee scan.log