Skip to content

feat: auto-fix Bun and npm lockfiles on PR branches - #10

Merged
peakematt merged 7 commits into
mainfrom
ideation/bun-lockfile-socket-firewall-scrub
Sep 14, 2026
Merged

peakematt merged 7 commits into
mainfrom
ideation/bun-lockfile-socket-firewall-scrub

Conversation

@peakematt

@peakematt peakematt commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Socket Firewall URLs saved in lockfiles can bind later installs to an endpoint that contributors or external CI cannot access. Bun can record those URLs directly; npm has a preventive omit-lockfile-registry-resolved setting, but also benefits from a cleanup backstop. Detecting or editing runner files alone does not repair the pull request branch.

This action fixes the branch itself. One invocation of workos/setup-socket-firewall/lockfile-scrub reads the selected committed lockfile from the PR head, normalizes it, and creates a commit on that same PR branch using GITHUB_TOKEN. It defaults to mode: fix and lockfile: bun.lock. The caller grants contents: write; no checkout, dependency installation, or separate commit/push step is required.

Bun URLs become the native empty resolved-URL field. npm package-lock.json and npm-shrinkwrap.json versions 1–3 retain their tarball paths with registry.npmjs.org replacing the Socket Firewall origin in resolved values. Nested repository-relative paths are supported. A clean file creates no commit; explicit mode: check reports whether repair is needed without writing. Outputs include changed and the repair commit-sha.

The action—not caller shell code—enforces branch safety. It accepts ordinary pull_request events, rejects default-branch writes, fails dirty forks with repair guidance, and refuses stale PR heads. GitHub's atomic createCommitOnBranch operation checks the expected head SHA and changes only the selected file, so a concurrent contributor push is not overwritten. It neither force-pushes nor retries denied or ambiguous writes. The Node 24 action runs only its own normalizer in an isolated directory; it does not execute target-repository code or pass the token to that subprocess.

A live test on this draft PR proved the complete path: the action created a verified github-actions[bot] commit, replacing the test Bun URL with an empty field while changing only that lockfile. The temporary trial workflow and fixture were removed afterward.

From the repository root, with Bash and Node.js 24+, these offline checks exercise branch-write guards, transformations, and the packaged release runtime without dependencies or live credentials:

node --test scripts/fix-lockfile.test.mjs scripts/scrub-npm-lockfile.test.mjs
bash scripts/scrub-lockfile.test.sh
bash scripts/build-release.test.sh

All 49 Node tests and the existing shell/release suites passed locally, along with ShellCheck, shfmt, and workflow linting. The six npm install smoke combinations and protected-registry smoke remain in CI.

Do not rely on GITHUB_TOKEN commits to run follow-up CI automatically. In the live trial, GitHub created action_required follow-up runs with no jobs executed; a repaired lockfile is not proof of fresh-head application CI. This PR supplies the complete self-fixing action, but does not yet install it in the four target repositories. Those workflows must use the signed action-only release SHA after source merge. Yarn and pnpm scrubbing remain out of scope.

Tracking: https://linear.app/workos/issue/HELP-723

Restore Socket Firewall Bun tarball URL fields to Bun native empty resolution fields.

Spec: docs/ideation/bun-lockfile-socket-firewall-scrub/spec-phase-1.md
Add explicit workspace-relative lockfile selection, preserve Bun defaults, and normalize npm resolved URL fields without reformatting. Cover npm lockfile versions 1–3 and shrinkwrap with tests and CI install smokes.

Spec: docs/ideation/bun-lockfile-socket-firewall-scrub/spec-phase-1.md
@peakematt peakematt changed the title feat: add Bun lockfile scrub action feat: add Bun and npm lockfile scrub action Sep 11, 2026
peakematt and others added 4 commits September 11, 2026 15:44
Preserve upstream public-token and fork-fallback behavior alongside npm scrub tests. Run the protected scrub smoke only when Socket Firewall is active.
Default to guarded GITHUB_TOKEN repair using atomic createCommitOnBranch. No checkout or caller-owned commit/push is required. Include a temporary PR-10-only live trial to verify branch updates.

Spec: docs/ideation/bun-lockfile-socket-firewall-scrub/spec-phase-1.md
The action created verified github-actions[bot] commit c66640c on PR #10, changing only the synthetic Bun lockfile. Live run 34844728085 passed. Keep the permanent controller, normalization and release tests.
@peakematt peakematt changed the title feat: add Bun and npm lockfile scrub action feat: auto-fix Bun and npm lockfiles on PR branches Sep 14, 2026
@peakematt

Copy link
Copy Markdown
Contributor Author

@greptile

@greptile-apps

greptile-apps Bot commented Sep 14, 2026

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

The current head appears safe to merge with no remaining actionable findings.

Summary

  • Normalizes supported lockfiles without executing target-repository code.
  • Uses GitHub’s atomic branch-commit API with stale-head, fork, and default-branch protections.
  • Adds unit, release-tree, npm compatibility, and protected-registry smoke coverage.
  • Documents permissions, supported formats, operational constraints, and follow-up CI limitations.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[pull_request event] --> B[Validate event, repository, mode, and lockfile path]
  B --> C[Fetch current PR metadata]
  C --> D{Open and event head still current?}
  D -- No --> X[Fail without writing]
  D -- Yes --> E[Read lockfile blob from PR head]
  E --> F[Normalize in isolated temporary directory]
  F --> G{Repair needed?}
  G -- No --> H[Return changed=false]
  G -- Yes --> I{Mode is check?}
  I -- Yes --> J[Return changed=true without commit]
  I -- No --> K{Same-repository, non-default branch?}
  K -- No --> X
  K -- Yes --> L[Create atomic single-file commit using expected head SHA]
  L --> M[Return changed=true and commit SHA]
Loading

Reviews (3) · Last reviewed commit: "docs: reflect observed bot-commit CI app..."

@peakematt
peakematt marked this pull request as ready for review September 14, 2026 13:19
@peakematt
peakematt requested review from a team as code owners September 14, 2026 13:19

@devin-ai-integration devin-ai-integration 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.

Devin Review found 1 potential issue.

Devin Review

Comment thread scripts/fix-lockfile.mjs
@peakematt

Copy link
Copy Markdown
Contributor Author

[from Pi]: @greptile please re-review the current head, dfe43cb, and report any remaining actionable findings and the updated confidence score. The Devin permission finding has been investigated: GitHub documents that GET /repos/{owner}/{repo}/pulls/{pull_number} accepts either Contents: read or Pull requests: read, so the existing contents: write permission suffices. Evidence is recorded in the resolved thread. No code or permission changes were made.

@peakematt
peakematt merged commit 62a7c4c into main Sep 14, 2026
16 checks passed
@peakematt
peakematt deleted the ideation/bun-lockfile-socket-firewall-scrub branch September 14, 2026 14:04
peakematt added a commit that referenced this pull request Sep 14, 2026
The automatic `v1` release after PR #10 failed with `GitHub-signed
release commit tree differs from the staged tree`, leaving the lockfile
repair action unpublished. The new `scripts/scrub-lockfile.sh` was
executable in the staged package, but GitHub's `createCommitOnBranch`
file additions cannot specify an executable mode for a new file.

This removes the helper's unnecessary executable bit (`100755` →
`100644`). The controller, CI, and tests already invoke it through
`bash`, so its behavior does not change. **No publisher logic, signature
verification, exact-tree checks, token permissions, or release workflow
is changed.**

The previous publisher mock returned the desired tree hash directly,
hiding this mismatch. The regression now constructs an actual Git tree
from the mutation payload, preserving existing file modes and assigning
`100644` to new files against a five-file pre-scrub release fixture. The
fixed package passes. Reintroducing the executable bit produces the same
release error and verifies that neither discovery ref moves and the
temporary staging branch is cleaned up. The packaged
controller/normalizer tests also run successfully with the
non-executable helper.

From the repository root, with Bash, Node.js 24+, Git, jq, and standard
command-line utilities, no credentials or dependency installation are
needed:

```bash
bash scripts/publish-release.test.sh
bash scripts/build-release.test.sh
node --test scripts/fix-lockfile.test.mjs scripts/scrub-npm-lockfile.test.mjs
```

These checks passed locally. The new publisher regression failed with
the original file mode before the fix. All 49 Node tests, the existing
shell suites, ShellCheck, shfmt, and workflow linting passed as well.

After this merges and main CI passes, the existing release workflow
should publish the new action-only commit. This PR does not publish a
release or manually move any refs; that live verification remains
necessary after merge.

Failed release run:
https://github.com/workos/setup-socket-firewall/actions/runs/34853295286

Related work:
#10
https://linear.app/workos/issue/HELP-723
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants