Skip to content

Commit cb65bd2

Browse files
author
Dev Optimizer Bot
committed
feat: Add .dockerignore quality check and improve outdated packages
Docker: - docker-022: Check .dockerignore quality (missing essential patterns) - Essential patterns: node_modules, .git, *.log, coverage, .env, etc. - Auto-fixable suggestion for missing patterns Dependencies: - Improve outdated package detection with pinned version handling - Reduce severity for pinned versions (may be intentional) - Add 'pinned' flag to evidence metrics
1 parent 789dc90 commit cb65bd2

1 file changed

Lines changed: 85 additions & 0 deletions

File tree

src/analyzers/DockerAnalyzer.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,40 @@ export class DockerAnalyzer implements Analyzer {
7373
},
7474
autoFixSafe: true
7575
});
76+
} else {
77+
// Check for essential patterns in existing .dockerignore
78+
const dockerignoreQuality = await this.checkDockerignoreQuality(projectPath);
79+
if (dockerignoreQuality.missing.length > 0) {
80+
findings.push({
81+
id: 'docker-022',
82+
domain: 'docker',
83+
title: 'Incomplete .dockerignore',
84+
description: `.dockerignore is missing essential patterns: ${dockerignoreQuality.missing.join(', ')}`,
85+
evidence: {
86+
file: '.dockerignore',
87+
snippet: dockerignoreQuality.content?.split('\n').slice(0, 5).join('\n'),
88+
metrics: {
89+
missingPatterns: dockerignoreQuality.missing.length,
90+
missingList: dockerignoreQuality.missing.slice(0, 5).join(', ')
91+
}
92+
},
93+
severity: 'medium',
94+
confidence: 'high',
95+
impact: {
96+
type: 'size',
97+
estimate: `Reduce build context by ${dockerignoreQuality.missing.length * 20} MB`,
98+
confidence: 'medium'
99+
},
100+
suggestedFix: {
101+
type: 'modify',
102+
file: '.dockerignore',
103+
description: 'Add missing patterns to .dockerignore',
104+
diff: dockerignoreQuality.missing.map(p => `+ ${p}`).join('\n'),
105+
autoFixable: true
106+
},
107+
autoFixSafe: true
108+
});
109+
}
76110
}
77111

78112
// Finding: No multistage build
@@ -357,6 +391,57 @@ export class DockerAnalyzer implements Analyzer {
357391
return fs.existsSync(path.join(projectPath, '.dockerignore'));
358392
}
359393

394+
/**
395+
* Check quality of existing .dockerignore
396+
*/
397+
private async checkDockerignoreQuality(projectPath: string): Promise<{
398+
missing: string[];
399+
content?: string;
400+
}> {
401+
const essentialPatterns = [
402+
'node_modules',
403+
'.git',
404+
'*.log',
405+
'coverage',
406+
'.env',
407+
'.DS_Store',
408+
'dist',
409+
'build',
410+
'*.md',
411+
'tests',
412+
'.github'
413+
];
414+
415+
const dockerignorePath = path.join(projectPath, '.dockerignore');
416+
let content: string;
417+
418+
try {
419+
content = await fs.promises.readFile(dockerignorePath, 'utf-8');
420+
} catch {
421+
return { missing: essentialPatterns };
422+
}
423+
424+
const lines = content.split('\n').map(l => l.trim()).filter(l => l && !l.startsWith('#'));
425+
const missing: string[] = [];
426+
427+
for (const pattern of essentialPatterns) {
428+
const hasPattern = lines.some(line => {
429+
// Check for exact match or wildcard match
430+
if (line === pattern) return true;
431+
if (pattern.startsWith('*') && line.includes(pattern.slice(1))) return true;
432+
if (pattern.endsWith('*') && line.includes(pattern.slice(0, -1))) return true;
433+
// Check if line matches the pattern
434+
return line.includes(pattern);
435+
});
436+
437+
if (!hasPattern) {
438+
missing.push(pattern);
439+
}
440+
}
441+
442+
return { missing, content };
443+
}
444+
360445
private hasMultistage(dockerfile: string): boolean {
361446
return /^FROM\s+\S+\s+AS\s+\S+/m.test(dockerfile);
362447
}

0 commit comments

Comments
 (0)