-
Notifications
You must be signed in to change notification settings - Fork 11.8k
fix(@angular/cli): quote registry args on Windows and reject shell metacharacters #33998
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
Changes from all commits
5ed1576
188f6d0
70b673e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
|
|
||
| import { SHELL_METACHARACTERS, validateRegistry } from './cli'; | ||
|
|
||
| describe('registry validation', () => { | ||
| describe('SHELL_METACHARACTERS', () => { | ||
| it('should match shell metacharacters', () => { | ||
| expect(SHELL_METACHARACTERS.test('&')).toBe(true); | ||
| expect(SHELL_METACHARACTERS.test('|')).toBe(true); | ||
| expect(SHELL_METACHARACTERS.test(';')).toBe(true); | ||
| expect(SHELL_METACHARACTERS.test('$')).toBe(true); | ||
| expect(SHELL_METACHARACTERS.test(String.fromCharCode(96))).toBe(true); | ||
| expect(SHELL_METACHARACTERS.test('(')).toBe(true); | ||
| expect(SHELL_METACHARACTERS.test(')')).toBe(true); | ||
| expect(SHELL_METACHARACTERS.test('<')).toBe(true); | ||
| expect(SHELL_METACHARACTERS.test('>')).toBe(true); | ||
| expect(SHELL_METACHARACTERS.test('"')).toBe(true); | ||
| expect(SHELL_METACHARACTERS.test("'")).toBe(true); | ||
| expect(SHELL_METACHARACTERS.test('\n')).toBe(true); | ||
| expect(SHELL_METACHARACTERS.test('\r')).toBe(true); | ||
| }); | ||
|
|
||
| it('should not match safe URL characters', () => { | ||
| expect(SHELL_METACHARACTERS.test('https://registry.example.com')).toBe(false); | ||
| expect(SHELL_METACHARACTERS.test('http://registry.example.com:8080')).toBe(false); | ||
| expect(SHELL_METACHARACTERS.test('https://registry.example.com/path')).toBe(false); | ||
| }); | ||
| }); | ||
|
|
||
| describe('validateRegistry', () => { | ||
| it('should reject URLs with shell metacharacters', () => { | ||
| expect(() => validateRegistry('https://example.com&cmd')).toThrow( | ||
| 'Option --registry contains invalid characters.', | ||
| ); | ||
| expect(() => validateRegistry('https://example.com|cmd')).toThrow( | ||
| 'Option --registry contains invalid characters.', | ||
| ); | ||
| expect(() => validateRegistry('https://example.com;cmd')).toThrow( | ||
| 'Option --registry contains invalid characters.', | ||
| ); | ||
| expect(() => validateRegistry('https://example.com$cmd')).toThrow( | ||
| 'Option --registry contains invalid characters.', | ||
| ); | ||
| expect(() => validateRegistry('https://example.com`cmd`')).toThrow( | ||
| 'Option --registry contains invalid characters.', | ||
| ); | ||
| expect(() => validateRegistry('https://example.com(cmd)')).toThrow( | ||
| 'Option --registry contains invalid characters.', | ||
| ); | ||
| expect(() => validateRegistry('https://example.com?q=">whoami')).toThrow( | ||
| 'Option --registry contains invalid characters.', | ||
| ); | ||
| }); | ||
|
|
||
| it('should accept valid URLs', () => { | ||
| expect(() => validateRegistry('https://registry.example.com')).not.toThrow(); | ||
| expect(() => validateRegistry('http://registry.example.com:8080')).not.toThrow(); | ||
| expect(() => validateRegistry('https://registry.example.com/path')).not.toThrow(); | ||
| }); | ||
|
|
||
| it('should reject invalid URLs', () => { | ||
| expect(() => validateRegistry('not-a-url')).toThrow( | ||
| 'Option --registry must be a valid URL.', | ||
| ); | ||
| }); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -107,7 +107,6 @@ export interface Host { | |
| */ | ||
| export const NodeJS_HOST: Host = { | ||
| stat, | ||
| requiresQuoting: platform() === 'win32', | ||
| mkdir, | ||
| readFile: (path: string) => readFile(path, { encoding: 'utf8' }), | ||
| copyFile: (src, dest) => copyFile(src, dest, constants.COPYFILE_FICLONE), | ||
|
|
@@ -157,9 +156,7 @@ export const NodeJS_HOST: Host = { | |
| cwd: options.cwd, | ||
| env, | ||
| } satisfies SpawnOptions; | ||
| const childProcess = isWin32 | ||
| ? spawn(`${command} ${args.join(' ')}`, spawnOptions) | ||
| : spawn(command, args, spawnOptions); | ||
| const childProcess = spawn(command, args, spawnOptions); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since the spawning logic on Windows has been changed from manually joining arguments into a single string to passing them as an array ( Because of this, the manual quoting enabled by Please update |
||
|
|
||
| let stdout = ''; | ||
| childProcess.stdout?.on('data', (data) => (stdout += data.toString())); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update the test suite to verify that the newly added shell metacharacters (such as
<,>,",',\n, and\r) are correctly matched bySHELL_METACHARACTERS.