Skip to content

ci: add rainix-npm-blacklist reusable workflow#230

Open
thedavidmeister wants to merge 6 commits into
mainfrom
2026-06-15-npm-blacklist-reusable
Open

ci: add rainix-npm-blacklist reusable workflow#230
thedavidmeister wants to merge 6 commits into
mainfrom
2026-06-15-npm-blacklist-reusable

Conversation

@thedavidmeister

@thedavidmeister thedavidmeister commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

What

Adds rainix-npm-blacklist.yaml, a workflow_call reusable that owns the npm-package blacklist security gate (scan the installed dependency tree for known-malicious packages). Consumers replace their inline npm-blacklist job with a short caller.

Inputs

  • install-command (string, required) — how to install the dependency tree before the scan, e.g. nix develop .#wasm-shell -c npm install --no-check. The checker runs npm ls --all, so this must populate node_modules for every scanned directory.
  • working-directories (string, optional, default .) — whitespace-separated list of NPM project dirs to scan, e.g. a YAML multiline of . packages/raindex packages/ui-components.
  • cachix-name (string, optional, default rainlanguage).

Secret

  • CACHIX_AUTH_TOKEN (optional) — for the nix-store Cachix cache; empty degrades to anonymous pull.

The job

checkout → nix-quick-install → cachix → cache-nix-action (all via the shared nix-cachix-setup composite, so the pinned third-party SHAs stay single-sourced) → run install-command → run the github-chore npm-blacklist action once over working-directories.

Design choice: install once, scan many

The inline job in raindex #2739 installs once, then calls the composite action 3× (one per working-directory) — cheap, because each extra call is just an npm ls in another dir. A naive matrix over directories would instead re-run the expensive install-command (wasm build + npm install, minutes) per directory.

A reusable workflow can't loop a composite uses: over a dynamic list in YAML, so to preserve install-once I taught the action itself to take a list. The companion PR rainlanguage/github-chore#8 adds a working-directories input to the npm-blacklist action that loops checker.sh over each dir (backward compatible — the singular working-directory still works). This reusable installs once and calls the action once with the full list. The directory iteration lives in the action, which is its right home; this workflow stays a thin install-once wrapper, and there is no per-directory re-install cost.

Dependency / bidirectional bootstrap: this reusable references rainlanguage/github-chore/.github/actions/npm-blacklist@main, whose working-directories input only exists once github-chore#8 is on main. The self-test here (and any consumer) is therefore red until github-chore#8 merges — the same one-time @main bootstrap pattern already documented for the rainix composites. Merge github-chore#8 first.

Self-test

Adds npm-blacklist-self-test.yaml, a caller that runs the reusable end to end against the real npm project in test/fixture/subgraph (npm ci then scan), mirroring how the composites are self-tested against test/fixture in test.yml. The fixture only depends on @graphprotocol/graph-ts, which is not blacklisted, so the scan is green.

Validation

actionlint is clean on both new files (actionlint .github/workflows/rainix-npm-blacklist.yaml .github/workflows/npm-blacklist-self-test.yaml → exit 0; the only repo-wide actionlint findings are pre-existing, in rainix-autopublish.yaml / rainix-sol-test.yaml).

First consumer

raindex #2739 is the first consumer: once this reusable and github-chore#8 are on main, that PR's inline npm-blacklist job (in both vercel-prod.yaml and vercel-preview.yaml) is replaced by a uses: of this reusable. That wiring is a follow-up — not part of this PR.

Closes #229

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added new GitHub Actions workflows for npm blacklist testing and validation, enabling automated dependency scanning in CI/CD pipelines.
  • Documentation

    • Improved descriptions and formatting across GitHub Actions configuration files for better clarity.

Upstream the npm-package blacklist security gate (scan the installed
dependency tree for known-malicious packages) into a rainix reusable, so
consumers stop copy-pasting the job inline.

The reusable owns the boilerplate — the shared nix + cachix preamble,
running the caller's `install-command` once, then scanning every listed
directory in a single call to the github-chore `npm-blacklist` action via
its `working-directories` input. The expensive dependency install runs
once and feeds every directory scanned, rather than re-installing per
directory.

Inputs: `install-command` (required), `working-directories` (whitespace
list, default `.`), `cachix-name`. Secret: `CACHIX_AUTH_TOKEN` (optional).

Adds a self-test caller that runs the reusable against the subgraph npm
project in test/fixture, mirroring how the composites are self-tested.

