| assert = require('assert') | ||
| weaver = require('../lib/weaver.js') | ||
| exec = require('child_process').exec | ||
| write = require('fs').writeFileSync | ||
| unlink = require('fs').unlinkSync | ||
| daemon = '../bin/weaver' | ||
| port = 58011 | ||
| config = "#{__dirname}/weaver_#{port}.json" | ||
| options = | ||
| cwd: __dirname | ||
| env: | ||
| PATH: process.env.PATH | ||
| WEAVER_TEST: 1 | ||
| WEAVER_PORT: port | ||
| (require 'vows') | ||
| .describe('cwd') | ||
| .addBatch | ||
| start: | ||
| topic: -> | ||
| # Write config | ||
| write config, JSON.stringify | ||
| tasks: | ||
| base: | ||
| cwd: '..' | ||
| count: 2 | ||
| executable: yes | ||
| source: 't/bin/sleep' | ||
| arguments: [[2011, 2111]] | ||
| # Start daemon | ||
| exec "#{daemon} --config #{config}", options, @callback | ||
| return | ||
| code: (error, stdout, stderr) -> assert not error | ||
| stdout: (error, stdout, stderr) -> assert not stdout | ||
| stderr: (error, stdout, stderr) -> assert not stderr | ||
| status: | ||
| topic: -> | ||
| # Check status | ||
| exec "#{daemon} status --nocolor", options, (args...) => | ||
| args[1] = args[1] | ||
| .replace(/\n$/, '') | ||
| .split(/\n/) | ||
| .map(($_) -> +/^\s*(\d+)/.exec($_)[1]) | ||
| @callback(args...) | ||
| return | ||
| code: (error, stdout, stderr) -> assert not error | ||
| stderr: (error, stdout, stderr) -> assert not stderr | ||
| stdout: (error, stdout, stderr) -> assert.equal stdout.length, 3 | ||
| exit: | ||
| topic: -> | ||
| # Remove config file | ||
| unlink config | ||
| # Stop daemon | ||
| exec "#{daemon} exit", options, @callback | ||
| return | ||
| code: (error, stdout, stderr) -> assert not error | ||
| stdout: (error, stdout, stderr) -> assert not stdout | ||
| stderr: (error, stdout, stderr) -> assert not stderr | ||
| .export(module) |
| assert = require('assert') | ||
| weaver = require('../lib/weaver.js') | ||
| exec = require('child_process').exec | ||
| write = require('fs').writeFileSync | ||
| unlink = require('fs').unlinkSync | ||
| daemon = '../bin/weaver' | ||
| port = 58012 | ||
| config = "#{__dirname}/weaver_#{port}.json" | ||
| options = | ||
| cwd: __dirname | ||
| env: | ||
| PATH: process.env.PATH | ||
| WEAVER_TEST: 1 | ||
| WEAVER_PORT: port | ||
| (require 'vows') | ||
| .describe('path') | ||
| .addBatch | ||
| start: | ||
| topic: -> | ||
| # Write config | ||
| write config, JSON.stringify | ||
| path: '../lib' | ||
| tasks: | ||
| base: | ||
| cwd: '../bin' | ||
| count: 3 | ||
| executable: yes | ||
| source: '../t/bin/sleep' | ||
| arguments: [[3012, 3112, 3212]] | ||
| # Start daemon | ||
| exec "#{daemon} --config #{config}", options, @callback | ||
| return | ||
| code: (error, stdout, stderr) -> assert not error | ||
| stdout: (error, stdout, stderr) -> assert not stdout | ||
| stderr: (error, stdout, stderr) -> assert not stderr | ||
| status: | ||
| topic: -> | ||
| # Check status | ||
| exec "#{daemon} status --nocolor", options, (args...) => | ||
| args[1] = args[1] | ||
| .replace(/\n$/, '') | ||
| .split(/\n/) | ||
| .map(($_) -> +/^\s*(\d+)/.exec($_)[1]) | ||
| @callback(args...) | ||
| return | ||
| code: (error, stdout, stderr) -> assert not error | ||
| stderr: (error, stdout, stderr) -> assert not stderr | ||
| stdout: (error, stdout, stderr) -> assert.equal stdout.length, 4 | ||
| exit: | ||
| topic: -> | ||
| # Remove config file | ||
| unlink config | ||
| # Stop daemon | ||
| exec "#{daemon} exit", options, @callback | ||
| return | ||
| code: (error, stdout, stderr) -> assert not error | ||
| stdout: (error, stdout, stderr) -> assert not stdout | ||
| stderr: (error, stdout, stderr) -> assert not stderr | ||
| .export(module) |
| assert = require('assert') | ||
| weaver = require('../lib/weaver.js') | ||
| exec = require('child_process').exec | ||
| write = require('fs').writeFileSync | ||
| unlink = require('fs').unlinkSync | ||
| daemon = '../bin/weaver' | ||
| port = 58013 | ||
| config = "#{__dirname}/weaver_#{port}.json" | ||
| options = | ||
| cwd: __dirname | ||
| env: | ||
| PATH: process.env.PATH | ||
| WEAVER_TEST: 1 | ||
| WEAVER_PORT: port | ||
| (require 'vows') | ||
| .describe('binary') | ||
| .addBatch | ||
| start: | ||
| topic: -> | ||
| # Write config | ||
| write config, JSON.stringify | ||
| path: '../lib' | ||
| tasks: | ||
| base: | ||
| count: 1 | ||
| executable: yes | ||
| source: 'bin/borken' | ||
| # Start daemon | ||
| exec "#{daemon} --config #{config}", options, @callback | ||
| return | ||
| code: (error, stdout, stderr) -> assert not error | ||
| stdout: (error, stdout, stderr) -> assert not stdout | ||
| stderr: (error, stdout, stderr) -> assert not stderr | ||
| status: | ||
| topic: -> | ||
| # Check status | ||
| exec "#{daemon} status --nocolor", options, (args...) => | ||
| args[1] = args[1] | ||
| .replace(/\n$/, '') | ||
| .split(/\n/) | ||
| .map(($_) -> +/^\s*(\d+)/.exec($_)[1]) | ||
| @callback(args...) | ||
| return | ||
| code: (error, stdout, stderr) -> assert not error | ||
| stderr: (error, stdout, stderr) -> assert not stderr | ||
| stdout: (error, stdout, stderr) -> assert.equal stdout.length, 2 | ||
| pid: (error, stdout, stderr) -> assert.equal stdout[1], 0 | ||
| exit: | ||
| topic: -> | ||
| # Remove config file | ||
| unlink config | ||
| # Stop daemon | ||
| exec "#{daemon} exit", options, @callback | ||
| return | ||
| code: (error, stdout, stderr) -> assert not error | ||
| stdout: (error, stdout, stderr) -> assert not stdout | ||
| stderr: (error, stdout, stderr) -> assert not stderr | ||
| .export(module) |
+105
| assert = require('assert') | ||
| weaver = require('../lib/weaver.js') | ||
| exec = require('child_process').exec | ||
| write = require('fs').writeFileSync | ||
| unlink = require('fs').unlinkSync | ||
| daemon = '../bin/weaver' | ||
| port = 58014 | ||
| config = "#{__dirname}/weaver_#{port}.json" | ||
| options = | ||
| cwd: __dirname | ||
| env: | ||
| PATH: process.env.PATH | ||
| WEAVER_TEST: 1 | ||
| WEAVER_PORT: port | ||
| status = [] | ||
| (require 'vows') | ||
| .describe('drop') | ||
| .addBatch | ||
| start: | ||
| topic: -> | ||
| # Write config | ||
| write config, JSON.stringify | ||
| tasks: | ||
| s1: | ||
| count: 4 | ||
| executable: yes | ||
| source: 'sleep' | ||
| arguments: [4014] | ||
| s2: | ||
| count: 2 | ||
| executable: yes | ||
| source: 'sleep' | ||
| arguments: [2014] | ||
| # Start daemon | ||
| exec "#{daemon} --config #{config}", options, @callback | ||
| return | ||
| code: (error, stdout, stderr) -> assert not error | ||
| stdout: (error, stdout, stderr) -> assert not stdout | ||
| stderr: (error, stdout, stderr) -> assert not stderr | ||
| status: | ||
| topic: -> | ||
| # Check status | ||
| exec "#{daemon} status --nocolor", options, (args...) => | ||
| args[1] = args[1] | ||
| .replace(/\n$/, '') | ||
| .split(/\n/) | ||
| .map(($_) -> +/^\s*(\d+)/.exec($_)[1]) | ||
| @callback(args...) | ||
| return | ||
| code: (error, stdout, stderr) -> assert not error | ||
| stderr: (error, stdout, stderr) -> assert not stderr | ||
| stdout: (error, stdout, stderr) -> assert.equal stdout.length, 7 | ||
| drop: | ||
| topic: (pid) -> | ||
| # Drop second group | ||
| exec "#{daemon} drop s2", options, => | ||
| # Get configuration dump | ||
| exec "#{daemon} dump --nocolor", options, (args...) => | ||
| dump = JSON.parse args[1] | ||
| # Check status | ||
| exec "#{daemon} status --nocolor", options, (args...) => | ||
| @callback(args..., pid, dump) | ||
| return | ||
| code: (error, stdout, stderr, pid, dump) -> assert not error | ||
| dump: (error, stdout, stderr, pid, dump) -> assert not dump.hasOwnProperty 's2' | ||
| stderr: (error, stdout, stderr, pid, dump) -> assert not stderr | ||
| stdout: (error, stdout, stderr, pid, dump) -> | ||
| status = stdout | ||
| .replace(/\n$/, '') | ||
| .split(/\n/) | ||
| .map(($_) -> +/^\s*(\d+)/.exec($_)[1]) | ||
| assert.equal status.length, 5 | ||
| assert.match stdout, /^(?:[\s\S](?!s2))+$/ | ||
| assert.equal pid[1], status[1] | ||
| assert.equal pid[2], status[2] | ||
| assert.equal pid[3], status[3] | ||
| assert.equal pid[4], status[4] | ||
| exit: | ||
| topic: -> | ||
| # Remove config file | ||
| unlink config | ||
| # Stop daemon | ||
| exec "#{daemon} exit", options, @callback | ||
| return | ||
| code: (error, stdout, stderr) -> assert not error | ||
| stdout: (error, stdout, stderr) -> assert not stdout | ||
| stderr: (error, stdout, stderr) -> assert not stderr | ||
| .export(module) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
+9
-0
| # Changelog | ||
| ## 0.2.0 | ||
| Released 2016-02-26 | ||
| * Upgrade extends weaver configuration instead of replacing it | ||
| * Added drop command | ||
| * Fixed argument validation for kill command | ||
| * Fixed crash on broken executables | ||
| ## 0.1.2 | ||
@@ -4,0 +13,0 @@ |
+105
-105
| 'use strict'; | ||
| var fs = require('fs'), | ||
| assert = require('assert'), | ||
| util = require('util'), | ||
| events = require('events'), | ||
| assert = require('assert'), | ||
| dirname = require('path').dirname, | ||
| resolve = require('path').resolve, | ||
@@ -37,3 +35,5 @@ fork = require('child_process').spawn, | ||
| */ | ||
| function Weaver () {} | ||
| function Weaver () { | ||
| return this; | ||
| } | ||
@@ -103,15 +103,8 @@ util.inherits(Weaver, events.EventEmitter); | ||
| * Parsed configuration file | ||
| * @property parameters | ||
| * @property config | ||
| * @type Object | ||
| */ | ||
| define('property', 'parameters', {}); | ||
| define('property', 'config', Object.create(null), { writable: false }); | ||
| /** | ||
| * Path to configuration file | ||
| * @property file | ||
| * @type String | ||
| */ | ||
| define('property', 'file', ''); | ||
| /** | ||
| * Extend Weaver with property or method | ||
@@ -127,3 +120,2 @@ * @method define | ||
| * @param {Object} options | ||
| * @chainable | ||
| */ | ||
@@ -141,9 +133,10 @@ define('method', 'task', Task); | ||
| * @method validate | ||
| * @param {Object} config | ||
| * @param {Object} configuration | ||
| * @return {Object} Valid configuration | ||
| */ | ||
| define('method', 'validate', function (config) { | ||
| var tasks = config.tasks; | ||
| define('method', 'validate', function (configuration) { | ||
| var tasks = configuration.tasks; | ||
| /* Validate schema */ | ||
| assert.ok(validator.validate(config, schema), 'Invalid configuration'); | ||
| assert.ok(validator.validate(configuration, schema), 'Invalid configuration'); | ||
@@ -171,3 +164,3 @@ /* Perform additional validation */ | ||
| return config; | ||
| return configuration; | ||
| }); | ||
@@ -179,3 +172,2 @@ | ||
| * @param {Number} code Exit code | ||
| * @chainable | ||
| */ | ||
@@ -205,4 +197,2 @@ define('method', 'die', function (code) { | ||
| }, timeout); | ||
| return this; | ||
| }); | ||
@@ -214,6 +204,7 @@ | ||
| * @param {String} data Configuration data | ||
| * @chainable | ||
| * @param {String} path Configuration path | ||
| */ | ||
| define('method', 'upgrade', function (data) { | ||
| var parameters; | ||
| define('method', 'upgrade', function (data, path) { | ||
| var parts = [path], | ||
| params; | ||
@@ -225,14 +216,28 @@ try { | ||
| /* Validate new state */ | ||
| parameters = this.validate(data); | ||
| params = this.validate(data); | ||
| } catch (error) { | ||
| error.message = 'Config error: ' + error.message; | ||
| this.emit('error', error); | ||
| } | ||
| if (parameters) { | ||
| this.parameters = parameters; | ||
| if (params) { | ||
| if (params.path) { | ||
| parts.push(params.path); | ||
| } | ||
| Object.keys(params.tasks) | ||
| .map(function (name) { | ||
| return params.tasks[name]; | ||
| }).forEach(function (task) { | ||
| task.cwd = resolve.apply(undefined, parts.concat(task.cwd || '.')); | ||
| }); | ||
| Object.keys(params.tasks) | ||
| .forEach(function (name) { | ||
| weaver.config[name] = params.tasks[name]; | ||
| }); | ||
| this.emit('upgrade'); | ||
| } | ||
| return this; | ||
| }); | ||
@@ -281,3 +286,2 @@ | ||
| * @param {Array} args Arguments | ||
| * @chainable | ||
| */ | ||
@@ -319,4 +323,2 @@ define('method', 'command', function (action, name, args) { | ||
| } | ||
| return this; | ||
| }); | ||
@@ -334,20 +336,2 @@ | ||
| /** | ||
| * Fired when configuration file should be re-read | ||
| * @event config | ||
| */ | ||
| define('handler', 'config', function () { | ||
| var that = this; | ||
| if (this.file) { | ||
| fs.readFile(this.file, function (error, data) { | ||
| if (error) { | ||
| that.emit('error', error); | ||
| } else { | ||
| that.upgrade(data); | ||
| } | ||
| }); | ||
| } | ||
| }); | ||
| /** | ||
| * Fired when tasks should be checked and upgraded | ||
@@ -357,18 +341,7 @@ * @event upgrade | ||
| define('handler', 'upgrade', function () { | ||
| var tasks = this.parameters.tasks, | ||
| path = this.parameters.path || '', | ||
| name; | ||
| var name; | ||
| if (path[0] !== '/') { | ||
| path = dirname(this.file) + '/' + path; | ||
| } | ||
| this.path = resolve(path); | ||
| for (name in tasks) { | ||
| /* Set cwd for tasks */ | ||
| tasks[name].cwd = tasks[name].cwd || this.path; | ||
| for (name in this.config) { | ||
| /* Create or update task */ | ||
| this.task(name, tasks[name]); | ||
| this.task(name, this.config[name]); | ||
| } | ||
@@ -390,2 +363,4 @@ }); | ||
| * @constructor | ||
| * @param {String} name Task group name | ||
| * @param {Object} options Task group configuration | ||
| */ | ||
@@ -403,2 +378,3 @@ function Task (name, options) { | ||
| task.upgrade(options); | ||
| return task; | ||
@@ -442,5 +418,3 @@ } | ||
| if (options) { | ||
| this.upgrade(options); | ||
| } | ||
| this.upgrade(options); | ||
@@ -522,25 +496,20 @@ return this; | ||
| * @method upgrade | ||
| * @param {Object} parameters | ||
| * @chainable | ||
| * @param {Object} options Task group configuration | ||
| */ | ||
| define('method', 'upgrade', function (parameters) { | ||
| var restart = false, | ||
| define('method', 'upgrade', function (options) { | ||
| var that = this, | ||
| restart = false, | ||
| i, l, pid, subtask, key; | ||
| /* Change parameters */ | ||
| if (parameters) { | ||
| for (key in mutable) { | ||
| /* Upgrade parameters */ | ||
| Object.keys(mutable) | ||
| .forEach(function (key) { | ||
| try { | ||
| if (this.hasOwnProperty(key) || key in parameters) { | ||
| assert.deepEqual(this[key], parameters[key]); | ||
| } | ||
| assert.deepEqual(that[key], options[key]); | ||
| } catch (change) { | ||
| this.upgradeParameter(key, parameters); | ||
| that.upgradeParameter(key, options[key]); | ||
| if (!mutable[key]) { | ||
| restart = true; | ||
| } | ||
| restart = restart || !mutable[key]; | ||
| } | ||
| } | ||
| } | ||
| }); | ||
@@ -550,2 +519,3 @@ /* Restart on demand */ | ||
| weaver.log(sprintf('Restart required for %s task group', this.name)); | ||
| this.restartSubtasks(); | ||
@@ -570,11 +540,12 @@ } | ||
| /** | ||
| * Upgrade task parameter with value from parameters object | ||
| * Upgrade task parameter with value | ||
| * @method upgradeParameter | ||
| * @param {String} key | ||
| * @param {Object} parameters | ||
| * @param {String} key Parameter name | ||
| * @param {Object} value Parameter value | ||
| */ | ||
| define('method', 'upgradeParameter', function (key, parameters) { | ||
| define('method', 'upgradeParameter', function (key, value) { | ||
| switch (key) { | ||
| case 'watch': | ||
| this.watch = parameters.watch || []; | ||
| this.watch = value || []; | ||
| Watcher.stop(this.watchHandler); | ||
@@ -585,6 +556,6 @@ Watcher.start(weaver, this.cwd, this.watch, this.watchHandler); | ||
| default: | ||
| if (key in parameters) { | ||
| this[key] = parameters[key]; | ||
| if (null == value) { | ||
| delete this[key]; | ||
| } else { | ||
| delete this[key]; | ||
| this[key] = value; | ||
| } | ||
@@ -630,3 +601,4 @@ } | ||
| * @method get | ||
| * @param {Number} pid | ||
| * @param {Number} pid | ||
| * @return {Object} Subtask | ||
| */ | ||
@@ -689,16 +661,27 @@ define('method', 'get', function (pid) { | ||
| /* Get subtask pid */ | ||
| subtask.pid = subtask.process.pid; | ||
| subtask.pid = subtask.process.pid || 0; | ||
| p1 = sprintf('%u (%s) ', subtask.pid, subtask.name); | ||
| p2 = sprintf('%u [%s] ', subtask.pid, subtask.name); | ||
| if (subtask.pid) { | ||
| p1 = sprintf('%u (%s) ', subtask.pid, subtask.name); | ||
| p2 = sprintf('%u [%s] ', subtask.pid, subtask.name); | ||
| /* Setup logger */ | ||
| subtask.process.stdout.on('data', this.log.bind(this, p1)); | ||
| subtask.process.stderr.on('data', this.log.bind(this, p2)); | ||
| /* Setup logger */ | ||
| subtask.process.stdout.on('data', this.log.bind(this, p1)); | ||
| subtask.process.stderr.on('data', this.log.bind(this, p2)); | ||
| /* Setup exit handler */ | ||
| subtask.process.once('exit', this.exitHandler.bind(this, subtask)); | ||
| /* Setup exit handler */ | ||
| subtask.process.once('exit', this.exitHandler.bind(this, subtask)); | ||
| weaver.log(sprintf('Task %u (%s) spawned', subtask.pid, subtask.name)); | ||
| weaver.log(sprintf('Task %u (%s) spawned', subtask.pid, subtask.name)); | ||
| } else { | ||
| subtask.status = 'E'; | ||
| subtask.code = 255; | ||
| subtask.process.once('error', function (error) { | ||
| weaver.emit('error', error); | ||
| }); | ||
| weaver.log(sprintf('Failed to start task (%s)', subtask.name)); | ||
| } | ||
| this.subtasks[id] = subtask; | ||
@@ -859,3 +842,4 @@ }, { target: Task.prototype }); | ||
| define('method', 'exitHandler', function (subtask, code, signal) { | ||
| var elapsed; | ||
| var restart = this.persistent, | ||
| elapsed; | ||
@@ -890,3 +874,3 @@ if (code === null) { | ||
| if (this.persistent && code) { | ||
| if (restart && code) { | ||
| elapsed = Date.now() - subtask.start; | ||
@@ -899,9 +883,25 @@ | ||
| )); | ||
| return; | ||
| restart = false; | ||
| } | ||
| } | ||
| if (this.persistent || subtask.status === 'R') { | ||
| if (subtask.status === 'R') { | ||
| /* Restart was requested */ | ||
| restart = true; | ||
| } | ||
| if (!(this.name in weaver.config)) { | ||
| /* Task was dropped */ | ||
| restart = false; | ||
| if (!this.subtasks.filter(function (subtask) { return !!subtask.pid }).length) { | ||
| /* All subtasks were stopped */ | ||
| delete weaver.tasks[this.name]; | ||
| } | ||
| } | ||
| if (restart) { | ||
| this.spawn(subtask.id); | ||
| } | ||
| }, { target: Task.prototype }); |
+1
-1
| { | ||
| "name" : "weaver", | ||
| "version" : "0.1.2", | ||
| "version" : "0.2.0", | ||
| "license" : "LGPL-3.0", | ||
@@ -5,0 +5,0 @@ "author" : "Alexander Nazarov <n4kz@n4kz.com>", |
+16
-14
@@ -22,4 +22,6 @@ # Weaver | ||
| weaver [--port <number>] [--config <path>] upgrade | ||
| weaver [--port <number>] <restart|stop> [[task|pid], ...] | ||
| weaver [--port <number>] restart [[task|pid], ...] | ||
| weaver [--port <number>] stop [[task|pid], ...] | ||
| weaver [--port <number>] kill <signal> [[task|pid], ...] | ||
| weaver [--port <number>] drop <task> | ||
| weaver [--port <number>] [--nocolor] status | ||
@@ -32,10 +34,10 @@ weaver [--port <number>] [--nocolor] dump | ||
| - `start` Start daemon if it was not started before. Default command | ||
| - `upgrade` Change or re-read config file | ||
| - `upgrade` Extend configuration with tasks from configuration file | ||
| - `restart` Restart all tasks, task group, task by pid | ||
| - `stop` Stop all tasks, task group, task by pid | ||
| - `kill` Send signal to task group or task by pid | ||
| - `drop` Stop task group and remove it from configuration | ||
| - `status` Show status for all tasks | ||
| - `dump` Show current weaver configuration | ||
| - `monitor` Show log messages from running weaver | ||
| - `dump` Show current configuration | ||
| - `monitor` Stream log messages from daemon | ||
| - `exit` Stop all tasks and exit | ||
@@ -45,7 +47,7 @@ | ||
| --config Configuration file. Required to start daemon with predefined tasks | ||
| --debug Do not fork and give additional output. Makes sense only for start [boolean] | ||
| --nocolor Do not use colors for output [boolean] | ||
| --help Show help [boolean] | ||
| --version Show version [boolean] | ||
| --config Configuration file [default: weaver.json] | ||
| --debug Do not fork and give additional output | ||
| --nocolor Do not use colors for output | ||
| --help Show help and exit | ||
| --version Show version and exit | ||
| --port Use specified port [default: 8092] | ||
@@ -119,4 +121,4 @@ | ||
| - `tasks` Task groups | ||
| - `count` Task count for group | ||
| - `source` Source file for task group | ||
| - `count` Task count for group. Can be zero | ||
| - `source` Source file or executable for task group. Relative to `cwd` or absolute | ||
| - `persistent` Restart task on unclean exit. Defaults to false. Boolean. Optional | ||
@@ -128,4 +130,4 @@ - `executable` Source is executable itself and v8 instance is not needed to run it. Defaults to false. Boolean. Optional | ||
| - `timeout` Timeout between SIGINT and SIGTERM for stop and restart commands. Defaults to 1000ms. Optional | ||
| - `cwd` Task group working directory. Defaults to path. Optional | ||
| - `runtime` Minimal runtime required for persistent task to be restarted after unclean exit | ||
| - `runtime` Minimal runtime required for persistent task to be restarted after unclean exit. Defaults to 1000ms. Optional | ||
| - `cwd` Task group working directory. Relative to `path` or absolute. Optional | ||
@@ -132,0 +134,0 @@ Configuration file is validated with JSON Schema from file `lib/schema.json`. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 4 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 4 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
87830
12.7%29
16%151
1.34%886
-0.45%