Created
July 10, 2012 01:31
-
-
Save zaach/3080442 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
/* | |
* This module can verify that packages installed during development are | |
* identical to those installed during deployment. The standard npm shrinkwrap | |
* only ensures that package versions are the same, but does not verify contents. | |
* This module checks the shasum of the package tarballs downloaded by npm during | |
* development and deployment to ensure they are the same. | |
* | |
* Usage: | |
* 1) Install you packages | |
* 2) Generate shrinkwrap | |
* 3) Generate a sealed shrinkwrap file (using this module) | |
* 4) Deploy code and install packages | |
* 5) Check sealed shrinkwrap against installed packages | |
* during deployment (after performing `npm install`). | |
* */ | |
const crypto = require('crypto'); | |
const fs = require('fs'); | |
const path = require('path'); | |
const CACHE_DIR = process.env['HOME'] + '/.npm'; | |
// generate shasums | |
function hashFile (filename, cb) { | |
var shasum = crypto.createHash('sha256'); | |
var s = fs.ReadStream(filename); | |
s.on('data', function(d) { | |
shasum.update(d); | |
}); | |
s.on('end', function() { | |
var d = shasum.digest('hex'); | |
if (cb) cb(null, d); | |
}); | |
} | |
// load (sealed) shrinkwrap file | |
function loadWrap (file) { | |
return JSON.parse(fs.readFileSync(path.resolve(file), "utf8")); | |
} | |
// Generate a shrinkseal file | |
// packageDir is the directory of the package you want to generate a shrinkseal file for | |
// there should be a shrinkwrap file in the directory root | |
// cacheDir is the directory where the dependency packages are cached | |
function generateSeal (shrinkwrapFile, cacheDir, cb) { | |
var wrap = loadWrap(shrinkwrapFile || 'npm-shrinkwrap.json'); | |
traverseWrap(wrap, cacheDir, | |
function (err, name, dep, d) { | |
if (err) throw err; | |
dep.shasum = d; | |
}, function (err, wrap) { | |
if (err) throw err; | |
fs.writeFile('sealed-npm-shrinkwrap.json',JSON.stringify(wrap, null, ' '), function (err) { | |
if (err) throw err; | |
}); | |
}); | |
} | |
// Check that the sealed shrinkwrap corresponds to the currently installed modules | |
// packageDir is the directory of the package you want to generate a shrinkseal file for | |
// there should be a shrinkwrap file in the directory root | |
// cacheDir is the directory where the dependency packages are cached | |
function checkSeal (sealedwrapFile, cacheDir, cb) { | |
var sealed = loadWrap(sealedwrapFile || 'sealed-npm-shrinkwrap.json'); | |
var errors = []; | |
traverseWrap(sealed, cacheDir, | |
function (err, name, dep, d) { | |
if (err) throw err; | |
if (dep.shasum !== d) { | |
errors.push({dep: name + ' ' + dep.version, expected: dep.shasum, actual: d}); | |
} | |
}, function (err, wrap) { | |
if (err) throw err; | |
if (errors.length) { | |
console.error(JSON.stringify(errors, null, ' ')); | |
process.exit(1); | |
} | |
}); | |
} | |
function traverseWrap (wrap, cacheDir, hashCB, endCB) { | |
var toHash = 0; | |
Object.keys(wrap.dependencies).forEach(function (depName) { | |
_traverseWrap(depName, wrap.dependencies[depName]); | |
}); | |
function _traverseWrap (name, dep) { | |
toHash++; | |
hashFile(path.resolve(path.join(cacheDir, name, dep.version, "package.tgz")), function (err, d) { | |
hashCB(err, name, dep, d); | |
if (--toHash === 0) { | |
endCB(err, wrap); | |
} | |
}); | |
if (dep.dependencies) { | |
Object.keys(dep.dependencies).forEach(function (depName) { | |
_traverseWrap(depName, dep.dependencies[depName]); | |
}); | |
} | |
} | |
} | |
exports.generateSeal = generateSeal; | |
exports.checkSeal = checkSeal; | |
//generateSeal(process.argv[2], process.argv[3] || CACHE_DIR); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment