@infograb/docker-slim-advisor 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +274 -0
- package/build/base-image-db-loader.d.ts +16 -0
- package/build/base-image-db-loader.js +72 -0
- package/build/base-image-db-loader.js.map +1 -0
- package/build/cli.d.ts +47 -0
- package/build/cli.js +142 -0
- package/build/cli.js.map +1 -0
- package/build/data/base-image-db-schema.d.ts +117 -0
- package/build/data/base-image-db-schema.js +108 -0
- package/build/data/base-image-db-schema.js.map +1 -0
- package/build/data/base-image-db.d.ts +21 -0
- package/build/data/base-image-db.js +190 -0
- package/build/data/base-image-db.js.map +1 -0
- package/build/exit-codes.d.ts +25 -0
- package/build/exit-codes.js +31 -0
- package/build/exit-codes.js.map +1 -0
- package/build/formatters/formatter-dispatcher.d.ts +15 -0
- package/build/formatters/formatter-dispatcher.js +27 -0
- package/build/formatters/formatter-dispatcher.js.map +1 -0
- package/build/formatters/json-formatter.d.ts +10 -0
- package/build/formatters/json-formatter.js +52 -0
- package/build/formatters/json-formatter.js.map +1 -0
- package/build/formatters/json-schema.d.ts +57 -0
- package/build/formatters/json-schema.js +13 -0
- package/build/formatters/json-schema.js.map +1 -0
- package/build/formatters/markdown-formatter.d.ts +12 -0
- package/build/formatters/markdown-formatter.js +97 -0
- package/build/formatters/markdown-formatter.js.map +1 -0
- package/build/formatters/terminal-formatter.d.ts +12 -0
- package/build/formatters/terminal-formatter.js +142 -0
- package/build/formatters/terminal-formatter.js.map +1 -0
- package/build/image-size-lookup.d.ts +35 -0
- package/build/image-size-lookup.js +187 -0
- package/build/image-size-lookup.js.map +1 -0
- package/build/multi-stage-detector.d.ts +29 -0
- package/build/multi-stage-detector.js +29 -0
- package/build/multi-stage-detector.js.map +1 -0
- package/build/output.d.ts +46 -0
- package/build/output.js +62 -0
- package/build/output.js.map +1 -0
- package/build/parser.d.ts +7 -0
- package/build/parser.js +123 -0
- package/build/parser.js.map +1 -0
- package/build/rules/alpine-swap.d.ts +10 -0
- package/build/rules/alpine-swap.js +81 -0
- package/build/rules/alpine-swap.js.map +1 -0
- package/build/rules/dockerignore-missing.d.ts +19 -0
- package/build/rules/dockerignore-missing.js +107 -0
- package/build/rules/dockerignore-missing.js.map +1 -0
- package/build/rules/index.d.ts +11 -0
- package/build/rules/index.js +22 -0
- package/build/rules/index.js.map +1 -0
- package/build/rules/package-cache-cleanup.d.ts +15 -0
- package/build/rules/package-cache-cleanup.js +89 -0
- package/build/rules/package-cache-cleanup.js.map +1 -0
- package/build/rules/run-merge.d.ts +12 -0
- package/build/rules/run-merge.js +67 -0
- package/build/rules/run-merge.js.map +1 -0
- package/build/rules/unnecessary-packages.d.ts +23 -0
- package/build/rules/unnecessary-packages.js +184 -0
- package/build/rules/unnecessary-packages.js.map +1 -0
- package/build/severity-filter.d.ts +22 -0
- package/build/severity-filter.js +31 -0
- package/build/severity-filter.js.map +1 -0
- package/build/size-estimator.d.ts +35 -0
- package/build/size-estimator.js +238 -0
- package/build/size-estimator.js.map +1 -0
- package/build/tty-detection.d.ts +20 -0
- package/build/tty-detection.js +33 -0
- package/build/tty-detection.js.map +1 -0
- package/build/types.d.ts +82 -0
- package/build/types.js +6 -0
- package/build/types.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON schema and TypeScript types for the base image size database.
|
|
3
|
+
*
|
|
4
|
+
* The DB is a static JSON bundle mapping "image:tag" keys to size/metadata entries.
|
|
5
|
+
* Used for Before/After size prediction without building Docker images.
|
|
6
|
+
*
|
|
7
|
+
* Design decisions:
|
|
8
|
+
* - Flat "image:tag" keying for O(1) lookup (vs nested image→tags structure)
|
|
9
|
+
* - Both compressed and uncompressed sizes for accurate estimation
|
|
10
|
+
* - Architecture defaults to amd64; field omitted when amd64 (saves JSON bytes)
|
|
11
|
+
* - slimAlternative references another key in the same DB
|
|
12
|
+
* - Schema version enables forward-compatible DB updates
|
|
13
|
+
*/
|
|
14
|
+
/** Current schema version — bump on breaking changes to the DB shape */
|
|
15
|
+
export declare const BASE_IMAGE_DB_SCHEMA_VERSION = 1;
|
|
16
|
+
/** Supported CPU architectures for image size data */
|
|
17
|
+
export type Architecture = 'amd64' | 'arm64' | 'arm/v7' | 'arm/v6' | '386' | 'ppc64le' | 's390x';
|
|
18
|
+
/** Default architecture assumed when arch field is omitted */
|
|
19
|
+
export declare const DEFAULT_ARCHITECTURE: Architecture;
|
|
20
|
+
/**
|
|
21
|
+
* Size and metadata for a single image:tag combination.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* {
|
|
25
|
+
* compressedBytes: 77_594_624,
|
|
26
|
+
* uncompressedBytes: 187_000_000,
|
|
27
|
+
* arch: "amd64",
|
|
28
|
+
* slimAlternative: "node:22-alpine",
|
|
29
|
+
* lastUpdated: "2026-04-01"
|
|
30
|
+
* }
|
|
31
|
+
*/
|
|
32
|
+
export interface ImageSizeEntry {
|
|
33
|
+
/** Compressed/pulled size in bytes (as reported by Docker Hub manifests) */
|
|
34
|
+
compressedBytes: number;
|
|
35
|
+
/**
|
|
36
|
+
* Uncompressed/on-disk size in bytes.
|
|
37
|
+
* Typically 2-3x compressed size. Used for more accurate layer estimation.
|
|
38
|
+
* When omitted, estimated as compressedBytes * UNCOMPRESSED_RATIO.
|
|
39
|
+
*/
|
|
40
|
+
uncompressedBytes?: number;
|
|
41
|
+
/**
|
|
42
|
+
* CPU architecture this size applies to.
|
|
43
|
+
* Omit for amd64 (the default). Only set for non-amd64 entries.
|
|
44
|
+
*/
|
|
45
|
+
arch?: Architecture;
|
|
46
|
+
/**
|
|
47
|
+
* Key of a smaller alternative image in the same DB.
|
|
48
|
+
* Format: "image:tag" — must be a valid key in the images map.
|
|
49
|
+
* Omit when no smaller alternative exists (e.g., alpine images).
|
|
50
|
+
*/
|
|
51
|
+
slimAlternative?: string;
|
|
52
|
+
/**
|
|
53
|
+
* ISO 8601 date when this entry's size was last verified.
|
|
54
|
+
* Used by the DB generator script to track staleness.
|
|
55
|
+
*/
|
|
56
|
+
lastUpdated?: string;
|
|
57
|
+
}
|
|
58
|
+
/** Metadata header for the base image size database JSON file */
|
|
59
|
+
export interface BaseImageDbMetadata {
|
|
60
|
+
/** Schema version for forward compatibility */
|
|
61
|
+
schemaVersion: number;
|
|
62
|
+
/** Human-readable description */
|
|
63
|
+
description: string;
|
|
64
|
+
/** ISO 8601 date when the DB was generated */
|
|
65
|
+
generatedAt: string;
|
|
66
|
+
/** Data source (e.g., "Docker Hub manifest API") */
|
|
67
|
+
source: string;
|
|
68
|
+
/** Total number of image:tag entries */
|
|
69
|
+
imageCount: number;
|
|
70
|
+
/** Default architecture assumed when entry.arch is omitted */
|
|
71
|
+
defaultArch: Architecture;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Root structure of the base-image-db.json file.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* {
|
|
78
|
+
* "_metadata": {
|
|
79
|
+
* "schemaVersion": 1,
|
|
80
|
+
* "description": "Static base image size database for docker-slim-advisor",
|
|
81
|
+
* "generatedAt": "2026-04-01",
|
|
82
|
+
* "source": "Docker Hub manifest API",
|
|
83
|
+
* "imageCount": 150,
|
|
84
|
+
* "defaultArch": "amd64"
|
|
85
|
+
* },
|
|
86
|
+
* "images": {
|
|
87
|
+
* "node:22": { "compressedBytes": 1100000000, "uncompressedBytes": 2800000000, "slimAlternative": "node:22-alpine" },
|
|
88
|
+
* "node:22-alpine": { "compressedBytes": 130023424, "uncompressedBytes": 340000000 },
|
|
89
|
+
* "scratch": { "compressedBytes": 0, "uncompressedBytes": 0 }
|
|
90
|
+
* }
|
|
91
|
+
* }
|
|
92
|
+
*/
|
|
93
|
+
export interface BaseImageDb {
|
|
94
|
+
_metadata: BaseImageDbMetadata;
|
|
95
|
+
images: Record<string, ImageSizeEntry>;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Default ratio of uncompressed to compressed size.
|
|
99
|
+
* Used when uncompressedBytes is omitted from an entry.
|
|
100
|
+
* Based on empirical observation: Docker images compress ~2.5:1 on average.
|
|
101
|
+
*/
|
|
102
|
+
export declare const UNCOMPRESSED_RATIO = 2.5;
|
|
103
|
+
/**
|
|
104
|
+
* Resolve the effective uncompressed size for an image entry.
|
|
105
|
+
* Uses the explicit value if present, otherwise estimates from compressed size.
|
|
106
|
+
*/
|
|
107
|
+
export declare function resolveUncompressedBytes(entry: ImageSizeEntry): number;
|
|
108
|
+
/**
|
|
109
|
+
* Resolve the effective architecture for an image entry.
|
|
110
|
+
* Returns explicit arch if set, otherwise the default (amd64).
|
|
111
|
+
*/
|
|
112
|
+
export declare function resolveArchitecture(entry: ImageSizeEntry): Architecture;
|
|
113
|
+
/**
|
|
114
|
+
* Validate a parsed BaseImageDb object. Returns error messages if invalid.
|
|
115
|
+
* Used by the DB generator script and tests to ensure data integrity.
|
|
116
|
+
*/
|
|
117
|
+
export declare function validateBaseImageDb(db: unknown): string[];
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON schema and TypeScript types for the base image size database.
|
|
3
|
+
*
|
|
4
|
+
* The DB is a static JSON bundle mapping "image:tag" keys to size/metadata entries.
|
|
5
|
+
* Used for Before/After size prediction without building Docker images.
|
|
6
|
+
*
|
|
7
|
+
* Design decisions:
|
|
8
|
+
* - Flat "image:tag" keying for O(1) lookup (vs nested image→tags structure)
|
|
9
|
+
* - Both compressed and uncompressed sizes for accurate estimation
|
|
10
|
+
* - Architecture defaults to amd64; field omitted when amd64 (saves JSON bytes)
|
|
11
|
+
* - slimAlternative references another key in the same DB
|
|
12
|
+
* - Schema version enables forward-compatible DB updates
|
|
13
|
+
*/
|
|
14
|
+
// --- Schema Version ---
|
|
15
|
+
/** Current schema version — bump on breaking changes to the DB shape */
|
|
16
|
+
export const BASE_IMAGE_DB_SCHEMA_VERSION = 1;
|
|
17
|
+
/** Default architecture assumed when arch field is omitted */
|
|
18
|
+
export const DEFAULT_ARCHITECTURE = 'amd64';
|
|
19
|
+
// --- Estimation Helpers ---
|
|
20
|
+
/**
|
|
21
|
+
* Default ratio of uncompressed to compressed size.
|
|
22
|
+
* Used when uncompressedBytes is omitted from an entry.
|
|
23
|
+
* Based on empirical observation: Docker images compress ~2.5:1 on average.
|
|
24
|
+
*/
|
|
25
|
+
export const UNCOMPRESSED_RATIO = 2.5;
|
|
26
|
+
/**
|
|
27
|
+
* Resolve the effective uncompressed size for an image entry.
|
|
28
|
+
* Uses the explicit value if present, otherwise estimates from compressed size.
|
|
29
|
+
*/
|
|
30
|
+
export function resolveUncompressedBytes(entry) {
|
|
31
|
+
return entry.uncompressedBytes ?? Math.round(entry.compressedBytes * UNCOMPRESSED_RATIO);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Resolve the effective architecture for an image entry.
|
|
35
|
+
* Returns explicit arch if set, otherwise the default (amd64).
|
|
36
|
+
*/
|
|
37
|
+
export function resolveArchitecture(entry) {
|
|
38
|
+
return entry.arch ?? DEFAULT_ARCHITECTURE;
|
|
39
|
+
}
|
|
40
|
+
// --- Validation ---
|
|
41
|
+
/**
|
|
42
|
+
* Validate a parsed BaseImageDb object. Returns error messages if invalid.
|
|
43
|
+
* Used by the DB generator script and tests to ensure data integrity.
|
|
44
|
+
*/
|
|
45
|
+
export function validateBaseImageDb(db) {
|
|
46
|
+
const errors = [];
|
|
47
|
+
if (db === null || typeof db !== 'object') {
|
|
48
|
+
return ['DB must be a non-null object'];
|
|
49
|
+
}
|
|
50
|
+
const obj = db;
|
|
51
|
+
// Validate metadata
|
|
52
|
+
if (!obj._metadata || typeof obj._metadata !== 'object') {
|
|
53
|
+
errors.push('Missing or invalid _metadata');
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
const meta = obj._metadata;
|
|
57
|
+
if (typeof meta.schemaVersion !== 'number') {
|
|
58
|
+
errors.push('_metadata.schemaVersion must be a number');
|
|
59
|
+
}
|
|
60
|
+
if (typeof meta.generatedAt !== 'string') {
|
|
61
|
+
errors.push('_metadata.generatedAt must be a string');
|
|
62
|
+
}
|
|
63
|
+
if (typeof meta.imageCount !== 'number') {
|
|
64
|
+
errors.push('_metadata.imageCount must be a number');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Validate images
|
|
68
|
+
if (!obj.images || typeof obj.images !== 'object') {
|
|
69
|
+
errors.push('Missing or invalid images map');
|
|
70
|
+
return errors;
|
|
71
|
+
}
|
|
72
|
+
const images = obj.images;
|
|
73
|
+
let entryCount = 0;
|
|
74
|
+
for (const [key, value] of Object.entries(images)) {
|
|
75
|
+
entryCount++;
|
|
76
|
+
if (!key.includes(':') && key !== 'scratch') {
|
|
77
|
+
errors.push(`Image key "${key}" missing tag (expected "image:tag" format)`);
|
|
78
|
+
}
|
|
79
|
+
if (value === null || typeof value !== 'object') {
|
|
80
|
+
errors.push(`Image "${key}" entry must be an object`);
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const entry = value;
|
|
84
|
+
if (typeof entry.compressedBytes !== 'number' || entry.compressedBytes < 0) {
|
|
85
|
+
errors.push(`Image "${key}" compressedBytes must be a non-negative number`);
|
|
86
|
+
}
|
|
87
|
+
if (entry.uncompressedBytes !== undefined) {
|
|
88
|
+
if (typeof entry.uncompressedBytes !== 'number' || entry.uncompressedBytes < 0) {
|
|
89
|
+
errors.push(`Image "${key}" uncompressedBytes must be a non-negative number`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (entry.slimAlternative !== undefined) {
|
|
93
|
+
if (typeof entry.slimAlternative !== 'string') {
|
|
94
|
+
errors.push(`Image "${key}" slimAlternative must be a string`);
|
|
95
|
+
}
|
|
96
|
+
else if (!images[entry.slimAlternative]) {
|
|
97
|
+
errors.push(`Image "${key}" slimAlternative "${entry.slimAlternative}" not found in DB`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Cross-check imageCount
|
|
102
|
+
const meta = obj._metadata;
|
|
103
|
+
if (meta && typeof meta.imageCount === 'number' && meta.imageCount !== entryCount) {
|
|
104
|
+
errors.push(`_metadata.imageCount (${meta.imageCount}) does not match actual count (${entryCount})`);
|
|
105
|
+
}
|
|
106
|
+
return errors;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=base-image-db-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-image-db-schema.js","sourceRoot":"","sources":["../../src/data/base-image-db-schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static database of popular base images and their sizes in bytes.
|
|
3
|
+
* Maps "image:tag" to compressed size. 100+ entries covering popular images.
|
|
4
|
+
*
|
|
5
|
+
* Sizes sourced from Docker Hub (approximate compressed sizes).
|
|
6
|
+
* Used for Before/After size prediction without building.
|
|
7
|
+
*/
|
|
8
|
+
export interface ImageEntry {
|
|
9
|
+
sizeBytes: number;
|
|
10
|
+
/** Lighter alternative image:tag, if one exists */
|
|
11
|
+
slimAlternative?: string;
|
|
12
|
+
}
|
|
13
|
+
/** Map of "image:tag" -> ImageEntry */
|
|
14
|
+
export declare const BASE_IMAGE_DB: Record<string, ImageEntry>;
|
|
15
|
+
/** Lookup image size by name and tag */
|
|
16
|
+
export declare function getImageSize(image: string, tag: string): number | undefined;
|
|
17
|
+
/** Get slim/alpine alternative for an image:tag, if one exists */
|
|
18
|
+
export declare function getSlimAlternative(image: string, tag: string): {
|
|
19
|
+
alternative: string;
|
|
20
|
+
alternativeSizeBytes: number;
|
|
21
|
+
} | undefined;
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static database of popular base images and their sizes in bytes.
|
|
3
|
+
* Maps "image:tag" to compressed size. 100+ entries covering popular images.
|
|
4
|
+
*
|
|
5
|
+
* Sizes sourced from Docker Hub (approximate compressed sizes).
|
|
6
|
+
* Used for Before/After size prediction without building.
|
|
7
|
+
*/
|
|
8
|
+
/** Map of "image:tag" -> ImageEntry */
|
|
9
|
+
export const BASE_IMAGE_DB = {
|
|
10
|
+
// ── Node.js ────────────────────────────────────────────────
|
|
11
|
+
'node:latest': { sizeBytes: 1_100_000_000, slimAlternative: 'node:slim' },
|
|
12
|
+
'node:22': { sizeBytes: 1_100_000_000, slimAlternative: 'node:22-slim' },
|
|
13
|
+
'node:22-bullseye': { sizeBytes: 1_100_000_000, slimAlternative: 'node:22-bullseye-slim' },
|
|
14
|
+
'node:22-bookworm': { sizeBytes: 1_100_000_000, slimAlternative: 'node:22-bookworm-slim' },
|
|
15
|
+
'node:20': { sizeBytes: 1_070_000_000, slimAlternative: 'node:20-slim' },
|
|
16
|
+
'node:20-bullseye': { sizeBytes: 1_070_000_000, slimAlternative: 'node:20-bullseye-slim' },
|
|
17
|
+
'node:20-bookworm': { sizeBytes: 1_070_000_000, slimAlternative: 'node:20-bookworm-slim' },
|
|
18
|
+
'node:18': { sizeBytes: 1_000_000_000, slimAlternative: 'node:18-slim' },
|
|
19
|
+
'node:18-bullseye': { sizeBytes: 1_000_000_000, slimAlternative: 'node:18-bullseye-slim' },
|
|
20
|
+
'node:18-bookworm': { sizeBytes: 1_000_000_000, slimAlternative: 'node:18-bookworm-slim' },
|
|
21
|
+
'node:22-slim': { sizeBytes: 220_000_000, slimAlternative: 'node:22-alpine' },
|
|
22
|
+
'node:20-slim': { sizeBytes: 220_000_000, slimAlternative: 'node:20-alpine' },
|
|
23
|
+
'node:18-slim': { sizeBytes: 200_000_000, slimAlternative: 'node:18-alpine' },
|
|
24
|
+
'node:22-alpine': { sizeBytes: 130_000_000 },
|
|
25
|
+
'node:20-alpine': { sizeBytes: 130_000_000 },
|
|
26
|
+
'node:18-alpine': { sizeBytes: 120_000_000 },
|
|
27
|
+
// ── Python ─────────────────────────────────────────────────
|
|
28
|
+
'python:latest': { sizeBytes: 1_020_000_000, slimAlternative: 'python:slim' },
|
|
29
|
+
'python:3': { sizeBytes: 1_020_000_000, slimAlternative: 'python:3-slim' },
|
|
30
|
+
'python:3.12': { sizeBytes: 1_020_000_000, slimAlternative: 'python:3.12-slim' },
|
|
31
|
+
'python:3.11': { sizeBytes: 1_000_000_000, slimAlternative: 'python:3.11-slim' },
|
|
32
|
+
'python:3.10': { sizeBytes: 990_000_000, slimAlternative: 'python:3.10-slim' },
|
|
33
|
+
'python:3.9': { sizeBytes: 980_000_000, slimAlternative: 'python:3.9-slim' },
|
|
34
|
+
'python:3.12-bookworm': { sizeBytes: 1_020_000_000, slimAlternative: 'python:3.12-slim' },
|
|
35
|
+
'python:3.12-bullseye': { sizeBytes: 1_020_000_000, slimAlternative: 'python:3.12-slim' },
|
|
36
|
+
'python:3-slim': { sizeBytes: 150_000_000, slimAlternative: 'python:3-alpine' },
|
|
37
|
+
'python:3.12-slim': { sizeBytes: 150_000_000, slimAlternative: 'python:3.12-alpine' },
|
|
38
|
+
'python:3.11-slim': { sizeBytes: 148_000_000, slimAlternative: 'python:3.11-alpine' },
|
|
39
|
+
'python:3.10-slim': { sizeBytes: 145_000_000, slimAlternative: 'python:3.10-alpine' },
|
|
40
|
+
'python:slim': { sizeBytes: 150_000_000, slimAlternative: 'python:alpine' },
|
|
41
|
+
'python:3.12-alpine': { sizeBytes: 55_000_000 },
|
|
42
|
+
'python:3.11-alpine': { sizeBytes: 55_000_000 },
|
|
43
|
+
'python:3.10-alpine': { sizeBytes: 52_000_000 },
|
|
44
|
+
'python:3-alpine': { sizeBytes: 55_000_000 },
|
|
45
|
+
'python:alpine': { sizeBytes: 55_000_000 },
|
|
46
|
+
// ── Ruby ───────────────────────────────────────────────────
|
|
47
|
+
'ruby:latest': { sizeBytes: 1_000_000_000, slimAlternative: 'ruby:slim' },
|
|
48
|
+
'ruby:3': { sizeBytes: 1_000_000_000, slimAlternative: 'ruby:3-slim' },
|
|
49
|
+
'ruby:3.3': { sizeBytes: 1_000_000_000, slimAlternative: 'ruby:3.3-slim' },
|
|
50
|
+
'ruby:3.2': { sizeBytes: 990_000_000, slimAlternative: 'ruby:3.2-slim' },
|
|
51
|
+
'ruby:3-slim': { sizeBytes: 210_000_000, slimAlternative: 'ruby:3-alpine' },
|
|
52
|
+
'ruby:3.3-slim': { sizeBytes: 210_000_000, slimAlternative: 'ruby:3.3-alpine' },
|
|
53
|
+
'ruby:3.3-alpine': { sizeBytes: 80_000_000 },
|
|
54
|
+
'ruby:3-alpine': { sizeBytes: 80_000_000 },
|
|
55
|
+
// ── Go ─────────────────────────────────────────────────────
|
|
56
|
+
'golang:latest': { sizeBytes: 850_000_000, slimAlternative: 'golang:alpine' },
|
|
57
|
+
'golang:1': { sizeBytes: 850_000_000, slimAlternative: 'golang:1-alpine' },
|
|
58
|
+
'golang:1.22': { sizeBytes: 850_000_000, slimAlternative: 'golang:1.22-alpine' },
|
|
59
|
+
'golang:1.21': { sizeBytes: 830_000_000, slimAlternative: 'golang:1.21-alpine' },
|
|
60
|
+
'golang:1.22-alpine': { sizeBytes: 260_000_000 },
|
|
61
|
+
'golang:1.21-alpine': { sizeBytes: 250_000_000 },
|
|
62
|
+
'golang:1-alpine': { sizeBytes: 260_000_000 },
|
|
63
|
+
'golang:alpine': { sizeBytes: 260_000_000 },
|
|
64
|
+
// ── Java (OpenJDK / Eclipse Temurin) ───────────────────────
|
|
65
|
+
'openjdk:latest': { sizeBytes: 670_000_000, slimAlternative: 'eclipse-temurin:21-jre-alpine' },
|
|
66
|
+
'openjdk:21': { sizeBytes: 670_000_000, slimAlternative: 'eclipse-temurin:21-jre-alpine' },
|
|
67
|
+
'openjdk:17': { sizeBytes: 650_000_000, slimAlternative: 'eclipse-temurin:17-jre-alpine' },
|
|
68
|
+
'openjdk:11': { sizeBytes: 630_000_000, slimAlternative: 'eclipse-temurin:11-jre-alpine' },
|
|
69
|
+
'eclipse-temurin:21': { sizeBytes: 400_000_000, slimAlternative: 'eclipse-temurin:21-jre-alpine' },
|
|
70
|
+
'eclipse-temurin:17': { sizeBytes: 380_000_000, slimAlternative: 'eclipse-temurin:17-jre-alpine' },
|
|
71
|
+
'eclipse-temurin:21-jre': { sizeBytes: 270_000_000, slimAlternative: 'eclipse-temurin:21-jre-alpine' },
|
|
72
|
+
'eclipse-temurin:17-jre': { sizeBytes: 260_000_000, slimAlternative: 'eclipse-temurin:17-jre-alpine' },
|
|
73
|
+
'eclipse-temurin:21-jre-alpine': { sizeBytes: 160_000_000 },
|
|
74
|
+
'eclipse-temurin:17-jre-alpine': { sizeBytes: 155_000_000 },
|
|
75
|
+
// ── Rust ───────────────────────────────────────────────────
|
|
76
|
+
'rust:latest': { sizeBytes: 1_400_000_000, slimAlternative: 'rust:slim' },
|
|
77
|
+
'rust:1': { sizeBytes: 1_400_000_000, slimAlternative: 'rust:1-slim' },
|
|
78
|
+
'rust:1.77': { sizeBytes: 1_400_000_000, slimAlternative: 'rust:1.77-slim' },
|
|
79
|
+
'rust:slim': { sizeBytes: 800_000_000, slimAlternative: 'rust:alpine' },
|
|
80
|
+
'rust:1-slim': { sizeBytes: 800_000_000, slimAlternative: 'rust:1-alpine' },
|
|
81
|
+
'rust:alpine': { sizeBytes: 500_000_000 },
|
|
82
|
+
'rust:1-alpine': { sizeBytes: 500_000_000 },
|
|
83
|
+
// ── PHP ────────────────────────────────────────────────────
|
|
84
|
+
'php:latest': { sizeBytes: 480_000_000, slimAlternative: 'php:cli-alpine' },
|
|
85
|
+
'php:8': { sizeBytes: 480_000_000, slimAlternative: 'php:8-cli-alpine' },
|
|
86
|
+
'php:8.3': { sizeBytes: 480_000_000, slimAlternative: 'php:8.3-cli-alpine' },
|
|
87
|
+
'php:8.3-fpm': { sizeBytes: 490_000_000, slimAlternative: 'php:8.3-fpm-alpine' },
|
|
88
|
+
'php:8.3-apache': { sizeBytes: 520_000_000, slimAlternative: 'php:8.3-fpm-alpine' },
|
|
89
|
+
'php:8.3-cli-alpine': { sizeBytes: 100_000_000 },
|
|
90
|
+
'php:8.3-fpm-alpine': { sizeBytes: 110_000_000 },
|
|
91
|
+
'php:8-cli-alpine': { sizeBytes: 100_000_000 },
|
|
92
|
+
'php:cli-alpine': { sizeBytes: 100_000_000 },
|
|
93
|
+
// ── .NET ───────────────────────────────────────────────────
|
|
94
|
+
'mcr.microsoft.com/dotnet/sdk:8.0': { sizeBytes: 880_000_000, slimAlternative: 'mcr.microsoft.com/dotnet/aspnet:8.0-alpine' },
|
|
95
|
+
'mcr.microsoft.com/dotnet/sdk:7.0': { sizeBytes: 850_000_000, slimAlternative: 'mcr.microsoft.com/dotnet/aspnet:7.0-alpine' },
|
|
96
|
+
'mcr.microsoft.com/dotnet/aspnet:8.0': { sizeBytes: 220_000_000, slimAlternative: 'mcr.microsoft.com/dotnet/aspnet:8.0-alpine' },
|
|
97
|
+
'mcr.microsoft.com/dotnet/aspnet:8.0-alpine': { sizeBytes: 110_000_000 },
|
|
98
|
+
'mcr.microsoft.com/dotnet/aspnet:7.0-alpine': { sizeBytes: 105_000_000 },
|
|
99
|
+
// ── OS base images ─────────────────────────────────────────
|
|
100
|
+
'ubuntu:latest': { sizeBytes: 78_000_000, slimAlternative: 'alpine:latest' },
|
|
101
|
+
'ubuntu:24.04': { sizeBytes: 78_000_000, slimAlternative: 'alpine:3.19' },
|
|
102
|
+
'ubuntu:22.04': { sizeBytes: 77_000_000, slimAlternative: 'alpine:3.19' },
|
|
103
|
+
'ubuntu:20.04': { sizeBytes: 73_000_000, slimAlternative: 'alpine:3.19' },
|
|
104
|
+
'debian:latest': { sizeBytes: 124_000_000, slimAlternative: 'debian:bookworm-slim' },
|
|
105
|
+
'debian:bookworm': { sizeBytes: 124_000_000, slimAlternative: 'debian:bookworm-slim' },
|
|
106
|
+
'debian:bullseye': { sizeBytes: 124_000_000, slimAlternative: 'debian:bullseye-slim' },
|
|
107
|
+
'debian:bookworm-slim': { sizeBytes: 74_000_000, slimAlternative: 'alpine:latest' },
|
|
108
|
+
'debian:bullseye-slim': { sizeBytes: 74_000_000, slimAlternative: 'alpine:latest' },
|
|
109
|
+
'alpine:latest': { sizeBytes: 7_800_000 },
|
|
110
|
+
'alpine:3.19': { sizeBytes: 7_800_000 },
|
|
111
|
+
'alpine:3.18': { sizeBytes: 7_400_000 },
|
|
112
|
+
'alpine:3.17': { sizeBytes: 7_000_000 },
|
|
113
|
+
'centos:latest': { sizeBytes: 231_000_000, slimAlternative: 'alpine:latest' },
|
|
114
|
+
'centos:7': { sizeBytes: 204_000_000, slimAlternative: 'alpine:latest' },
|
|
115
|
+
'amazonlinux:latest': { sizeBytes: 163_000_000, slimAlternative: 'alpine:latest' },
|
|
116
|
+
'amazonlinux:2023': { sizeBytes: 163_000_000, slimAlternative: 'alpine:latest' },
|
|
117
|
+
'amazonlinux:2': { sizeBytes: 163_000_000, slimAlternative: 'alpine:latest' },
|
|
118
|
+
'fedora:latest': { sizeBytes: 190_000_000, slimAlternative: 'alpine:latest' },
|
|
119
|
+
'fedora:39': { sizeBytes: 190_000_000, slimAlternative: 'alpine:latest' },
|
|
120
|
+
'archlinux:latest': { sizeBytes: 430_000_000, slimAlternative: 'alpine:latest' },
|
|
121
|
+
// ── Nginx ──────────────────────────────────────────────────
|
|
122
|
+
'nginx:latest': { sizeBytes: 187_000_000, slimAlternative: 'nginx:alpine' },
|
|
123
|
+
'nginx:1': { sizeBytes: 187_000_000, slimAlternative: 'nginx:1-alpine' },
|
|
124
|
+
'nginx:1.25': { sizeBytes: 187_000_000, slimAlternative: 'nginx:1.25-alpine' },
|
|
125
|
+
'nginx:alpine': { sizeBytes: 43_000_000 },
|
|
126
|
+
'nginx:1-alpine': { sizeBytes: 43_000_000 },
|
|
127
|
+
'nginx:1.25-alpine': { sizeBytes: 43_000_000 },
|
|
128
|
+
// ── Postgres ───────────────────────────────────────────────
|
|
129
|
+
'postgres:latest': { sizeBytes: 432_000_000, slimAlternative: 'postgres:alpine' },
|
|
130
|
+
'postgres:16': { sizeBytes: 432_000_000, slimAlternative: 'postgres:16-alpine' },
|
|
131
|
+
'postgres:15': { sizeBytes: 420_000_000, slimAlternative: 'postgres:15-alpine' },
|
|
132
|
+
'postgres:16-alpine': { sizeBytes: 115_000_000 },
|
|
133
|
+
'postgres:15-alpine': { sizeBytes: 112_000_000 },
|
|
134
|
+
'postgres:alpine': { sizeBytes: 115_000_000 },
|
|
135
|
+
// ── Redis ──────────────────────────────────────────────────
|
|
136
|
+
'redis:latest': { sizeBytes: 138_000_000, slimAlternative: 'redis:alpine' },
|
|
137
|
+
'redis:7': { sizeBytes: 138_000_000, slimAlternative: 'redis:7-alpine' },
|
|
138
|
+
'redis:alpine': { sizeBytes: 35_000_000 },
|
|
139
|
+
'redis:7-alpine': { sizeBytes: 35_000_000 },
|
|
140
|
+
// ── MySQL / MariaDB ────────────────────────────────────────
|
|
141
|
+
'mysql:latest': { sizeBytes: 580_000_000 },
|
|
142
|
+
'mysql:8': { sizeBytes: 580_000_000 },
|
|
143
|
+
'mariadb:latest': { sizeBytes: 405_000_000 },
|
|
144
|
+
'mariadb:11': { sizeBytes: 405_000_000 },
|
|
145
|
+
// ── Mongo ──────────────────────────────────────────────────
|
|
146
|
+
'mongo:latest': { sizeBytes: 740_000_000 },
|
|
147
|
+
'mongo:7': { sizeBytes: 740_000_000 },
|
|
148
|
+
// ── httpd / Apache ─────────────────────────────────────────
|
|
149
|
+
'httpd:latest': { sizeBytes: 168_000_000, slimAlternative: 'httpd:alpine' },
|
|
150
|
+
'httpd:2': { sizeBytes: 168_000_000, slimAlternative: 'httpd:2-alpine' },
|
|
151
|
+
'httpd:alpine': { sizeBytes: 55_000_000 },
|
|
152
|
+
'httpd:2-alpine': { sizeBytes: 55_000_000 },
|
|
153
|
+
// ── Traefik ────────────────────────────────────────────────
|
|
154
|
+
'traefik:latest': { sizeBytes: 150_000_000 },
|
|
155
|
+
'traefik:v3': { sizeBytes: 150_000_000 },
|
|
156
|
+
// ── Busybox / scratch ──────────────────────────────────────
|
|
157
|
+
'busybox:latest': { sizeBytes: 4_300_000 },
|
|
158
|
+
'scratch': { sizeBytes: 0 },
|
|
159
|
+
// ── Distroless ─────────────────────────────────────────────
|
|
160
|
+
'gcr.io/distroless/static-debian12': { sizeBytes: 2_500_000 },
|
|
161
|
+
'gcr.io/distroless/base-debian12': { sizeBytes: 20_000_000 },
|
|
162
|
+
'gcr.io/distroless/java21-debian12': { sizeBytes: 230_000_000 },
|
|
163
|
+
};
|
|
164
|
+
/** Lookup image size by name and tag */
|
|
165
|
+
export function getImageSize(image, tag) {
|
|
166
|
+
// Try exact match first
|
|
167
|
+
const key = `${image}:${tag}`;
|
|
168
|
+
if (BASE_IMAGE_DB[key])
|
|
169
|
+
return BASE_IMAGE_DB[key].sizeBytes;
|
|
170
|
+
// Try with 'latest' fallback
|
|
171
|
+
if (tag === 'latest' && BASE_IMAGE_DB[`${image}:latest`]) {
|
|
172
|
+
return BASE_IMAGE_DB[`${image}:latest`].sizeBytes;
|
|
173
|
+
}
|
|
174
|
+
return undefined;
|
|
175
|
+
}
|
|
176
|
+
/** Get slim/alpine alternative for an image:tag, if one exists */
|
|
177
|
+
export function getSlimAlternative(image, tag) {
|
|
178
|
+
const key = `${image}:${tag}`;
|
|
179
|
+
const entry = BASE_IMAGE_DB[key];
|
|
180
|
+
if (!entry?.slimAlternative)
|
|
181
|
+
return undefined;
|
|
182
|
+
const altEntry = BASE_IMAGE_DB[entry.slimAlternative];
|
|
183
|
+
if (!altEntry)
|
|
184
|
+
return undefined;
|
|
185
|
+
return {
|
|
186
|
+
alternative: entry.slimAlternative,
|
|
187
|
+
alternativeSizeBytes: altEntry.sizeBytes,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=base-image-db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-image-db.js","sourceRoot":"","sources":["../../src/data/base-image-db.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,uCAAuC;AACvC,MAAM,CAAC,MAAM,aAAa,GAA+B;IACvD,8DAA8D;IAC9D,aAAa,EAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE;IAC/E,SAAS,EAAY,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE;IAClF,kBAAkB,EAAG,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,uBAAuB,EAAE;IAC3F,kBAAkB,EAAG,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,uBAAuB,EAAE;IAC3F,SAAS,EAAY,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE;IAClF,kBAAkB,EAAG,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,uBAAuB,EAAE;IAC3F,kBAAkB,EAAG,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,uBAAuB,EAAE;IAC3F,SAAS,EAAY,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE;IAClF,kBAAkB,EAAG,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,uBAAuB,EAAE;IAC3F,kBAAkB,EAAG,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,uBAAuB,EAAE;IAC3F,cAAc,EAAO,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE;IAClF,cAAc,EAAO,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE;IAClF,cAAc,EAAO,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE;IAClF,gBAAgB,EAAK,EAAE,SAAS,EAAE,WAAW,EAAE;IAC/C,gBAAgB,EAAK,EAAE,SAAS,EAAE,WAAW,EAAE;IAC/C,gBAAgB,EAAK,EAAE,SAAS,EAAE,WAAW,EAAE;IAE/C,8DAA8D;IAC9D,eAAe,EAAM,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,aAAa,EAAE;IACjF,UAAU,EAAW,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE;IACnF,aAAa,EAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,kBAAkB,EAAE;IACtF,aAAa,EAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,kBAAkB,EAAE;IACtF,aAAa,EAAQ,EAAE,SAAS,EAAE,WAAW,EAAG,eAAe,EAAE,kBAAkB,EAAE;IACrF,YAAY,EAAS,EAAE,SAAS,EAAE,WAAW,EAAG,eAAe,EAAE,iBAAiB,EAAE;IACpF,sBAAsB,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,kBAAkB,EAAE;IACzF,sBAAsB,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,kBAAkB,EAAE;IACzF,eAAe,EAAM,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,iBAAiB,EAAE;IACnF,kBAAkB,EAAG,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,oBAAoB,EAAE;IACtF,kBAAkB,EAAG,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,oBAAoB,EAAE;IACtF,kBAAkB,EAAG,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,oBAAoB,EAAE;IACtF,aAAa,EAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE;IACjF,oBAAoB,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE;IAC/C,oBAAoB,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE;IAC/C,oBAAoB,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE;IAC/C,iBAAiB,EAAI,EAAE,SAAS,EAAE,UAAU,EAAE;IAC9C,eAAe,EAAM,EAAE,SAAS,EAAE,UAAU,EAAE;IAE9C,8DAA8D;IAC9D,aAAa,EAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE;IAC/E,QAAQ,EAAa,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,aAAa,EAAE;IACjF,UAAU,EAAW,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE;IACnF,UAAU,EAAW,EAAE,SAAS,EAAE,WAAW,EAAG,eAAe,EAAE,eAAe,EAAE;IAClF,aAAa,EAAQ,EAAE,SAAS,EAAE,WAAW,EAAG,eAAe,EAAE,eAAe,EAAE;IAClF,eAAe,EAAM,EAAE,SAAS,EAAE,WAAW,EAAG,eAAe,EAAE,iBAAiB,EAAE;IACpF,iBAAiB,EAAI,EAAE,SAAS,EAAE,UAAU,EAAE;IAC9C,eAAe,EAAM,EAAE,SAAS,EAAE,UAAU,EAAE;IAE9C,8DAA8D;IAC9D,eAAe,EAAM,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE;IACjF,UAAU,EAAW,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,iBAAiB,EAAE;IACnF,aAAa,EAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,oBAAoB,EAAE;IACtF,aAAa,EAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,oBAAoB,EAAE;IACtF,oBAAoB,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE;IAChD,oBAAoB,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE;IAChD,iBAAiB,EAAI,EAAE,SAAS,EAAE,WAAW,EAAE;IAC/C,eAAe,EAAM,EAAE,SAAS,EAAE,WAAW,EAAE;IAE/C,8DAA8D;IAC9D,gBAAgB,EAAK,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,+BAA+B,EAAE;IACjG,YAAY,EAAS,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,+BAA+B,EAAE;IACjG,YAAY,EAAS,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,+BAA+B,EAAE;IACjG,YAAY,EAAS,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,+BAA+B,EAAE;IACjG,oBAAoB,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,+BAA+B,EAAE;IAClG,oBAAoB,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,+BAA+B,EAAE;IAClG,wBAAwB,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,+BAA+B,EAAE;IACtG,wBAAwB,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,+BAA+B,EAAE;IACtG,+BAA+B,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE;IAC3D,+BAA+B,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE;IAE3D,8DAA8D;IAC9D,aAAa,EAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE;IAC/E,QAAQ,EAAa,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,aAAa,EAAE;IACjF,WAAW,EAAU,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,gBAAgB,EAAE;IACpF,WAAW,EAAU,EAAE,SAAS,EAAE,WAAW,EAAG,eAAe,EAAE,aAAa,EAAE;IAChF,aAAa,EAAQ,EAAE,SAAS,EAAE,WAAW,EAAG,eAAe,EAAE,eAAe,EAAE;IAClF,aAAa,EAAQ,EAAE,SAAS,EAAE,WAAW,EAAE;IAC/C,eAAe,EAAM,EAAE,SAAS,EAAE,WAAW,EAAE;IAE/C,8DAA8D;IAC9D,YAAY,EAAS,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE;IAClF,OAAO,EAAc,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,kBAAkB,EAAE;IACpF,SAAS,EAAY,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,oBAAoB,EAAE;IACtF,aAAa,EAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,oBAAoB,EAAE;IACtF,gBAAgB,EAAK,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,oBAAoB,EAAE;IACtF,oBAAoB,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE;IAChD,oBAAoB,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE;IAChD,kBAAkB,EAAG,EAAE,SAAS,EAAE,WAAW,EAAE;IAC/C,gBAAgB,EAAK,EAAE,SAAS,EAAE,WAAW,EAAE;IAE/C,8DAA8D;IAC9D,kCAAkC,EAAM,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,4CAA4C,EAAE;IACjI,kCAAkC,EAAM,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,4CAA4C,EAAE;IACjI,qCAAqC,EAAG,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,4CAA4C,EAAE;IACjI,4CAA4C,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE;IACxE,4CAA4C,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE;IAExE,8DAA8D;IAC9D,eAAe,EAAM,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE;IAChF,cAAc,EAAO,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE;IAC9E,cAAc,EAAO,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE;IAC9E,cAAc,EAAO,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE;IAC9E,eAAe,EAAM,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,sBAAsB,EAAE;IACxF,iBAAiB,EAAI,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,sBAAsB,EAAE;IACxF,iBAAiB,EAAI,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,sBAAsB,EAAE;IACxF,sBAAsB,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE;IACnF,sBAAsB,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE;IACnF,eAAe,EAAM,EAAE,SAAS,EAAE,SAAS,EAAE;IAC7C,aAAa,EAAQ,EAAE,SAAS,EAAE,SAAS,EAAE;IAC7C,aAAa,EAAQ,EAAE,SAAS,EAAE,SAAS,EAAE;IAC7C,aAAa,EAAQ,EAAE,SAAS,EAAE,SAAS,EAAE;IAC7C,eAAe,EAAM,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE;IACjF,UAAU,EAAW,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE;IACjF,oBAAoB,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE;IAClF,kBAAkB,EAAG,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE;IACjF,eAAe,EAAM,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE;IACjF,eAAe,EAAM,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE;IACjF,WAAW,EAAU,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE;IACjF,kBAAkB,EAAG,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE;IAEjF,8DAA8D;IAC9D,cAAc,EAAO,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,cAAc,EAAE;IAChF,SAAS,EAAY,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE;IAClF,YAAY,EAAS,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,mBAAmB,EAAE;IACrF,cAAc,EAAO,EAAE,SAAS,EAAE,UAAU,EAAE;IAC9C,gBAAgB,EAAK,EAAE,SAAS,EAAE,UAAU,EAAE;IAC9C,mBAAmB,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE;IAE9C,8DAA8D;IAC9D,iBAAiB,EAAI,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,iBAAiB,EAAE;IACnF,aAAa,EAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,oBAAoB,EAAE;IACtF,aAAa,EAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,oBAAoB,EAAE;IACtF,oBAAoB,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE;IAChD,oBAAoB,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE;IAChD,iBAAiB,EAAI,EAAE,SAAS,EAAE,WAAW,EAAE;IAE/C,8DAA8D;IAC9D,cAAc,EAAO,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,cAAc,EAAE;IAChF,SAAS,EAAY,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE;IAClF,cAAc,EAAO,EAAE,SAAS,EAAE,UAAU,EAAE;IAC9C,gBAAgB,EAAK,EAAE,SAAS,EAAE,UAAU,EAAE;IAE9C,8DAA8D;IAC9D,cAAc,EAAO,EAAE,SAAS,EAAE,WAAW,EAAE;IAC/C,SAAS,EAAY,EAAE,SAAS,EAAE,WAAW,EAAE;IAC/C,gBAAgB,EAAK,EAAE,SAAS,EAAE,WAAW,EAAE;IAC/C,YAAY,EAAS,EAAE,SAAS,EAAE,WAAW,EAAE;IAE/C,8DAA8D;IAC9D,cAAc,EAAO,EAAE,SAAS,EAAE,WAAW,EAAE;IAC/C,SAAS,EAAY,EAAE,SAAS,EAAE,WAAW,EAAE;IAE/C,8DAA8D;IAC9D,cAAc,EAAO,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,cAAc,EAAE;IAChF,SAAS,EAAY,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE;IAClF,cAAc,EAAO,EAAE,SAAS,EAAE,UAAU,EAAE;IAC9C,gBAAgB,EAAK,EAAE,SAAS,EAAE,UAAU,EAAE;IAE9C,8DAA8D;IAC9D,gBAAgB,EAAK,EAAE,SAAS,EAAE,WAAW,EAAE;IAC/C,YAAY,EAAS,EAAE,SAAS,EAAE,WAAW,EAAE;IAE/C,8DAA8D;IAC9D,gBAAgB,EAAK,EAAE,SAAS,EAAE,SAAS,EAAE;IAC7C,SAAS,EAAY,EAAE,SAAS,EAAE,CAAC,EAAE;IAErC,8DAA8D;IAC9D,mCAAmC,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE;IAC7D,iCAAiC,EAAI,EAAE,SAAS,EAAE,UAAU,EAAE;IAC9D,mCAAmC,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE;CAChE,CAAC;AAEF,wCAAwC;AACxC,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,GAAW;IACrD,wBAAwB;IACxB,MAAM,GAAG,GAAG,GAAG,KAAK,IAAI,GAAG,EAAE,CAAC;IAC9B,IAAI,aAAa,CAAC,GAAG,CAAC;QAAE,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC;IAE5D,6BAA6B;IAC7B,IAAI,GAAG,KAAK,QAAQ,IAAI,aAAa,CAAC,GAAG,KAAK,SAAS,CAAC,EAAE,CAAC;QACzD,OAAO,aAAa,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,SAAS,CAAC;IACpD,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,kBAAkB,CAAC,KAAa,EAAE,GAAW;IAC3D,MAAM,GAAG,GAAG,GAAG,KAAK,IAAI,GAAG,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,CAAC,KAAK,EAAE,eAAe;QAAE,OAAO,SAAS,CAAC;IAE9C,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IACtD,IAAI,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAC;IAEhC,OAAO;QACL,WAAW,EAAE,KAAK,CAAC,eAAe;QAClC,oBAAoB,EAAE,QAAQ,CAAC,SAAS;KACzC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exit code constants and determination logic.
|
|
3
|
+
*
|
|
4
|
+
* Exit codes:
|
|
5
|
+
* 0 - No HIGH severity findings
|
|
6
|
+
* 1 - HIGH severity findings present
|
|
7
|
+
* 2 - Runtime error (invalid input, file not found, etc.)
|
|
8
|
+
*/
|
|
9
|
+
import type { Recommendation, Severity } from './types.js';
|
|
10
|
+
/** Named exit codes for CLI process */
|
|
11
|
+
export declare const EXIT_CODE: {
|
|
12
|
+
/** No HIGH findings - all clear or only MEDIUM/LOW */
|
|
13
|
+
readonly SUCCESS: 0;
|
|
14
|
+
/** At least one HIGH severity finding present */
|
|
15
|
+
readonly HIGH_FINDINGS: 1;
|
|
16
|
+
/** Runtime error (bad input, missing file, parse failure) */
|
|
17
|
+
readonly ERROR: 2;
|
|
18
|
+
};
|
|
19
|
+
export type ExitCode = (typeof EXIT_CODE)[keyof typeof EXIT_CODE];
|
|
20
|
+
/**
|
|
21
|
+
* Determine the exit code based on analysis recommendations.
|
|
22
|
+
* Optionally respects a minimum severity filter - only considers
|
|
23
|
+
* findings at or above the given severity threshold.
|
|
24
|
+
*/
|
|
25
|
+
export declare function determineExitCode(recommendations: Recommendation[], minSeverity?: Severity): ExitCode;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exit code constants and determination logic.
|
|
3
|
+
*
|
|
4
|
+
* Exit codes:
|
|
5
|
+
* 0 - No HIGH severity findings
|
|
6
|
+
* 1 - HIGH severity findings present
|
|
7
|
+
* 2 - Runtime error (invalid input, file not found, etc.)
|
|
8
|
+
*/
|
|
9
|
+
import { filterBySeverity } from './severity-filter.js';
|
|
10
|
+
/** Named exit codes for CLI process */
|
|
11
|
+
export const EXIT_CODE = {
|
|
12
|
+
/** No HIGH findings - all clear or only MEDIUM/LOW */
|
|
13
|
+
SUCCESS: 0,
|
|
14
|
+
/** At least one HIGH severity finding present */
|
|
15
|
+
HIGH_FINDINGS: 1,
|
|
16
|
+
/** Runtime error (bad input, missing file, parse failure) */
|
|
17
|
+
ERROR: 2,
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Determine the exit code based on analysis recommendations.
|
|
21
|
+
* Optionally respects a minimum severity filter - only considers
|
|
22
|
+
* findings at or above the given severity threshold.
|
|
23
|
+
*/
|
|
24
|
+
export function determineExitCode(recommendations, minSeverity) {
|
|
25
|
+
const filtered = minSeverity
|
|
26
|
+
? filterBySeverity(recommendations, minSeverity)
|
|
27
|
+
: recommendations;
|
|
28
|
+
const hasHigh = filtered.some((r) => r.severity === 'HIGH');
|
|
29
|
+
return hasHigh ? EXIT_CODE.HIGH_FINDINGS : EXIT_CODE.SUCCESS;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=exit-codes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exit-codes.js","sourceRoot":"","sources":["../src/exit-codes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,uCAAuC;AACvC,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,sDAAsD;IACtD,OAAO,EAAE,CAAC;IACV,iDAAiD;IACjD,aAAa,EAAE,CAAC;IAChB,6DAA6D;IAC7D,KAAK,EAAE,CAAC;CACA,CAAC;AAIX;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC/B,eAAiC,EACjC,WAAsB;IAEtB,MAAM,QAAQ,GAAG,WAAW;QAC1B,CAAC,CAAC,gBAAgB,CAAC,eAAe,EAAE,WAAW,CAAC;QAChD,CAAC,CAAC,eAAe,CAAC;IAEpB,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC;IAC5D,OAAO,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC;AAC/D,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formatter dispatcher — maps OutputFormat to the correct formatter function.
|
|
3
|
+
*
|
|
4
|
+
* Single point of routing so the CLI and any future callers
|
|
5
|
+
* don't need to import each formatter individually.
|
|
6
|
+
*/
|
|
7
|
+
import type { AnalysisResult, Recommendation } from '../types.js';
|
|
8
|
+
import type { OutputFormat } from '../cli.js';
|
|
9
|
+
/** Formatter function signature shared by all three formatters */
|
|
10
|
+
export type FormatterFn = (result: AnalysisResult, filteredRecommendations: Recommendation[]) => string;
|
|
11
|
+
/**
|
|
12
|
+
* Select the formatter function for a given output format.
|
|
13
|
+
* Throws if format is not recognized (should not happen after CLI validation).
|
|
14
|
+
*/
|
|
15
|
+
export declare function getFormatter(format: OutputFormat): FormatterFn;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formatter dispatcher — maps OutputFormat to the correct formatter function.
|
|
3
|
+
*
|
|
4
|
+
* Single point of routing so the CLI and any future callers
|
|
5
|
+
* don't need to import each formatter individually.
|
|
6
|
+
*/
|
|
7
|
+
import { formatTerminal } from './terminal-formatter.js';
|
|
8
|
+
import { formatJson } from './json-formatter.js';
|
|
9
|
+
import { formatMarkdown } from './markdown-formatter.js';
|
|
10
|
+
/** Map of format name to its formatter function */
|
|
11
|
+
const FORMATTER_MAP = {
|
|
12
|
+
terminal: formatTerminal,
|
|
13
|
+
json: formatJson,
|
|
14
|
+
markdown: formatMarkdown,
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Select the formatter function for a given output format.
|
|
18
|
+
* Throws if format is not recognized (should not happen after CLI validation).
|
|
19
|
+
*/
|
|
20
|
+
export function getFormatter(format) {
|
|
21
|
+
const fn = FORMATTER_MAP[format];
|
|
22
|
+
if (!fn) {
|
|
23
|
+
throw new Error(`Unknown output format: ${format}`);
|
|
24
|
+
}
|
|
25
|
+
return fn;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=formatter-dispatcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter-dispatcher.js","sourceRoot":"","sources":["../../src/formatters/formatter-dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAQzD,mDAAmD;AACnD,MAAM,aAAa,GAAsC;IACvD,QAAQ,EAAE,cAAc;IACxB,IAAI,EAAE,UAAU;IAChB,QAAQ,EAAE,cAAc;CACzB,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,MAAoB;IAC/C,MAAM,EAAE,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,MAAM,IAAI,KAAK,CAAC,0BAA0B,MAAM,EAAE,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON formatter — converts AnalysisResult into versioned JSON output.
|
|
3
|
+
* Emits structured JSON to stdout for CI/CD pipeline consumption.
|
|
4
|
+
*/
|
|
5
|
+
import type { AnalysisResult, Recommendation } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Format an AnalysisResult as versioned JSON string.
|
|
8
|
+
* Findings are filtered by minimum severity before output.
|
|
9
|
+
*/
|
|
10
|
+
export declare function formatJson(result: AnalysisResult, filteredRecommendations: Recommendation[]): string;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON formatter — converts AnalysisResult into versioned JSON output.
|
|
3
|
+
* Emits structured JSON to stdout for CI/CD pipeline consumption.
|
|
4
|
+
*/
|
|
5
|
+
import { JSON_SCHEMA_VERSION } from './json-schema.js';
|
|
6
|
+
/** Convert bytes to human-readable string */
|
|
7
|
+
function formatBytes(bytes) {
|
|
8
|
+
if (bytes >= 1_000_000_000)
|
|
9
|
+
return `${(bytes / 1_000_000_000).toFixed(1)}GB`;
|
|
10
|
+
if (bytes >= 1_000_000)
|
|
11
|
+
return `${(bytes / 1_000_000).toFixed(0)}MB`;
|
|
12
|
+
if (bytes >= 1_000)
|
|
13
|
+
return `${(bytes / 1_000).toFixed(0)}KB`;
|
|
14
|
+
return `${bytes}B`;
|
|
15
|
+
}
|
|
16
|
+
/** Map a Recommendation to the JSON wire format */
|
|
17
|
+
function toJsonFinding(rec) {
|
|
18
|
+
return {
|
|
19
|
+
ruleId: rec.ruleId,
|
|
20
|
+
severity: rec.severity,
|
|
21
|
+
line: rec.line,
|
|
22
|
+
title: rec.title,
|
|
23
|
+
description: rec.description,
|
|
24
|
+
fix: rec.fix,
|
|
25
|
+
estimatedSavingsBytes: rec.estimatedSavingsBytes,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Format an AnalysisResult as versioned JSON string.
|
|
30
|
+
* Findings are filtered by minimum severity before output.
|
|
31
|
+
*/
|
|
32
|
+
export function formatJson(result, filteredRecommendations) {
|
|
33
|
+
const output = {
|
|
34
|
+
schemaVersion: JSON_SCHEMA_VERSION,
|
|
35
|
+
dockerfilePath: result.dockerfilePath,
|
|
36
|
+
isMultiStage: result.isMultiStage,
|
|
37
|
+
baseImage: result.baseImage,
|
|
38
|
+
estimatedBeforeSize: {
|
|
39
|
+
totalBytes: result.estimatedBeforeSizeBytes,
|
|
40
|
+
humanReadable: formatBytes(result.estimatedBeforeSizeBytes),
|
|
41
|
+
},
|
|
42
|
+
estimatedAfterSize: {
|
|
43
|
+
totalBytes: result.estimatedAfterSizeBytes,
|
|
44
|
+
humanReadable: formatBytes(result.estimatedAfterSizeBytes),
|
|
45
|
+
},
|
|
46
|
+
sizeReductionPercent: result.sizeReductionPercent,
|
|
47
|
+
totalFindings: result.recommendations.length,
|
|
48
|
+
findings: filteredRecommendations.map(toJsonFinding),
|
|
49
|
+
};
|
|
50
|
+
return JSON.stringify(output, null, 2);
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=json-formatter.js.map
|