The ValidateIntegrity class validates that package integrity hashes use SHA-512 algorithm for maximum security.
Creates a new integrity hash validator instance.
/**
* Creates a new integrity hash validator
* @param {Object} options - Validator configuration
* @param {Object} options.packages - Package object from parsed lockfile
* @throws {Error} If packages is not provided or not an object
*/
class ValidateIntegrity {
constructor(options: {
packages: Object;
});
}Requirements: The packages parameter must be an object (typically from ParseLockfile.parseSync().object). Throws an error if not provided or not an object.
Usage Examples:
const { ValidateIntegrity, ParseLockfile } = require('lockfile-lint-api');
// Parse lockfile first
const parser = new ParseLockfile({ lockfilePath: './package-lock.json' });
const lockfile = parser.parseSync();
// Create validator
const validator = new ValidateIntegrity({ packages: lockfile.object });Validates that all packages in the lockfile use SHA-512 integrity hashes.
/**
* Validates all packages use SHA-512 integrity hashes
* @param {Object} [options] - Validation options
* @param {string[]} [options.integrityExclude] - Array of package names to exclude from validation
* @returns {Object} Validation result with type ('success' or 'error') and errors array
* @throws {Error} If integrityExclude is provided but not an array
*/
validate(options?: {
integrityExclude?: string[];
}): {
type: 'success' | 'error';
errors: Array<{
message: string;
package: string;
}>;
}Behavior:
sha512 algorithmintegrity field are automatically skipped (e.g., git dependencies)integrityExclude list are skippedsha1, sha256)Integrity Hash Format:
npm integrity hashes follow the Subresource Integrity (SRI) format:
<algorithm>-<base64-hash>Examples:
sha512-ABC123... (recommended)sha256-ABC123... (weaker)sha1-ABC123... (weak, deprecated)Usage Examples:
const { ValidateIntegrity, ParseLockfile } = require('lockfile-lint-api');
// Basic usage - validate all packages
const parser = new ParseLockfile({ lockfilePath: './package-lock.json' });
const lockfile = parser.parseSync();
const validator = new ValidateIntegrity({ packages: lockfile.object });
const result = validator.validate();
if (result.type === 'success') {
console.log('All packages use SHA-512 integrity hashes');
} else {
console.error('Integrity validation failed:');
result.errors.forEach(error => {
console.error(` ${error.package}: ${error.message}`);
});
}Exclude Specific Packages:
const { ValidateIntegrity, ParseLockfile } = require('lockfile-lint-api');
const parser = new ParseLockfile({ lockfilePath: './package-lock.json' });
const lockfile = parser.parseSync();
const validator = new ValidateIntegrity({ packages: lockfile.object });
// Exclude legacy packages that can't be updated
const result = validator.validate({
integrityExclude: ['legacy-package', 'old-dependency', '@company/legacy-lib']
});
if (result.type === 'error') {
console.error('Non-excluded packages have weak integrity hashes:');
result.errors.forEach(error => console.error(error.message));
}CI/CD Integration:
const { ValidateIntegrity, ParseLockfile } = require('lockfile-lint-api');
function validateIntegrityInPipeline(lockfilePath) {
try {
const parser = new ParseLockfile({ lockfilePath });
const lockfile = parser.parseSync();
const validator = new ValidateIntegrity({ packages: lockfile.object });
const result = validator.validate();
if (result.type === 'error') {
console.error('Build failed: Weak integrity hashes detected!');
result.errors.forEach(error => {
console.error(` Package: ${error.package}`);
console.error(` ${error.message}`);
});
return false;
}
console.log('✓ All packages use strong SHA-512 integrity hashes');
return true;
} catch (error) {
console.error('Validation error:', error.message);
return false;
}
}
if (!validateIntegrityInPipeline('./package-lock.json')) {
process.exit(1);
}Validates a single package's integrity hash.
/**
* Validates a single package's integrity hash
* @param {string} packageName - Package key from the lockfile (e.g., 'lodash@4.17.21')
* @returns {boolean} True if package uses SHA-512 or has no integrity field, false otherwise
*/
validateSingle(packageName: string): boolean;Behavior:
true if the package's integrity hash uses sha512 algorithmtrue if the package has no integrity fieldfalse if the package uses a different hash algorithmUsage Examples:
const { ValidateIntegrity, ParseLockfile } = require('lockfile-lint-api');
const parser = new ParseLockfile({ lockfilePath: './package-lock.json' });
const lockfile = parser.parseSync();
const validator = new ValidateIntegrity({ packages: lockfile.object });
// Validate specific packages
const isLodashSecure = validator.validateSingle('lodash@4.17.21');
const isReactSecure = validator.validateSingle('react@18.2.0');
if (!isLodashSecure) {
console.error('lodash uses weak integrity hash');
}
// Check all critical packages
const criticalPackages = [
'express@4.18.2',
'jsonwebtoken@9.0.0',
'bcrypt@5.1.0'
];
criticalPackages.forEach(packageName => {
if (!validator.validateSingle(packageName)) {
console.error(`CRITICAL: ${packageName} uses weak integrity hash`);
process.exit(1);
}
});
console.log('All critical packages have strong integrity hashes');The validate() method returns a consistent result object:
interface IntegrityValidationResult {
type: 'success' | 'error';
errors: IntegrityValidationError[];
}
interface IntegrityValidationError {
message: string; // Detailed error message with expected and actual hash types
package: string; // Package name that failed validation
}Success Example:
{
type: 'success',
errors: []
}Error Example:
{
type: 'error',
errors: [
{
message: 'detected invalid integrity hash type for package: old-package@1.0.0\n expected: sha512\n actual: sha1-XYZ789...\n',
package: 'old-package@1.0.0'
}
]
}Integrity hash validation ensures package authenticity and prevents tampering:
Why SHA-512?
Security Audit Example:
const { ValidateIntegrity, ParseLockfile } = require('lockfile-lint-api');
function auditIntegrityHashes(lockfilePath) {
const parser = new ParseLockfile({ lockfilePath });
const lockfile = parser.parseSync();
const stats = {
total: 0,
withIntegrity: 0,
sha512: 0,
weak: []
};
for (const [packageName, metadata] of Object.entries(lockfile.object)) {
stats.total++;
if (metadata.integrity) {
stats.withIntegrity++;
const algorithm = metadata.integrity.split('-')[0];
if (algorithm === 'sha512') {
stats.sha512++;
} else {
stats.weak.push({
package: packageName,
algorithm: algorithm
});
}
}
}
console.log('Integrity Hash Audit Results:');
console.log(` Total packages: ${stats.total}`);
console.log(` With integrity: ${stats.withIntegrity}`);
console.log(` Using SHA-512: ${stats.sha512}`);
console.log(` Using weak hashes: ${stats.weak.length}`);
if (stats.weak.length > 0) {
console.log('\nPackages with weak hashes:');
stats.weak.forEach(({ package: pkg, algorithm }) => {
console.log(` ${pkg} (${algorithm})`);
});
}
return stats.weak.length === 0;
}
if (!auditIntegrityHashes('./package-lock.json')) {
console.error('\nAudit failed: Weak integrity hashes detected');
process.exit(1);
}The integrityExclude option allows excluding specific packages from validation:
Use Cases for Exclusion:
Exclusion Format:
Package names should match the prefix of the package key in the lockfile:
'lodash' matches 'lodash@4.17.21''@babel/core' matches '@babel/core@7.20.0'Usage Examples:
const { ValidateIntegrity, ParseLockfile } = require('lockfile-lint-api');
const parser = new ParseLockfile({ lockfilePath: './package-lock.json' });
const lockfile = parser.parseSync();
const validator = new ValidateIntegrity({ packages: lockfile.object });
// Exclude multiple packages
const result = validator.validate({
integrityExclude: [
'legacy-package',
'old-dependency',
'@company/legacy-lib',
'@types/old-types'
]
});
// Exclude all packages from a specific scope
const scopedExclusions = [
'@legacy/package-a',
'@legacy/package-b',
'@legacy/package-c'
];
const result2 = validator.validate({
integrityExclude: scopedExclusions
});Progressive Security Enforcement:
const { ValidateIntegrity, ParseLockfile } = require('lockfile-lint-api');
// Start with extensive exclusions, gradually reduce over time
const exclusionConfig = {
phase1: ['legacy-a', 'legacy-b', 'legacy-c', 'old-dep'], // Initial
phase2: ['legacy-a', 'legacy-b'], // After updates
phase3: ['legacy-a'], // Near completion
phase4: [] // Full enforcement
};
const currentPhase = process.env.SECURITY_PHASE || 'phase1';
const parser = new ParseLockfile({ lockfilePath: './package-lock.json' });
const lockfile = parser.parseSync();
const validator = new ValidateIntegrity({ packages: lockfile.object });
const result = validator.validate({
integrityExclude: exclusionConfig[currentPhase]
});
if (result.type === 'error') {
console.error(`Integrity validation failed (${currentPhase}):`);
result.errors.forEach(error => console.error(error.message));
process.exit(1);
}
console.log(`✓ Integrity validation passed (${currentPhase})`);Constructor Errors:
// Throws: 'expecting an object passed to validator constructor'
const validator = new ValidateIntegrity(); // Missing packages
const validator = new ValidateIntegrity({ packages: null }); // Invalid type
const validator = new ValidateIntegrity({ packages: [] }); // Array instead of objectValidation Errors:
const validator = new ValidateIntegrity({ packages: lockfile.object });
// Throws: 'excluded packages must be an array'
validator.validate({ integrityExclude: 'legacy-package' }); // String instead of array
validator.validate({ integrityExclude: { pkg: 'legacy' } }); // Object instead of array- and taking first part@ for version delimiter)integrity field are automatically skippedCombining integrity validation with other security checks:
const {
ParseLockfile,
ValidateIntegrity,
ValidateHttps,
ValidateHost,
ValidatePackageNames
} = require('lockfile-lint-api');
function comprehensiveSecurityValidation(lockfilePath) {
const parser = new ParseLockfile({ lockfilePath });
const lockfile = parser.parseSync();
const validations = [
{
name: 'HTTPS Protocol',
validator: new ValidateHttps({ packages: lockfile.object }),
validate: () => validator.validate()
},
{
name: 'Allowed Hosts',
validator: new ValidateHost({ packages: lockfile.object }),
validate: (v) => v.validate(['npm'])
},
{
name: 'Package Names',
validator: new ValidatePackageNames({ packages: lockfile.object }),
validate: (v) => v.validate()
},
{
name: 'Integrity Hashes',
validator: new ValidateIntegrity({ packages: lockfile.object }),
validate: (v) => v.validate({
integrityExclude: ['legacy-package']
})
}
];
let allPassed = true;
const allErrors = [];
validations.forEach(({ name, validator, validate }) => {
const result = validate(validator);
if (result.type === 'error') {
console.error(`\n✗ ${name} validation failed:`);
result.errors.forEach(error => {
console.error(` ${error.message}`);
allErrors.push({ validation: name, ...error });
});
allPassed = false;
} else {
console.log(`✓ ${name} validation passed`);
}
});
if (!allPassed) {
console.error(`\n${allErrors.length} total validation error(s) found`);
}
return allPassed;
}
if (!comprehensiveSecurityValidation('./package-lock.json')) {
console.error('\nLockfile security validation failed!');
process.exit(1);
}
console.log('\n✓ All security validations passed');| Algorithm | Status | Security Level | Use Case |
|---|---|---|---|
| SHA-1 | ⚠️ Deprecated | Very Weak | Never use |
| SHA-256 | ⚠️ Weak | Moderate | Avoid if possible |
| SHA-512 | ✓ Recommended | Strong | Use everywhere |
Migration Strategy:
If your lockfile contains packages with weak hashes:
npm update or yarn upgrade// Packages without integrity field are automatically skipped
{
'git-package@1.0.0': {
version: '1.0.0',
resolved: 'git+https://github.com/user/repo.git'
// No integrity field - automatically skipped
}
}// These will fail validation
integrity: 'sha1-ABC123...'
integrity: 'sha256-ABC123...'
// This will pass validation
integrity: 'sha512-ABC123...'// Exclusion matches by prefix
integrityExclude: ['lodash'] // Matches 'lodash@4.17.21', 'lodash@4.18.0', etc.
integrityExclude: ['@babel/core'] // Matches '@babel/core@7.20.0', '@babel/core@7.21.0', etc.