Skip to content

Commit 6c76c9e

Browse files
committedJun 15, 2020
Fixes missing shell escape for git commit message
1 parent 04df60b commit 6c76c9e

File tree

2 files changed

+141
-100
lines changed

2 files changed

+141
-100
lines changed
 

‎lib/git.js

+37-28
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,71 @@
1-
var contra = require('contra'),
2-
path = require('path'),
3-
fUtils = require('./files'),
4-
cp = require('child_process');
5-
6-
var gitApp = 'git', gitExtra = { env: process.env };
1+
var contra = require("contra"),
2+
path = require("path"),
3+
fUtils = require("./files"),
4+
cp = require("child_process");
75

6+
var gitApp = "git",
7+
gitExtra = { env: process.env };
88

99
var escapeQuotes = function (str) {
10-
if (typeof str === 'string') {
11-
return str.replace(/(["$`\\])/g, '\\$1');
10+
if (typeof str === "string") {
11+
return '"' + str.replace(/(["'$`\\])/g, "\\$1") + '"';
1212
} else {
1313
return str;
1414
}
1515
};
1616

1717
module.exports.isRepositoryClean = function (callback) {
18-
cp.exec(gitApp + ' ' + [ 'ls-files', '-m' ].join(' '), gitExtra, function (er, stdout, stderr) {
18+
cp.exec(gitApp + " " + ["ls-files", "-m"].join(" "), gitExtra, function (
19+
er,
20+
stdout,
21+
stderr
22+
) {
1923
// makeCommit parly inspired and taken from NPM version module
20-
var lines = stdout.trim().split('\n').filter(function (line) {
21-
var file = path.basename(line.replace(/.{1,2}\s+/, ''));
22-
return line.trim() && !line.match(/^\?\? /) && !fUtils.isPackageFile(line);
23-
}).map(function (line) {
24-
return line.trim()
25-
});
24+
var lines = stdout
25+
.trim()
26+
.split("\n")
27+
.filter(function (line) {
28+
var file = path.basename(line.replace(/.{1,2}\s+/, ""));
29+
return (
30+
line.trim() && !line.match(/^\?\? /) && !fUtils.isPackageFile(line)
31+
);
32+
})
33+
.map(function (line) {
34+
return line.trim();
35+
});
2636

2737
if (lines.length) {
28-
return callback(new Error('Git working directory not clean.\n'+lines.join('\n')));
38+
return callback(
39+
new Error("Git working directory not clean.\n" + lines.join("\n"))
40+
);
2941
}
3042
return callback();
3143
});
3244
};
3345

3446
module.exports.checkout = function (callback) {
35-
cp.exec(gitApp + ' checkout -- .', gitExtra, callback);
47+
cp.exec(gitApp + " checkout -- .", gitExtra, callback);
3648
};
3749

3850
module.exports.commit = function (files, message, newVer, tagName, callback) {
39-
message = message.replace('%s', newVer).replace('"', '').replace("'", '');
40-
files = files.map(function (file) {
41-
return '"' + escapeQuotes(file) + '"';
42-
}).join(' ');
51+
message = escapeQuotes(message.replace("%s", newVer));
52+
files = files.map(escapeQuotes).join(" ");
4353
var functionSeries = [
4454
function (done) {
45-
cp.exec(gitApp + ' add ' + files, gitExtra, done);
55+
cp.exec(gitApp + " add " + files, gitExtra, done);
4656
},
4757

4858
function (done) {
49-
cp.exec([gitApp, 'commit', '-m', '"' + message + '"'].join(' '), gitExtra, done);
59+
cp.exec([gitApp, "commit", "-m", message].join(" "), gitExtra, done);
5060
},
5161

5262
function (done) {
5363
cp.exec(
54-
[
55-
gitApp, 'tag', '-a', tagName, '-m', '"' + message + '"'
56-
].join(' '),
57-
gitExtra, done
64+
[gitApp, "tag", "-a", tagName, "-m", message].join(" "),
65+
gitExtra,
66+
done
5867
);
59-
}
68+
},
6069
];
6170
contra.series(functionSeries, callback);
6271
};

‎tests/git_test.js

+104-72
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
var version = require('../'),
2-
assert = require('assert'),
3-
fs = require('fs'),
4-
vinylFs = require('vinyl-fs'),
5-
path = require('path'),
6-
cp = require('child_process'),
7-
File = require('vinyl'),
8-
through = require('through2'),
9-
fUtil = require('../lib/files'),
10-
git = require('../lib/git');
11-
12-
describe('git', function () {
13-
var filename = 'package.json';
14-
var expectedPath = path.join(__dirname, './fixtures/', filename);
1+
var version = require("../"),
2+
assert = require("assert"),
3+
fs = require("fs"),
4+
vinylFs = require("vinyl-fs"),
5+
path = require("path"),
6+
cp = require("child_process"),
7+
File = require("vinyl"),
8+
through = require("through2"),
9+
fUtil = require("../lib/files"),
10+
git = require("../lib/git");
11+
12+
describe("git", function () {
13+
var filename = "package.json";
14+
var expectedPath = path.join(__dirname, "./fixtures/", filename);
1515
var expectedContent = fs.readFileSync(expectedPath);
1616

1717
var original = fUtil.loadFiles;
@@ -21,19 +21,19 @@ describe('git', function () {
2121
var originalCommit = git.commit;
2222
var originalCheckout = git.checkout;
2323

24-
before(function () {
24+
before(function () {
2525
vinylFs.dest = function () {
2626
return through.obj(function (file, enc, next) {
2727
this.push(file);
2828
next();
2929
});
30-
}
30+
};
3131

3232
var expectedFile = new File({
3333
base: __dirname,
3434
cwd: __dirname,
3535
path: expectedPath,
36-
contents: expectedContent
36+
contents: expectedContent,
3737
});
3838

3939
fUtil.loadFiles = function () {
@@ -57,130 +57,162 @@ describe('git', function () {
5757
cp.exec = exec;
5858
});
5959

60-
describe('#Update()', function(){
61-
it('should return error on unclean git repository when commit is given', function (done) {
60+
describe("#Update()", function () {
61+
it("should return error on unclean git repository when commit is given", function (done) {
6262
git.isRepositoryClean = function (cb) {
63-
return cb(new Error('Not clean'));
63+
return cb(new Error("Not clean"));
6464
};
6565

66-
version.update({
67-
version: '1.0.0',
68-
commitMessage: 'Message'
69-
}, function (err, data) {
70-
assert.ok(err);
71-
assert.equal(err.message, 'Not clean', 'Error message should be set by isRepositoryClean');
66+
version.update(
67+
{
68+
version: "1.0.0",
69+
commitMessage: "Message",
70+
},
71+
function (err, data) {
72+
assert.ok(err);
73+
assert.equal(
74+
err.message,
75+
"Not clean",
76+
"Error message should be set by isRepositoryClean"
77+
);
78+
79+
done();
80+
}
81+
);
82+
});
7283

84+
it("should return NOT error on unclean git repository when no commit message is given", function (done) {
85+
git.isRepositoryClean = function (cb) {
86+
return cb(new Error("Not clean"));
87+
};
88+
89+
version.update("1.0.0", function (err, data) {
90+
assert.ifError(err);
7391
done();
7492
});
7593
});
7694

77-
it('should return NOT error on unclean git repository when no commit message is given', function (done) {
95+
it("should sanitize commit message", function (done) {
7896
git.isRepositoryClean = function (cb) {
79-
return cb(new Error('Not clean'));
97+
return cb(null);
8098
};
8199

82-
version.update('1.0.0', function (err, data) {
83-
assert.ifError(err);
100+
cp.exec = function (cmd, extra, cb) {
101+
if (cmd.indexOf("-a") === -1) return cb(null);
102+
assert.equal('git tag -a v1.0.0 -m "Message \\`touch file\\`"', cmd);
84103
done();
104+
};
105+
106+
version.update({
107+
version: "1.0.0",
108+
commitMessage: "Message `touch file`",
85109
});
86110
});
87111

88-
it('should get updated version sent to commit when commit message is given', function (done) {
112+
it("should get updated version sent to commit when commit message is given", function (done) {
89113
git.isRepositoryClean = function (cb) {
90114
return cb(null);
91115
};
92116

93117
git.commit = function (files, message, newVer, tagName, callback) {
94-
assert.equal(message, 'Message');
95-
assert.equal(newVer, '1.0.0');
118+
assert.equal(message, "Message");
119+
assert.equal(newVer, "1.0.0");
96120
assert.equal(files[0], expectedPath);
97-
assert.equal(tagName, 'v1.0.0');
121+
assert.equal(tagName, "v1.0.0");
98122
return callback(null);
99123
};
100124

101-
version.update({
102-
version: '1.0.0',
103-
commitMessage: 'Message'
104-
}, function (err, data) {
105-
assert.ifError(err);
106-
done();
107-
});
125+
version.update(
126+
{
127+
version: "1.0.0",
128+
commitMessage: "Message",
129+
},
130+
function (err, data) {
131+
assert.ifError(err);
132+
done();
133+
}
134+
);
108135
});
109136

110-
it('should be able to override tagName', function (done) {
137+
it("should be able to override tagName", function (done) {
111138
git.isRepositoryClean = function (cb) {
112139
return cb(null);
113140
};
114141

115142
git.commit = function (files, message, newVer, tagName, callback) {
116-
assert.equal(tagName, 'v1.0.0-src');
143+
assert.equal(tagName, "v1.0.0-src");
117144
return callback(null);
118145
};
119146

120-
version.update({
121-
version: '1.0.0',
122-
commitMessage: 'Message',
123-
tagName: 'v%s-src'
124-
}, function (err, data) {
125-
assert.ifError(err);
126-
done();
127-
});
147+
version.update(
148+
{
149+
version: "1.0.0",
150+
commitMessage: "Message",
151+
tagName: "v%s-src",
152+
},
153+
function (err, data) {
154+
assert.ifError(err);
155+
done();
156+
}
157+
);
128158
});
129159

130-
it('should get flag defining if v-prefix should be used or not', function (done) {
160+
it("should get flag defining if v-prefix should be used or not", function (done) {
131161
git.isRepositoryClean = function (cb) {
132162
return cb(null);
133163
};
134164

135165
git.commit = function (files, message, newVer, noPrefix, callback) {
136-
assert.ok(noPrefix, 'No prefix should be true');
166+
assert.ok(noPrefix, "No prefix should be true");
137167
return callback(null);
138168
};
139169

140-
version.update({
141-
version: '1.0.0',
142-
commitMessage: 'Message',
143-
noPrefix: true
144-
}, function (err, data) {
145-
assert.ifError(err);
146-
done();
147-
});
170+
version.update(
171+
{
172+
version: "1.0.0",
173+
commitMessage: "Message",
174+
noPrefix: true,
175+
},
176+
function (err, data) {
177+
assert.ifError(err);
178+
done();
179+
}
180+
);
148181
});
149182

150-
it('should make tag with v-prefix per default', function (done) {
183+
it("should make tag with v-prefix per default", function (done) {
151184
git.isRepositoryClean = function (cb) {
152185
return cb(null);
153186
};
154187

155188
cp.exec = function (cmd, extra, cb) {
156-
if (cmd.indexOf('-a') === -1) return cb(null);
189+
if (cmd.indexOf("-a") === -1) return cb(null);
157190
assert.equal('git tag -a v1.0.0 -m "Message"', cmd);
158191
done();
159192
};
160193

161194
version.update({
162-
version: '1.0.0',
163-
commitMessage: 'Message'
195+
version: "1.0.0",
196+
commitMessage: "Message",
164197
});
165198
});
166199

167-
it('should make tag without v-prefix if specified', function (done) {
200+
it("should make tag without v-prefix if specified", function (done) {
168201
git.isRepositoryClean = function (cb) {
169202
return cb(null);
170203
};
171204

172205
cp.exec = function (cmd, extra, cb) {
173-
if (cmd.indexOf('-a') === -1) return cb(null);
206+
if (cmd.indexOf("-a") === -1) return cb(null);
174207
assert.equal('git tag -a 1.0.0 -m "Message"', cmd);
175208
done();
176209
};
177210

178211
version.update({
179-
version: '1.0.0',
180-
commitMessage: 'Message',
181-
noPrefix: true
212+
version: "1.0.0",
213+
commitMessage: "Message",
214+
noPrefix: true,
182215
});
183216
});
184217
});
185-
186-
});
218+
});

0 commit comments

Comments
 (0)
Please sign in to comment.