-
Notifications
You must be signed in to change notification settings - Fork 0
Home
Command-line tool for running web application security analyses via the Purplemet platform. Designed for CI/CD integration and local use.
🛡️ New to Purplemet? Proactive Web Attack Surface Management — discover real-time security insights with Purplemet's Web ASM platform. Dive into the official documentation to learn more, or explore the API reference.
- Installation
- Quick Start
- Commands
- Global Flags
- Configuration
- Output Formats
- Exit Codes
- CI/CD Integrations
- Examples
- Documentation
- Development
- License
curl -sSL https://raw.githubusercontent.com/Purplemet/cli/main/scripts/install.sh | shThe script detects your OS and architecture, downloads the binary, verifies the SHA256 checksum, and installs it to /usr/local/bin.
You can also download a specific version from Releases.
brew tap Purplemet/cli https://github.com/Purplemet/cli.git
brew install purplemet-cliShell completions for bash, zsh and fish are installed automatically. Open a new terminal (or run exec $SHELL) for them to take effect.
docker run --rm -e PURPLEMET_API_TOKEN=<token> ppmsupport/purplemet-cli analyze https://your-app.comImage: ppmsupport/purplemet-cli:latest — Alpine-based, ~15MB. See Docker documentation.
git clone https://github.com/Purplemet/cli.git
cd cli
make build
sudo make installRequires Go 1.25+.
Create a token at cloud.purplemet.com.
export PURPLEMET_API_TOKEN=<your-token>Or use a .env file in your project directory:
PURPLEMET_API_TOKEN=your-token-herepurplemet-cli auth check# Analyze by URL (auto-creates the site if it doesn't exist)
purplemet-cli analyze https://your-app.com
# Analyze by site UUID
purplemet-cli analyze a1b2c3d4-e5f6-7890-abcd-ef1234567890
# CI/CD mode: JSON output + severity gate
purplemet-cli analyze https://your-app.com --json --fail-on-severity highStarts an analysis on a site and polls until completion.
purplemet-cli analyze <siteId|url> [flags]Arguments:
| Argument | Description |
|---|---|
<siteId|url> |
Site UUID or URL to analyze. If a URL is given, the CLI resolves it to a site (or creates one automatically). |
Flags:
| Flag | Default | Description |
|---|---|---|
--no-create |
false |
Do not auto-create a new site if the URL is not found |
--format |
— | Output format: json, human, sarif, html
|
--output-file |
— | Write output to a file instead of stdout |
--poll-interval |
10000 |
Polling interval in ms while waiting for analysis completion (env: PURPLEMET_POLL_INTERVAL) |
--wait-timeout |
0 (unlimited) |
Global polling timeout in ms (env: PURPLEMET_WAIT_TIMEOUT) |
--no-quota-check |
false |
Skip the in-progress-analyses advisory check before launching |
-y, --yes
|
false |
Assume yes to confirmation prompts (e.g. when many analyses are already in progress) |
Security Gates:
Gates allow you to fail a pipeline based on specific security criteria. Multiple gates can be combined — the analysis fails if any gate triggers (exit code 1).
| Flag | Env Variable | Default | Description |
|---|---|---|---|
--fail-on-severity |
PURPLEMET_FAIL_SEVERITY |
— (disabled) | Fail if issues at or above: critical, high, medium, low, info
|
--fail-on-rating |
PURPLEMET_FAIL_RATING |
— | Fail if rating is at or worse than: A, B, C, D, E, F
|
--fail-on-cvss |
PURPLEMET_FAIL_CVSS |
0 (disabled) |
Fail if any issue has a CVSS score >= threshold (e.g. 9.0) |
--fail-on-eol |
PURPLEMET_FAIL_ON_EOL |
false |
Fail if end-of-life components are detected |
--fail-on-ssl |
PURPLEMET_FAIL_ON_SSL |
false |
Fail if SSL/TLS protocol issues are found |
--fail-on-cert |
PURPLEMET_FAIL_ON_CERT |
false |
Fail if certificate issues are found |
--fail-on-headers |
PURPLEMET_FAIL_ON_HEADERS |
false |
Fail if HTTP security header issues (CSP, HSTS, X-Frame-Options) are found |
--fail-on-cookies |
PURPLEMET_FAIL_ON_COOKIES |
false |
Fail if insecure cookies (HttpOnly, Secure, SameSite) are found |
--fail-on-unsafe |
PURPLEMET_FAIL_ON_UNSAFE |
false |
Fail if unsafe components are detected |
--fail-on-kev |
PURPLEMET_FAIL_ON_KEV |
false |
Fail if CISA Known Exploited Vulnerabilities are detected |
--fail-on-epss |
PURPLEMET_FAIL_ON_EPSS |
0 (disabled) |
Fail if any issue has an EPSS score >= threshold (e.g. 0.75) |
--fail-on-active-exploits |
PURPLEMET_FAIL_ON_ACTIVE_EXPLOITS |
false |
Fail if actively exploited vulnerabilities are detected |
--fail-on-ossf-score |
PURPLEMET_FAIL_ON_OSSF_SCORE |
0 (disabled) |
Fail if any component has an OpenSSF Scorecard score below threshold (e.g. 5.0) |
--fail-on-cert-expiry |
PURPLEMET_FAIL_ON_CERT_EXPIRY |
0 (disabled) |
Fail if any certificate expires within N days |
--fail-on-issue-count |
PURPLEMET_FAIL_ON_ISSUE_COUNT |
0 (disabled) |
Fail if total issue count >= threshold |
--require-waf |
PURPLEMET_REQUIRE_WAF |
false |
Fail if no WAF is detected |
--fail-on-sensitive-services |
PURPLEMET_FAIL_ON_SENSITIVE_SERVICES |
false |
Fail if sensitive services are exposed |
--exclude-tech |
PURPLEMET_EXCLUDE_TECH |
— | Fail if specified technologies are detected (comma-separated) |
Note: Issues explicitly ignored (via
purplemet-cli issues ignore) are always excluded from gate evaluation — an acknowledged risk should never re-fail a pipeline.
Examples:
# Basic analysis with human-readable output
purplemet-cli analyze https://your-app.com
# JSON output to file
purplemet-cli analyze https://your-app.com --format json --output-file report.json
# SARIF output (for GitHub Code Scanning)
purplemet-cli analyze https://your-app.com --format sarif --output-file results.sarif
# HTML report
purplemet-cli analyze https://your-app.com --format html --output-file report.html
# Fail pipeline if high or critical issues found
purplemet-cli analyze https://your-app.com --json --fail-on-severity high
# Analyze existing site only (no auto-creation)
purplemet-cli analyze https://your-app.com --no-create
# With timeout (5 minutes)
purplemet-cli analyze https://your-app.com --wait-timeout 300000purplemet-cli analyze stop <siteId> [analysisId]Stops a specific analysis (if analysisId is given) or all running analyses for the site.
Examples:
# Stop all running analyses for a site
purplemet-cli analyze stop a1b2c3d4-e5f6-7890-abcd-ef1234567890
# Stop a specific analysis
purplemet-cli analyze stop a1b2c3d4-... e9833020-...purplemet-cli auth checkValidates that the configured API token is accepted by the Purplemet API.
$ purplemet-cli auth check
Authenticated successfully.
$ purplemet-cli auth check --json
{"authenticated": true}purplemet-cli sites list [flags]Shares the standard pagination flags (see Pagination):
| Flag | Default | Description |
|---|---|---|
--limit |
100 |
Page size (1–1000) |
--offset |
0 |
Skip the first N items |
--page |
0 |
Page number, 1-indexed (alternative to --offset) |
--all |
false |
Fetch every page automatically (capped by --max) |
--max |
10000 |
Hard cap on items fetched when --all is set |
$ purplemet-cli sites list --page 2 --limit 20
ID URL
-------------------------------------- ---
…
Showing 21-40 of 142 site(s) — page 2 of 8 (next: --page 3)
# Fetch everything in one shot
$ purplemet-cli sites list --all
…
Showing 142 of 142 site(s) — all pages fetched
# Filter client-side with --query (works on every list command)
$ purplemet-cli sites list --query "url~=staging"
$ purplemet-cli issues list --all --query "severity=high,status=OPEN"See docs/configuration.md for the full
--query syntax (operators =, !=, ~=, !~).
purplemet-cli sites get <siteId>Displays detailed information about a site: URL, rating, score, issue counts, technologies, WAF, schedule.
purplemet-cli sites create <url> [flags]| Flag | Default | Description |
|---|---|---|
--description |
— | Optional description |
--vhost |
— | Virtual Host IP address (IPv4) |
--no-notification |
false |
Disable notifications |
--launch |
false |
Launch an analysis immediately after creation |
--restore |
false |
Restore a previously deleted site |
--schedule-frequency |
— | Schedule frequency: DAILY or WEEKLY
|
--schedule-day |
— | Day for WEEKLY analyses (e.g. monday) |
--schedule-time |
— | Time for scheduled analyses (e.g. 10:15) |
Examples:
# Create and immediately analyze
purplemet-cli sites create https://your-app.com --launch
# Create with weekly schedule
purplemet-cli sites create https://your-app.com \
--description "Production" \
--schedule-frequency WEEKLY \
--schedule-day monday \
--schedule-time 02:00purplemet-cli sites delete <siteId>purplemet-cli sites schedule <siteId> [flags]| Flag | Default | Description |
|---|---|---|
--frequency |
DAILY |
Analysis frequency: DAILY or WEEKLY
|
--day |
— | Day of week for WEEKLY analyses (e.g. monday) |
--time |
— | Time of day in UTC, HH:MM format (e.g. 02:00) |
--disable |
false |
Disable scheduled analyses |
Examples:
# Schedule daily analyses at 02:00 UTC
purplemet-cli sites schedule a1b2c3d4-... --frequency DAILY --time 02:00
# Schedule weekly analyses
purplemet-cli sites schedule a1b2c3d4-... --frequency WEEKLY --day monday --time 02:00
# Disable scheduled analyses
purplemet-cli sites schedule a1b2c3d4-... --disablepurplemet-cli diff <analysisId1> <analysisId2> --site-id <siteId>Compares two analyses and shows the delta: rating, score, issues, CVEs, technologies.
| Flag | Required | Description |
|---|---|---|
--site-id |
Yes | Site ID the analyses belong to |
Example:
$ purplemet-cli diff e983302a-... f094413b-... --site-id a1b2c3d4-...
Purplemet • Diff e983302a vs f094413b
Rating: B → A
Score: 3 → 1 (-2)
Issues: 12 → 5 (-7)
CVEs: 2 → 0 (-2)
Tech: 8 → 8 (0)
Changes by severity:
HIGH -2
MEDIUM -3
LOW -2purplemet-cli tech list [siteId|url]Lists technologies. Without an argument, returns the subscription-wide
inventory; with a siteId or URL, returns only technologies currently
detected on that site (and populates per-instance CVE counts that the
global view does not provide).
$ purplemet-cli tech list https://your-app.com
NAME CATEGORY VERSION EOL DETECTED CVEs
------ -------- ------- --- -------- ----
Nginx Web servers 1.25.3 - 2025-04-12 0
React JavaScript frame... 18.2.0 - 2025-04-12 0
PHP Server-side lang... 5.6.40 2018-12-31 2025-04-12 12purplemet-cli issues list [flags]Lists issues across all sites.
Subcommands:
| Subcommand | Description |
|---|---|
issues comment create <issueId> --contents "..." |
Add a comment to an issue |
issues comment list <issueId> |
List comments on an issue |
issues comment update <issueId> <commentId> --contents "..." |
Update a comment |
issues comment delete <issueId> <commentId> |
Delete a comment |
issues ignore <issueId> [id...] --reason <reason> |
Ignore one or more issues (reasons: RISK_ACCEPTED, NOT_APPLICABLE, FIX_IN_PROGRESS, BACKPORTING, FALSE_POSITIVE) |
issues activate <issueId> [id...] |
Re-activate previously ignored issues |
Manage domains tracked in your account (created manually or via discoveries).
# List domains, filter by name, fetch all pages
purplemet-cli domains list
purplemet-cli domains list --query "name~=internal"
purplemet-cli domains list --all
# Inspect / create / delete
purplemet-cli domains get <domainId>
purplemet-cli domains create example.com
purplemet-cli domains delete <domainId>A discovery enumerates web apps under a domain.
purplemet-cli discoveries list --query "status=DONE"
purplemet-cli discoveries get <discoveryId>
purplemet-cli discoveries stop <discoveryId># Certificates expiring soon (relies on the API ordering by validTo asc)
purplemet-cli certificates list --limit 20
# Filter by issuer or by status
purplemet-cli certificates list --query "issuer~=Let's Encrypt"
purplemet-cli certificates list --query "status=EXPIRED"
purplemet-cli certificates get <certId># IPs ordered by threat level / sites count (server-side)
purplemet-cli ip list --all
purplemet-cli ip list --query "threatLevel=HIGH"
purplemet-cli ip list --query "isp~=cloudflare"
purplemet-cli ip get <ipId>Network services exposed on your assets (HTTP, SSH, DB, etc.).
purplemet-cli services list --query "sensitive=true"
purplemet-cli services list --query "port=22"
purplemet-cli services get <serviceId>Differences detected between consecutive analyses (new tech, certificate rotation, header changes, etc.).
purplemet-cli changes list --query "priority=HIGH"
purplemet-cli changes list --query "type~=technology"
purplemet-cli changes get <changeId>Tags can be attached to sites, users, and tokens for grouping and access control.
purplemet-cli tags list
purplemet-cli tags create "production" --color "#FF0000" --description "Production assets"
purplemet-cli tags get <tagId>
purplemet-cli tags delete <tagId># List, get, download — works for any report type/format
purplemet-cli reports list --query "status=DONE"
purplemet-cli reports get <reportId>
purplemet-cli reports download <reportId> --output-file report.pdf
# Cancel a report still being generated
purplemet-cli reports cancel <reportId>Requires an ADMIN token. OPERATOR / READER tokens get
403 API_METHOD_NOT_ALLOWED.
purplemet-cli tokens list --query "role=ADMIN"
purplemet-cli tokens get <tokenId>
# Create — the secret is shown ONLY once on creation; token is active by default
purplemet-cli tokens create "ci-pipeline" --role OPERATOR --expires 2026-12-31
# Create in inactive state (must be activated from the UI before use)
purplemet-cli tokens create "ci-pipeline" --role OPERATOR --inactive
purplemet-cli tokens delete <tokenId>Requires an ADMIN token.
purplemet-cli users list --query "status=ENABLED"
purplemet-cli users get <userId>
purplemet-cli users create alice@example.com --first-name Alice --last-name Doe --role OPERATOR
purplemet-cli users disable <userId>
purplemet-cli users enable <userId>
purplemet-cli users delete <userId>Requires an ADMIN token.
# List active sessions, filter by user or IP
purplemet-cli sessions list --query "active=true"
purplemet-cli sessions list --query "userEmail~=@example.com"
# Revoke (alias: delete, terminate)
purplemet-cli sessions revoke <sessionId>purplemet-cli version$ purplemet-cli version
purplemet-cli v1.0.0 (abc1234) built 2025-01-15
$ purplemet-cli version --json
{"commit":"abc1234","date":"2025-01-15","version":"v1.0.0"}Bash, zsh and fish completions are installed automatically by Homebrew, install.sh and make install. For any other install path, run purplemet-cli completion <shell> --help for setup instructions.
These flags are available on all commands.
| Flag | Env Variable | Default | Description |
|---|---|---|---|
--token |
PURPLEMET_API_TOKEN |
— | API authentication token |
--base-url |
PURPLEMET_BASE_URL |
https://api.purplemet.com |
API base URL |
--timeout |
PURPLEMET_TIMEOUT |
30000 |
Per-request HTTP timeout in ms |
--json |
PURPLEMET_JSON |
false |
Machine-readable JSON output |
--verbose / -v
|
PURPLEMET_VERBOSE |
false |
Verbose logging to stderr |
--insecure |
PURPLEMET_INSECURE |
false |
Skip TLS certificate verification |
--config |
PURPLEMET_CONFIG |
— | Path to a project config file (default: auto-discover .purplemet.yml) |
--no-admin-warning |
PURPLEMET_NO_ADMIN_WARNING |
false |
Suppress the warning shown when invoking admin-only commands |
--fail-on-severity,--wait-timeoutand--poll-intervalare specific toanalyze(see above).
Configuration is resolved in priority order (first wins):
-
CLI flags (
--token,--json, etc.) -
Environment variables (
PURPLEMET_API_TOKEN, etc.) -
.envfile (auto-loaded from current directory) -
Project config file (
.purplemet.yml— auto-discovered from the current directory up to the project root) -
User config file (
~/.purplemet/config.yml) - Defaults
See Configuration documentation for full details.
The CLI automatically loads a .env file from the current directory:
PURPLEMET_API_TOKEN=your-token-here
PURPLEMET_FAIL_SEVERITY=high
PURPLEMET_WAIT_TIMEOUT=300000Put a .purplemet.yml at the root of your repository to capture the options used to analyze that project. The CLI auto-discovers it by walking up from the current working directory until it finds either the file or the project boundary (a .git/ directory).
# Default target for `purplemet-cli analyze` (siteId or URL).
# With this set you can simply run `purplemet-cli analyze` — no argument needed.
site: https://example.com
verbose: true
# Security gates for this project
fail_severity: high
fail_rating: C
fail_on_kev: true
fail_on_headers: true
exclude_tech:
- php
- javaLookup order used to locate the file:
-
--config <path>flag (explicit; errors if missing) -
$PURPLEMET_CONFIGenv var -
.purplemet.yml/.purplemet.yamlin the current directory, then each parent up to the first.git/
Security: a project config is meant to be committed, so it must not contain secrets. If a project file sets
token,basic_userorbasic_pass, those fields are stripped at load time and a warning is printed. Put secrets in env vars or in~/.purplemet/config.ymlinstead.
Typical use cases:
- Run
purplemet-cli analyzewithout arguments from any subfolder of the repo - Share the same gate configuration between local runs and CI/CD (one source of truth)
- Pin per-project exclusions (
exclude_tech) or thresholds (fail_on_epss) next to the code
Persistent user-level defaults — the right place for your API token and any personal preferences shared across all projects.
token: ppm_xxx
base_url: https://api.purplemet.com
poll_interval_ms: 10000
timeout_ms: 30000
verbose: true
fail_severity: highFor --fail-on-severity:
| Level | Blocks on |
|---|---|
critical |
Critical only |
high |
High + Critical |
medium |
Medium + High + Critical |
low |
Low + Medium + High + Critical |
info |
All issues |
The analyze command supports 4 output formats via --format or --json:
| Format | Flag | Description |
|---|---|---|
| Human | (default) | Colored text output with summary table |
| JSON |
--json or --format json
|
Machine-readable JSON with full analysis data |
| SARIF | --format sarif |
SARIF 2.1.0 for GitHub Code Scanning and compatible tools |
| HTML | --format html |
Standalone HTML report with visual styling |
Purplemet • Analysis e983302a-7c76-4dce-8b29-1c525652469f • DONE
Duration: 01:13
Grade: B (score: 3)
Issues: total=3 critical=0 high=0 medium=0 low=3 cve=0 kev=0
Tech: 8 technologies detected
WAF: CloudFlare
Message: Task completed in 69s.
{
"analysis": {
"id": "e983302a-7c76-4dce-8b29-1c525652469f",
"status": "DONE",
"rating": "B",
"score": 3,
"issueCnt": 3,
"issueCnts": { "CRITICAL": 0, "HIGH": 0, "MEDIUM": 0, "LOW": 3 },
"technologyCnt": 8,
"waf": "CloudFlare",
"issues": [
{
"severity": "low",
"name": "Missing Content-Security-Policy header",
"description": "..."
}
]
}
}SARIF 2.1.0 output is compatible with:
- GitHub Code Scanning (
github/codeql-action/upload-sarif) - Azure DevOps Advanced Security
- Any SARIF-compatible viewer
purplemet-cli analyze https://your-app.com --format sarif --output-file results.sarif| Code | Meaning | Recommended CI Action |
|---|---|---|
| 0 | Success — no issues above threshold | Pipeline passes |
| 1 | Vulnerabilities found above --fail-on-severity threshold |
Fail or warn — review findings |
| 2 | Analysis error on Purplemet platform | Fail — check target URL accessibility |
| 3 | Timeout (--wait-timeout exceeded) |
Fail — increase timeout or check manually |
| 4 | Network or HTTP API error | Fail — check token, network, rate limits |
| 5 | Usage error (invalid arguments) | Fail — fix command syntax |
| 6 | API contract error (unexpected response) | Fail — check CLI version, contact support |
purplemet-cli analyze https://your-app.com --json --fail-on-severity high
EXIT_CODE=$?
case $EXIT_CODE in
0) echo "Analysis passed — no issues above threshold" ;;
1) echo "WARNING: vulnerabilities found above threshold" ;;
2) echo "Analysis error — check target accessibility" ;;
3) echo "Timeout — increase --wait-timeout or check manually" ;;
*) echo "Error (exit code $EXIT_CODE)" ; exit 1 ;;
esacSee Exit codes documentation for full details.
Ready-to-use integrations for major CI/CD platforms:
| Platform | Type | Documentation |
|---|---|---|
| GitHub Actions | Composite Action | Guide · Action README |
| GitLab CI/CD | Include Template | Guide · Template |
| Bitbucket Pipelines | Docker Step | Guide · Template |
| Jenkins | Shared Library | Guide · Library |
| Azure DevOps | Marketplace Extension | Guide · Extension |
# Install
curl -sSL https://raw.githubusercontent.com/Purplemet/cli/main/scripts/install.sh | sh
# Analyze
PURPLEMET_API_TOKEN=$TOKEN purplemet-cli analyze https://your-app.com \
--json --fail-on-severity high --wait-timeout 300000Or with Docker:
docker run --rm \
-e PURPLEMET_API_TOKEN=$TOKEN \
ppmsupport/purplemet-cli analyze https://your-app.com --json --fail-on-severity high# Quick analysis with verbose output
purplemet-cli analyze https://your-app.com -v
# Check your sites
purplemet-cli sites list
# Get details for a site
purplemet-cli sites get a1b2c3d4-e5f6-7890-abcd-ef1234567890
# Create a site with a weekly schedule
purplemet-cli sites create https://your-app.com \
--schedule-frequency WEEKLY \
--schedule-day monday \
--schedule-time 02:00
# Compare two analyses
purplemet-cli diff <id1> <id2> --site-id <siteId># Blocking: fail the pipeline on high/critical issues
purplemet-cli analyze https://your-app.com --json --fail-on-severity high
# Non-blocking: always pass, inspect results
purplemet-cli analyze https://your-app.com --json || true
# With timeout for bounded execution
purplemet-cli analyze https://your-app.com --json \
--fail-on-severity high --wait-timeout 300000
# Generate SARIF for GitHub Code Scanning integration
purplemet-cli analyze https://your-app.com --format sarif --output-file results.sarif
# Advanced gates: block on CVEs, EOL, and require WAF
purplemet-cli analyze https://your-app.com --json \
--fail-on-severity high \
--fail-on-cvss 9.0 \
--fail-on-eol \
--fail-on-kev \
--require-waf
# Block on certificate expiring within 30 days
purplemet-cli analyze https://your-app.com --json \
--fail-on-cert-expiry 30
# Block if specific technologies are detected
purplemet-cli analyze https://your-app.com --json \
--exclude-tech "php,java"| Document | Description |
|---|---|
| Purplemet Platform | Official Purplemet product documentation (ratings, analyses, issues, remediation) |
| Interpreting Results | How to read reports, prioritize remediation, configure gates |
| Issues Management | Ignore, activate, and comment on issues |
| Technology Detection | List and monitor detected technologies |
| Configuration | Environment variables, config file, .env file, severity levels |
| Exit Codes | Detailed exit code reference with CI/CD recommendations |
| Docker | Docker image usage and CI/CD examples |
| FAQ & Troubleshooting | Common errors and solutions |
| Releases | Release history and binaries |
| API Reference | Official Purplemet REST API documentation (OpenAPI/Swagger) |
| Integrations | |
| GitHub Actions | Complete GitHub Actions guide |
| GitLab CI/CD | GitLab CI/CD integration guide |
| Bitbucket Pipelines | Bitbucket Pipelines guide |
| Jenkins | Jenkins integration guide |
| Azure DevOps | Azure DevOps integration guide |
make help # Show all targets
make build # Build for current platform
make test # Run tests with race detector
make lint # Run staticcheck
make lint-full # Run golangci-lint
make vet # Run go vet
make build-all # Cross-compile all platformsThe release workflow is fully automated and reproducible. Run these from a clean main branch:
make verify-build VERSION=v1.0.X # Verify local build matches CI build
make release VERSION=v1.0.X # Build, regenerate Formula, commit, tag (no push)
git push origin main && git push origin v1.0.Xmake verify-build is the recommended pre-release check. It runs make build-all locally, then runs the CI build:linux-amd64 job in docker via gitlab-ci-local, and compares the SHA256 of the resulting binaries. If they match, the local build is reproducible against CI and verify:formula-sha will pass.
Requires Docker running and gitlab-ci-local installed.