Skip to content

Commit

Permalink
Add validation of checksums
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasrockhu committed Apr 16, 2021
1 parent 6e56f7a commit 040839f
Show file tree
Hide file tree
Showing 4 changed files with 305 additions and 39 deletions.
243 changes: 208 additions & 35 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13152,62 +13152,119 @@ module.exports = {"$id":"log.json#","$schema":"http://json-schema.org/draft-06/s

"use strict";

var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
exports.__esModule = true;
var core = __webpack_require__(470);
var exec = __webpack_require__(986);
var fs = __webpack_require__(747);
var request = __webpack_require__(335);
var buildExec_1 = __webpack_require__(983);
var validate_1 = __webpack_require__(743);
var failCi;
try {
request({
json: false,
maxAttempts: 10,
timeout: 3000,
url: 'https://codecov.io/bash',
}, function (error, response, body) {
var _a = buildExec_1["default"](), execArgs = _a.execArgs, options = _a.options, filepath = _a.filepath, failCi = _a.failCi;
try {
if (error && failCi) {
throw error;
}
else if (error) {
core.warning("Codecov warning: " + error.message);
}
fs.writeFile(filepath, body, function (err) {
if (err && failCi) {
throw err;
}
else if (err) {
core.warning("Codecov warning: " + err.message);
}
exec.exec('bash', execArgs, options)["catch"](function (err) {
if (failCi) {
core.setFailed("Codecov failed with the following error: " + err.message);
}, function (error, response, body) { return __awaiter(void 0, void 0, void 0, function () {
var _a, execArgs, options, filepath, failCi, isValid, failure, error_1;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_a = buildExec_1["default"](), execArgs = _a.execArgs, options = _a.options, filepath = _a.filepath, failCi = _a.failCi;
_b.label = 1;
case 1:
_b.trys.push([1, 3, , 4]);
return [4 /*yield*/, validate_1["default"](body)];
case 2:
isValid = _b.sent();
if (!isValid) {
failure = 'Codecov failure: ' +
'Bash script checksums do not match published values. ' +
'Please contact [email protected] immediately.';
core.setFailed(failure);
throw new Error(failure);
}
else {
core.warning("Codecov warning: " + err.message);
if (error && failCi) {
throw error;
}
})
.then(function () {
unlinkFile();
});
var unlinkFile = function () {
fs.unlink(filepath, function (err) {
else if (error) {
core.warning("Codecov warning: " + error.message);
}
fs.writeFile(filepath, body, function (err) {
if (err && failCi) {
throw err;
}
else if (err) {
core.warning("Codecov warning: " + err.message);
}
exec.exec('bash', execArgs, options)["catch"](function (err) {
if (failCi) {
core.setFailed("Codecov failed with the following error: " + err.message);
}
else {
core.warning("Codecov warning: " + err.message);
}
})
.then(function () {
unlinkFile();
});
var unlinkFile = function () {
fs.unlink(filepath, function (err) {
if (err && failCi) {
throw err;
}
else if (err) {
core.warning("Codecov warning: " + err.message);
}
});
};
});
};
});
}
catch (error) {
core.setFailed("Codecov failed with the following error: " + error.message);
}
});
return [3 /*break*/, 4];
case 3:
error_1 = _b.sent();
core.setFailed("Codecov failed with the following error: " + error_1.message);
return [3 /*break*/, 4];
case 4: return [2 /*return*/];
}
});
}); });
}
catch (error) {
if (failCi) {
Expand Down Expand Up @@ -49116,7 +49173,123 @@ module.exports = function (data, opts) {


/***/ }),
/* 743 */,
/* 743 */
/***/ (function(__unusedmodule, exports, __webpack_require__) {

"use strict";

var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
exports.__esModule = true;
var crypto = __webpack_require__(417);
var core = __webpack_require__(470);
var request = __webpack_require__(335);
var validateUploader = function (body) { return __awaiter(void 0, void 0, void 0, function () {
var version, _i, _a, i, publicChecksum, uploaderChecksum;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
version = getVersion(body);
if (version === null) {
core.warning('Codecov could not identify the bash uploader version.');
return [2 /*return*/, false];
}
_i = 0, _a = [1, 256, 512];
_b.label = 1;
case 1:
if (!(_i < _a.length)) return [3 /*break*/, 4];
i = _a[_i];
return [4 /*yield*/, retrieveChecksum(version, i)];
case 2:
publicChecksum = _b.sent();
uploaderChecksum = calculateChecksum(body, i);
if (uploaderChecksum !== publicChecksum.trim()) {
core.warning("Codecov " + version + " checksums for SHA1 failed to match.\n" +
("Public checksum: " + publicChecksum) +
("Uploader checksum: " + uploaderChecksum));
return [2 /*return*/, false];
}
_b.label = 3;
case 3:
_i++;
return [3 /*break*/, 1];
case 4: return [2 /*return*/, true];
}
});
}); };
var retrieveChecksum = function (version, encryption) { return __awaiter(void 0, void 0, void 0, function () {
var url, response, err_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
url = "https://raw.githubusercontent.com/codecov/codecov-bash/" + version + "/SHA" + encryption + "SUM";
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, request({
maxAttempts: 10,
timeout: 3000,
url: url,
})];
case 2:
response = _a.sent();
return [2 /*return*/, response.body];
case 3:
err_1 = _a.sent();
core.warning("Codecov could not retrieve checksum SHA" + encryption + " at " + url);
return [2 /*return*/, false];
case 4: return [2 /*return*/];
}
});
}); };
var calculateChecksum = function (body, i) {
var shasum = crypto.createHash("sha" + i);
shasum.update(body);
return shasum.digest('hex') + " codecov";
};
var getVersion = function (body) {
var regex = /VERSION="(.*)+"/g;
var match = regex.exec(body);
return match ? match[1] : null;
};
exports["default"] = validateUploader;


