@platforma-sdk/package-builder-lib 1.4.0 → 1.4.1
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/dist/core/docker.cjs
CHANGED
|
@@ -84,8 +84,6 @@ function build(context, dockerfile, tag, softwarePackage, softwareVersion) {
|
|
|
84
84
|
"build",
|
|
85
85
|
"--platform",
|
|
86
86
|
require_defaults.DOCKER_BUILD_PLATFORM,
|
|
87
|
-
"--provenance=false",
|
|
88
|
-
"--sbom=false",
|
|
89
87
|
"-t",
|
|
90
88
|
tag,
|
|
91
89
|
context,
|
|
@@ -101,7 +99,8 @@ function build(context, dockerfile, tag, softwarePackage, softwareVersion) {
|
|
|
101
99
|
stdio: "inherit",
|
|
102
100
|
env: {
|
|
103
101
|
...process.env,
|
|
104
|
-
HOME: process.env.HOME || node_os.homedir()
|
|
102
|
+
HOME: process.env.HOME || node_os.homedir(),
|
|
103
|
+
BUILDX_NO_DEFAULT_ATTESTATIONS: "1"
|
|
105
104
|
}
|
|
106
105
|
});
|
|
107
106
|
if (result.error) throw result.error;
|
package/dist/core/docker.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docker.cjs","names":["os","path","fs"],"sources":["../../src/core/docker.ts"],"sourcesContent":["import { spawnSync } from \"node:child_process\";\nimport * as defaults from \"../defaults\";\nimport type * as artifacts from \"./schemas/artifacts\";\nimport * as util from \"./util\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\n\n/**\n * To allow entrypoint keep both docker and binary package at the same time, we create virtual entrypoint with ':docker' suffix,\n * as entrypoints could not keep two different artifacts at the same time.\n */\nexport function entrypointName(name: string): string {\n return name + \":docker\";\n}\n\nexport function isVirtualDockerEntrypointName(name: string): boolean {\n return name.endsWith(\":docker\");\n}\n\nexport function entrypointNameToOrigin(name: string): string {\n if (!isVirtualDockerEntrypointName(name)) {\n return name;\n }\n return name.substring(0, name.length - \":docker\".length);\n}\n\nexport function getImageHash(tag: string): string {\n const result = spawnSync(\n \"docker\",\n [\"image\", \"ls\", \"--filter=reference=\" + tag, \"--format={{.ID}}\"],\n {\n stdio: \"pipe\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n },\n );\n\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw util.CLIError(`local docker image check failed with status ${result.status}`);\n }\n\n const output = result.stdout.toString().trim();\n if (output.split(\"\\n\").length > 1) {\n throw util.CLIError(\n `package-builder internal logic error: more than one image found by exact tag match: ${output}`,\n );\n }\n\n return output;\n}\n\nexport function getImageEntrypoint(tag: string): string[] {\n const result = spawnSync(\n \"docker\",\n [\"image\", \"inspect\", tag, \"--format\", \"{{ .Config.Entrypoint | json }}\"],\n {\n stdio: \"pipe\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n },\n );\n\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw util.CLIError(`'docker image inspect' failed with status ${result.status}`);\n }\n\n const output = result.stdout.toString().trim(); // 'null' or '[<string>, ...]' in JSON format\n return (JSON.parse(output) ?? []) as string[];\n}\n\nexport function localImageExists(tag: string): boolean {\n return getImageHash(tag) !== \"\";\n}\n\nexport function remoteImageExists(tag: string): boolean {\n const result = spawnSync(\"docker\", [\"manifest\", \"inspect\", tag], {\n stdio: \"pipe\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n });\n\n if (result.error || result.status !== 0) {\n return false;\n }\n\n return true;\n}\n\nexport function build(\n context: string,\n dockerfile: string,\n tag: string,\n softwarePackage: string,\n softwareVersion: string | undefined,\n) {\n const result = spawnSync(\n \"docker\",\n [\n \"build\",\n // Pin platform so Platforma's linux/amd64 K8s nodes can run the image\n // regardless of host arch (cross-compile via qemu on non-x64 hosts).\n \"--platform\",\n defaults.DOCKER_BUILD_PLATFORM,\n // Disable buildkit's SLSA provenance + SBOM attestations. They embed\n // build-time timestamps into the manifest list, which produces a fresh\n // image digest on every build of identical source. That breaks the\n // content-addressable tag scheme (every dev rebuild re-pushes a new\n // tag) and defeats publishDockerImage's `remoteImageExists` smart-skip.\n \"--provenance=false\",\n \"--sbom=false\",\n \"-t\",\n tag,\n context,\n \"-f\",\n dockerfile,\n \"--label\",\n \"com.milaboratories.package-builder.software=true\",\n \"--label\",\n \"com.milaboratories.package-builder.software.package=\" + softwarePackage,\n \"--label\",\n \"com.milaboratories.package-builder.software.version=\" + softwareVersion,\n ],\n {\n stdio: \"inherit\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n },\n );\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw util.CLIError(`'docker build' failed with status ${result.status}`);\n }\n}\n\nexport function push(tag: string) {\n const result = spawnSync(\"docker\", [\"push\", tag], {\n stdio: \"inherit\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n });\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n const registry = tag.split(\"/\")[0];\n throw util.CLIError(\n `'docker push ${tag}' failed with status ${result.status}.\\n` +\n `If the error above mentions authentication or denied access, log in first:\\n` +\n ` aws sso login --profile research-poweruser <YOUR_PROFILE:research-poweruser?> \\n` +\n `Then login in docker:` +\n ` aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin ${registry}\\n` +\n `(for a private ECR use 'aws ecr' and your region instead of 'ecr-public'/us-east-1).`,\n );\n }\n}\n\nexport function addTag(imageIdOrTag: string, newTag: string) {\n const result = spawnSync(\"docker\", [\"image\", \"tag\", imageIdOrTag, newTag], {\n stdio: \"inherit\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n });\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw util.CLIError(`'docker tag' failed with status ${result.status}`);\n }\n}\n\nexport function removeTag(imageTag: string) {\n const result = spawnSync(\"docker\", [\"image\", \"rm\", imageTag], {\n stdio: \"inherit\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n });\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw util.CLIError(`'docker image rm' failed with status ${result.status}`);\n }\n}\n\n/**\n * Generate unique content-addressable image tag\n * @param artifactName: artifact name generated from package name and artifact ID (or explicitly set for artifact in .name field)\n * @param imageID: unique image content hash (docker image ID in docker ls)\n * @param registry: custom registry and repository to use for this image\n * @returns full image tag in format: <registry>/repository:<artifactName>.<imageID>\n */\nexport function generateRemoteTagName(\n artifactName: string,\n imageID: string,\n registry?: string,\n): string {\n return dockerTag(artifactName, imageID, registry);\n}\n\n/**\n * Generate unique content-addressable image tag out of directories and Dockerfile.\n * @param packageRoot: package root path from where to resolve artifact's paths (context, Dockerfile, ...)\n * @param artifact: docker artifact configuration\n * @returns full image tag in format: <registry>/repository:<artifactName>.<contentHash>\n */\nexport function generateLocalTagName(packageRoot: string, artifact: artifacts.dockerType): string {\n const dockerfile = dockerfileAbsPath(packageRoot, artifact);\n const context = contextAbsPath(packageRoot, artifact);\n const hash = contentHash(context, dockerfile);\n\n return dockerTag(\"local-image\", hash);\n}\n\n/**\n * Absolute path to autogenerated Dockerfile for given artifact.\n * @param packageRoot: package root path from where to resolve artifact's paths (context, Dockerfile, ...)\n * @param artifactID: artifact ID\n * @returns absolute path to autogenerated Dockerfile\n */\nexport function dockerfileAutogenPath(packageRoot: string, artifactID: string): string {\n return path.resolve(packageRoot, \"dist\", \"docker\", `Dockerfile-${artifactID}`);\n}\n\n/**\n * Resolve path to Dockerfile.\n * @param packageRoot: package root path from where to resolve artifact's paths (context, Dockerfile, ...)\n * @param artifact: docker artifact configuration\n * @returns absolute path to Dockerfile\n */\nfunction dockerfileAbsPath(packageRoot: string, artifact: artifacts.dockerType): string {\n return path.resolve(packageRoot, artifact.dockerfile ?? \"Dockerfile\");\n}\n\n/**\n * Resolve path to docker build context directory.\n * @param packageRoot: package root path from where to resolve artifact's paths (context, Dockerfile, ...)\n * @param artifact: docker artifact configuration\n * @returns absolute path to docker build context directory\n */\nfunction contextAbsPath(packageRoot: string, artifact: artifacts.dockerType): string {\n if (artifact.context === \"./\" || artifact.context === \".\") {\n throw util.CLIError(\n `Invalid Docker context: \"${artifact.context}\". Context cannot be \"./\" or \".\" - use absolute path or relative path without \"./\" prefix`,\n );\n }\n return path.resolve(packageRoot, artifact.context ?? \".\");\n}\n\n/**\n * Calculate cummulative hash of docker build context directory context and Dockerfile.\n * To speedup hash calculation, we do not read contents of each item in context dir but\n * use metadata (size, mtime, ...).\n *\n * @param contextFullPath: abs path to docker build context\n * @param dockerfileFullPath: abs path to Dockerfile\n * @returns hash of what the keep\n */\nfunction contentHash(contextFullPath: string, dockerfileFullPath: string): string {\n if (!fs.existsSync(dockerfileFullPath)) {\n throw util.CLIError(`Dockerfile '${dockerfileFullPath}' not found`);\n }\n\n if (!fs.existsSync(contextFullPath)) {\n throw util.CLIError(`Context '${contextFullPath}' not found`);\n }\n\n const contextHash = util.hashDirMetaSync(contextFullPath);\n const dockerfileContent = fs.readFileSync(dockerfileFullPath, \"utf8\");\n contextHash.update(dockerfileContent);\n\n return contextHash.digest(\"hex\").slice(0, 12);\n}\n\nfunction dockerTag(packageName: string, contentHash: string, registry?: string): string {\n const dockerRegistry = registry ?? defaults.DOCKER_REGISTRY;\n return `${dockerRegistry}:${packageName.replaceAll(\"/\", \".\")}.${contentHash}`;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"docker.cjs","names":["os","path","fs"],"sources":["../../src/core/docker.ts"],"sourcesContent":["import { spawnSync } from \"node:child_process\";\nimport * as defaults from \"../defaults\";\nimport type * as artifacts from \"./schemas/artifacts\";\nimport * as util from \"./util\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\n\n/**\n * To allow entrypoint keep both docker and binary package at the same time, we create virtual entrypoint with ':docker' suffix,\n * as entrypoints could not keep two different artifacts at the same time.\n */\nexport function entrypointName(name: string): string {\n return name + \":docker\";\n}\n\nexport function isVirtualDockerEntrypointName(name: string): boolean {\n return name.endsWith(\":docker\");\n}\n\nexport function entrypointNameToOrigin(name: string): string {\n if (!isVirtualDockerEntrypointName(name)) {\n return name;\n }\n return name.substring(0, name.length - \":docker\".length);\n}\n\nexport function getImageHash(tag: string): string {\n const result = spawnSync(\n \"docker\",\n [\"image\", \"ls\", \"--filter=reference=\" + tag, \"--format={{.ID}}\"],\n {\n stdio: \"pipe\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n },\n );\n\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw util.CLIError(`local docker image check failed with status ${result.status}`);\n }\n\n const output = result.stdout.toString().trim();\n if (output.split(\"\\n\").length > 1) {\n throw util.CLIError(\n `package-builder internal logic error: more than one image found by exact tag match: ${output}`,\n );\n }\n\n return output;\n}\n\nexport function getImageEntrypoint(tag: string): string[] {\n const result = spawnSync(\n \"docker\",\n [\"image\", \"inspect\", tag, \"--format\", \"{{ .Config.Entrypoint | json }}\"],\n {\n stdio: \"pipe\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n },\n );\n\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw util.CLIError(`'docker image inspect' failed with status ${result.status}`);\n }\n\n const output = result.stdout.toString().trim(); // 'null' or '[<string>, ...]' in JSON format\n return (JSON.parse(output) ?? []) as string[];\n}\n\nexport function localImageExists(tag: string): boolean {\n return getImageHash(tag) !== \"\";\n}\n\nexport function remoteImageExists(tag: string): boolean {\n const result = spawnSync(\"docker\", [\"manifest\", \"inspect\", tag], {\n stdio: \"pipe\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n });\n\n if (result.error || result.status !== 0) {\n return false;\n }\n\n return true;\n}\n\nexport function build(\n context: string,\n dockerfile: string,\n tag: string,\n softwarePackage: string,\n softwareVersion: string | undefined,\n) {\n const result = spawnSync(\n \"docker\",\n [\n \"build\",\n // Pin platform so Platforma's linux/amd64 K8s nodes can run the image\n // regardless of host arch (cross-compile via qemu on non-x64 hosts).\n \"--platform\",\n defaults.DOCKER_BUILD_PLATFORM,\n \"-t\",\n tag,\n context,\n \"-f\",\n dockerfile,\n \"--label\",\n \"com.milaboratories.package-builder.software=true\",\n \"--label\",\n \"com.milaboratories.package-builder.software.package=\" + softwarePackage,\n \"--label\",\n \"com.milaboratories.package-builder.software.version=\" + softwareVersion,\n ],\n {\n stdio: \"inherit\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n // Disables buildx default provenance so the image ID stays stable; podman ignores it.\n BUILDX_NO_DEFAULT_ATTESTATIONS: \"1\",\n },\n },\n );\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw util.CLIError(`'docker build' failed with status ${result.status}`);\n }\n}\n\nexport function push(tag: string) {\n const result = spawnSync(\"docker\", [\"push\", tag], {\n stdio: \"inherit\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n });\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n const registry = tag.split(\"/\")[0];\n throw util.CLIError(\n `'docker push ${tag}' failed with status ${result.status}.\\n` +\n `If the error above mentions authentication or denied access, log in first:\\n` +\n ` aws sso login --profile research-poweruser <YOUR_PROFILE:research-poweruser?> \\n` +\n `Then login in docker:` +\n ` aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin ${registry}\\n` +\n `(for a private ECR use 'aws ecr' and your region instead of 'ecr-public'/us-east-1).`,\n );\n }\n}\n\nexport function addTag(imageIdOrTag: string, newTag: string) {\n const result = spawnSync(\"docker\", [\"image\", \"tag\", imageIdOrTag, newTag], {\n stdio: \"inherit\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n });\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw util.CLIError(`'docker tag' failed with status ${result.status}`);\n }\n}\n\nexport function removeTag(imageTag: string) {\n const result = spawnSync(\"docker\", [\"image\", \"rm\", imageTag], {\n stdio: \"inherit\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n });\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw util.CLIError(`'docker image rm' failed with status ${result.status}`);\n }\n}\n\n/**\n * Generate unique content-addressable image tag\n * @param artifactName: artifact name generated from package name and artifact ID (or explicitly set for artifact in .name field)\n * @param imageID: unique image content hash (docker image ID in docker ls)\n * @param registry: custom registry and repository to use for this image\n * @returns full image tag in format: <registry>/repository:<artifactName>.<imageID>\n */\nexport function generateRemoteTagName(\n artifactName: string,\n imageID: string,\n registry?: string,\n): string {\n return dockerTag(artifactName, imageID, registry);\n}\n\n/**\n * Generate unique content-addressable image tag out of directories and Dockerfile.\n * @param packageRoot: package root path from where to resolve artifact's paths (context, Dockerfile, ...)\n * @param artifact: docker artifact configuration\n * @returns full image tag in format: <registry>/repository:<artifactName>.<contentHash>\n */\nexport function generateLocalTagName(packageRoot: string, artifact: artifacts.dockerType): string {\n const dockerfile = dockerfileAbsPath(packageRoot, artifact);\n const context = contextAbsPath(packageRoot, artifact);\n const hash = contentHash(context, dockerfile);\n\n return dockerTag(\"local-image\", hash);\n}\n\n/**\n * Absolute path to autogenerated Dockerfile for given artifact.\n * @param packageRoot: package root path from where to resolve artifact's paths (context, Dockerfile, ...)\n * @param artifactID: artifact ID\n * @returns absolute path to autogenerated Dockerfile\n */\nexport function dockerfileAutogenPath(packageRoot: string, artifactID: string): string {\n return path.resolve(packageRoot, \"dist\", \"docker\", `Dockerfile-${artifactID}`);\n}\n\n/**\n * Resolve path to Dockerfile.\n * @param packageRoot: package root path from where to resolve artifact's paths (context, Dockerfile, ...)\n * @param artifact: docker artifact configuration\n * @returns absolute path to Dockerfile\n */\nfunction dockerfileAbsPath(packageRoot: string, artifact: artifacts.dockerType): string {\n return path.resolve(packageRoot, artifact.dockerfile ?? \"Dockerfile\");\n}\n\n/**\n * Resolve path to docker build context directory.\n * @param packageRoot: package root path from where to resolve artifact's paths (context, Dockerfile, ...)\n * @param artifact: docker artifact configuration\n * @returns absolute path to docker build context directory\n */\nfunction contextAbsPath(packageRoot: string, artifact: artifacts.dockerType): string {\n if (artifact.context === \"./\" || artifact.context === \".\") {\n throw util.CLIError(\n `Invalid Docker context: \"${artifact.context}\". Context cannot be \"./\" or \".\" - use absolute path or relative path without \"./\" prefix`,\n );\n }\n return path.resolve(packageRoot, artifact.context ?? \".\");\n}\n\n/**\n * Calculate cummulative hash of docker build context directory context and Dockerfile.\n * To speedup hash calculation, we do not read contents of each item in context dir but\n * use metadata (size, mtime, ...).\n *\n * @param contextFullPath: abs path to docker build context\n * @param dockerfileFullPath: abs path to Dockerfile\n * @returns hash of what the keep\n */\nfunction contentHash(contextFullPath: string, dockerfileFullPath: string): string {\n if (!fs.existsSync(dockerfileFullPath)) {\n throw util.CLIError(`Dockerfile '${dockerfileFullPath}' not found`);\n }\n\n if (!fs.existsSync(contextFullPath)) {\n throw util.CLIError(`Context '${contextFullPath}' not found`);\n }\n\n const contextHash = util.hashDirMetaSync(contextFullPath);\n const dockerfileContent = fs.readFileSync(dockerfileFullPath, \"utf8\");\n contextHash.update(dockerfileContent);\n\n return contextHash.digest(\"hex\").slice(0, 12);\n}\n\nfunction dockerTag(packageName: string, contentHash: string, registry?: string): string {\n const dockerRegistry = registry ?? defaults.DOCKER_REGISTRY;\n return `${dockerRegistry}:${packageName.replaceAll(\"/\", \".\")}.${contentHash}`;\n}\n"],"mappings":"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"}
|
package/dist/core/docker.js
CHANGED
|
@@ -80,8 +80,6 @@ function build(context, dockerfile, tag, softwarePackage, softwareVersion) {
|
|
|
80
80
|
"build",
|
|
81
81
|
"--platform",
|
|
82
82
|
DOCKER_BUILD_PLATFORM,
|
|
83
|
-
"--provenance=false",
|
|
84
|
-
"--sbom=false",
|
|
85
83
|
"-t",
|
|
86
84
|
tag,
|
|
87
85
|
context,
|
|
@@ -97,7 +95,8 @@ function build(context, dockerfile, tag, softwarePackage, softwareVersion) {
|
|
|
97
95
|
stdio: "inherit",
|
|
98
96
|
env: {
|
|
99
97
|
...process.env,
|
|
100
|
-
HOME: process.env.HOME || os.homedir()
|
|
98
|
+
HOME: process.env.HOME || os.homedir(),
|
|
99
|
+
BUILDX_NO_DEFAULT_ATTESTATIONS: "1"
|
|
101
100
|
}
|
|
102
101
|
});
|
|
103
102
|
if (result.error) throw result.error;
|
package/dist/core/docker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docker.js","names":["util.CLIError","defaults.DOCKER_BUILD_PLATFORM","path","fs","util.hashDirMetaSync"],"sources":["../../src/core/docker.ts"],"sourcesContent":["import { spawnSync } from \"node:child_process\";\nimport * as defaults from \"../defaults\";\nimport type * as artifacts from \"./schemas/artifacts\";\nimport * as util from \"./util\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\n\n/**\n * To allow entrypoint keep both docker and binary package at the same time, we create virtual entrypoint with ':docker' suffix,\n * as entrypoints could not keep two different artifacts at the same time.\n */\nexport function entrypointName(name: string): string {\n return name + \":docker\";\n}\n\nexport function isVirtualDockerEntrypointName(name: string): boolean {\n return name.endsWith(\":docker\");\n}\n\nexport function entrypointNameToOrigin(name: string): string {\n if (!isVirtualDockerEntrypointName(name)) {\n return name;\n }\n return name.substring(0, name.length - \":docker\".length);\n}\n\nexport function getImageHash(tag: string): string {\n const result = spawnSync(\n \"docker\",\n [\"image\", \"ls\", \"--filter=reference=\" + tag, \"--format={{.ID}}\"],\n {\n stdio: \"pipe\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n },\n );\n\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw util.CLIError(`local docker image check failed with status ${result.status}`);\n }\n\n const output = result.stdout.toString().trim();\n if (output.split(\"\\n\").length > 1) {\n throw util.CLIError(\n `package-builder internal logic error: more than one image found by exact tag match: ${output}`,\n );\n }\n\n return output;\n}\n\nexport function getImageEntrypoint(tag: string): string[] {\n const result = spawnSync(\n \"docker\",\n [\"image\", \"inspect\", tag, \"--format\", \"{{ .Config.Entrypoint | json }}\"],\n {\n stdio: \"pipe\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n },\n );\n\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw util.CLIError(`'docker image inspect' failed with status ${result.status}`);\n }\n\n const output = result.stdout.toString().trim(); // 'null' or '[<string>, ...]' in JSON format\n return (JSON.parse(output) ?? []) as string[];\n}\n\nexport function localImageExists(tag: string): boolean {\n return getImageHash(tag) !== \"\";\n}\n\nexport function remoteImageExists(tag: string): boolean {\n const result = spawnSync(\"docker\", [\"manifest\", \"inspect\", tag], {\n stdio: \"pipe\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n });\n\n if (result.error || result.status !== 0) {\n return false;\n }\n\n return true;\n}\n\nexport function build(\n context: string,\n dockerfile: string,\n tag: string,\n softwarePackage: string,\n softwareVersion: string | undefined,\n) {\n const result = spawnSync(\n \"docker\",\n [\n \"build\",\n // Pin platform so Platforma's linux/amd64 K8s nodes can run the image\n // regardless of host arch (cross-compile via qemu on non-x64 hosts).\n \"--platform\",\n defaults.DOCKER_BUILD_PLATFORM,\n // Disable buildkit's SLSA provenance + SBOM attestations. They embed\n // build-time timestamps into the manifest list, which produces a fresh\n // image digest on every build of identical source. That breaks the\n // content-addressable tag scheme (every dev rebuild re-pushes a new\n // tag) and defeats publishDockerImage's `remoteImageExists` smart-skip.\n \"--provenance=false\",\n \"--sbom=false\",\n \"-t\",\n tag,\n context,\n \"-f\",\n dockerfile,\n \"--label\",\n \"com.milaboratories.package-builder.software=true\",\n \"--label\",\n \"com.milaboratories.package-builder.software.package=\" + softwarePackage,\n \"--label\",\n \"com.milaboratories.package-builder.software.version=\" + softwareVersion,\n ],\n {\n stdio: \"inherit\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n },\n );\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw util.CLIError(`'docker build' failed with status ${result.status}`);\n }\n}\n\nexport function push(tag: string) {\n const result = spawnSync(\"docker\", [\"push\", tag], {\n stdio: \"inherit\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n });\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n const registry = tag.split(\"/\")[0];\n throw util.CLIError(\n `'docker push ${tag}' failed with status ${result.status}.\\n` +\n `If the error above mentions authentication or denied access, log in first:\\n` +\n ` aws sso login --profile research-poweruser <YOUR_PROFILE:research-poweruser?> \\n` +\n `Then login in docker:` +\n ` aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin ${registry}\\n` +\n `(for a private ECR use 'aws ecr' and your region instead of 'ecr-public'/us-east-1).`,\n );\n }\n}\n\nexport function addTag(imageIdOrTag: string, newTag: string) {\n const result = spawnSync(\"docker\", [\"image\", \"tag\", imageIdOrTag, newTag], {\n stdio: \"inherit\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n });\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw util.CLIError(`'docker tag' failed with status ${result.status}`);\n }\n}\n\nexport function removeTag(imageTag: string) {\n const result = spawnSync(\"docker\", [\"image\", \"rm\", imageTag], {\n stdio: \"inherit\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n });\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw util.CLIError(`'docker image rm' failed with status ${result.status}`);\n }\n}\n\n/**\n * Generate unique content-addressable image tag\n * @param artifactName: artifact name generated from package name and artifact ID (or explicitly set for artifact in .name field)\n * @param imageID: unique image content hash (docker image ID in docker ls)\n * @param registry: custom registry and repository to use for this image\n * @returns full image tag in format: <registry>/repository:<artifactName>.<imageID>\n */\nexport function generateRemoteTagName(\n artifactName: string,\n imageID: string,\n registry?: string,\n): string {\n return dockerTag(artifactName, imageID, registry);\n}\n\n/**\n * Generate unique content-addressable image tag out of directories and Dockerfile.\n * @param packageRoot: package root path from where to resolve artifact's paths (context, Dockerfile, ...)\n * @param artifact: docker artifact configuration\n * @returns full image tag in format: <registry>/repository:<artifactName>.<contentHash>\n */\nexport function generateLocalTagName(packageRoot: string, artifact: artifacts.dockerType): string {\n const dockerfile = dockerfileAbsPath(packageRoot, artifact);\n const context = contextAbsPath(packageRoot, artifact);\n const hash = contentHash(context, dockerfile);\n\n return dockerTag(\"local-image\", hash);\n}\n\n/**\n * Absolute path to autogenerated Dockerfile for given artifact.\n * @param packageRoot: package root path from where to resolve artifact's paths (context, Dockerfile, ...)\n * @param artifactID: artifact ID\n * @returns absolute path to autogenerated Dockerfile\n */\nexport function dockerfileAutogenPath(packageRoot: string, artifactID: string): string {\n return path.resolve(packageRoot, \"dist\", \"docker\", `Dockerfile-${artifactID}`);\n}\n\n/**\n * Resolve path to Dockerfile.\n * @param packageRoot: package root path from where to resolve artifact's paths (context, Dockerfile, ...)\n * @param artifact: docker artifact configuration\n * @returns absolute path to Dockerfile\n */\nfunction dockerfileAbsPath(packageRoot: string, artifact: artifacts.dockerType): string {\n return path.resolve(packageRoot, artifact.dockerfile ?? \"Dockerfile\");\n}\n\n/**\n * Resolve path to docker build context directory.\n * @param packageRoot: package root path from where to resolve artifact's paths (context, Dockerfile, ...)\n * @param artifact: docker artifact configuration\n * @returns absolute path to docker build context directory\n */\nfunction contextAbsPath(packageRoot: string, artifact: artifacts.dockerType): string {\n if (artifact.context === \"./\" || artifact.context === \".\") {\n throw util.CLIError(\n `Invalid Docker context: \"${artifact.context}\". Context cannot be \"./\" or \".\" - use absolute path or relative path without \"./\" prefix`,\n );\n }\n return path.resolve(packageRoot, artifact.context ?? \".\");\n}\n\n/**\n * Calculate cummulative hash of docker build context directory context and Dockerfile.\n * To speedup hash calculation, we do not read contents of each item in context dir but\n * use metadata (size, mtime, ...).\n *\n * @param contextFullPath: abs path to docker build context\n * @param dockerfileFullPath: abs path to Dockerfile\n * @returns hash of what the keep\n */\nfunction contentHash(contextFullPath: string, dockerfileFullPath: string): string {\n if (!fs.existsSync(dockerfileFullPath)) {\n throw util.CLIError(`Dockerfile '${dockerfileFullPath}' not found`);\n }\n\n if (!fs.existsSync(contextFullPath)) {\n throw util.CLIError(`Context '${contextFullPath}' not found`);\n }\n\n const contextHash = util.hashDirMetaSync(contextFullPath);\n const dockerfileContent = fs.readFileSync(dockerfileFullPath, \"utf8\");\n contextHash.update(dockerfileContent);\n\n return contextHash.digest(\"hex\").slice(0, 12);\n}\n\nfunction dockerTag(packageName: string, contentHash: string, registry?: string): string {\n const dockerRegistry = registry ?? defaults.DOCKER_REGISTRY;\n return `${dockerRegistry}:${packageName.replaceAll(\"/\", \".\")}.${contentHash}`;\n}\n"],"mappings":";;;;;;;;;;;AAYA,SAAgB,eAAe,MAAsB;CACnD,OAAO,OAAO;AAChB;AAEA,SAAgB,8BAA8B,MAAuB;CACnE,OAAO,KAAK,SAAS,SAAS;AAChC;AAEA,SAAgB,uBAAuB,MAAsB;CAC3D,IAAI,CAAC,8BAA8B,IAAI,GACrC,OAAO;CAET,OAAO,KAAK,UAAU,GAAG,KAAK,SAAS,CAAgB;AACzD;AAEA,SAAgB,aAAa,KAAqB;CAChD,MAAM,SAAS,UACb,UACA;EAAC;EAAS;EAAM,wBAAwB;EAAK;CAAkB,GAC/D;EACE,OAAO;EACP,KAAK;GACH,GAAG,QAAQ;GACX,MAAM,QAAQ,IAAI,QAAQ,GAAG,QAAQ;EACvC;CACF,CACF;CAEA,IAAI,OAAO,OACT,MAAM,OAAO;CAEf,IAAI,OAAO,WAAW,GACpB,MAAMA,SAAc,+CAA+C,OAAO,QAAQ;CAGpF,MAAM,SAAS,OAAO,OAAO,SAAS,CAAC,CAAC,KAAK;CAC7C,IAAI,OAAO,MAAM,IAAI,CAAC,CAAC,SAAS,GAC9B,MAAMA,SACJ,uFAAuF,QACzF;CAGF,OAAO;AACT;AAEA,SAAgB,mBAAmB,KAAuB;CACxD,MAAM,SAAS,UACb,UACA;EAAC;EAAS;EAAW;EAAK;EAAY;CAAiC,GACvE;EACE,OAAO;EACP,KAAK;GACH,GAAG,QAAQ;GACX,MAAM,QAAQ,IAAI,QAAQ,GAAG,QAAQ;EACvC;CACF,CACF;CAEA,IAAI,OAAO,OACT,MAAM,OAAO;CAEf,IAAI,OAAO,WAAW,GACpB,MAAMA,SAAc,6CAA6C,OAAO,QAAQ;CAGlF,MAAM,SAAS,OAAO,OAAO,SAAS,CAAC,CAAC,KAAK;CAC7C,OAAQ,KAAK,MAAM,MAAM,KAAK,CAAC;AACjC;AAEA,SAAgB,iBAAiB,KAAsB;CACrD,OAAO,aAAa,GAAG,MAAM;AAC/B;AAEA,SAAgB,kBAAkB,KAAsB;CACtD,MAAM,SAAS,UAAU,UAAU;EAAC;EAAY;EAAW;CAAG,GAAG;EAC/D,OAAO;EACP,KAAK;GACH,GAAG,QAAQ;GACX,MAAM,QAAQ,IAAI,QAAQ,GAAG,QAAQ;EACvC;CACF,CAAC;CAED,IAAI,OAAO,SAAS,OAAO,WAAW,GACpC,OAAO;CAGT,OAAO;AACT;AAEA,SAAgB,MACd,SACA,YACA,KACA,iBACA,iBACA;CACA,MAAM,SAAS,UACb,UACA;EACE;EAGA;EACAC;EAMA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,yDAAyD;EACzD;EACA,yDAAyD;CAC3D,GACA;EACE,OAAO;EACP,KAAK;GACH,GAAG,QAAQ;GACX,MAAM,QAAQ,IAAI,QAAQ,GAAG,QAAQ;EACvC;CACF,CACF;CACA,IAAI,OAAO,OACT,MAAM,OAAO;CAEf,IAAI,OAAO,WAAW,GACpB,MAAMD,SAAc,qCAAqC,OAAO,QAAQ;AAE5E;AAEA,SAAgB,KAAK,KAAa;CAChC,MAAM,SAAS,UAAU,UAAU,CAAC,QAAQ,GAAG,GAAG;EAChD,OAAO;EACP,KAAK;GACH,GAAG,QAAQ;GACX,MAAM,QAAQ,IAAI,QAAQ,GAAG,QAAQ;EACvC;CACF,CAAC;CACD,IAAI,OAAO,OACT,MAAM,OAAO;CAEf,IAAI,OAAO,WAAW,GAAG;EACvB,MAAM,WAAW,IAAI,MAAM,GAAG,CAAC,CAAC;EAChC,MAAMA,SACJ,gBAAgB,IAAI,uBAAuB,OAAO,OAAO,8RAIkD,SAAS,uFAEtH;CACF;AACF;AAEA,SAAgB,OAAO,cAAsB,QAAgB;CAC3D,MAAM,SAAS,UAAU,UAAU;EAAC;EAAS;EAAO;EAAc;CAAM,GAAG;EACzE,OAAO;EACP,KAAK;GACH,GAAG,QAAQ;GACX,MAAM,QAAQ,IAAI,QAAQ,GAAG,QAAQ;EACvC;CACF,CAAC;CACD,IAAI,OAAO,OACT,MAAM,OAAO;CAEf,IAAI,OAAO,WAAW,GACpB,MAAMA,SAAc,mCAAmC,OAAO,QAAQ;AAE1E;;;;;;;;AAyBA,SAAgB,sBACd,cACA,SACA,UACQ;CACR,OAAO,UAAU,cAAc,SAAS,QAAQ;AAClD;;;;;;;AAQA,SAAgB,qBAAqB,aAAqB,UAAwC;CAChG,MAAM,aAAa,kBAAkB,aAAa,QAAQ;CAI1D,OAAO,UAAU,eAFJ,YADG,eAAe,aAAa,QACb,GAAG,UAEC,CAAC;AACtC;;;;;;;AAQA,SAAgB,sBAAsB,aAAqB,YAA4B;CACrF,OAAOE,OAAK,QAAQ,aAAa,QAAQ,UAAU,cAAc,YAAY;AAC/E;;;;;;;AAQA,SAAS,kBAAkB,aAAqB,UAAwC;CACtF,OAAOA,OAAK,QAAQ,aAAa,SAAS,cAAc,YAAY;AACtE;;;;;;;AAQA,SAAS,eAAe,aAAqB,UAAwC;CACnF,IAAI,SAAS,YAAY,QAAQ,SAAS,YAAY,KACpD,MAAMF,SACJ,4BAA4B,SAAS,QAAQ,0FAC/C;CAEF,OAAOE,OAAK,QAAQ,aAAa,SAAS,WAAW,GAAG;AAC1D;;;;;;;;;;AAWA,SAAS,YAAY,iBAAyB,oBAAoC;CAChF,IAAI,CAACC,KAAG,WAAW,kBAAkB,GACnC,MAAMH,SAAc,eAAe,mBAAmB,YAAY;CAGpE,IAAI,CAACG,KAAG,WAAW,eAAe,GAChC,MAAMH,SAAc,YAAY,gBAAgB,YAAY;CAG9D,MAAM,cAAcI,gBAAqB,eAAe;CACxD,MAAM,oBAAoBD,KAAG,aAAa,oBAAoB,MAAM;CACpE,YAAY,OAAO,iBAAiB;CAEpC,OAAO,YAAY,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG,EAAE;AAC9C;AAEA,SAAS,UAAU,aAAqB,aAAqB,UAA2B;CAEtF,OAAO,GADgB,YAAY,0DACV,GAAG,YAAY,WAAW,KAAK,GAAG,EAAE,GAAG;AAClE"}
|
|
1
|
+
{"version":3,"file":"docker.js","names":["util.CLIError","defaults.DOCKER_BUILD_PLATFORM","path","fs","util.hashDirMetaSync"],"sources":["../../src/core/docker.ts"],"sourcesContent":["import { spawnSync } from \"node:child_process\";\nimport * as defaults from \"../defaults\";\nimport type * as artifacts from \"./schemas/artifacts\";\nimport * as util from \"./util\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\n\n/**\n * To allow entrypoint keep both docker and binary package at the same time, we create virtual entrypoint with ':docker' suffix,\n * as entrypoints could not keep two different artifacts at the same time.\n */\nexport function entrypointName(name: string): string {\n return name + \":docker\";\n}\n\nexport function isVirtualDockerEntrypointName(name: string): boolean {\n return name.endsWith(\":docker\");\n}\n\nexport function entrypointNameToOrigin(name: string): string {\n if (!isVirtualDockerEntrypointName(name)) {\n return name;\n }\n return name.substring(0, name.length - \":docker\".length);\n}\n\nexport function getImageHash(tag: string): string {\n const result = spawnSync(\n \"docker\",\n [\"image\", \"ls\", \"--filter=reference=\" + tag, \"--format={{.ID}}\"],\n {\n stdio: \"pipe\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n },\n );\n\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw util.CLIError(`local docker image check failed with status ${result.status}`);\n }\n\n const output = result.stdout.toString().trim();\n if (output.split(\"\\n\").length > 1) {\n throw util.CLIError(\n `package-builder internal logic error: more than one image found by exact tag match: ${output}`,\n );\n }\n\n return output;\n}\n\nexport function getImageEntrypoint(tag: string): string[] {\n const result = spawnSync(\n \"docker\",\n [\"image\", \"inspect\", tag, \"--format\", \"{{ .Config.Entrypoint | json }}\"],\n {\n stdio: \"pipe\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n },\n );\n\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw util.CLIError(`'docker image inspect' failed with status ${result.status}`);\n }\n\n const output = result.stdout.toString().trim(); // 'null' or '[<string>, ...]' in JSON format\n return (JSON.parse(output) ?? []) as string[];\n}\n\nexport function localImageExists(tag: string): boolean {\n return getImageHash(tag) !== \"\";\n}\n\nexport function remoteImageExists(tag: string): boolean {\n const result = spawnSync(\"docker\", [\"manifest\", \"inspect\", tag], {\n stdio: \"pipe\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n });\n\n if (result.error || result.status !== 0) {\n return false;\n }\n\n return true;\n}\n\nexport function build(\n context: string,\n dockerfile: string,\n tag: string,\n softwarePackage: string,\n softwareVersion: string | undefined,\n) {\n const result = spawnSync(\n \"docker\",\n [\n \"build\",\n // Pin platform so Platforma's linux/amd64 K8s nodes can run the image\n // regardless of host arch (cross-compile via qemu on non-x64 hosts).\n \"--platform\",\n defaults.DOCKER_BUILD_PLATFORM,\n \"-t\",\n tag,\n context,\n \"-f\",\n dockerfile,\n \"--label\",\n \"com.milaboratories.package-builder.software=true\",\n \"--label\",\n \"com.milaboratories.package-builder.software.package=\" + softwarePackage,\n \"--label\",\n \"com.milaboratories.package-builder.software.version=\" + softwareVersion,\n ],\n {\n stdio: \"inherit\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n // Disables buildx default provenance so the image ID stays stable; podman ignores it.\n BUILDX_NO_DEFAULT_ATTESTATIONS: \"1\",\n },\n },\n );\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw util.CLIError(`'docker build' failed with status ${result.status}`);\n }\n}\n\nexport function push(tag: string) {\n const result = spawnSync(\"docker\", [\"push\", tag], {\n stdio: \"inherit\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n });\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n const registry = tag.split(\"/\")[0];\n throw util.CLIError(\n `'docker push ${tag}' failed with status ${result.status}.\\n` +\n `If the error above mentions authentication or denied access, log in first:\\n` +\n ` aws sso login --profile research-poweruser <YOUR_PROFILE:research-poweruser?> \\n` +\n `Then login in docker:` +\n ` aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin ${registry}\\n` +\n `(for a private ECR use 'aws ecr' and your region instead of 'ecr-public'/us-east-1).`,\n );\n }\n}\n\nexport function addTag(imageIdOrTag: string, newTag: string) {\n const result = spawnSync(\"docker\", [\"image\", \"tag\", imageIdOrTag, newTag], {\n stdio: \"inherit\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n });\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw util.CLIError(`'docker tag' failed with status ${result.status}`);\n }\n}\n\nexport function removeTag(imageTag: string) {\n const result = spawnSync(\"docker\", [\"image\", \"rm\", imageTag], {\n stdio: \"inherit\",\n env: {\n ...process.env, // PATH variable from parent process affects execution\n HOME: process.env.HOME || os.homedir(), // Ensure HOME is set\n },\n });\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw util.CLIError(`'docker image rm' failed with status ${result.status}`);\n }\n}\n\n/**\n * Generate unique content-addressable image tag\n * @param artifactName: artifact name generated from package name and artifact ID (or explicitly set for artifact in .name field)\n * @param imageID: unique image content hash (docker image ID in docker ls)\n * @param registry: custom registry and repository to use for this image\n * @returns full image tag in format: <registry>/repository:<artifactName>.<imageID>\n */\nexport function generateRemoteTagName(\n artifactName: string,\n imageID: string,\n registry?: string,\n): string {\n return dockerTag(artifactName, imageID, registry);\n}\n\n/**\n * Generate unique content-addressable image tag out of directories and Dockerfile.\n * @param packageRoot: package root path from where to resolve artifact's paths (context, Dockerfile, ...)\n * @param artifact: docker artifact configuration\n * @returns full image tag in format: <registry>/repository:<artifactName>.<contentHash>\n */\nexport function generateLocalTagName(packageRoot: string, artifact: artifacts.dockerType): string {\n const dockerfile = dockerfileAbsPath(packageRoot, artifact);\n const context = contextAbsPath(packageRoot, artifact);\n const hash = contentHash(context, dockerfile);\n\n return dockerTag(\"local-image\", hash);\n}\n\n/**\n * Absolute path to autogenerated Dockerfile for given artifact.\n * @param packageRoot: package root path from where to resolve artifact's paths (context, Dockerfile, ...)\n * @param artifactID: artifact ID\n * @returns absolute path to autogenerated Dockerfile\n */\nexport function dockerfileAutogenPath(packageRoot: string, artifactID: string): string {\n return path.resolve(packageRoot, \"dist\", \"docker\", `Dockerfile-${artifactID}`);\n}\n\n/**\n * Resolve path to Dockerfile.\n * @param packageRoot: package root path from where to resolve artifact's paths (context, Dockerfile, ...)\n * @param artifact: docker artifact configuration\n * @returns absolute path to Dockerfile\n */\nfunction dockerfileAbsPath(packageRoot: string, artifact: artifacts.dockerType): string {\n return path.resolve(packageRoot, artifact.dockerfile ?? \"Dockerfile\");\n}\n\n/**\n * Resolve path to docker build context directory.\n * @param packageRoot: package root path from where to resolve artifact's paths (context, Dockerfile, ...)\n * @param artifact: docker artifact configuration\n * @returns absolute path to docker build context directory\n */\nfunction contextAbsPath(packageRoot: string, artifact: artifacts.dockerType): string {\n if (artifact.context === \"./\" || artifact.context === \".\") {\n throw util.CLIError(\n `Invalid Docker context: \"${artifact.context}\". Context cannot be \"./\" or \".\" - use absolute path or relative path without \"./\" prefix`,\n );\n }\n return path.resolve(packageRoot, artifact.context ?? \".\");\n}\n\n/**\n * Calculate cummulative hash of docker build context directory context and Dockerfile.\n * To speedup hash calculation, we do not read contents of each item in context dir but\n * use metadata (size, mtime, ...).\n *\n * @param contextFullPath: abs path to docker build context\n * @param dockerfileFullPath: abs path to Dockerfile\n * @returns hash of what the keep\n */\nfunction contentHash(contextFullPath: string, dockerfileFullPath: string): string {\n if (!fs.existsSync(dockerfileFullPath)) {\n throw util.CLIError(`Dockerfile '${dockerfileFullPath}' not found`);\n }\n\n if (!fs.existsSync(contextFullPath)) {\n throw util.CLIError(`Context '${contextFullPath}' not found`);\n }\n\n const contextHash = util.hashDirMetaSync(contextFullPath);\n const dockerfileContent = fs.readFileSync(dockerfileFullPath, \"utf8\");\n contextHash.update(dockerfileContent);\n\n return contextHash.digest(\"hex\").slice(0, 12);\n}\n\nfunction dockerTag(packageName: string, contentHash: string, registry?: string): string {\n const dockerRegistry = registry ?? defaults.DOCKER_REGISTRY;\n return `${dockerRegistry}:${packageName.replaceAll(\"/\", \".\")}.${contentHash}`;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platforma-sdk/package-builder-lib",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "MiLaboratories Platforma Package builder engine (library)",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -31,15 +31,15 @@
|
|
|
31
31
|
"@milaboratories/resolve-helper": "1.1.3"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@platforma-open/milaboratories.runenv-python-3": "1.
|
|
34
|
+
"@platforma-open/milaboratories.runenv-python-3": "1.13.2",
|
|
35
35
|
"@types/archiver": "^6.0.3",
|
|
36
36
|
"@types/node": "~24.5.2",
|
|
37
37
|
"@vitest/coverage-istanbul": "^4.1.3",
|
|
38
38
|
"typescript": "7.0.2",
|
|
39
39
|
"vite": "^8.0.6",
|
|
40
40
|
"vitest": "^4.1.3",
|
|
41
|
+
"@milaboratories/build-configs": "2.0.2",
|
|
41
42
|
"@milaboratories/ts-configs": "1.4.0",
|
|
42
|
-
"@milaboratories/build-configs": "2.0.1",
|
|
43
43
|
"@milaboratories/ts-builder": "1.7.2"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { describe, it, expect, afterEach, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
const { spawnMock } = vi.hoisted(() => ({ spawnMock: vi.fn() }));
|
|
4
|
+
vi.mock("node:child_process", () => ({ spawnSync: spawnMock }));
|
|
5
|
+
|
|
6
|
+
const docker = await import("../docker");
|
|
7
|
+
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
vi.clearAllMocks();
|
|
10
|
+
vi.unstubAllEnvs();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
function runBuild() {
|
|
14
|
+
spawnMock.mockReturnValue({ status: 0 });
|
|
15
|
+
docker.build("/ctx", "/ctx/Dockerfile", "local:tag", "pkg/main", "1.0.0");
|
|
16
|
+
expect(spawnMock).toHaveBeenCalledTimes(1);
|
|
17
|
+
const [cmd, args, opts] = spawnMock.mock.calls[0] as [
|
|
18
|
+
string,
|
|
19
|
+
string[],
|
|
20
|
+
{ env: NodeJS.ProcessEnv },
|
|
21
|
+
];
|
|
22
|
+
return { cmd, args, env: opts.env };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
describe("docker.build", () => {
|
|
26
|
+
it("passes no buildx-only attestation flags, so podman accepts the command", () => {
|
|
27
|
+
const { cmd, args } = runBuild();
|
|
28
|
+
expect(cmd).toBe("docker");
|
|
29
|
+
expect(args[0]).toBe("build");
|
|
30
|
+
expect(args.some((a) => a.startsWith("--provenance") || a.startsWith("--sbom"))).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("disables buildx default attestations through the environment", () => {
|
|
34
|
+
const { env } = runBuild();
|
|
35
|
+
expect(env.BUILDX_NO_DEFAULT_ATTESTATIONS).toBe("1");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("overrides a user value that would enable default attestations", () => {
|
|
39
|
+
vi.stubEnv("BUILDX_NO_DEFAULT_ATTESTATIONS", "0");
|
|
40
|
+
const { env } = runBuild();
|
|
41
|
+
expect(env.BUILDX_NO_DEFAULT_ATTESTATIONS).toBe("1");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("pins the build platform", () => {
|
|
45
|
+
const { args } = runBuild();
|
|
46
|
+
expect(args.slice(args.indexOf("--platform"), args.indexOf("--platform") + 2)).toEqual([
|
|
47
|
+
"--platform",
|
|
48
|
+
"linux/amd64",
|
|
49
|
+
]);
|
|
50
|
+
});
|
|
51
|
+
});
|
package/src/core/docker.ts
CHANGED
|
@@ -114,13 +114,6 @@ export function build(
|
|
|
114
114
|
// regardless of host arch (cross-compile via qemu on non-x64 hosts).
|
|
115
115
|
"--platform",
|
|
116
116
|
defaults.DOCKER_BUILD_PLATFORM,
|
|
117
|
-
// Disable buildkit's SLSA provenance + SBOM attestations. They embed
|
|
118
|
-
// build-time timestamps into the manifest list, which produces a fresh
|
|
119
|
-
// image digest on every build of identical source. That breaks the
|
|
120
|
-
// content-addressable tag scheme (every dev rebuild re-pushes a new
|
|
121
|
-
// tag) and defeats publishDockerImage's `remoteImageExists` smart-skip.
|
|
122
|
-
"--provenance=false",
|
|
123
|
-
"--sbom=false",
|
|
124
117
|
"-t",
|
|
125
118
|
tag,
|
|
126
119
|
context,
|
|
@@ -138,6 +131,8 @@ export function build(
|
|
|
138
131
|
env: {
|
|
139
132
|
...process.env, // PATH variable from parent process affects execution
|
|
140
133
|
HOME: process.env.HOME || os.homedir(), // Ensure HOME is set
|
|
134
|
+
// Disables buildx default provenance so the image ID stays stable; podman ignores it.
|
|
135
|
+
BUILDX_NO_DEFAULT_ATTESTATIONS: "1",
|
|
141
136
|
},
|
|
142
137
|
},
|
|
143
138
|
);
|