npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ship.zone/runner

v2.0.0

Published

The isolated OCI job runner for ship.zone CI/CD

Readme

@ship.zone/runner

@ship.zone/runner is the outbound-only OCI execution agent for ship.zone CI/CD. It implements the runner protocol of @ship.zone/ci-spec (2.0.0) for the oci execution profile, validates leases and compiled jobs against the published schemas, and runs one fenced attempt at a time on a local Docker or Podman engine.

The control plane owns workflow compilation, scheduling, authorization, secrets policy, and canonical run state. This package owns runner registration, lease handling, isolated execution, bounded transfers, redacted logs, and terminal reporting.

Issue Reporting and Security

For reporting bugs, issues, or security vulnerabilities, please visit community.foss.global/. This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a code.foss.global/ account to submit Pull Requests directly.

Security Model

  • Only local Unix-socket Docker and Podman endpoints are accepted. Remote contexts and connections are rejected before capabilities are advertised.
  • Job images must be Linux images pinned by an exact SHA-256 digest. The image OS, architecture, and digest are checked before lease acceptance.
  • Every compiled step runs in a fresh container as a numeric non-root user with a read-only root, all capabilities dropped, no-new-privileges, private IPC, and CPU, memory, PID, shared-memory (/dev/shm), time, and writable-storage limits. The job's resources are these ceilings; omitted values take the runner defaults, and every value is bounded by the maximum the runner advertises.
  • The only network mode is none: every step container runs in a new network namespace whose only interface is its own loopback, so nothing leaves the sandbox and loopback ports never collide with another attempt. The runner exposes no service on that loopback. egress allowlists are not enforced by this runner, are never advertised, and cannot be configured.
  • Job containers receive no host paths, runtime sockets, devices, host namespaces, or arbitrary OCI arguments. Their only persistent writable mount is /workspace.
  • The shared workspace is an attempt-specific nodev,nosuid tmpfs with hard byte and entry ceilings. Imported executable files may run directly from it. A trusted static Rust helper imports source/cache staging, measures the workspace around every step, and exports only declared artifact/cache paths.
  • Helper containers use the exact job image only as an inert root filesystem. They override the entrypoint with the packaged static helper, have no network, and receive only the narrowly scoped CHOWN and DAC_OVERRIDE capabilities required for private staging ownership. Job containers do not receive those capabilities.
  • Step containers receive exactly the compiled step environment plus job secrets. Secret values are passed through the runtime environment rather than OCI command arguments.
  • The attempt's redaction set holds every secret value, every npm grant token, and each line of a value containing a line terminator (CR LF, LF, or CR), leaving out members shorter than 8 UTF-8 bytes; a short line of a multi-line value stays unmasked when printed on its own. Every member is replaced with *** in log output, per stream and across the attempt's interleaved chunk sequence, so no chunk and no concatenation of consecutive chunks contains one. An artifact or cache archive whose entry path, link target, or file content contains a member is never published: a required artifact or a cache completes the attempt system_error, an optional artifact is omitted and reported. Redaction matches exact bytes; a job that transforms a value can still disclose it, so the coordinator must not grant protected secrets to untrusted jobs.

Requirements

  • Deno 2
  • pnpm 11
  • Docker or Podman on Linux
  • A rootless runtime by default
  • Rust and configured cross-compilers when building the packaged helpers from source

Install

Add the published source package to a Deno project:

deno add npm:@ship.zone/runner

Then import the package through the generated import-map name. The npm export resolves to the prebuilt Deno JavaScript bundle and its rolled-up TypeScript declarations:

import { ShipRunner } from '@ship.zone/runner';

Without an import-map entry, use the npm package directly:

import { ShipRunner } from 'npm:@ship.zone/runner';

For development in this repository, install dependencies and build the npm bundle plus the static musl-based linux_amd64 and linux_arm64 helpers:

pnpm install
pnpm build

The published package includes dist_rust/runnerworkspace_linux_amd64_musl and dist_rust/runnerworkspace_linux_arm64_musl, the Rust source and manifests, rust/.cargo/config.toml, and the dependency notices. oci.workspaceHelperPath can select an explicit absolute helper path for development or controlled deployments.

Configured, packaged, and dependency-injected helper resolver paths are source files. Runtime verification reads the bounded regular source through one pinned file descriptor, hashes those exact bytes, and materializes an executable mode-0755 copy below the private mode-0700 runner state subdirectory as workspace-helpers/runnerworkspace_<target>_musl_<sha256>. Source permissions are not changed, so package managers may install the source without executable bits. The private parent directory is the host access boundary; mode 0755 lets capability-dropped helper containers execute the host-owned read-only bind mount. IOciRuntimeFacts.helperPath reports the validated materialized path used by host probes and OCI bind mounts, while helperSha256 reports its content digest. A private advisory lock serializes materialization. Existing digest paths are reused only after their type, single-link status, mode, and digest are revalidated without mutating them; the runner retains a bounded set for rollback, reclaims stale incomplete temporary copies, and rejects excessive recent temporary residue. The sole immediate-recovery exception is a validated temporary name and exact digest destination that still reference the same two-link inode after interruption; the runner removes the temporary name under the lock, verifies the destination became single-link, and then reuses it.

