diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 03a2373f..c39c8681 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -239,10 +239,16 @@ jobs: TAG: ${{ needs.plan.outputs.tag }} # why: the lease fails the push when main moved since plan, instead of releasing a commit # nobody checked; the pair goes atomically so a tag never exists without its commit. + # why: the token goes as the extraheader actions/checkout writes, set through git's + # GIT_CONFIG_* environment rather than `-c`, so it is in neither the remote URL nor git's argv. run: | + auth=$(printf 'x-access-token:%s' "$GITHUB_TOKEN" | base64 | tr -d '\n') + echo "::add-mask::$auth" + export GIT_CONFIG_COUNT=1 + export GIT_CONFIG_KEY_0="http.https://github.com/.extraheader" + export GIT_CONFIG_VALUE_0="AUTHORIZATION: basic $auth" git push --atomic --force-with-lease="refs/heads/main:$GITHUB_SHA" \ - "https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" \ - HEAD:refs/heads/main "refs/tags/$TAG" + "https://github.com/${GITHUB_REPOSITORY}.git" HEAD:refs/heads/main "refs/tags/$TAG" - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: notes diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index 101e5efe..e9c885b1 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -62,7 +62,7 @@ jobs: working-directory: . run: pnpm install --frozen-lockfile --ignore-scripts - name: Install dependencies - run: pnpm install --frozen-lockfile + run: pnpm install --frozen-lockfile --ignore-scripts - name: Build run: pnpm build - name: Check the HTTP API reference diff --git a/src/source-hygiene.test.ts b/src/source-hygiene.test.ts index 74e3aa62..e8039389 100644 --- a/src/source-hygiene.test.ts +++ b/src/source-hygiene.test.ts @@ -287,3 +287,66 @@ describe("a file at vendor/'s root", () => { expect(rootFiles).toEqual(["vendor/README.md"]); }); }); + +const workflowFiles = lsFiles([".github/workflows/"]).filter((name) => /\.ya?ml$/.test(name)); + +function workflowLines(pattern: RegExp): string[] { + return workflowFiles.flatMap((name) => + readFileSync(join(REPO_ROOT, name), "utf8") + .split("\n") + .flatMap((line, index) => + pattern.test(line) ? [`${name}:${index + 1}: ${line.trim()}`] : [], + ), + ); +} + +/** + * why: a dependency's lifecycle script runs arbitrary code inside a job that may hold a token, and + * a credential written into a URL lands in the process list and in any log that echoes the remote. + */ +describe("a GitHub workflow", () => { + it("was enumerated from the git index", () => { + expect(workflowFiles).toContain(".github/workflows/release.yml"); + expect(workflowFiles).toContain(".github/workflows/website.yml"); + }); + + it("passes --ignore-scripts to every pnpm install", () => { + const installs = workflowLines(/\bpnpm install\b/); + expect(installs.length).toBeGreaterThan(1); + expect(installs.filter((line) => !line.includes("--ignore-scripts"))).toEqual([]); + }); + + it("writes no credential into a URL", () => { + expect(workflowLines(/https?:\/\/[^/"'\n]*@/)).toEqual([]); + }); +}); + +describe("the Release workflow's push (.github/workflows/release.yml)", () => { + const release = readFileSync(join(REPO_ROOT, ".github/workflows/release.yml"), "utf8"); + const step = /\n {6}- name: Push\n[\s\S]*?(?=\n {6}- |\n\n)/.exec(release)?.[0] ?? ""; + const push = /git push(?:[^\n]*\\\n)*[^\n]*/.exec(step)?.[0] ?? ""; + + it("sends the token as the extraheader actions/checkout sets, through git's GIT_CONFIG_* environment, so it is in neither the remote URL nor git's arguments", () => { + expect(step).toContain( + `auth=$(printf 'x-access-token:%s' "$GITHUB_TOKEN" | base64 | tr -d '\\n')`, + ); + expect(step).toContain(`echo "::add-mask::$auth"`); + const exported = [ + `export GIT_CONFIG_COUNT=1`, + `export GIT_CONFIG_KEY_0="http.https://github.com/.extraheader"`, + `export GIT_CONFIG_VALUE_0="AUTHORIZATION: basic $auth"`, + ]; + for (const line of exported) { + expect(step).toContain(line); + expect(step.indexOf(line)).toBeLessThan(step.indexOf("git push")); + } + expect(push).toContain(`"https://github.com/\${GITHUB_REPOSITORY}.git"`); + expect(push).not.toMatch(/GITHUB_TOKEN|\$auth|\s-c\s/); + }); + + it("still pushes the release commit and its tag atomically, leased on the commit the plan checked", () => { + expect(push).toContain("--atomic"); + expect(push).toContain(`--force-with-lease="refs/heads/main:$GITHUB_SHA"`); + expect(push).toContain(`HEAD:refs/heads/main "refs/tags/$TAG"`); + }); +});