Skip to content

Units

If you’re a security lead asking “what did this run of this package actually pull, and what did we stop?”, this is the page you open. It renders the per-unit lens — the run-scoped dependency footprint that Units and run scope defines: everything one CI run of one unit resolved and installed transitively, plus everything the proxy blocked on the way.

Read the concept page first if the words unit (a package inside a monorepo) and run (one CI execution attributed to it) aren’t yet second nature. This page is about reading the lens, not defining it.

A unit only appears once a verified CI run has been attributed to it — the runner presented an OIDC identity Upwarden could pin to a repo, ref, and run. If a project’s units are missing or thin, the cause is almost always upstream: the runner isn’t wired for verified attribution yet. Fix that first with CI setup; the lens is only as complete as the identity feeding it (and, per the caveat below, never fully complete even then).

From your org, drill into a project to see its units. A single-package repo has exactly one unit; a monorepo lists one unit per package (web/, services/billing/, …), each with its own footprint. Open a unit to land on its most recent attributed run; runs are addressable individually, so a link to one run is shareable — paste it into a ticket and your coworker lands on the same footprint you’re looking at.

The first thing on the lens is a banner, and it is deliberate. It reads most observed, never complete.

Upwarden is a proxy: it sees a dependency because a package manager asked it for that dependency. It records traffic, which is a lower bound on the run’s true dependency set — a cached package, an un-wired tool, or a vendored dependency can be part of the build and never cross the proxy (the full list of gaps is on the concept page). So the footprint you’re reading is “most of what this run pulled, as observed” — trustworthy as a floor, dishonest if read as a ceiling.

The lens orders the footprint blocked-first. The packages the proxy refused to serve for this run — every BLOCKED and QUARANTINED decision — sit at the top, above the (usually much longer) list of installs that went through. That ordering is the whole point of the surface: a clean install list tells you what shipped, but the blocked list tells you what a supply-chain advisory, a cooldown window, a size-jump heuristic, or your own policy kept out of this build. That’s the exposure you came to read.

Each block carries its decision pill — BLOCKED or QUARANTINED — with the same meaning as everywhere else in the product (see Verdicts and the scanner for SAFE / BLOCKED / QUARANTINED on the wire, and why a QUARANTINED retry sometimes resolves to SAFE).

Every blocked entry is traceable to why it was blocked. The lens reuses the same reason surfaces the rest of the dashboard already uses — it doesn’t invent a second vocabulary:

  • Advisory-backed blocks (OSV / GHSA). When the block is anchored to an advisory, the entry surfaces the advisory detail — source (osv / ghsa), advisory ID (GHSA-… / CVE-…, linked to the upstream advisory page), severity, and the one-line summary. This is the same subpanel shape the audit log row detail and the packages search blocklist table render — same data, same 403 body the install request received. Hand the summary and the link to the developer; that’s their triage.
  • Policy / heuristic blocks. When the block came from a non-advisory layer — a per-tenant denylist, the freshness cooldown, a size-jump anomaly, or a build-tool fingerprint — the entry names that reason instead of an advisory. The mechanics of each layer live in Verdicts and the scanner; the advisory detail widget explains why these deliberately don’t carry an advisory panel.

The rule of thumb: advisory answers “what’s wrong with this package?”; policy reason answers “which of our controls stopped it?”. Between them, every block on the lens explains itself without a second lookup.

Three surfaces read the same underlying audit data at three different scopes. Reach for the one whose scope matches your question:

SurfaceScopeAnswers
Packages searchOrg-wide, per package”What is this org’s verdict for lodash, across all traffic and time?”
Units (this page)One run of one unit”What did this build of services/billing pull, and what did we block?”
Audit logRow-level, all events”Show me every individual decision — with filters, CI pivots, and CSV export.”

They compose. Start on Units when a build is what you’re investigating; pivot to packages search to ask whether a blocked package is a problem org-wide or just here; drop to the audit log when you need the raw rows, longer windows, actor trails, or an export. The unit lens is a grouping over audit rows sliced by the run identity that CI attribution stamps — it doesn’t replace the row-level log, it focuses it.

  • A developer reports a build broke with [UPWARDEN] BLOCKED. Open the unit for that build; the block is at the top (blocked-first), with its advisory or policy reason attached. You have the answer without leaving the page.
  • An advisory drops and you need per-service exposure. Open each affected unit’s latest run and read the blocked list; the run scope tells you which build was exposed, not just that the org saw the package somewhere.
  • You’re auditing what actually shipped in a release build. Read the installed footprint below the blocked list — remembering the most observed caveat: it’s a trustworthy floor, not a complete manifest.
  • Units and run scope — the concept behind this page: what a unit is, how a run maps to it, and why the model is “most observed”, never complete.
  • Advisory detail subpanel — the source / id / severity / summary block behind an advisory-backed block, reused here.
  • Verdicts and the scanner — what BLOCKED / QUARANTINED mean and which layer produced a policy-reason block.
  • Packages search — the org-wide, per-package view to pivot to when a block might be bigger than one build.
  • Audit log — the row-level record the unit lens groups over.