-
Notifications
You must be signed in to change notification settings - Fork 6
feat: add registry-url and scope inputs for npm auth #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
f14ab3c
feat: add registry-url and scope inputs for npm auth
fengmk2 ba0d868
fix: address review feedback for registry-url auth
fengmk2 ab3bdf7
fix: match setup-node's registry-url description wording
fengmk2 af16239
fix: describe registry-url behavior accurately (writes to $RUNNER_TEMP)
fengmk2 bbcd7f9
fix: validate registry URL, avoid param mutation, fix private registr…
fengmk2 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,133 @@ | ||
| import { describe, it, expect, beforeEach, afterEach, vi } from "vite-plus/test"; | ||
| import { join } from "node:path"; | ||
| import { existsSync, readFileSync, writeFileSync } from "node:fs"; | ||
| import { EOL } from "node:os"; | ||
| import { configAuthentication } from "./auth.js"; | ||
| import { exportVariable } from "@actions/core"; | ||
|
|
||
| vi.mock("@actions/core", () => ({ | ||
| debug: vi.fn(), | ||
| exportVariable: vi.fn(), | ||
| })); | ||
|
|
||
| vi.mock("node:fs", async () => { | ||
| const actual = await vi.importActual<typeof import("node:fs")>("node:fs"); | ||
| return { | ||
| ...actual, | ||
| existsSync: vi.fn(), | ||
| readFileSync: vi.fn(), | ||
| writeFileSync: vi.fn(), | ||
| }; | ||
| }); | ||
|
|
||
| describe("configAuthentication", () => { | ||
| const runnerTemp = "/tmp/runner"; | ||
|
|
||
| beforeEach(() => { | ||
| vi.stubEnv("RUNNER_TEMP", runnerTemp); | ||
| vi.mocked(existsSync).mockReturnValue(false); | ||
| }); | ||
|
|
||
| afterEach(() => { | ||
| vi.unstubAllEnvs(); | ||
| vi.resetAllMocks(); | ||
| }); | ||
|
|
||
| it("should write .npmrc with registry and auth token", () => { | ||
| configAuthentication("https://registry.npmjs.org/"); | ||
|
|
||
| const expectedPath = join(runnerTemp, ".npmrc"); | ||
| expect(writeFileSync).toHaveBeenCalledWith( | ||
| expectedPath, | ||
| expect.stringContaining("//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}"), | ||
| ); | ||
| expect(writeFileSync).toHaveBeenCalledWith( | ||
| expectedPath, | ||
| expect.stringContaining("registry=https://registry.npmjs.org/"), | ||
| ); | ||
| }); | ||
|
|
||
| it("should append trailing slash if missing", () => { | ||
| configAuthentication("https://registry.npmjs.org"); | ||
|
|
||
| expect(writeFileSync).toHaveBeenCalledWith( | ||
| expect.any(String), | ||
| expect.stringContaining("registry=https://registry.npmjs.org/"), | ||
| ); | ||
| }); | ||
|
|
||
| it("should auto-detect scope for GitHub Packages registry", () => { | ||
| vi.stubEnv("GITHUB_REPOSITORY_OWNER", "voidzero-dev"); | ||
|
|
||
| configAuthentication("https://npm.pkg.github.com"); | ||
|
|
||
| expect(writeFileSync).toHaveBeenCalledWith( | ||
| expect.any(String), | ||
| expect.stringContaining("@voidzero-dev:registry=https://npm.pkg.github.com/"), | ||
| ); | ||
| }); | ||
|
|
||
| it("should use explicit scope", () => { | ||
| configAuthentication("https://npm.pkg.github.com", "@myorg"); | ||
|
|
||
| expect(writeFileSync).toHaveBeenCalledWith( | ||
| expect.any(String), | ||
| expect.stringContaining("@myorg:registry=https://npm.pkg.github.com/"), | ||
| ); | ||
| }); | ||
|
|
||
| it("should prepend @ to scope if missing", () => { | ||
| configAuthentication("https://npm.pkg.github.com", "myorg"); | ||
|
|
||
| expect(writeFileSync).toHaveBeenCalledWith( | ||
| expect.any(String), | ||
| expect.stringContaining("@myorg:registry=https://npm.pkg.github.com/"), | ||
| ); | ||
| }); | ||
|
|
||
| it("should lowercase scope", () => { | ||
| configAuthentication("https://npm.pkg.github.com", "@MyOrg"); | ||
|
|
||
| expect(writeFileSync).toHaveBeenCalledWith( | ||
| expect.any(String), | ||
| expect.stringContaining("@myorg:registry=https://npm.pkg.github.com/"), | ||
| ); | ||
| }); | ||
|
|
||
| it("should preserve existing .npmrc content except registry lines", () => { | ||
| vi.mocked(existsSync).mockReturnValue(true); | ||
| vi.mocked(readFileSync).mockReturnValue( | ||
| `always-auth=true${EOL}registry=https://old.reg/${EOL}`, | ||
| ); | ||
|
|
||
| configAuthentication("https://registry.npmjs.org/"); | ||
|
|
||
| const written = vi.mocked(writeFileSync).mock.calls[0]![1] as string; | ||
| expect(written).toContain("always-auth=true"); | ||
| expect(written).not.toContain("https://old.reg/"); | ||
| expect(written).toContain("registry=https://registry.npmjs.org/"); | ||
| }); | ||
|
|
||
| it("should export NPM_CONFIG_USERCONFIG", () => { | ||
| configAuthentication("https://registry.npmjs.org/"); | ||
|
|
||
| expect(exportVariable).toHaveBeenCalledWith( | ||
| "NPM_CONFIG_USERCONFIG", | ||
| join(runnerTemp, ".npmrc"), | ||
| ); | ||
| }); | ||
|
|
||
| it("should export NODE_AUTH_TOKEN placeholder when not set", () => { | ||
| configAuthentication("https://registry.npmjs.org/"); | ||
|
|
||
| expect(exportVariable).toHaveBeenCalledWith("NODE_AUTH_TOKEN", "XXXXX-XXXXX-XXXXX-XXXXX"); | ||
| }); | ||
|
|
||
| it("should preserve existing NODE_AUTH_TOKEN", () => { | ||
| vi.stubEnv("NODE_AUTH_TOKEN", "my-real-token"); | ||
|
|
||
| configAuthentication("https://registry.npmjs.org/"); | ||
|
|
||
| expect(exportVariable).toHaveBeenCalledWith("NODE_AUTH_TOKEN", "my-real-token"); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| import { existsSync, readFileSync, writeFileSync } from "node:fs"; | ||
| import { EOL } from "node:os"; | ||
| import { resolve } from "node:path"; | ||
| import { debug, exportVariable } from "@actions/core"; | ||
|
|
||
| /** | ||
| * Configure npm registry authentication by writing a .npmrc file. | ||
| * Ported from actions/setup-node's authutil.ts. | ||
| */ | ||
| export function configAuthentication(registryUrl: string, scope?: string): void { | ||
| const npmrc = resolve(process.env.RUNNER_TEMP || process.cwd(), ".npmrc"); | ||
|
|
||
| if (!registryUrl.endsWith("/")) { | ||
| registryUrl += "/"; | ||
| } | ||
|
|
||
| writeRegistryToFile(registryUrl, npmrc, scope); | ||
fengmk2 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| function writeRegistryToFile(registryUrl: string, fileLocation: string, scope?: string): void { | ||
| // Auto-detect scope for GitHub Packages registry | ||
| if (!scope && registryUrl.includes("npm.pkg.github.com")) { | ||
| scope = process.env.GITHUB_REPOSITORY_OWNER; | ||
fengmk2 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| if (scope && !scope.startsWith("@")) { | ||
| scope = "@" + scope; | ||
| } | ||
|
|
||
| if (scope) { | ||
| scope = scope.toLowerCase() + ":"; | ||
| } else { | ||
| scope = ""; | ||
| } | ||
|
|
||
| debug(`Setting auth in ${fileLocation}`); | ||
|
|
||
| let newContents = ""; | ||
| if (existsSync(fileLocation)) { | ||
| const curContents = readFileSync(fileLocation, "utf8"); | ||
| for (const line of curContents.split(EOL)) { | ||
| // Preserve lines that don't set the scoped registry | ||
| if (!line.toLowerCase().startsWith(`${scope}registry`)) { | ||
| newContents += line + EOL; | ||
| } | ||
| } | ||
fengmk2 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| // Auth token line: remove protocol prefix from registry URL | ||
| const authString = registryUrl.replace(/^\w+:/, "") + ":_authToken=${NODE_AUTH_TOKEN}"; | ||
fengmk2 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| const registryString = `${scope}registry=${registryUrl}`; | ||
| newContents += `${authString}${EOL}${registryString}`; | ||
|
|
||
| writeFileSync(fileLocation, newContents); | ||
|
|
||
| exportVariable("NPM_CONFIG_USERCONFIG", fileLocation); | ||
| // Export placeholder if NODE_AUTH_TOKEN is not set so npm doesn't error | ||
| exportVariable("NODE_AUTH_TOKEN", process.env.NODE_AUTH_TOKEN || "XXXXX-XXXXX-XXXXX-XXXXX"); | ||
fengmk2 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.