Closes #229

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@thedavidmeister thedavidmeister self-assigned this Jun 15, 2026
@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a new rainix-npm-blacklist reusable GitHub Actions workflow parameterized by install-command, working-directories, and an optional CACHIX_AUTH_TOKEN secret, along with a self-test caller workflow. Five existing composite action YAML files receive description text reformats with no behavior changes.

Changes

npm-blacklist Reusable Workflow

Layer / File(s) Summary
Reusable workflow and self-test caller
.github/workflows/rainix-npm-blacklist.yaml, .github/workflows/npm-blacklist-self-test.yaml
rainix-npm-blacklist.yaml defines a workflow_call workflow with install-command, working-directories, and cachix-name inputs plus optional CACHIX_AUTH_TOKEN secret; it wires Nix/Cachix setup, runs the caller-provided install command, then invokes rainlanguage/github-chore/.github/actions/npm-blacklist@main across the specified directories. npm-blacklist-self-test.yaml calls the reusable on every push targeting test/fixture/subgraph with npm ci inside a wasm-shell.

Action Description Text Reformats

Layer / File(s) Summary
Description-only text reformats
.github/actions/cache/action.yml, .github/actions/checkout/action.yml, .github/actions/gh-release/action.yml, .github/actions/nix-cachix-setup/action.yml, .github/actions/rust-cache/action.yml
Action-level and input-level description strings are reflowed/rewrapped across YAML line breaks. No input names, defaults, required flags, runtime steps, or referenced action SHAs were changed.

Sequence Diagram(s)

sequenceDiagram
  participant Caller as npm-blacklist-self-test
  participant Reusable as rainix-npm-blacklist
  participant NixCachix as nix-cachix-setup
  participant BlacklistAction as github-chore/npm-blacklist

  Caller->>Reusable: workflow_call(install-command, working-directories, CACHIX_AUTH_TOKEN)
  Reusable->>NixCachix: setup Nix + Cachix environment
  NixCachix-->>Reusable: environment ready
  Reusable->>Reusable: run install-command (cd test/fixture/subgraph && npm ci)
  Reusable->>BlacklistAction: scan(working-directories=test/fixture/subgraph)
  BlacklistAction-->>Reusable: blacklist scan complete
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A reusable workflow hops into place,
scanning npm packages with elegant grace.
Descriptions rewrapped, no logic to fear,
the blacklist now shared — less drift every year.
One workflow to rule them, from fixture to prod,
this bunny approves with a satisfied nod! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding a reusable workflow for npm blacklist scanning.
Linked Issues check ✅ Passed The PR fully implements all requirements from issue #229: creates rainix-npm-blacklist.yaml reusable workflow with parameterized inputs (install-command, working-directories, CACHIX_AUTH_TOKEN), validates it with a self-test, and enables consumers to replace duplicate inline jobs.
Out of Scope Changes check ✅ Passed All changes are in scope: action.yml formatting updates are incidental to the main workflow additions, and the new workflows directly fulfill issue #229's stated objectives without unrelated modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 2026-06-15-npm-blacklist-reusable

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

thedavidmeister and others added 3 commits June 16, 2026 04:27
yamlfmt reflows the `>-` folded-scalar description bodies in the new
rainix-npm-blacklist reusable and in the composite actions onto single
lines, matching the `yamlfmt` pre-commit hook that `nix flake check`
runs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pass working-directory (singular) to the composite action — the action does not
accept working-directories (plural), which caused a warning and a fallback to
'.' where no package.json exists.

Co-Authored-By: Claude <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
.github/workflows/npm-blacklist-self-test.yaml (1)

12-19: ⚖️ Poor tradeoff

Consider testing multi-directory scanning.

The self-test only validates a single directory (test/fixture/subgraph), but the reusable workflow supports scanning multiple directories via a whitespace-separated list. While single-directory is the common case, adding a test with multiple directories would provide more complete coverage of the workflow's capabilities.

Example:

working-directories: >-
  test/fixture/subgraph
  test/fixture/another-package

This is optional since the multi-directory iteration logic resides in the npm-blacklist action itself, not in this thin wrapper workflow.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/npm-blacklist-self-test.yaml around lines 12 - 19, The
npm-blacklist-self-test workflow currently only tests a single directory in the
working-directories field, but the reusable workflow supports
whitespace-separated multiple directories. Add an additional test job (or modify
the existing npm-blacklist job) to validate multi-directory scanning by
specifying multiple directories in the working-directories field, such as
test/fixture/subgraph and another test fixture directory, to ensure the workflow
properly handles the multi-directory iteration capability.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/rainix-npm-blacklist.yaml:
- Around line 51-54: The `install-command` input is being directly interpolated
into the `run` step without any validation, creating a command injection
vulnerability. Restrict the `install-command` input to a predefined set of safe
commands by adding a `choices` constraint to the input definition in the
`inputs` section of the workflow, or alternatively implement validation logic
before the `run` step that checks the input against an allowlist of permitted
commands and fails the workflow if an unexpected value is provided. This ensures
only trusted install commands can be executed regardless of who modifies calling
workflows.

