diff --git a/.github/workflows/backup-daily.yml b/.github/workflows/backup-daily.yml index f995394..18d333c 100644 --- a/.github/workflows/backup-daily.yml +++ b/.github/workflows/backup-daily.yml @@ -5,7 +5,11 @@ on: schedule: - cron: 0 6 * * * +# backup.yml only uses GITHUB_TOKEN (passed to called workflows +# automatically); AWS access comes from the runner's instance profile. +permissions: + contents: read + jobs: s3-backup-daily: uses: narrative-io/common-github/.github/workflows/backup.yml@ad6b23573ee7a7573f6499818f61429cc5238e76 # 2026-07-16 - secrets: inherit diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b20b0fe..0c5cfa7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 @@ -79,6 +81,8 @@ jobs: node-version: ['20.19', '22', '24'] steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 @@ -93,8 +97,12 @@ jobs: - run: bun install --frozen-lockfile - run: bun run build + # adhoc-packages is suppressed on this step because installing outside a + # lockfile is the test, not an oversight: it reproduces what a third party + # does with the published tarball — the one just built above — inside a + # throwaway /tmp consumer. Nothing installed here is published. - name: Pack and install into a bare consumer - run: | + run: | # zizmor: ignore[adhoc-packages] set -euo pipefail npm pack --pack-destination /tmp tarball=$(ls /tmp/narrative.io-app-bridge-*.tgz) @@ -129,9 +137,12 @@ jobs: # A wrong `types` condition in the export map still runs fine at runtime # and silently degrades every TypeScript consumer to `any`, so check the # two module resolutions consumers actually use. + # adhoc-packages is suppressed on this step: a pinned typescript is + # installed into the throwaway /tmp consumer, purely to typecheck the + # export map. Nothing installed here is published. - name: Resolve types through the export map working-directory: /tmp/consumer - run: | + run: | # zizmor: ignore[adhoc-packages] set -euo pipefail npm install --no-save typescript@5.9.3 >/dev/null cat > check.ts <<'EOF' @@ -161,6 +172,7 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 + persist-credentials: false - name: Setup Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 @@ -177,7 +189,11 @@ jobs: BEFORE: ${{ github.event.before }} run: | set -euo pipefail - if [ "$BEFORE" = "0000000000000000000000000000000000000000" ] || [ -z "$BEFORE" ]; then + # A force-push leaves github.event.before pointing at a commit that the + # rewrite orphaned. Orphans are unreachable from any ref, so even + # fetch-depth: 0 does not fetch them and the range is invalid. + if [ "$BEFORE" = "0000000000000000000000000000000000000000" ] || [ -z "$BEFORE" ] \ + || ! git cat-file -e "$BEFORE^{commit}" 2>/dev/null; then from="${{ github.sha }}~1" else from="$BEFORE" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e919a63..0ce9b0c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,23 +20,36 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + # Caching is disabled in this workflow on purpose. This job holds + # `id-token: write` and publishes to npm under Narrative's identity, so + # anything restored from cache would be baked into a signed release. + # Cache scope is per-repository, not per-branch, so an entry poisoned from + # any branch would reach this build. - name: Setup Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: bun-version: 1.3.14 + no-cache: true - name: Setup Node.js for npm publish uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.18.0 registry-url: 'https://registry.npmjs.org' + # Defaults to true and self-activates from package.json's + # `packageManager` field, so it must be turned off explicitly. + package-manager-cache: false # Trusted publishing needs npm >= 11.5.1; the runner's bundled npm may be # older, and an older npm falls back to looking for a token that does not # exist here. + # adhoc-packages is suppressed below: a newer npm than the runner ships + # cannot come from this project's lockfile. - name: Ensure npm supports trusted publishing - run: npm i -g npm@^11.5.1 + run: npm i -g npm@^11.5.1 # zizmor: ignore[adhoc-packages] # setup-node's `registry-url` always writes # `//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}` into a temp .npmrc. diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 0000000..97500e7 --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,26 @@ +name: GitHub Actions Security Analysis with zizmor 🌈 + +on: + push: + branches: ["main"] + pull_request: + branches: ["**"] + +permissions: {} + +jobs: + zizmor: + name: Run zizmor 🌈 + runs-on: ubuntu-latest + permissions: + security-events: write # Required for upload-sarif (used by zizmor-action) to upload SARIF files. + contents: read # Only needed for private repos. Needed to clone the repo. + actions: read # Only needed for private repos. Needed for upload-sarif to read workflow run info. + steps: + - name: Checkout repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Run zizmor 🌈 + uses: zizmorcore/zizmor-action@6fc4b006235f201fdab3722e17240ab420d580e5 # v0.6.1