Skip to content

Learn Drydock

Review what ships, not just what changed.

Drydock is a release checkpoint for package maintainers. It opens the package that is about to be published, compares it with the last release, points to risky changes, and gives a human the final decision.

About 5 minutes · No security background required · npm, PyPI, VS Code, and atpm

On this page

Start here

A second pair of eyes at the last responsible moment.

Pull requests show source changes. Registries deliver built archives. Drydock sits between those two moments and reviews the exact release candidate before it becomes public.

The artifact gap

Pull requestsource

The code your team reviewed

Tests, configuration, and source files before packaging. Useful context, but not necessarily the bytes a registry will serve.

Release candidateartifact

The package your users receive

Generated files, bundled dependencies, lifecycle scripts, binaries, and package metadata after the build has finished.

The question Drydock answers

Does this release candidate contain anything the maintainer should understand before it ships?

The review loop

Release checkpointcandidate → evidence → decision
  1. 01Hold

    npm, atpm, or GitHub pauses a built release candidate.

  2. 02Review

    Drydock compares the artifact, explains findings, and records provenance.

  3. 03Decide

    A maintainer approves or rejects. Drydock never publishes the package.

What the review tells you
Release delta
What changed?
A file-by-file diff against the most relevant published version.
Risk signals
What needs attention?
Install hooks, process execution, network access, credential reads, native code, and ecosystem-specific risks.
Provenance
Are these the reviewed bytes?
Package identity, artifact hashes, baseline choice, and the evidence behind every recommendation.

Inside a report

Example review@acme/cli · 4.2.0 → 4.3.0
manual review required
Recommendation
Do not approve yet

The release adds an install-time script and a new network-capable file.

Release delta
2 new findings

Findings are pinned to the changed files and lines that introduced them.

Artifact context
1 existing finding

Pre-existing package risk stays visible without drowning out this release.

Provenance
4 artifacts verified

Names, versions, baselines, and SHA-256 digests show exactly what was reviewed.

A finding is evidence, not a verdict. Open the file, read the highlighted diff, check whether the behavior is intended, and record the reason for your decision. Clean reports still wait for a human when the release path is gated.

Safety model

Package contents are hostile evidence

Drydock reads bounded file listings and text samples. It never installs, imports, builds, executes, or renders package-provided active content.

Publish credentials stay elsewhere

npm tokens are isolated from the sandbox. Workflow releases keep their publish credential in GitHub Actions. Drydock never needs it.

Deterministic checks stay authoritative

The AI reviewer is advisory and on by default behind a per-organization killswitch. Its findings can raise concern but never downgrade a deterministic finding.

Failures do not become approvals

Missing, malformed, ambiguous, or unverifiable evidence keeps a gated release blocked instead of silently passing it.

Choose a release path

Put the checkpoint where your release already pauses.

Every path creates the same kind of Drydock report. The difference is who holds the candidate while you review it and where the final decision happens.

Compare the paths

npm stage publish

npm only
npm stage publish
Best for
Maintainers already using npm stage publish.
Held by
npm holds the unpublished package.
Decision
You finish or decline the publish in npm with 2FA.
Follow this setup →

atpm trusted publishing

atpm
npm stage publish --provenance
Best for
atpm packages using OIDC trusted publishing.
Held by
The publisher's AT Protocol repository holds the candidate.
Decision
You approve in atpm; Drydock only shows you what changed.
Follow this setup →

GitHub workflow gate

Preview
environment: production
Best for
PyPI, npm, VS Code, monorepos, and CI-first releases.
Held by
A GitHub Environment holds the publish job.
Decision
You approve or reject the job from Drydock.
Follow this setup →
Quick decision

Use npm staging for npm's private candidate store. For atpm, open the credential-free staged review from the link on your staged dashboard. For PyPI, the VS Code Marketplace, or other CI-first releases, use a GitHub workflow gate.

Path 1 · npm stage publish

npm holds the candidate; you keep the approval.

This is the shortest route for npm. Stage the package, let Drydock review the private tarball, then return to npm to publish or discard it.

