mirror of
https://github.com/aljazceru/goose.git
synced 2025-12-18 22:54:24 +01:00
allowlist blocks and shift SSE to warning (#2445)
This commit is contained in:
5
Justfile
5
Justfile
@@ -79,6 +79,11 @@ run-ui:
|
||||
@echo "Running UI..."
|
||||
cd ui/desktop && npm install && npm run start-gui
|
||||
|
||||
run-ui-only:
|
||||
@echo "Running UI..."
|
||||
cd ui/desktop && npm install && npm run start-gui
|
||||
|
||||
|
||||
# Run UI with alpha changes
|
||||
run-ui-alpha:
|
||||
@just release-binary
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
IMPORTANT: currently GOOSE_ALLOWLIST is used in main.ts in ui/desktop, and not in goose-server. The following is for reference in case it is used on the server side for launch time enforcement.
|
||||
|
||||
# Goose Extension Allowlist
|
||||
|
||||
The allowlist feature provides a security mechanism for controlling which MCP commands can be used by goose.
|
||||
@@ -24,9 +26,11 @@ If this environment variable is not set, no allowlist restrictions will be appli
|
||||
In certain development or testing scenarios, you may need to bypass the allowlist restrictions. You can do this by setting the `GOOSE_ALLOWLIST_BYPASS` environment variable to `true`:
|
||||
|
||||
```bash
|
||||
export GOOSE_ALLOWLIST_BYPASS=true
|
||||
# For the GUI, you can have it show a warning instead of blocking (but it will always show a warning):
|
||||
export GOOSE_ALLOWLIST_WARNING=true
|
||||
```
|
||||
|
||||
|
||||
When this environment variable is set to `true` (case insensitive), the allowlist check will be bypassed and all commands will be allowed, even if the `GOOSE_ALLOWLIST` environment variable is set.
|
||||
|
||||
## Allowlist File Format
|
||||
|
||||
@@ -498,7 +498,15 @@ export default function App() {
|
||||
}
|
||||
}, [view]);
|
||||
|
||||
// TODO: modify
|
||||
// Configuration for extension security
|
||||
const config = window.electron.getConfig();
|
||||
// If GOOSE_ALLOWLIST_WARNING is true, use warning-only mode (STRICT_ALLOWLIST=false)
|
||||
// If GOOSE_ALLOWLIST_WARNING is not set or false, use strict blocking mode (STRICT_ALLOWLIST=true)
|
||||
const STRICT_ALLOWLIST = config.GOOSE_ALLOWLIST_WARNING === true ? false : true;
|
||||
console.log(
|
||||
`Extension security mode: ${STRICT_ALLOWLIST ? 'Strict' : 'Warning-only'} (GOOSE_ALLOWLIST_WARNING=${config.GOOSE_ALLOWLIST_WARNING})`
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
console.log('Setting up extension handler');
|
||||
const handleAddExtension = async (_event: IpcRendererEvent, link: string) => {
|
||||
@@ -510,10 +518,18 @@ export default function App() {
|
||||
window.electron.logInfo(`Adding extension from deep link ${link}`);
|
||||
setPendingLink(link);
|
||||
|
||||
// Fetch the allowlist and check if the command is allowed
|
||||
// Default values for confirmation dialog
|
||||
let warningMessage = '';
|
||||
let label = 'OK';
|
||||
let title = 'Confirm Extension Installation';
|
||||
let isBlocked = false;
|
||||
let useDetailedMessage = false;
|
||||
|
||||
// For SSE extensions (with remoteUrl), always use detailed message
|
||||
if (remoteUrl) {
|
||||
useDetailedMessage = true;
|
||||
} else {
|
||||
// For command-based extensions, check against allowlist
|
||||
try {
|
||||
const allowedCommands = await window.electron.getAllowedExtensions();
|
||||
|
||||
@@ -524,22 +540,59 @@ export default function App() {
|
||||
);
|
||||
|
||||
if (!isCommandAllowed) {
|
||||
// Not in allowlist - use detailed message and show warning/block
|
||||
useDetailedMessage = true;
|
||||
title = '⛔️ Untrusted Extension ⛔️';
|
||||
|
||||
if (STRICT_ALLOWLIST) {
|
||||
// Block installation completely unless override is active
|
||||
isBlocked = true;
|
||||
label = 'Extension Blocked';
|
||||
warningMessage =
|
||||
'\n\n⛔️ BLOCKED: This extension command is not in the allowed list. ' +
|
||||
'Installation is blocked by your administrator. ' +
|
||||
'Please contact your administrator if you need this extension.';
|
||||
} else {
|
||||
// Allow override (either because STRICT_ALLOWLIST is false or secret key combo was used)
|
||||
label = 'Override and install';
|
||||
warningMessage =
|
||||
'\n\n⚠️ WARNING: This extension command is not in the allowed list. Installing extensions from untrusted sources may pose security risks. Please contact and admin if you are unsusure or want to allow this extension.';
|
||||
'\n\n⚠️ WARNING: This extension command is not in the allowed list. ' +
|
||||
'Installing extensions from untrusted sources may pose security risks. ' +
|
||||
'Please contact an admin if you are unsure or want to allow this extension.';
|
||||
}
|
||||
}
|
||||
// If in allowlist, use simple message (useDetailedMessage remains false)
|
||||
}
|
||||
// If no allowlist, use simple message (useDetailedMessage remains false)
|
||||
} catch (error) {
|
||||
console.error('Error checking allowlist:', error);
|
||||
}
|
||||
}
|
||||
|
||||
const messageDetails = remoteUrl ? `Remote URL: ${remoteUrl}` : `Command: ${command}`;
|
||||
// Set the appropriate message based on the extension type and allowlist status
|
||||
if (useDetailedMessage) {
|
||||
// Detailed message for SSE extensions or non-allowlisted command extensions
|
||||
const detailedMessage = remoteUrl
|
||||
? `You are about to install the ${extName} extension which connects to:\n\n${remoteUrl}\n\nThis extension will be able to access your conversations and provide additional functionality.`
|
||||
: `You are about to install the ${extName} extension which runs the command:\n\n${command}\n\nThis extension will be able to access your conversations and provide additional functionality.`;
|
||||
|
||||
setModalMessage(`${detailedMessage}${warningMessage}`);
|
||||
} else {
|
||||
// Simple message for allowlisted command extensions or when no allowlist exists
|
||||
const messageDetails = `Command: ${command}`;
|
||||
setModalMessage(
|
||||
`Are you sure you want to install the ${extName} extension?\n\n${messageDetails}${warningMessage}`
|
||||
`Are you sure you want to install the ${extName} extension?\n\n${messageDetails}`
|
||||
);
|
||||
}
|
||||
|
||||
setExtensionConfirmLabel(label);
|
||||
setExtensionConfirmTitle(title);
|
||||
|
||||
// If blocked, disable the confirmation button functionality by setting a special flag
|
||||
if (isBlocked) {
|
||||
setPendingLink(null); // Clear the pending link so confirmation does nothing
|
||||
}
|
||||
|
||||
setModalVisible(true);
|
||||
} catch (error) {
|
||||
console.error('Error handling add-extension event:', error);
|
||||
@@ -550,7 +603,7 @@ export default function App() {
|
||||
return () => {
|
||||
window.electron.off('add-extension', handleAddExtension);
|
||||
};
|
||||
}, []);
|
||||
}, [STRICT_ALLOWLIST]);
|
||||
|
||||
// Focus the first found input field
|
||||
useEffect(() => {
|
||||
@@ -584,6 +637,10 @@ export default function App() {
|
||||
} finally {
|
||||
setPendingLink(null);
|
||||
}
|
||||
} else {
|
||||
// This case happens when pendingLink was cleared due to blocking
|
||||
console.log('Extension installation blocked by allowlist restrictions');
|
||||
setModalVisible(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -272,6 +272,8 @@ let appConfig = {
|
||||
GOOSE_API_HOST: 'http://127.0.0.1',
|
||||
GOOSE_PORT: 0,
|
||||
GOOSE_WORKING_DIR: '',
|
||||
// If GOOSE_ALLOWLIST_WARNING env var is not set, defaults to false (strict blocking mode)
|
||||
GOOSE_ALLOWLIST_WARNING: process.env.GOOSE_ALLOWLIST_WARNING === 'true',
|
||||
secretKey: generateSecretKey(),
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user