mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-09 16:02:36 +01:00
c66b4a55efdc5675b5a5146197078b94de6407da
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e3041f5481 |
fix(ci): let the lockfile bot own the sandbox provider lockfiles (#19522)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The repository has a supply-chain rule: contributors do not commit lockfiles. A bot and verified Dependabot commits write them. > - The rule checks only the root `pnpm-lock.yaml`. > - The sandbox providers are outside the root workspace, so they have two more pnpm lockfiles. Pull requests edited them by hand, for example #12791, #18839 and #19489. > - This pull request makes the same rule and the same bot cover those two lockfiles. > - The benefit is one lockfile rule for every managed pnpm lockfile, and no lockfile edits in contributor pull requests. ## Linked Issues or Issue Description Refs #19489 **What existing behavior does this improve?** The lockfile policy and the lockfile refresh bot. **Subsystem affected** CI: `.github/scripts/lockfile-trust.mjs`, `.github/workflows/refresh-lockfile.yml`, and the sandbox provider installs. **Current behavior** `lockfile-trust.mjs` blocks contributor edits to `pnpm-lock.yaml` only. A contributor can edit `scripts/typecheck-sandbox-providers/pnpm-lock.yaml` or `packages/plugins/sandbox-providers/daytona/pnpm-lock.yaml`, and CI passes. The refresh bot does not update these files. `typecheck:test-programs` fails on a stale provider lockfile and tells the contributor to commit a new one. **Proposed behavior** The policy blocks contributor edits to all three lockfiles. The refresh bot regenerates all three after merge. CI resolves a stale provider lockfile in place for the run, as it does for the root lockfile. **Reason and benefit** Lockfile content comes only from the bot or from verified Dependabot commits. Contributors do not need to run pnpm in special folders. **Breaking changes** None. A pull request that edits a provider lockfile now fails the policy check. Remove the lockfile change from the pull request. The bot commits it after merge. ## What Changed - `lockfile-trust.mjs` now exports `LOCKFILES`: the root lockfile, the shared sandbox provider lockfile, and the Daytona lockfile. The policy blocks contributor edits to each of them. A Dependabot pull request must match a verified Dependabot commit for each lockfile that it changes. The `merged` command and the reporting-lock proof still use only the root lockfile. - `check-pr-lockfile.mjs` (advisory check) uses the same list. - `refresh-lockfile.yml`: - A job-level `LOCKFILES` env lists the same three files. A test checks that it equals the policy list. - A new step regenerates the two provider lockfiles with `--resolution-only --ignore-scripts --no-frozen-lockfile`. - The unexpected-changes check, the change check, and `git add` cover all three lockfiles. - The release-age gate checks the added versions in every lockfile. - A held refresh saves all three lockfiles at their repository paths, with a `source-locks.sha256` file. The next run reuses them only if every master lockfile is unchanged. An artifact in the old format is not reused. - The PR title is now `chore(lockfile): refresh pnpm lockfiles`. - `check-lockfile-release-age.mjs` accepts more than one `--base`/`--head` pair. - `scripts/typecheck-test-programs.mjs`: if the frozen install of the provider workspace fails, the script resolves the lockfile in place and installs frozen again. - `scripts/build-standalone-public-packages.mjs`: the same fallback applies to a package with a committed lockfile (Daytona). `release.sh` already restores tracked files when it exits. - `doc/DEVELOPING.md` and `doc/RELEASE-AUTOMATION-SETUP.md` describe the managed lockfiles. They also say that the Pi and Kimi distribution lockfiles stay hand-managed, because they hold attested provider pins. ## Verification - `node --test .github/scripts/tests/*.test.mjs scripts/__tests__/build-standalone-concurrency.test.mjs`: 731 tests pass. New tests cover: - the policy for provider lockfiles, including a real git history with a Dependabot commit and a later hand edit - the workflow and policy lists match - the unexpected-changes check, run with bash against a fixture - a held refresh round trip, and its invalidation when a provider lockfile changes on master - the release-age gate across lockfile pairs - the inline fallback in both install scripts - `node --test scripts/typecheck-test-programs.test.mjs`: the install tests pass. Two tests fail locally only because this worktree has no root `node_modules` (no `tsc`). They also fail without this change. - I ran the new bot commands on master with pnpm 9.15.4. No package version changed. pnpm 9.15.4 removes `libc:` fields and adds `deprecated:` notes, so the first refresh is a metadata-only change. The release-age gate passes it because it adds no versions. - I ran the release-age and held-lock steps locally with bash against this commit. The gate reported `eligible=true`, and `sha256sum --check` accepted the saved hashes. - The workflow YAML parses, and `bash -n` accepts every `run` block. - Not testable before merge: the policy job loads `lockfile-trust.mjs` from the base branch, so the new rule applies only to pull requests opened after this merges. The refresh workflow runs only on master. ## Risks - The release build now resolves a stale Daytona lockfile in place, from the registry. The root release install already resolves without a frozen lockfile, so this is the same level of trust. - The paid runner e2e job still installs Daytona with `--frozen-lockfile`. After a Daytona manifest change merges, its Daytona cases fail until the bot's refresh merges. This matches the rule that paid jobs refuse a new root lockfile until its refresh merges. - Dependabot pull requests for the provider entries in #19489 change a provider lockfile. They pass only if each lockfile matches a verified Dependabot commit, the same as for the root lockfile. - Low risk otherwise: the bot keeps its existing token, environment, and merge rules. ## Model Used - Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with tool use (shell, file edits, and git). ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
7d194e901f |
feat(ci): merge lockfile refresh PRs through a dedicated bot (#18238)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - CI owns `pnpm-lock.yaml`. Contributors do not commit it, so a poisoned lockfile cannot come in from a community PR. > - `refresh-lockfile.yml` regenerates the lockfile from the manifests on master and opens a PR. > - That PR waits on required checks and code owner review. A `GITHUB_TOKEN` push does not start the checks, so a maintainer must merge each PR by hand. > - The PR content comes only from manifests that maintainers already reviewed on master. A human review adds little. > - This pull request lets a dedicated GitHub App merge the refresh PR at once, without CI or review. > - A release-age gate holds the merge when the refresh adds a package version that is less than 3 days old on npm. > - The benefit is a lockfile loop that closes itself, without a bypass for any identity that other workflows can use. ## Linked Issues or Issue Description Refs #12115 (the same stuck-PR problem, fixed there by starting the checks). Refs #18219 (an example refresh PR that needed a manual approval and merge). **What happened?** Each lockfile refresh PR stays open until a code owner approves it and a maintainer merges it. The required checks `ci / verify` and `ci / e2e` also do not start, because the workflow pushes with `GITHUB_TOKEN`. **Expected behavior** The refresh PR merges with no human action and no CI run, unless it adds a package version that is too new to trust without review. **Steps to reproduce** Merge a manifest change to master. Look at the `chore/refresh-lockfile` PR that the workflow opens. It stays blocked. ## What Changed - `refresh-lockfile.yml` runs in a new `lockfile-refresh` environment. Only `master` can use this environment. - The workflow creates a token for a dedicated lockfile bot app after dependency resolution is complete. The token has only contents and pull request write access. - The workflow merges with `gh pr merge --squash --admin --match-head-commit <sha>`, not `--auto`. It merges only the commit that it pushed. - New `.github/scripts/check-lockfile-release-age.mjs` compares the base and refreshed lockfiles. It looks up the npm publish time of each added package version. The bot merges only when every version is at least 3 days old. A lookup error, a missing publish time, a non-registry version, or a resolution that is not a plain registry tarball also holds the merge. - When the gate holds the PR, the workflow posts or updates one report comment on the PR and does not merge. - A daily schedule runs the refresh again, so a held PR merges after its versions are old enough. - A held run uploads its lockfile as a `held-pnpm-lock` artifact. The artifact records the hash of the master lockfile it started from. The next master run resolves from it only while master still has that lockfile, so held versions stay while their manifests do not change, and a maintainer's lockfile correction replaces them. The workflow does not read the PR branch for this, because users with write access can push to it. - The generated PR body now describes the gate. - `tests/runner-e2e/OPERATIONS.md` now says that the bot can merge the report-lock correction without review, under the same gate. - New `lockfile-refresh-merge.test.mjs` pins the merge safeguards: the environment, the step order, the gate conditions, and `--match-head-commit`. - `doc/RELEASE-AUTOMATION-SETUP.md` §8.1 tells an admin how to create the app, the environment, and the ruleset bypass. It also tells why we do not use `github-actions` or `commitperclip` for the bypass. ## Verification - `node --test .github/scripts/tests/check-lockfile-release-age.test.mjs .github/scripts/tests/lockfile-refresh-*.test.mjs` passes (17/17). - I ran the gate against the real lockfile diff of #18219 and the live npm registry. With 3 days, all 7 added versions passed (`eligible=true`). With 60 days, it held all 7 `turbo` 2.11.10 versions (9.1 days old) and wrote the report. - The workflow YAML parses. actionlint did not run, because it is not installed locally and Docker was not available. - No live run yet. After the admin setup in §8.1, run the workflow with `workflow_dispatch` on master, or merge a manifest change. Then make sure that the bot opens and merges the refresh PR. ## Risks - **Setup order.** An org admin must do the steps in §8.1 before this PR merges. If not, the next refresh fails at the token step, and the PR stays open for a manual merge, as it does now. - **No CI on lockfile changes.** A bad resolution can land on master without a check. The next manifest PR or the canary release shows the problem. - **Release-age gate limits.** The gate stops only fast-detected attacks on new versions. A malicious version that stays undetected for more than 3 days still merges without review. Lockfile changes that add very new versions now wait for a maintainer or up to 3 days. - **Bypass scope.** The app bypasses the master ruleset only in pull request mode. It cannot push to master directly. Only the master-only `lockfile-refresh` environment holds its key. If the key leaks, the holder can merge any open PR past review. Rotate the key if you think it leaked. - **More master runs.** A merge by an app token starts push workflows on master. A merge by `GITHUB_TOKEN` does not. After each lockfile merge, the canary release runs, and the refresh workflow runs again with no change. ## Model Used - Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, in Claude Code with tool use (shell, file edit, GitHub CLI). ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |