Drydock reviews package artifacts before a maintainer approves publication. It compares the candidate with a tag-aware published baseline, runs deterministic supply-chain checks, optionally sends changed-file evidence to Cloudflare Workers AI, and saves a review report.
Approval stays outside Drydock: maintainers approve in npm, npmjs.com, or GitHub with their own required 2FA/review step. Drydock never publishes and never collects approval codes.
Drydock runs as a hosted service at drydock.org; this repository is its source, and it can be self-hosted on your own Cloudflare account. To add it to a release, jump to Add Drydock to your release.
Aikido Security sponsors Drydock's development. Sponsorship funds the work; it does not influence detection rules, findings, or risk scoring.
If you publish from GitHub Actions, use a workflow gate. It is the path for npm, PyPI, and VS Code
alike, and it is what the example repositories below use. npm stage publish is a shortcut for npm
maintainers who already publish that way from a terminal — if you don't, skip it. Both paths produce
the same review report; they differ only in who holds the candidate while you read it.
CI builds the release and uploads it. A GitHub Environment pauses the publish job until you accept the review in Drydock, then the same job publishes the exact reviewed bytes.
-
Sign in at drydock.org and create the organization that owns the release.
-
In
Organization settings → GitHub App, install the Drydock GitHub App on the account that hosts the repository. -
In the repository's
Settings → Environments, create an environment (for exampleproduction) and enable Drydock as a custom deployment protection rule. -
Back in Drydock settings, map that repository and environment to your organization.
-
Split your release workflow into a build job that uploads the artifacts and a publish job pinned to the protected environment:
jobs: pack: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm ci - run: npm pack --pack-destination dist - run: cd dist && sha256sum *.tgz > SHA256SUMS - uses: actions/upload-artifact@v4 with: name: npm-release-candidates path: dist/ publish: needs: pack environment: production # Drydock holds this job permissions: { id-token: write, contents: read } steps: - uses: actions/download-artifact@v4 with: { name: npm-release-candidates, path: dist } - run: cd dist && sha256sum --check --strict SHA256SUMS - run: npm publish dist/*.tgz --access public --provenance
-
Push a release. The publish job pauses, Drydock reviews the uploaded artifacts, and accepting the review releases the job. Rejecting it fails the release closed.
There is no Drydock manifest to maintain: package name, version, and ecosystem are read from metadata
inside the uploaded .tgz, .whl, .tar.gz, or .vsix. A monorepo upload becomes one report per
package, and the job continues only once every package is accepted. The publish job must publish the
bytes it downloaded — rebuilding after approval breaks the review boundary, which is what the
SHA256SUMS record/check pair enforces.
Full workflows for each ecosystem: PyPI CI example,
npm monorepo CI example, and
docs/workflow-gates.md.
npm holds a private staged tarball; Drydock reviews it and you finish the publish in npm with your own 2FA.
- Create a Drydock organization, then on npmjs.com generate a granular access token with
Packages and scopes: Read-onlyandOrganizations: No accesscovering the scopes you publish. - Paste it into
Organization settings → npm access. - Run
npm stage publishfrom the package directory. Drydock discovers the stage, scans it, and shows the report. - Record your decision in Drydock, then complete or discard the publish on npm — on npmjs.com or
with the
npm stage approve/npm stage rejectcommand Drydock shows you.
The longer walkthrough of both paths — what the report contains, how the credential boundary works, and per-ecosystem workflow examples — lives at drydock.org/docs.
drydock.org/docs is the guide for maintainers setting Drydock up. The
files below are the engineering and operator reference for working on Drydock or self-hosting it;
start with docs/README.md to pick the smallest relevant one. Common entry points:
docs/self-hosting.md— local setup, Cloudflare resources, deployment, GitHub App, and Slack setup.docs/architecture.md— runtime components, trust boundaries, adapters, storage, and API shape.docs/security-model.md— non-negotiable security posture.docs/workflow-gates.md— GitHub Environment gate contract for PyPI, npm, and VS Code workflow-gated releases.docs/release-safety.md,docs/security-detection-corpus.md,docs/detection-eval.md, anddocs/e2e-test-environment.md— verification and detection quality.
server/ Hono Worker, scan pipeline, adapters, persistence, webhooks
src/ Preact UI and typed API models
drizzle/ D1 migrations
docs/ Architecture, security, workflow, setup, and test references
test/ Vitest, Worker-runtime, security corpus, and fake-registry e2e
Requirements: Node 22.14.0+ and pnpm 11.1.1 (pinned in package.json).
pnpm install
cp .dev.vars.example .dev.vars
pnpm run devThe dev server runs the Worker and UI through Vite at http://localhost:5173. Edit .dev.vars with local Cloudflare, Better Auth, npm, GitHub App, Slack, and optional Workers AI/Flagship values as described in docs/self-hosting.md.
Useful commands:
pnpm run lint
pnpm run format:check
pnpm run typecheck
pnpm run test
pnpm run test:e2e
pnpm run verifyFor deterministic browser testing without real staged publishes, use the local fake-registry harness in docs/e2e-test-environment.md. For an agent-readable product walkthrough, use docs/agent-tour.md.
The checked-in wrangler.jsonc describes the maintainers' deployment. Self-hosters copy
docs/examples/wrangler.self-host.jsonc to the gitignored wrangler.self-host.jsonc, pass it explicitly to
Vite, migrations, and secret commands, then deploy the config generated by the Vite build. See
docs/self-hosting.md for the complete flow.
Core Cloudflare bindings are D1 (DB), the Dynamic Worker loader (LOADER), and Workers AI
(AI). Queue (SCAN_QUEUE), R2 (ARTIFACTS), KV (COMPARE_CACHE), Flagship (FLAGS),
Analytics Engine (PRODUCT_ANALYTICS), email (SEND_EMAIL), and static assets (ASSETS) support
the corresponding optional or deployed features.
Important secrets/vars:
BETTER_AUTH_SECRET,BETTER_AUTH_URLNPM_CONNECTIONS_ENCRYPTION_KEYGITHUB_APP_ID,GITHUB_APP_SLUG,GITHUB_APP_CLIENT_ID,GITHUB_APP_CLIENT_SECRET,GITHUB_APP_PRIVATE_KEY,GITHUB_APP_WEBHOOK_SECRET, and optionalGITHUB_APP_STATE_SECRETSLACK_CLIENT_ID,SLACK_CLIENT_SECRET
Run pnpm run cf-typegen after changing Cloudflare bindings.
The authenticated JSON API lives under /api/v1. The main resources are:
- scans: create/list/read/export reports, compare published baselines, and fetch prior file samples;
- npm connection: read public metadata, store/rotate, validate, and remove the current organization token;
- release targets and workflow gates: map GitHub repositories/environments, review queued gate artifacts, and post accept/reject decisions;
- auth/org/settings helpers for Better Auth-backed sessions and organization membership.
Consult route definitions under server/routes/ for exact request/response shapes; shared types are imported by the UI from server/.
- Package artifacts are untrusted evidence and are never executed.
- npm credentials are encrypted at rest, decrypted only for registry access, and never passed into the Dynamic Worker sandbox.
- The sandbox can fetch only through constrained brokers/gateways and returns bounded metadata/text evidence.
- AI review is advisory and on by default behind the
ai-reviewkillswitch, and cannot downgrade deterministic findings. - Raw tarballs are not retained by default; persisted reports use redacted summaries and canonical report JSON.
See docs/security-model.md for the full contract.
Drydock is open-source software released under the Apache License 2.0.
