ci: activate Node-first pnpm setup for PRs (#12810)

## Thinking Path

> - Paperclip validates every change through an immutable reusable PR
workflow.
> - That caller still pinned a revision that ran pnpm setup before Node
setup.
> - The implementation fix in #12808 is therefore present on master but
inactive for ordinary PR CI.
> - Advancing the immutable caller pin activates the already tested
Node-first workflow.
> - A focused contract prevents the caller from silently returning to
the old revision.
> - The benefit is a faster PR feedback loop without changing product
code or secret boundaries.

## Linked Issues or Issue Description

Refs #12808

## What Changed

- Pin ordinary PR CI to trusted workflow revision
`a0a78ee60946a5f79f85b2bd0584fc766fae43bb`.
- Assert that the reusable workflow call is canonical, unique, and
SHA-pinned to that audited revision.

## Verification

- Focused workflow security test: 8/8.
- Prettier passed.
- Actionlint passed.
- `git diff --check` passed.

## Risks

Low risk. The change only advances an immutable reusable-workflow pin to
a revision whose full ordinary CI and security checks passed. Product
code and credentials are unchanged.

## Model Used

OpenAI Codex GPT-5 with agentic reasoning and repository tool use.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used
- [x] I have linked the related public PR
- [x] I have not referenced internal issue links
- [x] My branch name describes the change
- [x] I have run focused tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have considered and documented risks
This commit is contained in:
Dotta 2026-09-03 21:28:49 -05:00 committed by GitHub
parent f449b05bc5
commit 89bf6a33c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 23 additions and 1 deletions

View File

@ -10,4 +10,4 @@ permissions:
jobs:
ci:
uses: paperclipai/paperclip/.github/workflows/pr-trusted.yml@f038633bf5b04163ff985ef0542876bd9f455379
uses: paperclipai/paperclip/.github/workflows/pr-trusted.yml@a0a78ee60946a5f79f85b2bd0584fc766fae43bb

View File

@ -3,6 +3,8 @@ import path from "node:path";
import { describe, expect, it } from "vitest";
const repositoryRoot = path.resolve(import.meta.dirname, "../..");
const ordinaryPrTrustedWorkflowRevision =
"a0a78ee60946a5f79f85b2bd0584fc766fae43bb";
const fullStackTestNeeds =
/needs:\s*\[\s*authorize,\s*target_lock,\s*catalog,\s*daytona_image,\s*build_runner_artifacts,\s*build_remote_provider_pack,?\s*\]/u;
const buildRunnerNeeds =
@ -11,6 +13,26 @@ const buildRemoteProviderPackNeeds =
/needs:\s*\[\s*authorize,\s*target_lock,\s*catalog,\s*daytona_image,\s*build_runner_artifacts,?\s*\]/u;
describe("public repository paid workflow security", () => {
it("pins ordinary PR CI to the trusted Node-before-pnpm workflow", async () => {
const ordinaryPrWorkflow = await readFile(
path.join(repositoryRoot, ".github/workflows/pr.yml"),
"utf8",
);
const trustedWorkflowCalls = [
...ordinaryPrWorkflow.matchAll(
/^\s+uses:\s+(paperclipai\/paperclip\/\.github\/workflows\/pr-trusted\.yml)@([0-9a-f]{40})$/gmu,
),
];
expect(trustedWorkflowCalls).toHaveLength(1);
expect(trustedWorkflowCalls[0]?.[1]).toBe(
"paperclipai/paperclip/.github/workflows/pr-trusted.yml",
);
expect(trustedWorkflowCalls[0]?.[2]).toBe(
ordinaryPrTrustedWorkflowRevision,
);
});
it("keeps pnpm bootstrap registry telemetry out of trusted workflow setup", async () => {
for (const workflowName of [
"runner-full-stack-e2e.yml",