anthropics / anthropics/claude-code-action

restoreConfigFromBase ENOENT on .claude/ symlinks whose target is outside SENSITIVE_PATHS (regression after dereference + Bun 1.3.14)

Open
#1,319 1 comment 5 reactions 0 assignees View on GitHub
bug p1
Dominant language
TypeScript
Stars
8.9k
Forks
2.1k
Avg merge
3d 9h
Merged PRs (30d)
10

Description

## Summary

`restoreConfigFromBase` crashes with `ENOENT: no such file or directory, statx ''` when the snapshotted PR directory contains a symlink whose **target lives outside the `SENSITIVE_PATHS` set** (e.g. `.claude/skills/ → ../../.agents/skills/`).

This is a regression introduced on 2026-05-14 by the combination of:
- **#1186** ("fix: dereference symlinks when snapshotting sensitive paths to `.claude-pr/`", merged 22:36 UTC) — added `dereference: true` to the `cpSync` call.
- **#1312** ("chore: bump pinned Bun to 1.3.14", merged 22:55 UTC) — Bun went from `1.3.6` to `1.3.14` in the same `v1` rollout (22:56 UTC, commit `51ea8ea`).

The earlier fix #1186 closed #1187 / #1220 / #1311, but those issues were all about symlinks **whose target is itself a SENSITIVE_PATH entry** (e.g. `CLAUDE.md → AGENTS.md`). The fix does not cover the case here: the symlink lives inside `.claude/` but points to a sibling directory (`.agents/`) that is NOT in `SENSITIVE_PATHS`, so `cpSync` with `dereference: true` follows the symlink and then `statx` fails the moment it traverses out of the snapshot tree.

## Repro

Workflow:
```yaml
- uses: anthropics/claude-code-action@v1
```

Repo layout:
```
.claude/skills/shadcn -> ../../.agents/skills/shadcn # symlink (in repo, tracked as mode 120000)
.agents/skills/shadcn/ # real directory (tracked, present after actions/checkout@v5)
```

Note: the symlink target IS present on disk after checkout — `.agents/` is a regular tracked directory in the repo. The failure is not "dangling symlink".

## Failure log

```
Restoring .claude, .mcp.json, .claude.json, .gitmodules, .ripgreprc, CLAUDE.md, CLAUDE.local.md, .husky from origin/master (PR head is untrusted)
##[error]Action failed with error: ENOENT: no such file or directory, statx '.claude/skills/shadcn'
```

## Confirmed timeline

- **Last green run**: action SHA `86eb26bf0139bdd75acd15ea5f00f45ee0a284c2`, runner `bun-version: 1.3.6`, 2026-05-14 18:02 UTC.
- **First red run** (same workflow, same repo, same symlink): action SHA `51ea8ea73a139f2a74ff649e3092c25a904aed7e`, runner `bun-version: 1.3.14`, 2026-05-15 13:28 UTC.
- Workflow file and repo symlink unchanged across that window.
- Every PR in our repo has failed identically since 5/15 (multiple branches and authors).

## Hypothesis on the failure mode

In `src/github/operations/restore-config.ts`:
```ts
for (const p of SENSITIVE_PATHS) {
if (existsSync(p)) {
cpSync(p, `.claude-pr/${p}`, { recursive: true, dereference: true });
}
}
```

When `cpSync` recurses into `.claude/` and reaches `.claude/skills/shadcn`, `dereference: true` makes it follow the symlink and `statx` the target. Bun 1.3.14 appears to throw on this where 1.3.6 tolerated it — possibly stricter symlink/statx semantics, or an interaction with how Bun materializes the dereferenced path during recursive copy.

(We have not isolated whether the immediate cause is Bun 1.3.14 itself or the `dereference: true` + Bun 1.3.14 combination, but reverting either piece to the pre-2026-05-14 state restores green CI.)

## Suggested directions

1. Skip individual entries whose resolved target lies outside `SENSITIVE_PATHS`, or
2. Wrap each per-entry `cpSync` in a try/catch that warns and falls back to snapshotting the link as a link (not its content), or
3. Reproduce against Bun 1.3.14 specifically and report upstream if this is a Bun regression.

## Workaround users can apply now

Pin the action to the last good SHA in their workflow:
```yaml
uses: anthropics/claude-code-action@86eb26bf0139bdd75acd15ea5f00f45ee0a284c2 # last v1 before 2026-05-14 22:56 UTC
```

This avoids both the `dereference: true` change and Bun 1.3.14. Confirmed green again with this pin.

## Affected scope

Not a single-repo issue — this hits any repo whose `.claude/` includes a symlink pointing outside `SENSITIVE_PATHS` (a reasonable pattern for sharing prompts/skills between two top-level directories like `.claude/` and `.agents/`).

Contributor guide

Open the contributing guide

Research direction

Start in src/github/operations/restore-config.ts and inspect the per-entry cpSync call using dereference: true. Reproduce the .claude/skills/shadcn symlink case with Bun 1.3.14, comparing it with Bun 1.3.6 or the pre-regression behavior. Done means restoreConfigFromBase completes without ENOENT for links targeting tracked paths outside SENSITIVE_PATHS while retaining the intended snapshot behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
bun, typescript
Domain
devops, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.