MainSDK
Search⌘K
Interfaces

Security and privacy

Dependency checks

deps

Catch made-up, brand-new and look-alike packages, known advisories, denied licences and unreviewed install scripts in your dependencies when you run mainsdk check, with a 24-hour cache and a clear notice offline.

Building for 0.5ships as a beta APIPhase 1 · Core, public betaSpec dependency-checkFree in your app, Apache-2.0

Status Status is where the work is: Planned (in a milestone, not started), Building (tickets in progress), Preview (usable, may change), then the stability it ships at.

Stability The promise an interface ships with.

  • Stable Follows semantic versioning; breaking changes need a new major, 12 months of overlap and a codemod.
  • Beta Usable in production; may change before it becomes stable.
  • Experimental May change or go away; needs an explicit opt-in in main.yaml.
Stability levels
Updated 2026-10-28

The deps gate of mainsdk check flags made-up, brand-new and look-alike packages, advisories, denied licences and unreviewed install scripts in your dependencies. It runs in the CLI only and is free.

At a glance

deps:
  min-age: 7d                    # a direct dependency first published more recently is reported
  licences: { deny: [AGPL-3.0-only, SSPL-1.0], allow: [], unknown: warn }
  advisories:
    fail-on: high                # critical | high | moderate | low | none
    ignore:
      - { id: GHSA-xxxx-xxxx-xxxx, until: 2027-01-31, reason: "Not reachable: only used in tests" }
  scripts: { allow: [esbuild, sharp] }
  offline: info                  # info | fail

Calls

  • mainsdk check

Guarantees

Whatever the driver.

  • Runs only in the CLI; nothing loads in the app or its request path
  • Reads pnpm, npm, yarn (classic and Berry) and bun lockfiles into one component list
  • A registry token goes only to the host it is configured for, never to another registry or to OSV
  • Offline is an info finding, not a failure, and answers are cached for 24 hours

Drivers

2 drivers. Select one to see its line in main.yaml.

main.yamlOSV.dev advisories (default)
deps:
  driver: osv

Change this one line to swap providers; your calls stay the same.OSV.dev advisories integration

Codes

CodeWhere it appearsMeaning
MAIN-DEPS-0001Checkmainsdk check, before deployA direct dependency isn't on its registry: possibly a name a model made up, and anyone may register it (high)
MAIN-DEPS-0002Checkmainsdk check, before deployA direct dependency's first version is younger than deps.min-age (high)
MAIN-DEPS-0003Checkmainsdk check, before deployA direct dependency's name is one edit away from a popular package it isn't (medium)
MAIN-DEPS-0004Checkmainsdk check, before deployA resolved package has a known advisory; at or above advisories.fail-on it fails, below it warns
MAIN-DEPS-0005Checkmainsdk check, before deployA package's licence is denied, outside a non-empty allow list, or unknown with unknown: fail
MAIN-DEPS-0006Checkmainsdk check, before deployA package runs an install script (preinstall, install, postinstall) and isn't in deps.scripts.allow (warning)
MAIN-DEPS-0007Checkmainsdk check, before deployAdvisories and package ages weren't checked because the network was unavailable (info, or a failure with offline: fail)
MAIN-DEPS-0008Checkmainsdk check, before deployAn advisory ignore entry has expired, or has no until or reason

Features

Nothing here has shipped yet. Each feature lands in its phase; the spec ticket builds it.

FeaturePhaseMilestoneSpec ticket
Lockfile readers for pnpm, npm, yarn and bunPhase 10.5dependency-check#lockfiles
Unknown, brand-new and look-alike direct dependenciesPhase 10.5dependency-check#registry-rules
Advisories from OSV with severity, fixed version and pathPhase 10.5dependency-check#advisories
Licence policy over SPDX expressionsPhase 10.5dependency-check#licences
Install scripts and the offline cachePhase 10.5dependency-check#scripts-offline
Licences in the seal's SBOMPhase 10.5dependency-check#seal

Quick start

bash
npx mainsdk check

The gate needs no setting. mainsdk check asks the registry and OSV.dev once, keeps the answers for 24 hours under .mainsdk/cache/deps/, and then runs every gate.

Configuration

Add a deps section to main.yaml to change the policy. Every key is optional.

main.yaml
deps:
  min-age: 7d                    # a direct dependency first published more recently is reported
  licences:
    deny: [AGPL-1.0-or-later, AGPL-3.0-only, AGPL-3.0-or-later, SSPL-1.0]   # the default list
    allow: []                    # when not empty, any licence outside it is reported
    unknown: warn                # warn | fail
  advisories:
    fail-on: high                # critical | high | moderate | low | none
    ignore:
      - { id: GHSA-xxxx-xxxx-xxxx, until: 2027-01-31, reason: "Not reachable: only used in tests" }
  scripts:
    allow: [esbuild, sharp]      # packages allowed to run install scripts
  offline: info                  # info | fail; fail is for CI with network access
KeyTypeWhat it does
min-agedurationA direct dependency first published more recently is reported (MAIN-DEPS-0002)
licences.denylistLicences that fail the gate. Defaults to the AGPL and SSPL list shown
licences.allowlistWhen not empty, any licence outside it is reported
licences.unknownstringwarn or fail for a package whose licence cannot be read
advisories.fail-onstringcritical, high, moderate, low or none; at or above it fails, below it warns
advisories.ignorelistAdvisories to skip, each with an id, an until date and a reason
scripts.allowlistPackages allowed to run install scripts
offlinestringinfo or fail when the network is unavailable; fail is for CI

What you get

The deps gate of mainsdk check reads your lockfile and the installed packages and tells you, before CI or a deploy does, that a dependency is a name a model made up, was published two days ago, is one letter from a popular package, has a known advisory, carries a licence you can't ship under, or runs an install script nobody allowed. Every finding names the package, the version, why and the fix. It runs in the CLI only: nothing of it loads in your app or its request path. It is free.

What it reads

  • Lockfiles: pnpm-lock.yaml (v9), package-lock.json (v3), yarn.lock (classic and Berry) and bun.lock. Every format gives the same list: name, version, direct or transitive, and the path from a direct dependency. Workspace packages are left out.
  • Direct dependencies: the dependencies, devDependencies, optionalDependencies and peerDependencies of every workspace package.json.
  • Registries: the registry and @scope:registry lines of .npmrc (project, then user), else the public npm registry. A token goes only to the host it is configured for, never to another registry and never to OSV.
  • Installed packages: each node_modules/<name>/package.json (and pnpm's store) for the licence and install scripts. A package that isn't installed has no licence or script finding.

Offline and the cache

With no network and no cache younger than 24 hours, the gate reports MAIN-DEPS-0007 once and still runs the lockfile, licence and script rules. An unreachable registry or OSV never blocks a local check; after the first failure the CLI stops asking, so an offline run costs one timeout. Set offline: fail in CI, where the network is there.

What it always does

  • Runs only in the CLI, never in the app (ADR-0074).
  • Sends no credentials to OSV, and registry tokens only to their own host.
  • Gives the same component list for the same dependencies in any lockfile format.

Errors and checks

CodeMeaning
MAIN-DEPS-0001A direct dependency isn't on its registry. Anyone may register a name a model made up.
MAIN-DEPS-0002A direct dependency's first version is younger than deps.min-age.
MAIN-DEPS-0003A direct dependency is one edit away from a popular package it isn't (names under 4 characters are skipped; private registries are skipped).
MAIN-DEPS-0004A resolved package has an advisory, with its id, severity, fixed version and dependency path. At or above fail-on it fails; below it warns.
MAIN-DEPS-0005A licence is denied, outside a non-empty allow, or unknown with unknown: fail. OR passes when any branch passes, AND needs every part, WITH keeps the base licence's result.
MAIN-DEPS-0006A package runs preinstall, install or postinstall and isn't in scripts.allow (a warning).
MAIN-DEPS-0007The network was unavailable, so advisories and ages weren't checked (info, or a failure with offline: fail).
MAIN-DEPS-0008An advisory ignore has expired or has no until or reason; the advisory is reported again.

Each code's cause and fix is in check codes.

Swapping drivers

deps has no driver. It runs in the CLI against your lockfile, the registry and OSV.dev, so there is nothing to swap.

Testing

The gate's tests run against a fake registry, a fake private registry and a fake OSV server, so none reaches a real host (packages/cli/test/deps.test.ts). In your own CI, run npx mainsdk check with offline: fail so a missing network fails the build.

Next

Was this page helpful?

↑↓ moveEnter openEsc close

Not decided yet