Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/docker-doctor/src/agents/sanitize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const flatten = (value: string, maxLength: number): string => {
export const sanitizeMessage = (message: string): string =>
flatten(message, MAX_MESSAGE_LENGTH);

// Paths are attacker-controlled in the same way messages are -- a filename
// may legally contain newlines and ANSI escapes on every platform we run on.
// Paths are attacker-controlled in the same way messages are. On Linux and
// macOS a filename may contain newlines and ANSI escapes.
export const sanitizePath = (filePath: string): string =>
flatten(filePath, MAX_PATH_LENGTH);
2 changes: 1 addition & 1 deletion packages/docker-doctor/src/agents/skill-install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const getSkillSourceDirectory = (): string | null => {
// default, or each agent's global dir (e.g. ~/.claude/skills; universal
// agents share ~/.agents/skills) when `global`.
// Best-effort: returns null when the bundled skill is missing or the install
// throws — callers treat that as "skill not installed", never as a failure.
// throws.
export const installSkillForAgents = async (
agents: SkillAgentType[],
options: { projectRoot: string; global?: boolean }
Expand Down
10 changes: 0 additions & 10 deletions packages/docker-doctor/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,6 @@ const runRulesEngine = async (
await setTimeout(100);
}

// 1. Scan Dockerfiles in parallel
const dockerfileResults = await Promise.all(
project.dockerfiles.map(async (df): Promise<FileResult> => {
const fullPath = path.join(rootDir, df);
Expand Down Expand Up @@ -623,7 +622,6 @@ const runRulesEngine = async (
await setTimeout(100);
}

// 2. Scan Compose files in parallel
const composeResults = await Promise.all(
project.composeFiles.map(async (cf): Promise<FileResult> => {
const fullPath = path.join(rootDir, cf);
Expand Down Expand Up @@ -675,7 +673,6 @@ const WHITESPACE_RUN = /\s+/gu;
const flattenMessage = (message: string): string =>
message.replaceAll(WHITESPACE_RUN, " ").trim();

// Exit 2 wins over 1 whenever any file went unanalyzed, in every output mode.
const scanExitCode = (scanIncomplete: boolean, failing: boolean): number => {
if (scanIncomplete) {
return SCAN_FAILURE_EXIT_CODE;
Expand Down Expand Up @@ -830,7 +827,6 @@ const writeMachineReport = (
console.log(JSON.stringify(report, null, 2));
};

// Prints the result in the requested output mode and returns the exit code.
const writeScanOutput = async (
scan: ScanOutcome,
options: OutputOptions
Expand Down Expand Up @@ -953,15 +949,13 @@ program
.description("Static analysis for Dockerfile and Docker Compose files")
.version(packageJson.version, "-V, --version", "display the version number");

// The default scan command's options, as commander parses them.
interface ScanOptions {
config?: string;
json: boolean;
score: boolean;
verbose: boolean;
}

// Default scan command
program
.argument("[dir]", "directory to scan", ".")
.option("-v, --verbose", "show verbose diagnostics description", false)
Expand Down Expand Up @@ -1034,7 +1028,6 @@ program
}

setStatus("Loading configuration...");
// Load config first
// Warnings go to stderr so the --json and --score stdout contracts
// stay machine-readable.
const configPath = await resolveConfigPath(options.config, rootDir);
Expand All @@ -1045,7 +1038,6 @@ program

setStatus("Scanning workspace files...");

// Project discovery, minus anything the config ignores
const project = await discoverProject(rootDir, {
ignoreFiles: config.ignore?.files,
onSkippedDirectory: (skippedDir) => {
Expand All @@ -1055,7 +1047,6 @@ program
},
});

// Collect all diagnostics
const fileContents: Record<string, string> = {};

const projectFilesList = [
Expand Down Expand Up @@ -1247,7 +1238,6 @@ program
process.exitCode = result.failed.length > 0 ? 1 : 0;
});

// Rules subcommand group
const rules = program
.command("rules")
.description("manage and list configuration rules");
Expand Down
6 changes: 0 additions & 6 deletions packages/docker-doctor/src/formatters/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import chalk from "chalk";

import { hasText } from "../text";

// True for a line number a code frame can point at. A missing, zero or NaN
// line gets no frame, as the truthiness test before it decided.
const isLineNumber = (line: number | undefined): line is number =>
line !== undefined && line !== 0 && !Number.isNaN(line);

Expand Down Expand Up @@ -56,7 +54,6 @@ const printDiscoveredFiles = (project: ProjectInfo): void => {
};

const printMigrationWarning = (diagnostics: Diagnostic[]): void => {
// Migration-scale checks: the same rule firing many times.
const findingsByRule = new Map<
string,
{ count: number; files: Set<string> }
Expand Down Expand Up @@ -137,7 +134,6 @@ const printDiagnosticsByFile = (
): void => {
console.log(`\nFound ${chalk.bold(diagnostics.length)} issue(s):`);

// Group by file
const filesGrouped = new Map<string, Diagnostic[]>();

for (const d of diagnostics) {
Expand Down Expand Up @@ -168,7 +164,6 @@ const printDiagnosticsByFile = (
const lineInfo = isLineNumber(d.line) ? `:${d.line}` : "";
console.log(` ${sevColor(prefix)} [${chalk.dim(d.rule)}]${lineInfo}`);

// Print Code Frame
const content = fileContents[file];
printCodeFrame(content, d.line, sevColor);

Expand Down Expand Up @@ -380,7 +375,6 @@ export const formatTerminal = async (
printDiscoveredFiles(project);
}

// Calculate scores per category once
const categoryIssueCounts = {
"Best Practices": 0,
Compose: 0,
Expand Down
1 change: 0 additions & 1 deletion packages/docker-doctor/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import packageJson from "../package.json" with { type: "json" };

// Re-export core programmatic API
export {
discoverProject,
parseDockerfile,
Expand Down
2 changes: 0 additions & 2 deletions packages/docker-doctor/src/text.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
// True for a string with at least one character, which is what a truthiness
// test on a string that may be missing checked.
export const hasText = (value: string | null | undefined): value is string =>
value !== undefined && value !== null && value !== "";
3 changes: 0 additions & 3 deletions packages/docker-doctor/src/workflow-scaffold.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ const fileExists = async (filePath: string): Promise<boolean> => {
}
};

// `dir` and each of its ancestors, nearest first.
const selfAndAncestors = (dir: string): string[] => {
const dirs = [dir];
let parent = path.dirname(dir);
Expand Down Expand Up @@ -51,8 +50,6 @@ const findRepositoryRoot = async (dir: string): Promise<string | null> => {
// workflow without consent. GitHub only runs workflows from the repository
// root, so a scan of a subdirectory writes the workflow at that root and
// passes the subdirectory as the action's `directory` input.
// confirmOverwrite is injected so the caller owns the prompt and the
// function is testable without a TTY.
export const scaffoldActionWorkflow = async (options: {
actionRef: string;
confirmOverwrite: () => Promise<boolean>;
Expand Down
Loading