/***/ }),
/* 744 */
/***/ (function(module) {

Expand Down
15 changes: 11 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const fs = require('fs');
const request = require('requestretry');

import buildExec from './buildExec';
import validateUploader from './validate';

let failCi;
try {
Expand All @@ -13,13 +14,19 @@ try {
maxAttempts: 10,
timeout: 3000,
url: 'https://codecov.io/bash',
}, (error, response, body) => {
const bashVersion = body.match('VERSION=\"(.*)\"');
conosole.log(bashVersion);

}, async (error, response, body) => {
const {execArgs, options, filepath, failCi} = buildExec();

try {
const isValid = await validateUploader(body);
if (!isValid) {
const failure = 'Codecov failure: ' +
'Bash script checksums do not match published values. ' +
'Please contact [email protected] immediately.';
core.setFailed(failure);
throw new Error(failure);
}

if (error && failCi) {
throw error;
} else if (error) {
Expand Down
28 changes: 28 additions & 0 deletions src/validate.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import validateUploader from './validate';

const request = require('requestretry');

const bashScript = (async () => {
try {
const script = await request({
json: false,
maxAttempts: 10,
timeout: 3000,
url: 'https://codecov.io/bash',
});
return script.body;
} catch (err) {
throw err;
}
});

test('validChecksums', async () => {
const valid = await validateUploader(await bashScript());
expect(valid).toBeTruthy();
});

test('invalidChecksums', async () => {
const script = await bashScript();
const valid = await validateUploader(script.substring(0, script.length - 1));
expect(valid).toBeFalsy();
});
58 changes: 58 additions & 0 deletions src/validate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const crypto = require('crypto');

const core = require('@actions/core');

const request = require('requestretry');

const validateUploader = async (body) => {
const version = getVersion(body);
if (version === null) {
core.warning('Codecov could not identify the bash uploader version.');
return false;
}

for (const i of [1, 256, 512]) {
const publicChecksum = await retrieveChecksum(version, i);
const uploaderChecksum = calculateChecksum(body, i);
if (uploaderChecksum !== publicChecksum.trim()) {
core.warning(
`Codecov ${version} checksums for SHA1 failed to match.\n` +
`Public checksum: ${publicChecksum}` +
`Uploader checksum: ${uploaderChecksum}`,
);
return false;
}
}
return true;
};

const retrieveChecksum = async (version, encryption) => {
const url = `https://raw.githubusercontent.com/codecov/codecov-bash/${version}/SHA${encryption}SUM`;
try {
const response = await request({
maxAttempts: 10,
timeout: 3000,
url: url,
});
return response.body;
} catch (err) {
core.warning(
`Codecov could not retrieve checksum SHA${encryption} at ${url}`,
);
return false;
}
};

const calculateChecksum = (body, i) => {
const shasum = crypto.createHash(`sha${i}`);
shasum.update(body);
return `${shasum.digest('hex')} codecov`;
};

const getVersion = (body) => {
const regex = /VERSION="(.*)+"/g;
const match = regex.exec(body);
return match ? match[1] : null;
};

export default validateUploader;

0 comments on commit 040839f

Please sign in to comment.