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

@freedomofpress/webcat-cli

v0.1.2

Published

WEBCAT CLI for creating, validating, and packaging enrollments and manifests.

Readme

WEBCAT CLI

Utilities for creating, validating, and packaging WEBCAT enrollments and manifests.

Quick Start

This utility, together with the GitHub Actions provided in the same repository, can be used to quickly integrate and enroll a web application or domain into WEBCAT. Below are the recommended steps.

Prepare the web application for compatibility

Before anything else, you should evaluate whether your website or web application is compatible with WEBCAT. There are a few strict requirements:

  • The frontend must be fully static (i.e., no server-generated HTML, JavaScript, or CSS).
  • No inline JavaScript is allowed.
  • A Content Security Policy (CSP) must be provided via an HTTP header and must satisfy specific constraints (see: CSP Guide, explanation blog post).

See the following examples and porting guides (outdated):

At the end, you should have compiled a webcat.config.json base file for your use case.

Decide and prepare enrollment information

A WEBCAT manifest describes a web application by listing its files, cryptographic hashes, CSP policies, and additional metadata useful for auditability. But how is this information verified?

Manifests are authenticated using either Sigsum or Sigstore signatures. The metadata required to validate these signatures or attestations must be registered beforehand with WEBCAT’s distributed validation system.

Changes to enrollment information are:

  • Transparently logged
  • Auditable
  • Subject to a delay (cool-down window)

Keep this in mind: if you make a mistake, you may need to wait before updating the enrollment again.

The first decision you must make is whether to use Sigsum or Sigstore.

Choosing Sigsum

Sigsum, developed by Glasklar Teknik, provides:

  • Compact Ed25519 signatures
  • Easy offline signing
  • Threshold signing support in WEBCAT

You can choose among multiple transparency logs and witness policies, or even run your own witness if you want to define your own trust roots.

Sigsum is generally the better choice if:

  • You want offline, manual signing
  • You do not want to depend on GitHub or other centralized infrastructure

However, due to current tooling limitations, Sigsum is less convenient for fully automated deployment workflows.

To learn more about Sigsum and how to write a policy, see Sigsum's Getting Started guide.

Choosing Sigstore

If you choose Sigstore, WEBCAT provides GitHub Actions that support automated deployments.

[!WARNING] Sigstore support is still a work in progress. Custom claims are not yet supported, but will be added soon.

In theory, WEBCAT also supports a bring-your-own Sigstore deployment. This is not documented here due to its complexity. This guide assumes you are using the Sigstore Public Good instance, the same one used by GitHub and public container registries.

The Sigstore workflow consists of two actions:

  • Enrollment Update Action - Source / Example usage

    • Fetches the latest trust material using TUF
    • Updates enrollment information if changes are detected
    • Submits the updated enrollment for re-evaluation by the distributed system (This submission step will soon be integrated directly into the CLI.)

[!CAUTION] Currently, verification is based on the GitHub workflow identity (workflow name). This has known security limitations until custom claims are supported, but is acceptable while WEBCAT is in alpha.

  • Manifest Update Action - Example Usage

    • Generates, signs, and bundles a WEBCAT manifest

See the webcat-demo-test repository for a complete, end-to-end example of this flow. Note: due to how the Sigstore is claimed in Github Action, this has to be copied in the target repository and should not be invoked directly from the webcat0-cli one.

Using the CLI

If you are using Sigsum

Take a look at demo.sh.

If you are using Sigstore

Refer to the GitHub Actions described above.

Requirements

  • Node.js 20 or newer.
  • sigsum-submit must be available on your $PATH for manifest sign operations.
  • A Sigsum trust policy and keypair for signing manifests.
  • An OIDC identity token in the environment (CI-supported) or interactive login for manifest sign --type sigstore.

Installation

npm install @freedomofpress/webcat-cli

To run the installed CLI:

npx webcat --help

Sigsum needs to be installed separately, as it currently is only available as a Go binary:

go install sigsum.org/sigsum-go/cmd/sigsum-key@latest
go install sigsum.org/sigsum-go/cmd/sigsum-submit@latest

Enrollment helpers

The enrollment namespace manages Sigsum or Sigstore enrollment payloads. Sigsum enrollments are the default; use --type sigstore along with --issuer, --identity, and either --trusted-root or --community-trusted-root to build Sigstore enrollments.

| Command | Purpose | | --- | --- | | enrollment create | Compile a Sigsum policy file and create a normalized enrollment JSON document. | | enrollment canonicalize | Canonicalize an enrollment JSON document using canonical JSON rules. | | enrollment hash | Canonicalize and SHA-256 hash an enrollment, outputting a base64url digest. |

Example – hash the sample enrollment definition:

npx tsx src/cli.ts enrollment hash -i examples/enrollment.json
# => TSNydkDZBv6QNZ3m7ZuBP9fFj0TD6hHDmzcwu9ulK3A

The canonicalized document (useful for audits) can be produced with:

npx tsx src/cli.ts enrollment canonicalize -i examples/enrollment.json

Manifest helpers

The manifest namespace operates on WEBCAT manifests:

| Command | Purpose | | --- | --- | | manifest generate | Scan a directory of static assets, apply a manifest config, and embed a timestamp for --type sigsum (Sigsum log); sigstore manifests omit timestamps. | | manifest sign | Sign a manifest with Sigsum (default) or Sigstore and attach proofs/bundles. | | manifest canonicalize | Canonicalize an existing manifest JSON document. | | manifest hash | Canonicalize and SHA-256 hash a manifest, outputting a base64url digest. | | manifest verify | Verify signatures in a manifest (or bundle) against an enrollment and print the policy hash. |