Registrynpm stage publish
Drydock connectionRead-scoped npm token
Final approvalnpm 2FA

Connect npm once

  1. 01
    Create a Drydock organization for the team that publishes the package.
  2. 02
    On npmjs.com, generate a granular access token with Packages and scopes: Read-only on the packages you stage and Organizations: No access. A scoped package like @nanostores/i18n is covered by selecting the @nanostores scope there; the Organizations permission is for member and settings management, which Drydock never reads.
  3. 03
    Open Organization settings → npm access and paste the token.
  4. 04
    Save. Drydock encrypts the token and checks it against the registry right away.
  5. 05
    Drydock now discovers packages in npm stage publish automatically. Use Check npm on the dashboard when you want an immediate refresh.

Run a release review

  1. 01
    From the package directory, run npm stage publish. npm uploads the candidate but does not make it public.
  2. 02
    Drydock discovers the stage and queues a scan. You can also trigger discovery with Check npm.
  3. 03
    Open the report. Start with the recommendation, then inspect release-delta findings and the highlighted file diff. The baseline follows the staged dist-tag when possible, so beta and maintenance releases compare against the right line.
  4. 04
    Record your decision and reason in Drydock. Then finish on npm with your normal 2FA — either on npm's staged-packages page, or with the npm stage approve / npm stage reject command Drydock shows you after saving.
Credential boundary

The npm token is encrypted at rest and only attached by the registry gateway for allowed npm endpoints. The archive sandbox never sees it, and Drydock never receives the credential that completes the publish.

Path 2 · atpm trusted publishing

The publisher holds a public, content-addressed candidate.

atpm uses GitHub OIDC for trusted publishing, so CI needs no long-lived token. A staged release is a public record in the publisher's AT Protocol repository, and Drydock verifies its provenance and reviews its content-addressed blob directly.

Publisher policyStage allowed, publish denied
Drydock accountNot required
Final approvalYours, in atpm

Set the publisher policy

  1. 01
    In the publisher's AT Protocol repository, configure the package's dev.atpm.alpha.trustPublisher record with the GitHub owner, repository, and workflow allowed to stage it.
  2. 02
    Set allowStage: true and allowPublish: false. The workflow may upload a candidate, but it cannot make that candidate public — so the release is already paused before anyone reviews it.
  3. 03
    Publish with --provenance. The Sigstore attestation is what lets a review say where the release was built, and whether that matches the record above.

Review before publishing

  1. 01
    From the package directory, run npm stage publish --provenance. atpm stores the candidate without publishing it.
  2. 02
    Open the Drydock link beside the candidate on your staged dashboard. No account and no sign-in: a staged record is public, so the review is too.
  3. 03
    Read the diff against the release this candidate would replace, plus the verified build repository and workflow, package identity, and SHA-512 binding.
  4. 04
    Approve or withdraw in atpm, with npm stage approve <id> or npm stage reject <id>. Drydock takes no part in that decision.
Credential boundary

Drydock reads public AT Protocol records and content-addressed blobs. It receives no atpm credential and cannot stage, approve, reject, or publish a package.

Path 3 · GitHub workflow gates Preview

When the registry can't pause, the workflow can.

CI uploads built files and reaches a protected publish job. GitHub asks Drydock for a decision before the held job continues.

Supported evidencewhl, tar.gz, tgz, vsix
Release holdGitHub Environment
Publish credentialStays in GitHub Actions

Connect GitHub once

  1. 01
    Create or choose the Drydock organization that owns the release.
  2. 02
    Open Organization settings → GitHub App and install the Drydock GitHub App on the account that hosts your repository.
  3. 03
    In the repository, create a GitHub Environment such as production and enable Drydock as a custom deployment protection rule.
  4. 04
    Back in Drydock settings, map that repository and environment to the organization. You can optionally narrow the gate to one artifact name.
  5. 05
    Add a build job that uploads release candidates and a publish job that uses the protected environment. Start from one of the examples below.

Prepare the release artifacts

