mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 12:21:13 -05:00
Improved regex for auto-execution of chained commands (#158)
* Improved regex for auto-execution of chained commands
This commit is contained in:
5
.changeset/large-crews-hunt.md
Normal file
5
.changeset/large-crews-hunt.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"roo-cline": patch
|
||||
---
|
||||
|
||||
Improved regex for auto-execution of chained commands
|
||||
@@ -523,7 +523,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
|
||||
}
|
||||
|
||||
// Split command by chaining operators
|
||||
const commands = command.split(/&&|\|\||;|\||\$\(|`/).map(cmd => cmd.trim())
|
||||
const commands = command.split(/&&|\|\||;|(?<!"[^"]*)\|(?![^"]*")|\$\(|`/).map(cmd => cmd.trim())
|
||||
|
||||
// Check if all individual commands are allowed
|
||||
return commands.every((cmd) => {
|
||||
|
||||
@@ -429,7 +429,12 @@ describe('ChatView - Auto Approval Tests', () => {
|
||||
'npm test && npm run build',
|
||||
'npm test; npm run build',
|
||||
'npm test || npm run build',
|
||||
'npm test | npm run build'
|
||||
'npm test | npm run build',
|
||||
// Add test for quoted pipes which should be treated as part of the command, not as a chain operator
|
||||
'echo "hello | world"',
|
||||
'npm test "param with | inside" && npm run build',
|
||||
// PowerShell command with Select-String
|
||||
'npm test 2>&1 | Select-String -NotMatch "node_modules" | Select-String "FAIL|Error"'
|
||||
]
|
||||
|
||||
for (const command of allowedChainedCommands) {
|
||||
@@ -438,7 +443,7 @@ describe('ChatView - Auto Approval Tests', () => {
|
||||
// First hydrate state with initial task
|
||||
mockPostMessage({
|
||||
alwaysAllowExecute: true,
|
||||
allowedCommands: ['npm test', 'npm run build'],
|
||||
allowedCommands: ['npm test', 'npm run build', 'echo', 'Select-String'],
|
||||
clineMessages: [
|
||||
{
|
||||
type: 'say',
|
||||
@@ -452,7 +457,7 @@ describe('ChatView - Auto Approval Tests', () => {
|
||||
// Then send the chained command ask message
|
||||
mockPostMessage({
|
||||
alwaysAllowExecute: true,
|
||||
allowedCommands: ['npm test', 'npm run build'],
|
||||
allowedCommands: ['npm test', 'npm run build', 'echo', 'Select-String'],
|
||||
clineMessages: [
|
||||
{
|
||||
type: 'say',
|
||||
@@ -498,15 +503,20 @@ describe('ChatView - Auto Approval Tests', () => {
|
||||
'npm test; rm -rf /',
|
||||
'npm test || rm -rf /',
|
||||
'npm test | rm -rf /',
|
||||
// Test subshell execution using $() and backticks
|
||||
'npm test $(echo dangerous)',
|
||||
'npm test `echo dangerous`'
|
||||
'npm test `echo dangerous`',
|
||||
// Test unquoted pipes with disallowed commands
|
||||
'npm test | rm -rf /',
|
||||
// Test PowerShell command with disallowed parts
|
||||
'npm test 2>&1 | Select-String -NotMatch "node_modules" | rm -rf /'
|
||||
]
|
||||
|
||||
disallowedChainedCommands.forEach(command => {
|
||||
// First hydrate state with initial task
|
||||
mockPostMessage({
|
||||
alwaysAllowExecute: true,
|
||||
allowedCommands: ['npm test'],
|
||||
allowedCommands: ['npm test', 'Select-String'],
|
||||
clineMessages: [
|
||||
{
|
||||
type: 'say',
|
||||
@@ -520,7 +530,7 @@ describe('ChatView - Auto Approval Tests', () => {
|
||||
// Then send the chained command ask message
|
||||
mockPostMessage({
|
||||
alwaysAllowExecute: true,
|
||||
allowedCommands: ['npm test'],
|
||||
allowedCommands: ['npm test', 'Select-String'],
|
||||
clineMessages: [
|
||||
{
|
||||
type: 'say',
|
||||
@@ -545,6 +555,121 @@ describe('ChatView - Auto Approval Tests', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('handles complex PowerShell command chains correctly', async () => {
|
||||
render(
|
||||
<ExtensionStateContextProvider>
|
||||
<ChatView
|
||||
isHidden={false}
|
||||
showAnnouncement={false}
|
||||
hideAnnouncement={() => {}}
|
||||
showHistoryView={() => {}}
|
||||
/>
|
||||
</ExtensionStateContextProvider>
|
||||
)
|
||||
|
||||
// Test PowerShell specific command chains
|
||||
const powershellCommands = {
|
||||
allowed: [
|
||||
'npm test 2>&1 | Select-String -NotMatch "node_modules"',
|
||||
'npm test 2>&1 | Select-String "FAIL|Error"',
|
||||
'npm test 2>&1 | Select-String -NotMatch "node_modules" | Select-String "FAIL|Error"'
|
||||
],
|
||||
disallowed: [
|
||||
'npm test 2>&1 | Select-String -NotMatch "node_modules" | rm -rf /',
|
||||
'npm test 2>&1 | Select-String "FAIL|Error" && del /F /Q *',
|
||||
'npm test 2>&1 | Select-String -NotMatch "node_modules" | Remove-Item -Recurse'
|
||||
]
|
||||
}
|
||||
|
||||
// Test allowed PowerShell commands
|
||||
for (const command of powershellCommands.allowed) {
|
||||
jest.clearAllMocks()
|
||||
|
||||
mockPostMessage({
|
||||
alwaysAllowExecute: true,
|
||||
allowedCommands: ['npm test', 'Select-String'],
|
||||
clineMessages: [
|
||||
{
|
||||
type: 'say',
|
||||
say: 'task',
|
||||
ts: Date.now() - 2000,
|
||||
text: 'Initial task'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
mockPostMessage({
|
||||
alwaysAllowExecute: true,
|
||||
allowedCommands: ['npm test', 'Select-String'],
|
||||
clineMessages: [
|
||||
{
|
||||
type: 'say',
|
||||
say: 'task',
|
||||
ts: Date.now() - 2000,
|
||||
text: 'Initial task'
|
||||
},
|
||||
{
|
||||
type: 'ask',
|
||||
ask: 'command',
|
||||
ts: Date.now(),
|
||||
text: command,
|
||||
partial: false
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
await waitFor(() => {
|
||||
expect(vscode.postMessage).toHaveBeenCalledWith({
|
||||
type: 'askResponse',
|
||||
askResponse: 'yesButtonClicked'
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Test disallowed PowerShell commands
|
||||
for (const command of powershellCommands.disallowed) {
|
||||
jest.clearAllMocks()
|
||||
|
||||
mockPostMessage({
|
||||
alwaysAllowExecute: true,
|
||||
allowedCommands: ['npm test', 'Select-String'],
|
||||
clineMessages: [
|
||||
{
|
||||
type: 'say',
|
||||
say: 'task',
|
||||
ts: Date.now() - 2000,
|
||||
text: 'Initial task'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
mockPostMessage({
|
||||
alwaysAllowExecute: true,
|
||||
allowedCommands: ['npm test', 'Select-String'],
|
||||
clineMessages: [
|
||||
{
|
||||
type: 'say',
|
||||
say: 'task',
|
||||
ts: Date.now() - 2000,
|
||||
text: 'Initial task'
|
||||
},
|
||||
{
|
||||
type: 'ask',
|
||||
ask: 'command',
|
||||
ts: Date.now(),
|
||||
text: command,
|
||||
partial: false
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
expect(vscode.postMessage).not.toHaveBeenCalledWith({
|
||||
type: 'askResponse',
|
||||
askResponse: 'yesButtonClicked'
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user