Overview
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=offturns 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 withdocker-compose.ymlfrom 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=reportcomputes 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
- docs/SETUP.md: build, run and test; the container stack; serving the gate over HTTPS.
- docs/CONFIGURATION.md: every setting, with its default.
- docs/REFERENCE_DEPLOYMENT.md: a deployment you can run end to end.
- docs/FAILURE_MODES.md: every way the gate can fail, what the developer sees, and the test that keeps each row true.
- docs/EGRESS.md: exactly what the gate connects out to.
- docs/CONFIG_SURFACE.md: where settings come from, and what can never influence them.
- docs/MODE_MATRIX.md: what each combination of modes does.
- docs/CLIENT_TRUST.md: making clients trust a private CA.
- docs/TEST_TIERS.md and docs/E2E_TESTING.md: how the tests are organised, what runs where and when, and how to run the real-client suite yourself.
- SECURITY.md: how to report a vulnerability.
- CHANGELOG.md: what has shipped.
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.
Yellow Jack