Phase 1: Add ESLint/Prettier config + baseline auto-fixes
This commit is contained in:
@@ -30,7 +30,7 @@ function validateDNSRecord(data) {
|
||||
if (!subdomainRegex.test(data.subdomain)) {
|
||||
errors.push({
|
||||
field: 'subdomain',
|
||||
message: 'Invalid subdomain format. Use only letters, numbers, and hyphens (1-63 chars)'
|
||||
message: 'Invalid subdomain format. Use only letters, numbers, and hyphens (1-63 chars)',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ function validateDNSRecord(data) {
|
||||
subdomain: data.subdomain.toLowerCase().trim(),
|
||||
domain: data.domain ? data.domain.toLowerCase().trim() : null,
|
||||
ip: data.ip.trim(),
|
||||
ttl: data.ttl ? parseInt(data.ttl, 10) : 3600
|
||||
ttl: data.ttl ? parseInt(data.ttl, 10) : 3600,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ function validateDockerDeployment(data) {
|
||||
if (!nameRegex.test(data.name)) {
|
||||
errors.push({
|
||||
field: 'name',
|
||||
message: 'Invalid container name. Use only letters, numbers, underscores, periods, and hyphens'
|
||||
message: 'Invalid container name. Use only letters, numbers, underscores, periods, and hyphens',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ function validateDockerDeployment(data) {
|
||||
if (!imageRegex.test(data.image)) {
|
||||
errors.push({
|
||||
field: 'image',
|
||||
message: 'Invalid Docker image format'
|
||||
message: 'Invalid Docker image format',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ function validateDockerDeployment(data) {
|
||||
if (!portRegex.test(port)) {
|
||||
errors.push({
|
||||
field: `ports[${index}]`,
|
||||
message: 'Invalid port format. Use "host:container" or "host:container/protocol"'
|
||||
message: 'Invalid port format. Use "host:container" or "host:container/protocol"',
|
||||
});
|
||||
} else {
|
||||
const [, hostPort, containerPort] = port.match(portRegex);
|
||||
@@ -193,7 +193,7 @@ function validateDockerDeployment(data) {
|
||||
if (!envKeyRegex.test(key)) {
|
||||
errors.push({
|
||||
field: `environment.${key}`,
|
||||
message: 'Invalid environment variable name'
|
||||
message: 'Invalid environment variable name',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ function validateDockerDeployment(data) {
|
||||
if (typeof value !== 'string' && typeof value !== 'number' && typeof value !== 'boolean') {
|
||||
errors.push({
|
||||
field: `environment.${key}`,
|
||||
message: 'Environment variable value must be string, number, or boolean'
|
||||
message: 'Environment variable value must be string, number, or boolean',
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -219,7 +219,7 @@ function validateDockerDeployment(data) {
|
||||
image: data.image.trim(),
|
||||
ports: data.ports || [],
|
||||
volumes: data.volumes || [],
|
||||
environment: data.environment || {}
|
||||
environment: data.environment || {},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ function validateFilePath(filePath, allowedBasePaths = []) {
|
||||
'C:\\Windows',
|
||||
'C:\\Program Files',
|
||||
'/var/run',
|
||||
'/var/lib/docker'
|
||||
'/var/lib/docker',
|
||||
];
|
||||
|
||||
const lowerPath = normalized.toLowerCase();
|
||||
@@ -284,7 +284,7 @@ function validateVolumePath(volume, index) {
|
||||
if (!match) {
|
||||
errors.push({
|
||||
field: `volumes[${index}]`,
|
||||
message: 'Invalid volume format. Use "host:container" or "host:container:mode"'
|
||||
message: 'Invalid volume format. Use "host:container" or "host:container:mode"',
|
||||
});
|
||||
return errors;
|
||||
}
|
||||
@@ -297,7 +297,7 @@ function validateVolumePath(volume, index) {
|
||||
} catch (error) {
|
||||
errors.push({
|
||||
field: `volumes[${index}].hostPath`,
|
||||
message: `Invalid host path: ${error.message}`
|
||||
message: `Invalid host path: ${error.message}`,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ function validateVolumePath(volume, index) {
|
||||
if (containerPath.includes('..') || !path.isAbsolute(containerPath)) {
|
||||
errors.push({
|
||||
field: `volumes[${index}].containerPath`,
|
||||
message: 'Container path must be absolute and not contain ..'
|
||||
message: 'Container path must be absolute and not contain ..',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -313,7 +313,7 @@ function validateVolumePath(volume, index) {
|
||||
if (mode && !['ro', 'rw', 'z', 'Z'].includes(mode)) {
|
||||
errors.push({
|
||||
field: `volumes[${index}].mode`,
|
||||
message: 'Invalid volume mode. Use ro, rw, z, or Z'
|
||||
message: 'Invalid volume mode. Use ro, rw, z, or Z',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -333,7 +333,7 @@ function validateURL(url, options = {}) {
|
||||
require_protocol: options.requireProtocol !== false,
|
||||
require_valid_protocol: true,
|
||||
allow_underscores: false,
|
||||
...options
|
||||
...options,
|
||||
};
|
||||
|
||||
if (!validator.isURL(url, validatorOptions)) {
|
||||
@@ -451,7 +451,7 @@ function isPrivateIP(ip) {
|
||||
/^169\.254\./,
|
||||
/^::1$/,
|
||||
/^fc00:/,
|
||||
/^fe80:/
|
||||
/^fe80:/,
|
||||
];
|
||||
|
||||
return privateRanges.some(range => range.test(ip));
|
||||
@@ -496,7 +496,7 @@ async function validateSecurePath(requestedPath, allowedRoots, auditLogger = nul
|
||||
auditLogger.logSecurityEvent('path_traversal_blocked', {
|
||||
requestedPath,
|
||||
reason: 'null_byte_detected',
|
||||
severity: 'high'
|
||||
severity: 'high',
|
||||
});
|
||||
}
|
||||
throw new ValidationError('Invalid path - null byte detected', 'path');
|
||||
@@ -510,7 +510,7 @@ async function validateSecurePath(requestedPath, allowedRoots, auditLogger = nul
|
||||
/\.\%2f/i, // .%2F (encoded ./)
|
||||
/%2e\./i, // %2E.
|
||||
/\.\\/, // .\ (Windows)
|
||||
/%5c/i // URL encoded backslash
|
||||
/%5c/i, // URL encoded backslash
|
||||
];
|
||||
|
||||
if (suspiciousPatterns.some(pattern => pattern.test(requestedPath)) ||
|
||||
@@ -520,7 +520,7 @@ async function validateSecurePath(requestedPath, allowedRoots, auditLogger = nul
|
||||
requestedPath,
|
||||
decodedPath,
|
||||
reason: 'traversal_sequence_detected',
|
||||
severity: 'high'
|
||||
severity: 'high',
|
||||
});
|
||||
}
|
||||
throw new ValidationError('Path traversal detected', 'path');
|
||||
@@ -581,7 +581,7 @@ async function validateSecurePath(requestedPath, allowedRoots, auditLogger = nul
|
||||
realPath,
|
||||
allowedRoots,
|
||||
reason: 'outside_allowed_roots',
|
||||
severity: 'critical'
|
||||
severity: 'critical',
|
||||
});
|
||||
}
|
||||
throw new ValidationError('Access denied - path is outside allowed directories', 'path');
|
||||
@@ -602,5 +602,5 @@ module.exports = {
|
||||
sanitizeString,
|
||||
isValidPort,
|
||||
isPrivateIP,
|
||||
validateSecurePath
|
||||
validateSecurePath,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user