mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 01:56:46 +00:00
feat(core)!: Introduce insecure mode in task runner (#16911)
This commit is contained in:
@@ -2,6 +2,20 @@
|
||||
|
||||
This list shows all the versions which include breaking changes and how to upgrade.
|
||||
|
||||
## 1.102.0
|
||||
|
||||
### What changed?
|
||||
|
||||
The `N8N_RUNNERS_ALLOW_PROTOTYPE_MUTATION` flag has been replaced with `N8N_RUNNERS_INSECURE_MODE`. The new flag
|
||||
disables all task runner security measures and is intended as an escape hatch for users who value compatibility
|
||||
with libraries like `puppeteer` at the cost of security.
|
||||
|
||||
### When is action necessary?
|
||||
|
||||
If you are using the `N8N_RUNNERS_ALLOW_PROTOTYPE_MUTATION` flag, or if you find that the task runner does not
|
||||
currently support an external module that you rely on, then consider setting `N8N_RUNNERS_INSECURE_MODE=true`,
|
||||
at your own risk.
|
||||
|
||||
## 1.98.0
|
||||
|
||||
### What changed?
|
||||
|
||||
@@ -138,7 +138,15 @@ export abstract class BaseCommand<F = never> {
|
||||
await Container.get(CommunityPackagesService).init();
|
||||
}
|
||||
|
||||
if (this.needsTaskRunner && this.globalConfig.taskRunners.enabled) {
|
||||
const taskRunnersConfig = this.globalConfig.taskRunners;
|
||||
|
||||
if (this.needsTaskRunner && taskRunnersConfig.enabled) {
|
||||
if (taskRunnersConfig.insecureMode) {
|
||||
this.logger.warn(
|
||||
'TASK RUNNER CONFIGURED TO START IN INSECURE MODE. This is discouraged for production use. Please consider using secure mode instead.',
|
||||
);
|
||||
}
|
||||
|
||||
const { TaskRunnerModule } = await import('@/task-runners/task-runner-module');
|
||||
await Container.get(TaskRunnerModule).start();
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ describe('TaskRunnerProcess', () => {
|
||||
const runnerConfig = mockInstance(TaskRunnersConfig);
|
||||
runnerConfig.enabled = true;
|
||||
runnerConfig.mode = 'internal';
|
||||
runnerConfig.insecureMode = false;
|
||||
const authService = mock<TaskBrokerAuthService>();
|
||||
let taskRunnerProcess = new TaskRunnerProcess(logger, runnerConfig, authService, mock());
|
||||
|
||||
@@ -78,7 +79,7 @@ describe('TaskRunnerProcess', () => {
|
||||
'DEPLOYMENT_NAME',
|
||||
'NODE_PATH',
|
||||
'GENERIC_TIMEZONE',
|
||||
'N8N_RUNNERS_ALLOW_PROTOTYPE_MUTATION',
|
||||
'N8N_RUNNERS_INSECURE_MODE',
|
||||
])('should propagate %s from env as is', async (envVar) => {
|
||||
jest.spyOn(authService, 'createGrantToken').mockResolvedValue('grantToken');
|
||||
process.env[envVar] = 'custom value';
|
||||
@@ -150,7 +151,7 @@ describe('TaskRunnerProcess', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should use --disallow-code-generation-from-strings and --disable-proto=delete flags', async () => {
|
||||
it('on secure mode, should use --disallow-code-generation-from-strings and --disable-proto=delete flags', async () => {
|
||||
jest.spyOn(authService, 'createGrantToken').mockResolvedValue('grantToken');
|
||||
|
||||
await taskRunnerProcess.start();
|
||||
@@ -161,5 +162,22 @@ describe('TaskRunnerProcess', () => {
|
||||
expect.stringContaining('/packages/@n8n/task-runner/dist/start.js'),
|
||||
]);
|
||||
});
|
||||
|
||||
it('on insecure mode, should not use --disallow-code-generation-from-strings and --disable-proto=delete flags', async () => {
|
||||
jest.spyOn(authService, 'createGrantToken').mockResolvedValue('grantToken');
|
||||
runnerConfig.insecureMode = true;
|
||||
const insecureTaskRunnerProcess = new TaskRunnerProcess(
|
||||
logger,
|
||||
runnerConfig,
|
||||
authService,
|
||||
mock(),
|
||||
);
|
||||
|
||||
await insecureTaskRunnerProcess.start();
|
||||
|
||||
expect(spawnMock.mock.calls[0].at(1)).toEqual([
|
||||
expect.stringContaining('/packages/@n8n/task-runner/dist/start.js'),
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -59,7 +59,7 @@ export class TaskRunnerProcess extends TypedEmitter<TaskRunnerProcessEventMap> {
|
||||
'NODE_FUNCTION_ALLOW_BUILTIN',
|
||||
'NODE_FUNCTION_ALLOW_EXTERNAL',
|
||||
'N8N_SENTRY_DSN',
|
||||
'N8N_RUNNERS_ALLOW_PROTOTYPE_MUTATION',
|
||||
'N8N_RUNNERS_INSECURE_MODE',
|
||||
// Metadata about the environment
|
||||
'N8N_VERSION',
|
||||
'ENVIRONMENT',
|
||||
@@ -67,6 +67,8 @@ export class TaskRunnerProcess extends TypedEmitter<TaskRunnerProcessEventMap> {
|
||||
'NODE_PATH',
|
||||
] as const;
|
||||
|
||||
private readonly mode: 'insecure' | 'secure' = 'secure';
|
||||
|
||||
constructor(
|
||||
logger: Logger,
|
||||
private readonly runnerConfig: TaskRunnersConfig,
|
||||
@@ -80,6 +82,8 @@ export class TaskRunnerProcess extends TypedEmitter<TaskRunnerProcessEventMap> {
|
||||
'Task Runner Process cannot be used in external mode',
|
||||
);
|
||||
|
||||
this.mode = this.runnerConfig.insecureMode ? 'insecure' : 'secure';
|
||||
|
||||
this.logger = logger.scoped('task-runner');
|
||||
|
||||
this.runnerLifecycleEvents.on('runner:failed-heartbeat-check', () => {
|
||||
@@ -109,13 +113,14 @@ export class TaskRunnerProcess extends TypedEmitter<TaskRunnerProcessEventMap> {
|
||||
startNode(grantToken: string, taskBrokerUri: string) {
|
||||
const startScript = require.resolve('@n8n/task-runner/start');
|
||||
|
||||
return spawn(
|
||||
'node',
|
||||
['--disallow-code-generation-from-strings', '--disable-proto=delete', startScript],
|
||||
{
|
||||
env: this.getProcessEnvVars(grantToken, taskBrokerUri),
|
||||
},
|
||||
);
|
||||
const flags =
|
||||
this.mode === 'secure'
|
||||
? ['--disallow-code-generation-from-strings', '--disable-proto=delete']
|
||||
: [];
|
||||
|
||||
return spawn('node', [...flags, startScript], {
|
||||
env: this.getProcessEnvVars(grantToken, taskBrokerUri),
|
||||
});
|
||||
}
|
||||
|
||||
@OnShutdown()
|
||||
|
||||
Reference in New Issue
Block a user