For npm, PyPI, and VS Code, there is no Drydock manifest to maintain. Upload built .whl, .tar.gz, .tgz, or .vsix files before the protected job starts. Drydock derives the ecosystem, package name, and version from metadata inside each archive.

Generate SHA256SUMS beside the artifacts during the build, upload it with them, and verify it in the publish job. The digests in the Drydock report should match. Most importantly: download and publish the uploaded files—never rebuild after approval.

Large compiled PyPI releases can upload one bounded artifact per wheel or sdist. Name the shards pypi-release-candidate-* and set the release target's ecosystem to PyPI; Drydock then processes them one at a time while keeping every distribution in the review and provenance. A target left on auto-detect has no name to match, so it keeps the smaller single-upload limits.

Monorepos work as one gate

Drydock groups uploaded files by package and opens a separate report for each one. The held job continues only after every package is approved; rejecting one blocks the release set.

Workflow examples

Each workflow has the same contract: build once, record checksums, upload, pause at the environment, verify the download, and publish without rebuilding.

PyPI with Trusted Publishing
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.x"
      - run: python -m pip install build
      - run: python -m build
      - run: cd dist && sha256sum *.whl *.tar.gz > SHA256SUMS
      - uses: actions/upload-artifact@v4
        with:
          name: pypi-release-candidate
          path: dist/

  publish:
    needs: build
    environment: production
    permissions:
      id-token: write
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: pypi-release-candidate
          path: dist
      - run: cd dist && sha256sum --check --strict SHA256SUMS
      - run: rm dist/SHA256SUMS
      - uses: pypa/gh-action-pypi-publish@release/v1
npm packed artifacts
jobs:
  pack:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run pack:all # write dist/*.tgz
      - run: cd dist && sha256sum *.tgz > SHA256SUMS
      - uses: actions/upload-artifact@v4
        with:
          name: npm-release-candidates
          path: dist/

  publish:
    needs: pack
    environment: production
    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: |
          for tgz in dist/*.tgz; do
            npm publish "$tgz" --access public --provenance
          done
VS Code extension
jobs:
  package:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npx @vscode/vsce package --out dist/extension.vsix
      - run: cd dist && sha256sum *.vsix > SHA256SUMS
      - uses: actions/upload-artifact@v4
        with:
          name: vscode-release-candidate
          path: dist/

  publish:
    needs: package
    environment: production
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: vscode-release-candidate
          path: dist
      - run: cd dist && sha256sum --check --strict SHA256SUMS
      - run: npx @vscode/vsce publish --packagePath dist/extension.vsix
Authentication stays in the publish job

Add the registry authentication your release already uses—for example PyPI Trusted Publishing, npm trusted publishing or a scoped token, or a VS Code Marketplace token—to the protected publish job. Drydock does not receive those credentials.

Approve or reject the gate

  1. 01
    The publish job reaches environment: production. GitHub pauses it and sends Drydock a signed protection-rule request.
  2. 02
    Drydock fetches the uploaded artifacts, verifies identity and digests, and creates one report per package.
  3. 03
    Review every report in the release set. Approve intended changes or reject the gate when evidence is unsafe, unexpected, or incomplete.
  4. 04
    After every package is approved, Drydock releases the GitHub job, which verifies SHA256SUMS and publishes the downloaded files. Any rejection stops the whole release.
Fail closed

If Drydock cannot verify the webhook, resolve the artifact set, parse a package, finish a scan, or return a safe decision, the workflow does not get a silent pass.

Diffs in dependency PRs

Review the bumps you merge, not just the releases you ship.

The same public diff pages work from the consumer side. A Renovate or Dependabot PR names an exact version pair, so the published-package diff has a predictable URL — no account, token, or API call. Set it up once and every dependency bump links its own diff.

Links, not lookups

Both integrations add plain markdown links. Nothing contacts Drydock when a PR renders — only when a reviewer clicks — and the linked pages serve public-registry data anonymously.

Ready when your release is

Add the checkpoint before the next publish.

Connect npm for the shortest path, or install the GitHub App to protect a CI release. Your first report will make the model concrete.