← All docs

Overview

From README.md at v0.1.0 ·View the source on GitHub

A package firewall you run yourself. Yellow Jack sits between your developers and the public package registries (npm, PyPI, Maven Central, Docker/OCI, Go modules) and decides, at the moment a package is pulled, whether it is allowed in. Every decision is recorded with its reason, and a refused developer is told why and what happens next.

“Your firewall stops at the package manager. Yellow Jack starts there.”

The name is the maritime yellow jack: the quarantine flag a ship flies so its cargo is held and inspected before it may enter port.

What it does

  • Known-malware list. Packages and individual releases named in a malware advisory are refused before the registry is contacted. Build the list from the public OpenSSF Malicious Packages data with scripts/build-malware-feed.py.
  • Release cooldown. A release younger than a configured age is held back, and the resolver is steered to the newest release old enough to trust. On by default for npm, PyPI, Maven and Go modules (FW_MIN_RELEASE_AGE_DAYS); not enforced for container images, which carry no trustworthy publish date.
  • Allow and block lists. Your organisation’s own decisions, by package or by exact release, re-read while the gate runs. The console shows them; you edit them in your list files (or through CONSOLE_LIST_REPO, on a console image you build with git).
  • OpenSSF Scorecard (optional). Score each package’s source repository on demand, on your own infrastructure, and hold packages below a threshold for a person to review. FW_SCORECARD_MODE=off turns scoring off entirely. Scanning on your own machines (FW_SCORECARD_MODE=local) runs the scheduler and scanner, which are not published as images: build and run them with docker-compose.yml from this repository. The Helm chart does not run local mode.
  • Decisions, recorded. An append-only audit log of every allow and refusal, with the rule that fired, searchable in the console and exportable as NDJSON.
  • A console. An overview of what the gate is doing, a queue of packages waiting for a person, every refusal explained, the policy in plain words, package lookup, request and download volumes, and sign-in with OIDC.
  • Report mode. FW_MODE=report computes every verdict and refuses nothing, so the gate can be introduced without breaking a single build.
  • Zero egress to us. The gate talks only to the registries you configure. No telemetry, no licence server, no call home. docs/EGRESS.md says how to verify it.

How clients reach it. Package managers are configured to use Yellow Jack as their registry (for example npm config set registry http://yellowjack:8080). It is a gate for clients that use it: a client pointed straight at the public registry does not pass through it, so pair it with egress rules if that must not happen.

Quick start

On Kubernetes. The Helm chart installs an npm gate, the control plane, the console and an evaluation Postgres. Each release publishes the chart and its images (FIPS 140-3 builds, amd64 and arm64), with the chart pinned to the images by digest (docs/RELEASING.md):

helm install yj oci://ghcr.io/flyyellowjack/charts/yellowjack --version 0.1.0 --wait

To build from source instead, build the images from this repository, push them to a registry your cluster can pull from, and install the chart in deploy/helm/yellowjack:

REG=registry.example.com/yj          # your registry
docker build -t $REG/yellowjack/firewall:dev -f Dockerfile .
docker build -t $REG/yellowjack/approval:dev -f approval/Dockerfile .
docker build -t $REG/yellowjack/console:dev  -f console/Dockerfile .
for i in firewall approval console; do docker push $REG/yellowjack/$i:dev; done

helm install yj deploy/helm/yellowjack \
  --set images.firewall.repository=$REG/yellowjack/firewall \
  --set images.approval.repository=$REG/yellowjack/approval \
  --set images.console.repository=$REG/yellowjack/console \
  --wait

The install prints the gate’s address. Point a client at it (npm config set registry http://yj-yellowjack-gate-npm:8080 from inside the cluster). Before production, read the three items at the top of values.yaml: your own upstream registry and public URL, your own database, and pinning images by digest.

See it refuse something in about a minute: QUICKSTART.md. One binary, one deny list, no account and no database.

Run the whole thing, with the console: docs/REFERENCE_DEPLOYMENT.md puts the gate in front of a package registry with the console to read its decisions, and docs/DEMO.md seeds a local stack with real packages so every console page has something true to show.

go build -o yellowjack .    # the gate
./yellowjack                # an npm gate on :8080; FW_ECOSYSTEM=npm|pypi|oci|maven|go

Check an install before it runs: yj dry-run

Some build tools wrap pip or npm themselves, so nothing can sit in the middle of the install. yj asks the firewall first. It runs the real package manager’s own resolve-only mode against the gate, so the gate’s verdicts apply exactly as they would to the install, and prints what the gate would refuse, in the gate’s own words, or what it would serve:

Each release carries yj for Linux, macOS (amd64 and arm64) and Windows (amd64), with a SHA256SUMS file signed by the release workflow. Install it without Go, checking the signature and then the checksum (cosign does the first):

V=0.1.0 P=linux-amd64     # or linux-arm64, darwin-arm64, darwin-amd64
U=https://github.com/flyyellowjack/yellowjack/releases/download/v$V
for f in yj-$P SHA256SUMS SHA256SUMS.sigstore.json; do curl -fsSLO "$U/$f"; done
cosign verify-blob --bundle SHA256SUMS.sigstore.json \
  --certificate-identity "https://github.com/flyyellowjack/yellowjack/.github/workflows/release.yml@refs/tags/v$V" \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com SHA256SUMS
grep " yj-$P\$" SHA256SUMS | sha256sum -c -     # macOS: shasum -a 256 -c
chmod +x yj-$P && sudo mv yj-$P /usr/local/bin/yj && yj --version

Windows, and what the signature does and does not prove, are in docs/RELEASING.md. From source: go build -o yj ./yj.

export YJ_GATE=http://firewall.internal:8080
yj dry-run npm install left-pad debug@4     # npm 7+
yj dry-run pip install -r requirements.txt  # pip 22.2+

It exits 0 when nothing would be refused, 1 when something would, and 2 when it could not tell (a failure that was not the firewall’s is never reported as a refusal). It does not resolve dependencies itself; npm and pip do.

Documentation

Repository layout

*.go                 the gate (proxy, decision engine, one Ecosystem per registry type)
approval/            control plane: approval queue, audit log, scores (Postgres)
console/             the web console
scheduler/ scanner/  on-demand OpenSSF Scorecard scans, one short-lived container each
yj/                  the dry-run CLI: what the firewall would say before you install
cache/               optional caching front door
deploy/              Helm chart and the reference deployment
e2e/                 end-to-end tests with real package managers
docs/                operator and contributor documentation

Contributing

See CONTRIBUTING.md. Every change is tested at three tiers (unit, a real client, and an attacker’s view); docs/TEST_TIERS.md explains what that means.

License

GNU Affero General Public License v3.0 (see LICENSE). AGPLv3 also covers networked use, so modifications stay open when someone runs Yellow Jack as a hosted service, not only when they distribute the binary. © 2026 Yellow Jack.