mirror of
https://github.com/semantic-release/semantic-release.git
synced 2026-10-25 23:49:36 +00:00
8d905a56e8
## Problem `EGITNOPERMISSION` interpolates `options.repositoryUrl` into the error `details`. By the time this error is thrown (`index.js`, after `verifyAuth` fails), `options.repositoryUrl` has been replaced with the result of `getGitAuthUrl()`, which can embed CI credentials (`GH_TOKEN`, `GITHUB_TOKEN`, `GL_TOKEN`, `BB_TOKEN`, …) as basic-auth in the URL. The existing masking covers most paths — terminal output goes through the `hookStd(hideSensitive(env))` hook, the CLI masks the inspected error before printing, and fail-plugin inputs are masked via `hideSensitiveValues` — but the thrown error object itself is rethrown **unmasked** to programmatic API consumers after `unhook()`. Any wrapper that catches the error and reports `error.details` elsewhere (PR comment, CI annotation, error tracker) would leak the token. ## Fix Use `options.originalRepositoryURL` — the URL as configured, saved before `getGitAuthUrl()` rewrites it — in the error details, falling back to `repositoryUrl` when it isn't set (e.g. when the error factory is invoked directly with a partial context). ## Testing - Added `test/definitions/errors.test.js` covering that the details contain the original URL and not the credential-bearing one, plus the fallback. - `npx ava test/definitions/` and `npm run lint:prettier` pass. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
25 lines
873 B
JavaScript
25 lines
873 B
JavaScript
import test from "ava";
|
|
import { EGITNOPERMISSION } from "../../lib/definitions/errors.js";
|
|
|
|
test("EGITNOPERMISSION does not expose the authenticated repository URL", (t) => {
|
|
const error = EGITNOPERMISSION({
|
|
options: {
|
|
originalRepositoryURL: "https://github.com/owner/repo.git",
|
|
repositoryUrl: "https://x-access-token:secret-token@github.com/owner/repo.git",
|
|
},
|
|
branch: { name: "master" },
|
|
});
|
|
|
|
t.true(error.details.includes("https://github.com/owner/repo.git"));
|
|
t.false(error.details.includes("secret-token"));
|
|
});
|
|
|
|
test("EGITNOPERMISSION falls back to the repository URL if the original URL is not available", (t) => {
|
|
const error = EGITNOPERMISSION({
|
|
options: { repositoryUrl: "https://github.com/owner/repo.git" },
|
|
branch: { name: "master" },
|
|
});
|
|
|
|
t.true(error.details.includes("https://github.com/owner/repo.git"));
|
|
});
|