mirror of
https://github.com/dorny/paths-filter.git
synced 2026-07-07 06:45:38 +00:00
fix: force C locale for git error detection
This commit is contained in:
parent
3b88640d2c
commit
174ff883c9
31
.github/workflows/pull-request-verification.yml
vendored
31
.github/workflows/pull-request-verification.yml
vendored
@ -82,17 +82,48 @@ jobs:
|
||||
# pre-2.32 -> ignores GIT_CONFIG_GLOBAL -> exercises the HOME-only path
|
||||
# bookworm: git 2.39, "dubious ownership" wording, honors GIT_CONFIG_GLOBAL
|
||||
container: ['node:24-bullseye', 'node:24-bookworm']
|
||||
locale: ['']
|
||||
include:
|
||||
# zh_CN: git translates the dubious-ownership message via gettext - proves
|
||||
# detection works on non-English stderr regardless of the container's locale.
|
||||
# A CJK locale is the most adversarial probe (multibyte, non-Latin) whose
|
||||
# catalog actually translates this message (ja does not exist, ko lacks it)
|
||||
- container: 'node:24-bookworm'
|
||||
locale: 'zh_CN.UTF-8'
|
||||
container: ${{ matrix.container }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Generate locale
|
||||
if: matrix.locale != ''
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y locales
|
||||
echo '${{ matrix.locale }} UTF-8' >> /etc/locale.gen
|
||||
locale-gen
|
||||
- name: Verify dubious ownership is reproduced
|
||||
run: |
|
||||
if git status; then
|
||||
echo "::error::git succeeded - environment no longer reproduces dubious ownership"
|
||||
exit 1
|
||||
fi
|
||||
- name: Verify git message is localized
|
||||
if: matrix.locale != ''
|
||||
env:
|
||||
LC_ALL: ${{ matrix.locale }}
|
||||
run: |
|
||||
if stderr=$(git status 2>&1 >/dev/null); then
|
||||
echo "::error::git succeeded - environment no longer reproduces dubious ownership"
|
||||
exit 1
|
||||
fi
|
||||
echo "$stderr"
|
||||
if echo "$stderr" | grep -qE 'dubious ownership|unsafe repository'; then
|
||||
echo "::error::git message is not translated - the locale variant would not test anything"
|
||||
exit 1
|
||||
fi
|
||||
- uses: ./
|
||||
id: filter
|
||||
env:
|
||||
LC_ALL: ${{ matrix.locale }}
|
||||
with:
|
||||
token: ''
|
||||
filters: '.github/filters.yml'
|
||||
|
||||
@ -173,7 +173,7 @@ describe('ensureSafeDirectory', () => {
|
||||
})
|
||||
|
||||
test('activates temporary HOME and adds reported directories on first call', async () => {
|
||||
expect(getGitEnv()).toBeUndefined()
|
||||
expect(getGitEnv()['HOME']).not.toContain('paths-filter-git-home-')
|
||||
|
||||
const added = await ensureSafeDirectory(DUBIOUS_STDERR)
|
||||
|
||||
@ -224,12 +224,33 @@ describe('ensureSafeDirectory', () => {
|
||||
|
||||
test('cleanup removes the temporary HOME and resets state', async () => {
|
||||
await ensureSafeDirectory(DUBIOUS_STDERR)
|
||||
const tempHome = getGitEnv()?.['HOME']
|
||||
expect(tempHome).toBeDefined()
|
||||
const tempHome = getGitEnv()['HOME']
|
||||
expect(tempHome).toContain('paths-filter-git-home-')
|
||||
|
||||
await cleanup()
|
||||
|
||||
expect(getGitEnv()).toBeUndefined()
|
||||
expect(fs.existsSync(tempHome as string)).toBe(false)
|
||||
expect(getGitEnv()['HOME']).not.toContain('paths-filter-git-home-')
|
||||
expect(fs.existsSync(tempHome)).toBe(false)
|
||||
})
|
||||
|
||||
test('getGitEnv mirrors process.env and forces LC_ALL=C before activation', () => {
|
||||
process.env['SOME_PRESERVED_VARIABLE'] = 'preserved'
|
||||
process.env['LC_ALL'] = 'de_DE.UTF-8'
|
||||
|
||||
const env = getGitEnv()
|
||||
|
||||
expect(env['SOME_PRESERVED_VARIABLE']).toBe('preserved')
|
||||
expect(env['HOME']).toBe(runnerTemp)
|
||||
expect(env['LC_ALL']).toBe('C')
|
||||
})
|
||||
|
||||
test('getGitEnv contains the temporary HOME and forces LC_ALL=C after activation', async () => {
|
||||
process.env['LC_ALL'] = 'de_DE.UTF-8'
|
||||
|
||||
await ensureSafeDirectory(DUBIOUS_STDERR)
|
||||
|
||||
const env = getGitEnv()
|
||||
expect(env['HOME']).toContain('paths-filter-git-home-')
|
||||
expect(env['LC_ALL']).toBe('C')
|
||||
})
|
||||
})
|
||||
|
||||
26
dist/index.js
vendored
26
dist/index.js
vendored
@ -903,10 +903,12 @@ function parseRepositoryPath(stderr) {
|
||||
return (_a = stderr.match(REPOSITORY_PATH_PATTERN)) === null || _a === void 0 ? void 0 : _a[1];
|
||||
}
|
||||
exports.parseRepositoryPath = parseRepositoryPath;
|
||||
// Returns undefined until the workaround is activated - git commands of currently
|
||||
// working users keep inheriting process.env unchanged.
|
||||
// Until the workaround is activated this mirrors process.env; afterwards it applies the
|
||||
// temporary HOME redirect. In both cases LC_ALL=C is forced so git emits untranslated
|
||||
// messages and isDubiousOwnershipError / parseRepositoryPath match regardless of the
|
||||
// container's locale.
|
||||
function getGitEnv() {
|
||||
return gitEnv;
|
||||
return { ...(gitEnv !== null && gitEnv !== void 0 ? gitEnv : cloneDefinedEnv(process.env)), LC_ALL: 'C' };
|
||||
}
|
||||
exports.getGitEnv = getGitEnv;
|
||||
// Marks directories reported by git as safe, using a temporary HOME so no configuration
|
||||
@ -923,7 +925,7 @@ async function ensureSafeDirectory(stderr) {
|
||||
let added = false;
|
||||
for (const dir of [parseRepositoryPath(stderr), process.env.GITHUB_WORKSPACE, process.cwd()]) {
|
||||
if (dir && !safeDirectories.has(dir)) {
|
||||
await (0, exec_1.exec)('git', ['config', '--global', '--add', 'safe.directory', dir], { env: gitEnv });
|
||||
await (0, exec_1.exec)('git', ['config', '--global', '--add', 'safe.directory', dir], { env: getGitEnv() });
|
||||
safeDirectories.add(dir);
|
||||
added = true;
|
||||
}
|
||||
@ -968,12 +970,7 @@ async function createTempGitHome(baseTempDir, env) {
|
||||
exports.createTempGitHome = createTempGitHome;
|
||||
// Exported for tests
|
||||
function buildGitEnv(tempHome, env) {
|
||||
const newEnv = {};
|
||||
for (const [key, value] of Object.entries(env)) {
|
||||
if (value !== undefined) {
|
||||
newEnv[key] = value;
|
||||
}
|
||||
}
|
||||
const newEnv = cloneDefinedEnv(env);
|
||||
// A changed HOME redirects git of any version to the temp config. GIT_CONFIG_GLOBAL is redirected
|
||||
// only when already set - on git >= 2.32 it replaces both global config files, so setting it
|
||||
// unconditionally would hide an existing $XDG_CONFIG_HOME/git/config from git
|
||||
@ -989,6 +986,15 @@ function resolveTempBaseDir(env) {
|
||||
return env.RUNNER_TEMP || os.tmpdir();
|
||||
}
|
||||
exports.resolveTempBaseDir = resolveTempBaseDir;
|
||||
function cloneDefinedEnv(env) {
|
||||
const newEnv = {};
|
||||
for (const [key, value] of Object.entries(env)) {
|
||||
if (value !== undefined) {
|
||||
newEnv[key] = value;
|
||||
}
|
||||
}
|
||||
return newEnv;
|
||||
}
|
||||
async function copyFileIfExists(source, destination) {
|
||||
try {
|
||||
await fs.promises.access(source, fs.constants.R_OK);
|
||||
|
||||
@ -22,10 +22,12 @@ export function parseRepositoryPath(stderr: string): string | undefined {
|
||||
return stderr.match(REPOSITORY_PATH_PATTERN)?.[1]
|
||||
}
|
||||
|
||||
// Returns undefined until the workaround is activated - git commands of currently
|
||||
// working users keep inheriting process.env unchanged.
|
||||
export function getGitEnv(): {[key: string]: string} | undefined {
|
||||
return gitEnv
|
||||
// Until the workaround is activated this mirrors process.env; afterwards it applies the
|
||||
// temporary HOME redirect. In both cases LC_ALL=C is forced so git emits untranslated
|
||||
// messages and isDubiousOwnershipError / parseRepositoryPath match regardless of the
|
||||
// container's locale.
|
||||
export function getGitEnv(): {[key: string]: string} {
|
||||
return {...(gitEnv ?? cloneDefinedEnv(process.env)), LC_ALL: 'C'}
|
||||
}
|
||||
|
||||
// Marks directories reported by git as safe, using a temporary HOME so no configuration
|
||||
@ -45,7 +47,7 @@ export async function ensureSafeDirectory(stderr: string): Promise<boolean> {
|
||||
let added = false
|
||||
for (const dir of [parseRepositoryPath(stderr), process.env.GITHUB_WORKSPACE, process.cwd()]) {
|
||||
if (dir && !safeDirectories.has(dir)) {
|
||||
await exec('git', ['config', '--global', '--add', 'safe.directory', dir], {env: gitEnv})
|
||||
await exec('git', ['config', '--global', '--add', 'safe.directory', dir], {env: getGitEnv()})
|
||||
safeDirectories.add(dir)
|
||||
added = true
|
||||
}
|
||||
@ -96,12 +98,7 @@ export async function createTempGitHome(
|
||||
|
||||
// Exported for tests
|
||||
export function buildGitEnv(tempHome: string, env: {[key: string]: string | undefined}): {[key: string]: string} {
|
||||
const newEnv: {[key: string]: string} = {}
|
||||
for (const [key, value] of Object.entries(env)) {
|
||||
if (value !== undefined) {
|
||||
newEnv[key] = value
|
||||
}
|
||||
}
|
||||
const newEnv = cloneDefinedEnv(env)
|
||||
// A changed HOME redirects git of any version to the temp config. GIT_CONFIG_GLOBAL is redirected
|
||||
// only when already set - on git >= 2.32 it replaces both global config files, so setting it
|
||||
// unconditionally would hide an existing $XDG_CONFIG_HOME/git/config from git
|
||||
@ -117,6 +114,16 @@ export function resolveTempBaseDir(env: {[key: string]: string | undefined}): st
|
||||
return env.RUNNER_TEMP || os.tmpdir()
|
||||
}
|
||||
|
||||
function cloneDefinedEnv(env: {[key: string]: string | undefined}): {[key: string]: string} {
|
||||
const newEnv: {[key: string]: string} = {}
|
||||
for (const [key, value] of Object.entries(env)) {
|
||||
if (value !== undefined) {
|
||||
newEnv[key] = value
|
||||
}
|
||||
}
|
||||
return newEnv
|
||||
}
|
||||
|
||||
async function copyFileIfExists(source: string, destination: string): Promise<void> {
|
||||
try {
|
||||
await fs.promises.access(source, fs.constants.R_OK)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user