manifest generate skips dotfiles and dotfolders by default; pass --include-dotfiles to include them. Use --exclude <path> (repeatable) to omit specific files or directories from the scan.

Example – hash the provided manifest:

npx tsx src/cli.ts manifest hash -i examples/manifest.json
# => 8OYr4SFw2U2NR2efE69FAKZicf_2QbUGxXT7kxN1C80

Example – verify a bundle:

npx tsx src/cli.ts manifest verify examples/bundle.json

Sigstore signing

Sigstore signing defaults to the community Fulcio/Rekor services. You can override the endpoints with --fulcio-url, --rekor-url, and --tsa-url when signing.

To sign with Sigstore using an ambient OIDC token (for example, in CI):

npx tsx src/cli.ts manifest sign \
  --type sigstore \
  --input manifest.json

If you already have an OIDC ID token, you can pass it explicitly:

npx tsx src/cli.ts manifest sign \
  --type sigstore \
  --input manifest.json \
  --oidc-token "$OIDC_ID_TOKEN"

To perform an interactive device authorization flow (opens a browser and prompts for a code):

npx tsx src/cli.ts manifest sign \
  --type sigstore \
  --input manifest.json \
  --interactive

To use custom Sigstore infrastructure:

npx tsx src/cli.ts manifest sign \
  --type sigstore \
  --input manifest.json \
  --fulcio-url https://fulcio.example.com \
  --rekor-url https://rekor.example.com \
  --tsa-url https://tsa.example.com \
  --oidc-issuer https://oauth2.example.com/auth \
  --oidc-client-id example-client \
  --interactive

Bundle helpers

Use bundle create to combine an enrollment and a manifest (with signatures) into a WEBCAT bundle that can be distributed to verifiers:

npx tsx src/cli.ts bundle create -e examples/enrollment.json -m examples/manifest.json > bundle.json

The resulting bundle.json matches the fixture located in examples/bundle.json.

End-to-end example (based on demo.sh)

The repository includes demo.sh, which exercises the full workflow. The commands below mirror that script so you can quickly test the CLI end to end:

# 1) Prepare demo keys
mkdir -p keys
sigsum-key generate -o keys/key1
sigsum-key generate -o keys/key2
HEX1=$(sigsum-key to-hex -k keys/key1.pub)
HEX2=$(sigsum-key to-hex -k keys/key2.pub)

# 2) Create trust policy and app config
cat > trust_policy <<'EOF'
log 4644af2abd40f4895a003bca350f9d5912ab301a49c77f13e5b6d905c20a5fe6 https://test.sigsum.org/barreleye
witness poc.sigsum.org/nisse 1c25f8a44c635457e2e391d1efbca7d4c2951a0aef06225a881e46b98962ac6c
witness rgdd.se/poc-witness  28c92a5a3a054d317c86fc2eeb6a7ab2054d6217100d0be67ded5b74323c5806
group  demo-quorum-rule any poc.sigsum.org/nisse rgdd.se/poc-witness
quorum demo-quorum-rule
EOF

cat > webcat.config.json <<'EOF'
{
  "app": "https://github.com/element-hq/element-web",
  "version": "1.12.3",
  "default_csp": "default-src 'none'; style-src 'self' 'unsafe-inline'; script-src 'self' 'wasm-unsafe-eval'; img-src * blob: data:; connect-src * blob:; font-src 'self' data: ; media-src * blob: data:; child-src blob: data:; worker-src 'self'; frame-src blob: data:; form-action 'self'; manifest-src 'self'; frame-ancestors 'self'",
  "default_index": "index.html",
  "default_fallback": "/error.html",
  "wasm": ["8A7Ecx-qI7PnFNAOiNTRDi31wKQn06K0rm41Jv3RTvc"],
  "extra_csp": {}
}
EOF

# 3) Produce enrollment and manifest
TMPDIR=$(mktemp -d)
echo index > "$TMPDIR/index.html"
echo error > "$TMPDIR/error.html"

npm run start -- enrollment create \
  --policy-file trust_policy \
  --threshold 1 \
  --max-age 15552000 \
  --cas-url https://cas.demoelement.com \
  --signer "$HEX1" \
  --signer "$HEX2" \
  --output enrollment.json

npm run start -- manifest generate \
  --policy-file trust_policy \
  --config webcat.config.json \
  --directory "$TMPDIR" \
  --output manifest_unsigned.json

npm run start -- manifest sign \
  --policy-file trust_policy \
  -i manifest_unsigned.json \
  -k keys/key1 \
  -o manifest.json

# 4) Bundle and verify
npm run start -- bundle create --enrollment enrollment.json --manifest manifest.json --output bundle.json
npm run start -- manifest verify bundle.json

The script prints intermediate JSON artifacts with jq so you can inspect the resulting enrollment, manifest, and bundle.

webcat.config.json schema

The manifest generator expects a Webcat config file (commonly webcat.config.json or a JSON equivalent) matching the schema below:

| Field | Type | Description | | --- | --- | --- | | app | string | Origin URL of the application being packaged. | | version | string | Git tag to be used for reproducibility and auditing. | | default_csp | string | Base Content-Security-Policy applied to all assets. | | default_index | string | Default index file served when a directory is requested; leading / is stripped automatically. | | default_fallback | string | Absolute path served when a file is missing. | | wasm | string[] | Optional list of base64url SHA-256 digests for inline WebAssembly modules. .wasm files are added automatically during generation. | | extra_csp | Record<string, string> | Optional per-path CSP overrides; keys must start with /. | {} or { "/app": "default-src 'none'" } |

Use the JSON example in the workflow above as a starting point and adjust fields to match your application.