---

Nitpick comments:
In @.github/workflows/npm-blacklist-self-test.yaml:
- Around line 12-19: The npm-blacklist-self-test workflow currently only tests a
single directory in the working-directories field, but the reusable workflow
supports whitespace-separated multiple directories. Add an additional test job
(or modify the existing npm-blacklist job) to validate multi-directory scanning
by specifying multiple directories in the working-directories field, such as
test/fixture/subgraph and another test fixture directory, to ensure the workflow
properly handles the multi-directory iteration capability.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 966b41a0-7f26-4cf1-98a5-22a54df312df

📥 Commits

Reviewing files that changed from the base of the PR and between 0574dad and cd1fe3a.

📒 Files selected for processing (7)
  • .github/actions/cache/action.yml
  • .github/actions/checkout/action.yml
  • .github/actions/gh-release/action.yml
  • .github/actions/nix-cachix-setup/action.yml
  • .github/actions/rust-cache/action.yml
  • .github/workflows/npm-blacklist-self-test.yaml
  • .github/workflows/rainix-npm-blacklist.yaml

Comment on lines +51 to +54
# Install the dependency tree once; the blacklist checker inspects it but
# never installs, so a single install feeds every directory scanned below.
- name: Install npm dependencies
run: ${{ inputs.install-command }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find all workflows that call rainix-npm-blacklist
rg -t yaml -A 5 'uses:.*rainix-npm-blacklist' --glob '.github/workflows/*'

Repository: rainlanguage/rainix

Length of output: 212


🏁 Script executed:

#!/bin/bash
# First, verify the file exists
ls -la .github/workflows/rainix-npm-blacklist.yaml

# Check lines 51-54 to see the actual code
echo "=== Lines 51-54 ===" 
sed -n '51,54p' .github/workflows/rainix-npm-blacklist.yaml

# View more context around those lines
echo "=== Context (40-60) ==="
sed -n '40,60p' .github/workflows/rainix-npm-blacklist.yaml

# Check if there's input validation defined
echo "=== Looking for inputs definition ==="
grep -n "inputs:" .github/workflows/rainix-npm-blacklist.yaml -A 20

Repository: rainlanguage/rainix

Length of output: 2693


🏁 Script executed:

#!/bin/bash
# Search for workflow calls to rainix-npm-blacklist without file type restriction
# Try different search patterns
echo "=== Searching for uses: rainix-npm-blacklist ==="
rg 'rainix-npm-blacklist' .github/workflows/ -A 3

echo "=== Searching for any references to this workflow ==="
rg 'rainix-npm-blacklist' . --type yaml 2>/dev/null | head -20

echo "=== List all yaml files in .github/workflows ==="
find .github/workflows -name "*.yaml" -o -name "*.yml"

Repository: rainlanguage/rainix

Length of output: 2025


Command injection risk via template expansion in run step.

The install-command input is expanded directly into the run step without validation. While workflow_call limits callers to workflows within the same repository, an attacker with repository write access could modify calling workflows to inject arbitrary shell commands through this input.

Since the input is defined as a required string with no validation constraints, consider restricting it to a predefined set of safe commands or validating against a pattern. The self-test caller currently uses a hardcoded trusted input, but this pattern should not be assumed for future callers.

🧰 Tools
🪛 zizmor (1.25.2)

[error] 54-54: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/rainix-npm-blacklist.yaml around lines 51 - 54, The
`install-command` input is being directly interpolated into the `run` step
without any validation, creating a command injection vulnerability. Restrict the
`install-command` input to a predefined set of safe commands by adding a
`choices` constraint to the input definition in the `inputs` section of the
workflow, or alternatively implement validation logic before the `run` step that
checks the input against an allowlist of permitted commands and fails the
workflow if an unexpected value is provided. This ensures only trusted install
commands can be executed regardless of who modifies calling workflows.

Source: Linters/SAST tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Upstream the npm-package-blacklist CI job into a rainix reusable workflow

1 participant