dockerfilelint
Advanced tools
Comparing version 0.0.4 to 0.0.5
@@ -1,3 +0,1 @@ | ||
var commands = module.exports = { | ||
@@ -9,3 +7,3 @@ expose_container_port_only: function(args) { | ||
if (port.split(':').length > 1) { | ||
result.push({name: 'expose_host_port', message: 'EXPOSE should only specify a container port, not a host port'}); | ||
result.push('expose_host_port'); | ||
} | ||
@@ -26,3 +24,3 @@ }); | ||
if (label.split('=').length !== 2) { | ||
result.push({name: 'label_invalid', message: 'LABEL command should contain one or more key=value pairs'}); | ||
result.push('label_invalid'); | ||
} | ||
@@ -47,5 +45,5 @@ }); | ||
if (baseImage.length === 1) { | ||
result.push({name: 'missing_tag', message: 'Base images should have a declared tag'}); | ||
result.push('missing_tag'); | ||
} else if (baseImage[1] === 'latest') { | ||
result.push({name: 'latest_tag', message: 'Base images should use a pinned tag, not latest'}); | ||
result.push('latest_tag'); | ||
} | ||
@@ -59,3 +57,3 @@ | ||
if (args.trim().match(/\S+/g).length != 1) { | ||
result.push({name: 'extra_args', message: 'USER command should only include a single username'}); | ||
result.push('extra_args'); | ||
} | ||
@@ -70,5 +68,5 @@ | ||
if (emails.length === 0) { | ||
result.push({name: 'missing_args', message: 'MAINTAINER should include an email address'}); | ||
result.push('missing_args'); | ||
} else if (emails.length > 1) { | ||
result.push({name: 'extra_args', message: 'MAINTAINER command should only include a single author'}); | ||
result.push('extra_args'); | ||
} | ||
@@ -90,3 +88,3 @@ | ||
if (!commands.param_count_min(args, 2)) { | ||
result.push({name: 'missing_args', message: 'ADD command found with less than 2 arguments.'}); | ||
result.push('missing_args'); | ||
} | ||
@@ -102,3 +100,3 @@ | ||
if (!commands.is_dir_in_context(source)) { | ||
result.push({name: 'add_src_invalid', message: 'ADD source locations must be local to the Docker build context.'}); | ||
result.push('add_src_invalid'); | ||
} | ||
@@ -110,3 +108,3 @@ }); | ||
if (args.slice(-1)[0] !== '/') { | ||
result.push({name: 'add_dest_invalid', message: 'When ADD source includes wildcards or multiple locations, dest must be a directory'}); | ||
result.push('add_dest_invalid'); | ||
} | ||
@@ -127,3 +125,3 @@ } | ||
if (args.match(/\S+/g).length > 1) { | ||
result.push({name: 'invalid_workdir', message: 'WORKDIR cannot include spaces unless wrapped in quotes.'}); | ||
result.push('invalid_workdir'); | ||
} | ||
@@ -157,6 +155,6 @@ | ||
if (!v.includes('=')) { | ||
result.push({name: 'invalid_format', message: 'ENV should contain key=value'}); | ||
result.push('invalid_format'); | ||
} | ||
if (v.match(/\S+/g).length > 1) { | ||
result.push({name: 'invalid_format', message: 'Unquoted ENV should not contain whitespace'}); | ||
result.push('invalid_format'); | ||
} | ||
@@ -163,0 +161,0 @@ }); |
@@ -5,2 +5,3 @@ 'use strict'; | ||
var run_checks = require('./run_checks'); | ||
var messages = require('./messages'); | ||
@@ -50,3 +51,3 @@ module.exports.run = function(content) { | ||
cmdFound: false, | ||
messages: [] | ||
items: [] | ||
} | ||
@@ -56,3 +57,3 @@ | ||
var result = runLine(state, instructions, idx); | ||
state.messages = state.messages.concat(result.messages); | ||
state.items = state.items.concat(result.items); | ||
@@ -68,8 +69,9 @@ // We care about only having 1 cmd instruction | ||
return state.messages; | ||
return state.items; | ||
} | ||
function runLine(state, instructions, idx) { | ||
// return messages in an object with the line number as key, value is array of messages for this line | ||
var messages = []; | ||
// return items in an object with the line number as key, value is array of items for this line | ||
var items = []; | ||
var line = parseInt(idx) + 1; | ||
@@ -79,3 +81,3 @@ // All Dockerfile commands require parameters, this is an error if not | ||
if (instruction.trim().match(/\S+/g).length === 1) { | ||
messages.push({line: parseInt(idx)+1, name: 'required_params', message: 'Command \'' + instruction + '\' without parameters'}); | ||
items.push(messages.build('required_params', line)); | ||
} | ||
@@ -88,3 +90,3 @@ | ||
if (instruction.trim().match(/\S+/g)[0] !== cmd.toUpperCase()) { | ||
messages.push({line: parseInt(idx)+1, name: 'uppercase_commands', message: 'Command \'' + instruction.trim().match(/\S+/g)[0] + '\' should be upper case'}); | ||
items.push(messages.build('uppercase_commands', line)); | ||
} | ||
@@ -95,3 +97,3 @@ | ||
if ((state.instructionsProcessed === 0 && cmd !== 'from') || (state.instructionsProcessed !== 0 && cmd === 'from')) { | ||
messages.push({line: parseInt(idx)+1, name: 'from_first', message: 'FROM command should be the first line in a Dockerfile.'}); | ||
items.push(messages.build('from_first', line)); | ||
} | ||
@@ -103,3 +105,3 @@ | ||
if (!args) { | ||
messages.push({line: parseInt(idx)+1, name: 'invalid_line', message: 'Line is invalid'}); | ||
items.push(messages.build('invalid_line', line)); | ||
} | ||
@@ -111,3 +113,3 @@ | ||
if (arg.trim().toLowerCase() === 'sudo') { | ||
messages.push({line: parseInt(idx)+1, name: 'sudo_usage', message: 'sudo usage is not allowed. Commands will run as sudo.'}); | ||
items.push(messages.build('sudo_usage', line)); | ||
} | ||
@@ -119,9 +121,9 @@ }.bind(this)); | ||
case 'from': | ||
checks.base_image_tag(args).forEach(function(message) { | ||
messages.push({line: parseInt(idx)+1, name: message.name, message: message.message}); | ||
checks.base_image_tag(args).forEach(function(item) { | ||
items.push(messages.build(item, line)); | ||
}); | ||
break; | ||
case 'maintainer': | ||
checks.valid_maintainer(args).forEach(function(message) { | ||
messages.push({line: parseInt(idx)+1, name: message.name, message: message.message}); | ||
checks.valid_maintainer(args).forEach(function(item) { | ||
items.push(messages.build(item, line)); | ||
}); | ||
@@ -136,3 +138,3 @@ break; | ||
if (!run_checks.aptget_hasyes(aptget_command)) { | ||
messages.push({line: parseInt(idx)+1, name: 'apt-get_missing_param', message: 'apt-get commands should include a -y flag'}); | ||
items.push(messages.build('apt-get_missing_param', line)); | ||
} | ||
@@ -143,16 +145,16 @@ } | ||
if (!run_checks.aptget_hasnorecommends(aptget_command)) { | ||
messages.push({line: parseInt(idx)+1, name: 'apt-get_recommends', message: 'apt-get install commands should include a --no-install-recommends flag'}); | ||
items.push(messages.build('apt-get_recommends', line)); | ||
} | ||
} else if (subcommand === 'update') { | ||
if (!run_checks.includes_rmaptlists(args)) { | ||
messages.push({line: parseInt(idx)+1, name: 'apt-get_missing_rm', message: 'apt-get update should include a matching /var/lib/apt/lists/*'}) | ||
items.push(messages.build('apt-get_missing_rm', line)); | ||
} | ||
} else if (subcommand === 'upgrade') { | ||
messages.push({line: parseInt(idx)+1, name: 'apt-get-upgrade', message: 'apt-get upgrade is not allowed'}); | ||
items.push(messages.build('apt-get-upgrade', line)); | ||
} else if (subcommand === 'dist-upgrade') { | ||
messages.push({line: parseInt(idx)+1, name: 'apt-get-dist-upgrade', message: 'apt-get dist-upgrade is not allowed'}); | ||
items.push(messages.build('apt-get-dist-upgrade', line)); | ||
} | ||
}); | ||
if ((subcommands.indexOf('update') > -1) && (subcommands.indexOf('install') === -1)) { | ||
messages.push({line: parseInt(idx)+1, name: 'apt-get-update_require_install', message: 'apt-get update commands must be paired with apt-get install commands'}); | ||
items.push(messages.build('apt-get-update_require_install', line)); | ||
} | ||
@@ -163,9 +165,9 @@ break; | ||
case 'label': | ||
checks.label_format(args).forEach(function(message) { | ||
messages.push({line: parseInt(idx)+1, name: message.name, message: message.message}); | ||
checks.label_format(args).forEach(function(item) { | ||
items.push(messages.build(item, line)); | ||
}); | ||
break; | ||
case 'expose': | ||
checks.expose_container_port_only(args).forEach(function(message) { | ||
messages.push({line: parseInt(idx)+1, name: message.name, message: message.message}); | ||
checks.expose_container_port_only(args).forEach(function(item) { | ||
items.push(messages.build(item, line)); | ||
}); | ||
@@ -175,3 +177,3 @@ args.match(/\S+/g).forEach(function(port) { | ||
if (!port.includes(':')) { // Just eliminate a double message here | ||
messages.push({line: parseInt(idx)+1, name: 'invalid_port', message: 'EXPOSE should be a valid port number'}); | ||
items,push(messages.build('invalid_port', line)); | ||
} | ||
@@ -182,9 +184,9 @@ } | ||
case 'env': | ||
checks.is_valid_env(args).forEach(function(message) { | ||
messages.push({line: parseInt(idx)+1, name: message.name, message: message.message}); | ||
checks.is_valid_env(args).forEach(function(item) { | ||
items.push(messages.build(item, line)); | ||
}); | ||
break; | ||
case 'add': | ||
checks.is_valid_add(args).forEach(function(message) { | ||
messages.push({line: parseInt(idx)+1, name: message.name, message: message.message}); | ||
checks.is_valid_add(args).forEach(function(item) { | ||
items.push(messages.build(item, line)); | ||
}); | ||
@@ -199,9 +201,9 @@ break; | ||
case 'user': | ||
checks.valid_user(args).forEach(function(message) { | ||
messages.push({line: parseInt(idx)+1, name: message.name, message: message.message}); | ||
checks.valid_user(args).forEach(function(item) { | ||
items.push(messages.build(item, line)); | ||
}); | ||
break; | ||
case 'workdir': | ||
checks.is_valid_workdir(args).forEach(function(message) { | ||
messages.push({line: parseInt(idx)+1, name: message.name, message: message.message}); | ||
checks.is_valid_workdir(args).forEach(function(item) { | ||
items.push(messages.build(item, line)); | ||
}); | ||
@@ -216,3 +218,3 @@ break; | ||
default: | ||
messages.push({line: parseInt(idx)+1, name: 'invalid_command', message: 'Only supported Dockerfile commands are allowed'}); | ||
items.push(messages.build('invalid_command', line)); | ||
break; | ||
@@ -224,4 +226,4 @@ } | ||
command: cmd, | ||
messages: messages | ||
items: items | ||
}; | ||
} |
{ | ||
"name": "dockerfilelint", | ||
"version": "0.0.4", | ||
"version": "0.0.5", | ||
"description": "A linter for Dockerfiles to find bugs and encourage best practices", | ||
@@ -5,0 +5,0 @@ "main": "./lib/index.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
37709
22
674