Zuke is a build-automation framework, so it runs inside other people's pipelines and publishes itself to a public registry. Supply-chain integrity is therefore the primary concern, and this document describes how the project is hardened and how to report problems.
Zuke is largely AI-written (see the README). Review before you rely on it. Every package is
1.xon full semver; depend on the caret range (jsr:@zuke/core@^1) rather than an exact version, so patch fixes reach you — see Versioning & compatibility.
Please report security issues privately — do not open a public issue.
- Use GitHub's "Report a vulnerability" button under the repository's Security tab (Private Vulnerability Reporting). This opens a private advisory visible only to you and the maintainers.
- Include affected version(s), reproduction steps, and impact. A minimal proof of concept helps us triage quickly.
We aim to acknowledge a report within a few days and to coordinate a fix and disclosure timeline with you. Fixes ship in a new release; the advisory is published once a patched version is available.
Credit: reporters are credited by name in the published advisory (and in the release notes of the fix) unless they ask to remain anonymous.
Only the latest published version of each @zuke/* package receives
security fixes. Depending on the caret range keeps you on it.
What the project does to keep releases trustworthy. The security assurance case justifies why these measures meet the project's security requirements — the threat model, the trust boundaries, and the design-principle arguments behind the list below:
- Zero runtime dependencies. Every published package declares no dependency
but
@zuke/core, so nothing third-party is shipped to consumers. The build layer is separate and does have them:@std/yamlforbuild/,cspellandrelease-pleaseinstalled from npm on demand, and four checksum-verified binaries (the Codecov CLI, zizmor, actionlint, gitleaks) provisioned by the build'stoolchain(). All of it is dev/release-time only. - Injection-free command execution. All process execution goes through
Deno.Commandwith a discrete argv array — there is no shell string, so interpolated values can never be reinterpreted as shell syntax. - Trusted publishing via OIDC. Packages publish to JSR with a short-lived
OIDC token (
id-token: write); no long-lived registry tokens or secrets are stored. JSR records build provenance for each published version. - Least-privilege CI. The default workflow token is
contents: read. The release pipeline is split so thereleasejob (contents/pull-requests: write) and thepublishJsrjob (id-token: write) never hold each other's privileges. - Pinned, monitored Actions. Every GitHub Action is pinned to a full commit
SHA, with a version comment kept current by Dependabot. Every job that holds a
write-scoped token runs
step-security/harden-runnerwith anegress-policy: blockallowlist, so outbound access is enforced rather than merely audited. Thetestjob inci.ymlis the exception: it holds no token and only runs the test suite. - Pinned toolchain. The
./zukelauncher bootstraps a pinned Deno version, so CI and local builds install a known version rather than a movinglatest. Dependencies are resolved against a committeddeno.lock, enforced with--frozen. The scanner CLIs are pinned and checksum-verified inbuild/scanners.tsand provisioned by the build itself, so the security workflow needs no install step and nothing has to be present onPATH. - Scanning via Zuke. The supply-chain scanners run as a typed Zuke build
target —
./zuke securitydrives zizmor (Actions SAST), actionlint, and gitleaks (secrets) through@zuke/security, failing the build on findings. (The package also wraps osv-scanner, semgrep, and Trivy for consumers whose projects have lockfiles/manifests those tools support.) Code-level SARIF for the GitHub Security tab comes from CodeQL, run by the committedcodeql.ymlworkflow on every pull request, push to master, and a weekly schedule — analyzing the TypeScript sources and, via theactionsquery pack, the workflow YAML itself — and from OpenSSF Scorecard, which runs as a native action workflow.
- Bootstrap launchers.
./zukeand./zuke.ps1install Deno on first use by downloading the pinned release archive from GitHub and verifying it against a per-platform SHA-256 baked into the launcher. No install script is fetched or executed.DENO_VERSION=latestis refused — a moving target has no checksum to pin — and overriding the version requires supplying a matchingDENO_SHA256, so the launcher never runs an unverified binary. To skip the bootstrap entirely, install Deno yourself so the launcher finds it onPATH. deno publish --allow-dirty. The publish step currently allows a dirty tree as a backstop. The merged release tree should already be clean; once a real release confirms this, drop the flag for the strongest "published == committed source" guarantee.contents: write+persist-credentialson thecijob. Thecijob inci.ymlruns onpull_requestwithcontents: writeandactions/checkout'spersist-credentials: true, because the AI lint fixer may push a fix commit back to the PR branch. This is a deliberate trade-off, and it is fork-safe:pull_request(notpull_request_target) runs with the base repository's read-onlyGITHUB_TOKENfor a fork PR, so the elevated write and persisted credential apply only to same-repository branches, never to code a fork controls. Workflow egress is audited bystep-security/harden-runner.
Every published @zuke/* version can be verified against this repository:
- Provenance (signature). Packages are published to JSR via OIDC trusted publishing, and JSR records a Sigstore provenance attestation for each version — signed by the release workflow's short-lived OIDC identity, so there is no long-lived private key anywhere, let alone on the distribution site. To verify, open the version on jsr.io and check its provenance panel: it names this repository, the exact commit, and the workflow run that published it. A version without provenance, or with provenance naming another repository, should be treated as compromised and reported (see above).
- Source equality. The published artifacts are the committed source files (there is no build/compile step), so a version's contents can be diffed directly against its provenance-named commit.
- Launcher downloads. The
./zuke/zuke.ps1launchers verify the Deno archive they bootstrap against a per-platform SHA-256 baked into the launcher, as described under "Known trade-offs".
Git tags are created by release-please through the GitHub API and are not GPG-signed; the provenance attestation above is the release signature to rely on.
The same scanners are exposed as Zuke tasks via
@zuke/security, so any consumer can run them in their
own pipeline:
import { SecurityTasks } from "jsr:@zuke/security";
await SecurityTasks.zizmor((s) => s.paths(".github/workflows"));
await SecurityTasks.osvScanner((s) => s.lockfile("package-lock.json"));In this repository, deno task zuke security runs the bundled set (zizmor,
actionlint, gitleaks); the target provisions each one itself, so nothing needs
to be installed on PATH first.
These cannot be set from files in the repo; configure them in GitHub settings:
- Branch protection on
master: require a pull request with at least one review, require CODEOWNER review, require status checks (CI, CodeQL) to pass, dismiss stale approvals on new commits, and disallow force-pushes. - Restrict release-PR merges to maintainers.
- Keep CodeQL code scanning default setup OFF. The committed
codeql.ymlis the advanced configuration and the single source of code-scanning analysis; enabling default setup for the same language makes GitHub reject the workflow's SARIF uploads. The GitHub-managed Code Quality analysis is a separate feature and can stay enabled alongside it. - Enable secret scanning and push protection (free for public repos).
- Require 2FA for all maintainers, on both GitHub and JSR.
- Scope the JSR ↔ repo OIDC link so publishing is allowed only from this repository's release workflow.