Fix lint issues

This commit is contained in:
Jason Ginchereau
2026-06-17 14:39:18 -10:00
parent 59a9650ce0
commit cc4da7ddff
7 changed files with 36 additions and 71 deletions
+4 -16
View File
@@ -125,10 +125,7 @@ describe('listAndValidate (real archives)', () => {
const archive = buildTarArchive([
{path: 'cache/file.txt', type: 'File', body: Buffer.from('hi')}
])
const archivePath = writeArchive(
'clean.tar.gz',
zlib.gzipSync(archive)
)
const archivePath = writeArchive('clean.tar.gz', zlib.gzipSync(archive))
const violations = await listAndValidate(
archivePath,
CompressionMethod.Gzip,
@@ -259,10 +256,7 @@ describe('listAndValidate (real archives)', () => {
},
{path: 'cache/sub/c.txt', type: 'File', body: Buffer.from('4')}
])
const archivePath = writeArchive(
'mixed.tar.gz',
zlib.gzipSync(archive)
)
const archivePath = writeArchive('mixed.tar.gz', zlib.gzipSync(archive))
const violations = await listAndValidate(
archivePath,
CompressionMethod.Gzip,
@@ -277,10 +271,7 @@ describe('listAndValidate (real archives)', () => {
const archive = buildTarArchive([
{path: 'cache/dev', type: 'CharacterDevice'}
])
const archivePath = writeArchive(
'chardev.tar.gz',
zlib.gzipSync(archive)
)
const archivePath = writeArchive('chardev.tar.gz', zlib.gzipSync(archive))
const violations = await listAndValidate(
archivePath,
CompressionMethod.Gzip,
@@ -295,10 +286,7 @@ describe('listAndValidate (real archives)', () => {
const archive = buildTarArchive([
{path: 'cache/tiny.txt', type: 'File', body: Buffer.from('1')}
])
const archivePath = writeArchive(
'single.tar.gz',
zlib.gzipSync(archive)
)
const archivePath = writeArchive('single.tar.gz', zlib.gzipSync(archive))
const violations = await listAndValidate(
archivePath,
CompressionMethod.Gzip,
+19 -27
View File
@@ -8,7 +8,8 @@ import {
} from '../src/internal/pathValidation'
const IS_WINDOWS = process.platform === 'win32'
const CASE_INSENSITIVE = process.platform === 'win32' || process.platform === 'darwin'
const CASE_INSENSITIVE =
process.platform === 'win32' || process.platform === 'darwin'
describe('deriveAllowedRoots', () => {
const cwd = IS_WINDOWS ? 'C:\\workspace' : '/workspace'
@@ -63,9 +64,7 @@ describe('deriveAllowedRoots', () => {
describe('negation handling', () => {
test('negation pattern (! prefix) is dropped from allowed roots', () => {
const input = IS_WINDOWS
? ['!C:\\foo\\secret']
: ['!/foo/secret']
const input = IS_WINDOWS ? ['!C:\\foo\\secret'] : ['!/foo/secret']
expect(deriveAllowedRoots(input, cwd)).toEqual([])
})
@@ -107,9 +106,9 @@ describe('deriveAllowedRoots', () => {
process.env['CACHE_TEST_ROOT'] = IS_WINDOWS ? 'C:\\envroot' : '/envroot'
try {
const expected = IS_WINDOWS ? 'C:\\envroot\\sub' : '/envroot/sub'
expect(
deriveAllowedRoots(['${CACHE_TEST_ROOT}/sub'], cwd)
).toEqual([expected])
expect(deriveAllowedRoots(['${CACHE_TEST_ROOT}/sub'], cwd)).toEqual([
expected
])
} finally {
if (original === undefined) delete process.env['CACHE_TEST_ROOT']
else process.env['CACHE_TEST_ROOT'] = original
@@ -132,12 +131,14 @@ describe('deriveAllowedRoots', () => {
test('%VAR% Windows-style expands an environment variable', () => {
const original = process.env['CACHE_TEST_WIN_ROOT']
process.env['CACHE_TEST_WIN_ROOT'] = IS_WINDOWS ? 'C:\\winroot' : '/winroot'
process.env['CACHE_TEST_WIN_ROOT'] = IS_WINDOWS
? 'C:\\winroot'
: '/winroot'
try {
const expected = IS_WINDOWS ? 'C:\\winroot\\sub' : '/winroot/sub'
expect(
deriveAllowedRoots(['%CACHE_TEST_WIN_ROOT%/sub'], cwd)
).toEqual([expected])
expect(deriveAllowedRoots(['%CACHE_TEST_WIN_ROOT%/sub'], cwd)).toEqual([
expected
])
} finally {
if (original === undefined) delete process.env['CACHE_TEST_WIN_ROOT']
else process.env['CACHE_TEST_WIN_ROOT'] = original
@@ -170,9 +171,9 @@ describe('deriveAllowedRoots', () => {
const expected = IS_WINDOWS
? 'C:\\envroot*odd\\sub'
: '/envroot*odd/sub'
expect(
deriveAllowedRoots(['${CACHE_TEST_ROOT}/sub'], cwd)
).toEqual([expected])
expect(deriveAllowedRoots(['${CACHE_TEST_ROOT}/sub'], cwd)).toEqual([
expected
])
} finally {
if (original === undefined) delete process.env['CACHE_TEST_ROOT']
else process.env['CACHE_TEST_ROOT'] = original
@@ -290,7 +291,7 @@ describe('validateEntry', () => {
test('deeply nested file', () => {
const r = validateEntry(
'node_modules/' + Array(50).fill('sub').join('/') + '/foo.js',
`node_modules/${Array(50).fill('sub').join('/')}/foo.js`,
undefined,
'File',
allowedRoots,
@@ -379,7 +380,7 @@ describe('validateEntry', () => {
test('filename containing .. as substring (not segment)', () => {
for (const name of ['..hidden', 'file..txt', 'a..b/c']) {
const r = validateEntry(
'node_modules/' + name,
`node_modules/${name}`,
undefined,
'File',
allowedRoots,
@@ -529,13 +530,7 @@ describe('validateEntry', () => {
})
test('Windows drive-relative (no slash)', () => {
const r = validateEntry(
'C:foo',
undefined,
'File',
allowedRoots,
cwd
)
const r = validateEntry('C:foo', undefined, 'File', allowedRoots, cwd)
expect(r.ok).toBe(false)
if (!r.ok) expect(r.code).toBe('ABSOLUTE_PATH')
})
@@ -1069,10 +1064,7 @@ describe('formatViolationSummary', () => {
})
test('shows up to maxShown items verbatim', () => {
const out = formatViolationSummary(
[v('a'), v('b'), v('c')],
5
)
const out = formatViolationSummary([v('a'), v('b'), v('c')], 5)
expect(out).toContain(' - a')
expect(out).toContain(' - b')
expect(out).toContain(' - c')
+3 -9
View File
@@ -203,9 +203,7 @@ describe('extractTar path validation integration', () => {
})
test('clean archive: no throw, extraction proceeds normally', async () => {
jest
.spyOn(listAndValidate, 'listAndValidate')
.mockResolvedValue([])
jest.spyOn(listAndValidate, 'listAndValidate').mockResolvedValue([])
const warnSpy = jest.spyOn(core, 'warning').mockImplementation()
const execMock = jest.spyOn(exec, 'exec').mockResolvedValue(0)
@@ -234,9 +232,7 @@ describe('extractTar path validation integration', () => {
} catch (err) {
expect(err).toBeInstanceOf(CacheIntegrityError)
expect((err as CacheIntegrityError).code).toBe('PARSE_ERROR')
expect((err as CacheIntegrityError).message).toMatch(
/tar parse error/
)
expect((err as CacheIntegrityError).message).toMatch(/tar parse error/)
}
expect(execMock).not.toHaveBeenCalled()
expect(mkdirMock).not.toHaveBeenCalled()
@@ -341,9 +337,7 @@ describe('extractTar path validation integration', () => {
pathValidation: 'warn'
})
expect(listMock.mock.calls[0][1]).toBe(
CompressionMethod.ZstdWithoutLong
)
expect(listMock.mock.calls[0][1]).toBe(CompressionMethod.ZstdWithoutLong)
})
})
})
+1 -3
View File
@@ -17,9 +17,7 @@ import {HttpClientError} from '@actions/http-client'
export type {DownloadOptions, UploadOptions}
export {CacheIntegrityError}
export type {
CacheIntegrityErrorCode
} from './internal/cacheIntegrityError.js'
export type {CacheIntegrityErrorCode} from './internal/cacheIntegrityError.js'
export type {
PathValidationMode,
PathValidationViolation
+1 -3
View File
@@ -172,9 +172,7 @@ async function streamArchiveTo(
const tail = stderrTruncated ? ' (stderr truncated)' : ''
reject(
new Error(
`zstd ${cause}${
zstdStderr ? `: ${zstdStderr.trim()}` : ''
}${tail}`
`zstd ${cause}${zstdStderr ? `: ${zstdStderr.trim()}` : ''}${tail}`
)
)
}
+5 -9
View File
@@ -55,7 +55,7 @@ export type ValidationResult =
*/
export interface PreparedAllowedRoots {
readonly caseInsensitive: boolean
readonly roots: ReadonlyArray<PreparedRoot>
readonly roots: readonly PreparedRoot[]
}
interface PreparedRoot {
@@ -231,7 +231,10 @@ function segmentHasGlob(seg: string): boolean {
function expandEnvVars(input: string): string {
let result = input
// ${VAR} — see segmentHasGlob for the polynomial-redos rationale.
result = result.replace(/\$\{([^}]+)\}/g, (_, name) => process.env[name] ?? '') // lgtm[js/polynomial-redos]
result = result.replace(
/\$\{([^}]+)\}/g,
(_, name) => process.env[name] ?? ''
) // lgtm[js/polynomial-redos]
// $VAR (POSIX-style identifier)
result = result.replace(
/\$([A-Za-z_][A-Za-z0-9_]*)/g,
@@ -456,13 +459,6 @@ function resolveEntry(entryPath: string, extractCwd: string): string {
return path.resolve(extractCwd, native)
}
function isUnderAnyRoot(resolved: string, roots: string[]): boolean {
for (const root of roots) {
if (isUnderRoot(resolved, root)) return true
}
return false
}
/**
* Precompute a {@link PreparedAllowedRoots} from a raw roots array. Call
* once per `listAndValidate` invocation and reuse for every entry.
+3 -4
View File
@@ -374,10 +374,9 @@ function reportViolations(
core.info(formatViolationSummary(violations))
for (const v of violations) {
core.debug(
`path-validation: code=${v.code} type=${v.entryType} path=${v.path}` +
(v.linkpath ? ` linkpath=${v.linkpath}` : '') +
` resolved=${v.resolved}` +
` reason=${v.reason}`
`path-validation: code=${v.code} type=${v.entryType} path=${v.path}${
v.linkpath ? ` linkpath=${v.linkpath}` : ''
} resolved=${v.resolved} reason=${v.reason}`
)
}
}