dockerfilelint
Advanced tools
Comparing version 1.1.2 to 1.1.3
@@ -0,1 +1,3 @@ | ||
var parser = require('./parser'); | ||
var commands = module.exports = { | ||
@@ -19,10 +21,10 @@ expose_container_port_only: function(args) { | ||
label_format: function(args) { | ||
var labels = args.match(/\S+/g); | ||
// format LABEL <key>=<value> <key>=<value> <key>=<value> ... | ||
// we do not support the old format LABEL <key> <value> | ||
var result = []; | ||
labels.forEach(function(label) { | ||
if (label.split('=').length !== 2) { | ||
result.push('label_invalid'); | ||
} | ||
}); | ||
try { | ||
parser.nameVal(args); | ||
} catch(e) { | ||
result.push('label_invalid'); | ||
} | ||
return result; | ||
@@ -136,23 +138,28 @@ }, | ||
is_valid_env: function(args) { | ||
// Dockerfile syntax is either a=b c=d (no internal spaces) or a b c d (for spaces) | ||
var p = args.match(/\S+/g); | ||
// if there is not a = in the first element, we shoud assume it's the second format above | ||
if (!p[0].includes('=')) { | ||
var words = parser.words(args); | ||
if (words.length === 0) { | ||
return []; | ||
} else { | ||
var result = []; | ||
var vars = args.match(/\S+/g); | ||
vars.forEach(function(v) { | ||
if (!v.includes('=')) { | ||
result.push('invalid_format'); | ||
} | ||
if (v.match(/\S+/g).length > 1) { | ||
result.push('invalid_format'); | ||
} | ||
}); | ||
} | ||
// format ENV <key> <value> | ||
if (!words[0].includes('=')) { | ||
return []; | ||
} | ||
// format ENV <key>=<value> ... | ||
var result = []; | ||
try { | ||
parser.nameVal(args); | ||
} catch(e) { | ||
result.push('invalid_format'); | ||
} | ||
return result; | ||
}, | ||
return result; | ||
is_valid_shell: function(args) { | ||
// Dockerfile syntax requires that args be in JSON array format | ||
var parsed = JSON.parse(args); | ||
if (parsed.constructor !== Array) { | ||
return ['invalid_format']; | ||
} | ||
return []; | ||
} | ||
} |
@@ -0,1 +1,2 @@ | ||
var parser = require('./parser'); | ||
@@ -6,5 +7,18 @@ var command_parser = module.exports = { | ||
split_commands: function(args) { | ||
return args.split('&&').map(function(command) { | ||
return command.trim(); | ||
var commands = []; | ||
var idx = 0; | ||
parser.words(args).forEach(function(word) { | ||
if (['||', '&&', ';;', '|&'].indexOf(word) > -1) { | ||
idx++; | ||
return | ||
} | ||
if (commands.length < idx+1) { | ||
commands[idx] = []; | ||
} | ||
commands[idx].push(word); | ||
}); | ||
var c = commands.map(function(command) { | ||
return command.join(' '); | ||
}); | ||
return c; | ||
}, | ||
@@ -18,2 +32,3 @@ | ||
command = command.trim(); | ||
command = command_parser.command_strip_env(command); | ||
if (command.startsWith(prefix)) { | ||
@@ -38,2 +53,15 @@ prefixCommands.push(command); | ||
command_strip_env: function(command) { | ||
var result = []; | ||
var prefix = true; | ||
parser.words(command).forEach(function(word) { | ||
if (prefix && word.match(/.*[^\\]=.*/)) { | ||
return; | ||
} | ||
prefix = false; | ||
result.push(word); | ||
}); | ||
return result.join(' '); | ||
}, | ||
command_has_part: function(command, commandPart) { | ||
@@ -40,0 +68,0 @@ return command.match(/\S+/g).some(function(part) { |
@@ -260,2 +260,7 @@ 'use strict'; | ||
break; | ||
case 'shell': | ||
checks.is_valid_shell(args).forEach(function(item) { | ||
items.push(messages.build(state.rules, item, line)); | ||
}); | ||
break; | ||
default: | ||
@@ -262,0 +267,0 @@ items.push(messages.build(state.rules, 'invalid_command', line)); |
@@ -1,2 +0,1 @@ | ||
var reference = require('./reference'); | ||
@@ -16,12 +15,12 @@ | ||
if (name in rules) { | ||
if (!this.parseBool(rules[name])) { | ||
if (!messages.parseBool(rules[name])) { | ||
return null; | ||
} | ||
} | ||
var message = reference[name]; | ||
if (!message) { | ||
message = { | ||
title: name, | ||
description: 'No description for message' | ||
}; | ||
var message = {}; | ||
if (name in reference) { | ||
Object.assign(message, reference[name]); | ||
} else { | ||
message.title = name; | ||
message.description = 'No description for message'; | ||
} | ||
@@ -32,3 +31,3 @@ | ||
return message; | ||
}, | ||
} | ||
}; |
{ | ||
"name": "dockerfilelint", | ||
"version": "1.1.2", | ||
"version": "1.1.3", | ||
"description": "A linter for Dockerfiles to find bugs and encourage best practices", | ||
@@ -34,3 +34,3 @@ "main": "./lib/index.js", | ||
"lodash": "^4.3.0", | ||
"yargs": "^3.32.0" | ||
"yargs": "^6.6.0" | ||
}, | ||
@@ -40,8 +40,8 @@ "devDependencies": { | ||
"coveralls": "^2.11.6", | ||
"eslint": "^1.10.3", | ||
"eslint": "^3.2.2", | ||
"eslint-config-defaults": "^9.0.0", | ||
"mocha": "^2.4.5", | ||
"nyc": "^5.6.0", | ||
"standard-version": "^2.3.0" | ||
"nyc": "^10.1.2", | ||
"mocha": "^3.0.0", | ||
"standard-version": "^4.0.0" | ||
} | ||
} |
# Linter and validator for Dockerfile | ||
[![Coverage Status](https://coveralls.io/repos/github/replicatedhq/dockerfilelint/badge.svg?branch=master)](https://coveralls.io/github/replicatedhq/dockerfilelint?branch=master) | ||
[![Build Status](https://travis-ci.org/replicatedhq/dockerfilelint.svg?branch=master)](https://travis-ci.org/replicatedhq/dockerfilelint.svg?branch=master) | ||
[![Build Status](https://travis-ci.org/replicatedhq/dockerfilelint.svg?branch=master)](https://travis-ci.org/replicatedhq/dockerfilelint) | ||
`Dockerfilelint` is an npm module that analyzes a Dockerfile and looks for common traps, mistakes and helps enforce best practices: | ||
`Dockerfilelint` is an node module that analyzes a Dockerfile and looks for common traps, mistakes and helps enforce best practices: | ||
## Testing | ||
Start unit tests with `npm test` | ||
Start unit tests with `npm test` or `yarn run test` | ||
@@ -58,3 +58,3 @@ ## Running | ||
```shell | ||
sudo docker run -v `pwd`/Dockerfile:/Dockerfile dockerfilelint /Dockerfile | ||
docker run -v `pwd`/Dockerfile:/Dockerfile replicated/dockerfilelint /Dockerfile | ||
``` | ||
@@ -61,0 +61,0 @@ |
@@ -24,6 +24,14 @@ var expect = require('chai').expect | ||
it("validates label command in key=value format", function(){ | ||
expect(checks.label_format("")).to.be.empty; | ||
expect(checks.label_format("key=value")).to.be.empty; | ||
expect(checks.label_format("key=value key=value")).to.be.empty; | ||
expect(checks.label_format("namespace.key=value")).to.be.empty; | ||
expect(checks.label_format("key=\"value value\"")).to.be.empty; | ||
expect(checks.label_format("key=value value")).to.have.length(1); | ||
expect(checks.label_format("key key=value")).to.have.length(1); | ||
expect(checks.label_format("key=value\\ value")).to.be.empty; | ||
expect(checks.label_format("key=")).to.be.empty; | ||
expect(checks.label_format("key= ")).to.be.empty; | ||
expect(checks.label_format("key")).to.have.length(1); | ||
expect(checks.label_format("key value")).to.have.length(2); | ||
expect(checks.label_format("key value")).to.have.length(1); | ||
}); | ||
@@ -30,0 +38,0 @@ }); |
@@ -101,3 +101,3 @@ 'use strict'; | ||
expect(fileReport.uniqueIssues).to.equal(3); | ||
expect(fileReport.contentArray).to.have.length(34); | ||
expect(fileReport.contentArray).to.have.length(40); | ||
expect(fileReport.itemsByLine).to.deep.equal({ | ||
@@ -130,3 +130,3 @@ '5': [ items[0] ], | ||
expect(fileReport.uniqueIssues).to.equal(1); | ||
expect(fileReport.contentArray).to.have.length(34); | ||
expect(fileReport.contentArray).to.have.length(40); | ||
expect(fileReport.itemsByLine).to.deep.equal({ | ||
@@ -176,3 +176,3 @@ '6': [ items[0] ] | ||
expect(file2Report.uniqueIssues).to.equal(2); | ||
expect(file2Report.contentArray).to.have.length(34); | ||
expect(file2Report.contentArray).to.have.length(40); | ||
expect(file2Report.itemsByLine).to.deep.equal({ | ||
@@ -250,3 +250,3 @@ '5': [ file2Items[0] ], | ||
category: 'Deprecation', | ||
line: 21 | ||
line: 25 | ||
} | ||
@@ -276,3 +276,3 @@ ]; | ||
'', | ||
'Line 21: ' + chalk.magenta('EXPOSE 80:80'), | ||
'Line 25: ' + chalk.magenta('EXPOSE 80:80'), | ||
'Issue Category Title Description', | ||
@@ -279,0 +279,0 @@ ' ' + chalk.red('4') + ' ' + chalk.red.inverse('Deprecation') + ' ' + chalk.red('Expose Only') + ' ' + chalk.gray('Using `EXPOSE` to specify a host port is not allowed.'), |
@@ -67,2 +67,23 @@ var expect = require('chai').expect | ||
describe("#shell", function() { | ||
it("validates the shell command is accepted when entered correctly", function() { | ||
expect(dockerfilelint.run('./test/examples', fs.readFileSync('./test/examples/Dockerfile.shell.pass', 'UTF-8'))).to.be.empty; | ||
}); | ||
it("validates the shell command detects invalid shell commands", function() { | ||
var expected = [ | ||
{ title: 'Invalid Argument Format', | ||
line: 4, | ||
rule: 'invalid_format'} | ||
]; | ||
var result = dockerfilelint.run('./test/examples', fs.readFileSync('./test/examples/Dockerfile.shell.fail', 'UTF-8')); | ||
_.forEach(result, function(r) { | ||
delete r['description']; | ||
delete r['category']; | ||
}); | ||
expect(result).to.have.length(expected.length); | ||
expect(result).to.deep.equal(expected); | ||
}); | ||
}); | ||
describe("#misc", function(){ | ||
@@ -73,6 +94,6 @@ it("validates the misc Dockerfile have the exact right issues reported", function(){ | ||
rule: 'from_first', | ||
line: 6 }, | ||
line: 4 }, | ||
{ title: 'First Command Must Be FROM', | ||
rule: 'from_first', | ||
line: 6 }, | ||
line: 5 }, | ||
{ title: 'Base Image Missing Tag', | ||
@@ -107,3 +128,3 @@ rule: 'missing_tag', | ||
rule: 'apt-get_missing_param', | ||
line: 14 }, | ||
line: 13 }, | ||
{ title: '`apt-get upgrade` Is Not Allowed', | ||
@@ -129,33 +150,30 @@ rule: 'apt-get-upgrade', | ||
rule: 'apkadd-missing_nocache_or_updaterm', | ||
line: 17 }, | ||
line: 21 }, | ||
{ title: 'Consider `--virtual` when using apk add and del together in a command.', | ||
rule: 'apkadd-missing-virtual', | ||
line: 18 }, | ||
line: 22 }, | ||
{ title: 'Invalid Port Exposed', | ||
rule: 'invalid_port', | ||
line: 20 }, | ||
line: 24 }, | ||
{ title: 'Expose Only Container Port', | ||
rule: 'expose_host_port', | ||
line: 21 }, | ||
line: 25 }, | ||
{ title: 'Invalid Argument Format', | ||
rule: 'invalid_format', | ||
line: 23 }, | ||
line: 27 }, | ||
{ title: 'Label Is Invalid', | ||
rule: 'label_invalid', | ||
line: 24 }, | ||
{ title: 'Label Is Invalid', | ||
rule: 'label_invalid', | ||
line: 24 }, | ||
line: 29 }, | ||
{ title: 'Extra Arguments', | ||
rule: 'extra_args', | ||
line: 26 }, | ||
line: 31 }, | ||
{ title: 'Invalid WORKDIR', | ||
rule: 'invalid_workdir', | ||
line: 27 }, | ||
line: 32 }, | ||
{ title: 'Invalid ADD Source', | ||
rule: 'add_src_invalid', | ||
line: 31 }, | ||
line: 36 }, | ||
{ title: 'Invalid ADD Destination', | ||
rule: 'add_dest_invalid', | ||
line: 31 } | ||
line: 36 } | ||
]; | ||
@@ -162,0 +180,0 @@ |
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
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
176916
44
1680
+ Addedcamelcase@3.0.0(transitive)
+ Addederror-ex@1.3.2(transitive)
+ Addedfind-up@1.1.2(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedget-caller-file@1.0.3(transitive)
+ Addedgraceful-fs@4.2.11(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedhosted-git-info@2.8.9(transitive)
+ Addedis-arrayish@0.2.1(transitive)
+ Addedis-core-module@2.16.1(transitive)
+ Addedis-utf8@0.2.1(transitive)
+ Addedload-json-file@1.1.0(transitive)
+ Addednormalize-package-data@2.5.0(transitive)
+ Addedparse-json@2.2.0(transitive)
+ Addedpath-exists@2.1.0(transitive)
+ Addedpath-parse@1.0.7(transitive)
+ Addedpath-type@1.1.0(transitive)
+ Addedpify@2.3.0(transitive)
+ Addedpinkie@2.0.4(transitive)
+ Addedpinkie-promise@2.0.1(transitive)
+ Addedread-pkg@1.1.0(transitive)
+ Addedread-pkg-up@1.0.1(transitive)
+ Addedrequire-directory@2.1.1(transitive)
+ Addedrequire-main-filename@1.0.1(transitive)
+ Addedresolve@1.22.10(transitive)
+ Addedsemver@5.7.2(transitive)
+ Addedset-blocking@2.0.0(transitive)
+ Addedspdx-correct@3.2.0(transitive)
+ Addedspdx-exceptions@2.5.0(transitive)
+ Addedspdx-expression-parse@3.0.1(transitive)
+ Addedspdx-license-ids@3.0.20(transitive)
+ Addedstrip-bom@2.0.0(transitive)
+ Addedsupports-preserve-symlinks-flag@1.0.0(transitive)
+ Addedvalidate-npm-package-license@3.0.4(transitive)
+ Addedwhich-module@1.0.0(transitive)
+ Addedyargs@6.6.0(transitive)
+ Addedyargs-parser@4.2.1(transitive)
- Removedcamelcase@2.1.1(transitive)
- Removedwindow-size@0.1.4(transitive)
- Removedyargs@3.32.0(transitive)
Updatedyargs@^6.6.0