The ValidateScheme class validates that package URLs use whitelisted URI schemes (protocols).
Creates a new URI scheme validator instance.
/**
* Creates a new URI scheme 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 ValidateScheme {
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 { ValidateScheme, 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 ValidateScheme({ packages: lockfile.object });Validates that all packages in the lockfile use allowed URI schemes.
/**
* Validates all packages use allowed URI schemes
* @param {string[]} schemes - Array of allowed scheme strings (e.g., ['https:', 'http:'])
* @returns {Object} Validation result with type ('success' or 'error') and errors array
* @throws {Error} If schemes is not an array
*/
validate(schemes: string[]): {
type: 'success' | 'error';
errors: Array<{
message: string;
package: string;
}>;
}Scheme Format:
Schemes should include the trailing colon (:) character:
'https:', 'http:', 'git:', 'file:''https', 'http', 'git', 'file'Behavior:
resolved field are automatically skipped (e.g., local filesystem packages)Usage Examples:
const { ValidateScheme, ParseLockfile } = require('lockfile-lint-api');
// Allow only HTTPS
const parser = new ParseLockfile({ lockfilePath: './package-lock.json' });
const lockfile = parser.parseSync();
const validator = new ValidateScheme({ packages: lockfile.object });
const result1 = validator.validate(['https:']);
if (result1.type === 'success') {
console.log('All packages use HTTPS scheme');
} else {
console.error('Scheme validation failed:');
result1.errors.forEach(error => {
console.error(` ${error.package}: ${error.message}`);
});
}
// Allow both HTTPS and HTTP
const result2 = validator.validate(['https:', 'http:']);
// Allow Git schemes for development
const result3 = validator.validate(['https:', 'git:', 'git+ssh:']);
// Allow file:// URLs for local development
const result4 = validator.validate(['https:', 'file:']);CI/CD Integration Example:
const { ValidateScheme, ParseLockfile } = require('lockfile-lint-api');
function validateProductionSchemes(lockfilePath) {
try {
const parser = new ParseLockfile({ lockfilePath });
const lockfile = parser.parseSync();
const validator = new ValidateScheme({ packages: lockfile.object });
// Production: Only HTTPS allowed
const result = validator.validate(['https:']);
if (result.type === 'error') {
console.error('Production build failed: Invalid URI schemes detected!');
result.errors.forEach(error => {
console.error(` Package: ${error.package}`);
console.error(` ${error.message}`);
});
return false;
}
console.log('✓ All packages use secure HTTPS scheme');
return true;
} catch (error) {
console.error('Validation error:', error.message);
return false;
}
}
if (!validateProductionSchemes('./package-lock.json')) {
process.exit(1);
}Environment-Specific Validation:
const { ValidateScheme, ParseLockfile } = require('lockfile-lint-api');
function validateSchemesByEnvironment(lockfilePath) {
const parser = new ParseLockfile({ lockfilePath });
const lockfile = parser.parseSync();
const validator = new ValidateScheme({ packages: lockfile.object });
const env = process.env.NODE_ENV || 'development';
let allowedSchemes;
switch (env) {
case 'production':
// Production: Only HTTPS
allowedSchemes = ['https:'];
break;
case 'staging':
// Staging: HTTPS and HTTP
allowedSchemes = ['https:', 'http:'];
break;
case 'development':
// Development: Allow all common schemes
allowedSchemes = ['https:', 'http:', 'git:', 'git+ssh:', 'file:'];
break;
default:
allowedSchemes = ['https:'];
}
const result = validator.validate(allowedSchemes);
if (result.type === 'error') {
console.error(`Scheme validation failed for ${env} environment:`);
result.errors.forEach(error => console.error(error.message));
return false;
}
console.log(`✓ All schemes valid for ${env} environment`);
return true;
}
if (!validateSchemesByEnvironment('./package-lock.json')) {
process.exit(1);
}The validate() method returns a consistent result object:
interface SchemeValidationResult {
type: 'success' | 'error';
errors: SchemeValidationError[];
}
interface SchemeValidationError {
message: string; // Detailed error message with expected and actual schemes
package: string; // Package name that failed validation
}Success Example:
{
type: 'success',
errors: []
}Error Example:
{
type: 'error',
errors: [
{
message: 'detected invalid scheme(s) for package: some-package@1.0.0\n expected: https:,http:\n actual: git:\n',
package: 'some-package@1.0.0'
}
]
}Here are common URI schemes you might encounter in lockfiles:
'https:' - HTTP over TLS/SSL (most common, recommended)'http:' - Unencrypted HTTP (not recommended for production)'git:' - Git protocol (unencrypted)'git+ssh:' - Git over SSH (secure)'git+http:' - Git over HTTP (insecure)'git+https:' - Git over HTTPS (secure)'file:' - Local filesystem (common in development)'ssh:' - SSH protocol'ftp:' - FTP protocol (rare, not recommended)URI scheme validation is important for:
git: or ftp:Security Best Practices:
// Production: Strictest - HTTPS only
const productionSchemes = ['https:'];
// Staging: Moderate - HTTPS and HTTP
const stagingSchemes = ['https:', 'http:'];
// Development: Flexible - Include Git for private repos
const developmentSchemes = ['https:', 'http:', 'git+ssh:', 'git+https:', 'file:'];
// NEVER allow in production
const unsafeSchemes = ['git:', 'http:', 'ftp:'];ValidateScheme is more flexible than ValidateHttps:
ValidateHttps:
https: protocol onlyValidateScheme:
Example:
const { ValidateHttps, ValidateScheme, ParseLockfile } = require('lockfile-lint-api');
const parser = new ParseLockfile({ lockfilePath: './package-lock.json' });
const lockfile = parser.parseSync();
// ValidateHttps: Strict HTTPS-only
const httpsValidator = new ValidateHttps({ packages: lockfile.object });
const httpsResult = httpsValidator.validate();
// ValidateScheme: Flexible scheme list
const schemeValidator = new ValidateScheme({ packages: lockfile.object });
const schemeResult = schemeValidator.validate(['https:', 'http:']);
// Both check protocols, but ValidateScheme is more configurableConstructor Errors:
// Throws: 'expecting an object passed to validator constructor'
const validator = new ValidateScheme(); // Missing packages
const validator = new ValidateScheme({ packages: null }); // Invalid type
const validator = new ValidateScheme({ packages: [] }); // Array instead of objectValidation Errors:
const validator = new ValidateScheme({ packages: lockfile.object });
// Throws: 'validate method requires an array'
validator.validate('https:'); // String instead of array
validator.validate({ scheme: 'https:' }); // Object instead of arrayURL.protocol property to extract scheme:) in the protocol checkresolved field)Pre-commit Hook with Scheme Validation:
#!/usr/bin/env node
const { ValidateScheme, ParseLockfile } = require('lockfile-lint-api');
const fs = require('fs');
const ALLOWED_PRODUCTION_SCHEMES = ['https:'];
const lockfiles = ['package-lock.json', 'yarn.lock'];
let hasErrors = false;
lockfiles.forEach(lockfile => {
if (!fs.existsSync(lockfile)) {
return;
}
const parser = new ParseLockfile({ lockfilePath: lockfile });
const parsed = parser.parseSync();
const validator = new ValidateScheme({ packages: parsed.object });
const result = validator.validate(ALLOWED_PRODUCTION_SCHEMES);
if (result.type === 'error') {
console.error(`\nScheme validation failed for ${lockfile}:`);
result.errors.forEach(error => console.error(error.message));
hasErrors = true;
}
});
if (hasErrors) {
console.error('\nCommit rejected: Only HTTPS schemes allowed');
console.error('Run in development environment or update package sources');
process.exit(1);
}
console.log('✓ Scheme validation passed');Comprehensive Security with Multiple Validators:
const {
ParseLockfile,
ValidateScheme,
ValidateHost,
ValidateIntegrity
} = require('lockfile-lint-api');
function comprehensiveValidation(lockfilePath) {
const parser = new ParseLockfile({ lockfilePath });
const lockfile = parser.parseSync();
// 1. Validate URI schemes
const schemeValidator = new ValidateScheme({ packages: lockfile.object });
const schemeResult = schemeValidator.validate(['https:']);
// 2. Validate allowed hosts
const hostValidator = new ValidateHost({ packages: lockfile.object });
const hostResult = hostValidator.validate(['npm']);
// 3. Validate integrity hashes
const integrityValidator = new ValidateIntegrity({ packages: lockfile.object });
const integrityResult = integrityValidator.validate();
const allErrors = [
...schemeResult.errors,
...hostResult.errors,
...integrityResult.errors
];
if (allErrors.length > 0) {
console.error('Lockfile validation failed:');
allErrors.forEach(error => console.error(error.message));
return false;
}
console.log('✓ All validations passed');
return true;
}
if (!comprehensiveValidation('./package-lock.json')) {
process.exit(1);
}// Correct format (with colon)
validator.validate(['https:', 'http:', 'git:']);
// Incorrect format (without colon) - will not match
validator.validate(['https', 'http', 'git']); // Will fail validation// Allow multiple schemes
const result = validator.validate(['https:', 'http:', 'git+ssh:']);
// All packages must use one of the allowed schemes
// Package with 'https:' - PASS
// Package with 'http:' - PASS
// Package with 'git+ssh:' - PASS
// Package with 'git:' - FAIL (not in whitelist)// Packages without resolved field are automatically skipped
{
'local-package@1.0.0': {
version: '1.0.0'
// No resolved field - automatically skipped
}
}