Runtime verification creates one private .runtime-probe-owner_<id> marker in the helper state. Host tmpfs probes include that owner in their exact directory names, and OCI runtime probe volumes carry the same ship.zone.runner.runtime-probe-owner label. This lets interrupted verification be cleaned by the same state owner without touching unowned probes or probes from another runner. The runner syncs both the helper-directory entry and a newly created owner marker before using them.

Configure And Run

Create a private runner configuration:

deno run --allow-all \
  npm:@ship.zone/runner init \
  --control-plane https://foss.global \
  --runtime-path /usr/bin/docker

Register with a one-time bootstrap token, then start the daemon:

SHIP_RUNNER_BOOTSTRAP_TOKEN='<one-time token>' \
  deno run --allow-all \
  npm:@ship.zone/runner register
deno run --allow-all \
  npm:@ship.zone/runner run

--allow-all is required because Deno reserves direct /dev/shm access for that mode. The runner uses /dev/shm for fail-closed host tmpfs verification before registration and must already be trusted with unrestricted subprocess execution for the configured OCI runtime.

Replace run with once to claim at most one job or config to print the effective configuration with credentials masked. Within this repository, deno task dev -- <command> is the equivalent development invocation. SHIP_RUNNER_CONFIG selects a config path; the default is ./runner.config.json.

init writes the config with mode 0600. Registration verifies the runtime and protocol discovery document before advertising capabilities, durably journals the exact registration request without the bootstrap token, then atomically replaces the bootstrap token with the returned runner credential. An interrupted registration replays the journaled request and rejects configuration drift. Credential rotation from session and runner-heartbeat responses is persisted before the new credential becomes active.

The default policy includes:

  • rootless Docker at /usr/bin/docker;
  • labels for Linux, the current architecture, and OCI;
  • network none only;
  • job user 65532:65532;
  • a 4 GiB maximum logical workspace and 100,000 entries;
  • bounded source, artifact, cache, log, environment, and staging limits;
  • a 1 GiB free-space and 10,000-inode staging reserve.

Plain HTTP control planes are rejected except for explicitly enabled loopback development URLs.

Execution Lifecycle

For each claim, the runner:

  1. Validates the lease against the published JobLease schema, the compiled job against the runner job schema and the specification version acceptance rule, the RFC 8785 compiledPlanDigest, internal job coherence, the lease coherence of grants, bindings, and npmGrants, fit against the immutable advertised capability snapshot, and all runner execution policy before image inspection or pull. A lease that fails any check, or that this runner does not execute, is abandoned as runner_error before acceptance.
  2. Pulls or locates the exact image digest, validates its Linux architecture, and probes it with the inert helper.
  3. Writes a private interrupted-attempt journal and sends the explicit fenced acceptance request. Source transfer and execution do not start before HTTP 204.
  4. Downloads and validates the source tar.gz, then restores readable caches in declaration order into private host staging.
  5. Imports staging into the bounded tmpfs and runs compiled steps in declaration order, stopping at the first non-zero exit.
  6. Publishes successful read-write caches and artifacts selected by their when policy as deterministic, replayable tar.gz transfers.
  7. Cleans staging, helper/step containers, and the tmpfs volume before sending the idempotent terminal completion, then clears the recovery journal after the coordinator accepts it.

An attempt-scoped inert holder container keeps Docker's local-driver tmpfs mounted while fresh step and helper containers come and go. It runs no image-provided command and is removed with the workspace.

On restart, a new session first removes stale labeled containers and volumes locally, scavenges only the runner's known host-staging directories and journal temporary files, then reads the secret-free journal and calls the recovery endpoint to revoke and reconcile the interrupted attempt. Work is never resumed, and a coordinator outage cannot retain prior staging.

Job Timeout

The attempt deadline is the job's timeoutMs, measured with a monotonic clock from the moment the runner receives HTTP 204 for its acceptance. It covers source extraction, cache restoration, and every step. When it is reached before execution ends, the runner terminates execution as for a cancellation, force-stopping within the configured stop timeout of at most 30 seconds, archives the artifacts declared when: always or when: failure, publishes no read-write cache, and completes timed_out. Artifact collection and upload, cache publication, and completion follow execution and are bounded only by the fence. Whichever of an accepted cancellation and the deadline comes first decides the outcome: canceled or timed_out.

Cancellation And Fencing

Job heartbeats renew the coordinator-time lease and acknowledge cancellation directives. A cancellation immediately begins termination, bounds TERM-to-KILL by the coordinator's terminateBy deadline, and completes with the same cancellation request ID. Heartbeats continue during bounded termination.

HTTP 409 fencing loss, authentication loss, or coordinator-time lease expiry stops work and suppresses subsequent logs, transfers, and completion. Graceful runner shutdown abandons the exact accepted identity instead of reporting a successful terminal result.

Logs use nested fenced identity, zero-based sequencing, exact acknowledgements, streaming secret redaction, and UTF-8 byte limits. Reaching the negotiated total log limit fails closed and terminates the attempt as system_error; output is never silently truncated.

Runner Protocol

The runner implements the specification version of the @ship.zone/ci-spec package it is built against (its ciSpecVersion, currently 2.0.0), and sends it as spec in registration and session requests. It refuses a coordinator whose discovery, registration, or session spec has another major version, so a 2.x runner never talks to a 1.x (@foss.global/ci-spec) coordinator, and a coordinator answers a runner of another major version with HTTP 409 spec_incompatible. Every capability the runner advertises is defined in 2.0.0, so it sends the same capability snapshot to every coordinator of major version 2. A leased job is accepted only when its spec has the same major version and is not newer than the implemented version; any other job is abandoned as runner_error.

The runner advertises the oci profile, container isolation, the native linux/<arch> platform of its verified OCI engine, the none network mode, its transfer limits, resources maxima for memory, CPUs, PIDs, and shared memory, an empty leaseFeatures list because it uses no image pull grants, candidate bindings, or npm read grants, and maximumTimeoutMs, its configured oci.maximumTimeoutMs. It refuses, by abandoning the lease as runner_error before acceptance, every lease it cannot execute as specified: the vm and oci-image profiles, microvm isolation, egress networks, candidate images with bindings, image grants, jobs with npmRead and their npmGrants, and jobs whose timeoutMs exceeds oci.maximumTimeoutMs.

The reserved step environment names are SHIPZONE_CI_MATRIX_JSON and SHIPZONE_CI_INPUTS_JSON, each carrying canonical RFC 8785 JSON. A job whose step environment defines any other SHIPZONE_CI_* name, or whose secret targets use any SHIPZONE_CI_* name, is rejected.

All endpoints are below /api/runner. Registration uses the one-time bootstrap bearer token; subsequent requests use the renewable runner credential. Every request body is validated against its published OpenAPI component before it is sent, and every response before it is used.

| Operation | Endpoint | Idempotency | | ---------------- | --------------------------------------------------------- | ------------------------------------------ | | Discover | GET /api/runner | Public exact descriptor | | Register | POST runners/register | registrationRequestId and canonical body | | Start session | POST runners/{runnerId}/sessions | sessionRequestId and canonical body | | Runner heartbeat | POST runners/{runnerId}/heartbeat | Current runner session | | Claim | POST jobs/claim | claimRequestId and capability snapshot | | Accept | POST jobs/{jobId}/attempts/{attemptId}/accept | acceptRequestId and full identity | | Job heartbeat | POST jobs/{jobId}/attempts/{attemptId}/heartbeat | Fenced identity | | Log | POST jobs/{jobId}/attempts/{attemptId}/logs | Attempt and sequence | | Complete | POST jobs/{jobId}/attempts/{attemptId}/complete | completionRequestId and terminal body | | Abandon | POST jobs/{jobId}/attempts/{attemptId}/abandon | abandonRequestId and canonical body | | Recover | POST jobs/recover | Current session and recoveryRequestId | | Source | GET sources/{sha256} | Immutable attempt-bound digest | | Artifact | PUT jobs/{jobId}/attempts/{attemptId}/artifacts/{name} | transferRequestId and metadata | | Cache | GET/PUT jobs/{jobId}/attempts/{attemptId}/caches/{name} | Fenced declaration and transfer ID |

Transient retry statuses are 429, 502, 503, and 504. Exact retries reuse the same request ID and canonical body. Request, response, archive, extracted-data, entry, and stream sizes are bounded. Each source, artifact, or cache archive also has a fixed 134,217,728-byte metadata ceiling across its normalized UTF-8 entry paths and symbolic-link targets. Implicit parent directories count against the workspace entry limit, and symbolic-link validation retains at most 1,000,000 canonical path components.

Library API

The package exports its runner components for controlled embedding:

import {
  ArtifactManager,
  CacheManager,
  defaultRunnerConfig,
  OciExecutor,
  RunnerApiClient,
  ShipRunner,
  SourceWorkspaceManager,
} from '@ship.zone/runner';

The CLI is the supported complete assembly. Embedded callers must preserve the same runtime verification, discovery, lifecycle, fencing, cleanup, and credential-persistence ordering.

Verification

deno task fmt --check
deno task lint
deno task check
pnpm test
pnpm build
pnpm pack --dry-run

The real Docker integration is opt-in and requires a locally available digest-pinned Linux image:

SHIP_RUNNER_OCI_TEST=1 \
SHIP_RUNNER_OCI_IMAGE='alpine@sha256:<digest>' \
deno test --allow-all test/oci-executor.test.ts

It verifies direct execution of an imported workspace file, shared multi-step state, helper ownership, selected export, hardlink rejection, inode exhaustion, and container/volume cleanup against the real runtime.

License and Legal Information

This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the repository license file. Dependency notices for the npm bundle and the packaged static helper binaries are in third-party-licenses.md, with the complete applicable musl inventory in musl-copyright.md.

Please note: The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.

Trademarks

This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.

Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.

Company Information

Task Venture Capital GmbH Registered at District Court Bremen HRB 35230 HB, Germany

For any legal inquiries or further information, please contact us via email at [email protected].

By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.