@cyclonedx/cdxgen 12.3.2 → 12.4.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/README.md +70 -22
- package/bin/audit.js +21 -7
- package/bin/cdxgen.js +238 -116
- package/bin/convert.js +28 -13
- package/bin/hbom.js +490 -0
- package/bin/repl.js +580 -29
- package/bin/validate.js +34 -4
- package/bin/verify.js +40 -5
- package/data/README.md +298 -25
- package/data/component-tags.json +6 -0
- package/data/crypto-oid.json +16 -0
- package/data/predictive-audit-allowlist.json +11 -0
- package/data/queries-darwin.json +12 -1
- package/data/queries-win.json +7 -1
- package/data/queries.json +39 -2
- package/data/rules/ai-agent-governance.yaml +16 -0
- package/data/rules/asar-archives.yaml +150 -0
- package/data/rules/chrome-extensions.yaml +8 -0
- package/data/rules/ci-permissions.yaml +171 -15
- package/data/rules/container-risk.yaml +14 -7
- package/data/rules/dependency-sources.yaml +76 -5
- package/data/rules/hbom-compliance.yaml +325 -0
- package/data/rules/hbom-performance.yaml +307 -0
- package/data/rules/hbom-security.yaml +248 -0
- package/data/rules/host-topology.yaml +165 -0
- package/data/rules/mcp-servers.yaml +18 -3
- package/data/rules/obom-runtime.yaml +907 -22
- package/data/rules/package-integrity.yaml +36 -0
- package/data/rules/rootfs-hardening.yaml +179 -0
- package/data/rules/vscode-extensions.yaml +9 -0
- package/lib/audit/index.js +209 -8
- package/lib/audit/index.poku.js +332 -0
- package/lib/audit/reporters.js +222 -0
- package/lib/audit/targets.js +146 -1
- package/lib/audit/targets.poku.js +186 -0
- package/lib/cli/asar.poku.js +328 -0
- package/lib/cli/index.js +647 -127
- package/lib/cli/index.poku.js +1905 -187
- package/lib/evinser/evinser.js +14 -9
- package/lib/helpers/agentFormulationParser.js +6 -2
- package/lib/helpers/agentFormulationParser.poku.js +42 -0
- package/lib/helpers/analyzer.js +1444 -38
- package/lib/helpers/analyzer.poku.js +409 -0
- package/lib/helpers/analyzerScope.js +712 -0
- package/lib/helpers/asarutils.js +1556 -0
- package/lib/helpers/asarutils.poku.js +443 -0
- package/lib/helpers/auditCategories.js +12 -0
- package/lib/helpers/auditCategories.poku.js +32 -0
- package/lib/helpers/cbomutils.js +271 -1
- package/lib/helpers/cbomutils.poku.js +248 -5
- package/lib/helpers/chromextutils.js +25 -3
- package/lib/helpers/chromextutils.poku.js +68 -0
- package/lib/helpers/ciParsers/githubActions.js +79 -0
- package/lib/helpers/ciParsers/githubActions.poku.js +103 -0
- package/lib/helpers/communityAiConfigParser.js +15 -5
- package/lib/helpers/communityAiConfigParser.poku.js +71 -0
- package/lib/helpers/depsUtils.js +5 -0
- package/lib/helpers/depsUtils.poku.js +55 -0
- package/lib/helpers/display.js +336 -23
- package/lib/helpers/display.poku.js +179 -43
- package/lib/helpers/evidenceUtils.js +58 -0
- package/lib/helpers/evidenceUtils.poku.js +54 -0
- package/lib/helpers/exportUtils.js +9 -0
- package/lib/helpers/gtfobins.js +142 -8
- package/lib/helpers/gtfobins.poku.js +24 -1
- package/lib/helpers/hbom.js +710 -0
- package/lib/helpers/hbom.poku.js +496 -0
- package/lib/helpers/hbomAnalysis.js +268 -0
- package/lib/helpers/hbomAnalysis.poku.js +249 -0
- package/lib/helpers/hbomLoader.js +35 -0
- package/lib/helpers/hostTopology.js +803 -0
- package/lib/helpers/hostTopology.poku.js +363 -0
- package/lib/helpers/inventoryStats.js +69 -0
- package/lib/helpers/inventoryStats.poku.js +86 -0
- package/lib/helpers/lolbas.js +19 -1
- package/lib/helpers/lolbas.poku.js +23 -0
- package/lib/helpers/mcpConfigParser.js +21 -5
- package/lib/helpers/mcpConfigParser.poku.js +39 -2
- package/lib/helpers/osqueryTransform.js +47 -0
- package/lib/helpers/osqueryTransform.poku.js +47 -0
- package/lib/helpers/plugins.js +349 -0
- package/lib/helpers/plugins.poku.js +57 -0
- package/lib/helpers/propertySanitizer.js +121 -0
- package/lib/helpers/protobom.js +156 -45
- package/lib/helpers/protobom.poku.js +140 -5
- package/lib/helpers/remote/dependency-track.js +36 -3
- package/lib/helpers/remote/dependency-track.poku.js +44 -0
- package/lib/helpers/source.js +24 -0
- package/lib/helpers/source.poku.js +32 -0
- package/lib/helpers/utils.js +2454 -198
- package/lib/helpers/utils.poku.js +1798 -74
- package/lib/managers/binary.e2e.poku.js +367 -0
- package/lib/managers/binary.js +2306 -350
- package/lib/managers/binary.poku.js +1700 -1
- package/lib/managers/docker.js +441 -95
- package/lib/managers/docker.poku.js +1479 -14
- package/lib/server/server.js +2 -24
- package/lib/server/server.poku.js +36 -1
- package/lib/stages/postgen/annotator.js +38 -0
- package/lib/stages/postgen/annotator.poku.js +107 -1
- package/lib/stages/postgen/auditBom.js +121 -18
- package/lib/stages/postgen/auditBom.poku.js +2967 -990
- package/lib/stages/postgen/hostTopologyAudit.poku.js +186 -0
- package/lib/stages/postgen/postgen.js +192 -1
- package/lib/stages/postgen/postgen.poku.js +321 -0
- package/lib/stages/postgen/ruleEngine.js +116 -0
- package/lib/stages/pregen/envAudit.js +14 -3
- package/package.json +24 -21
- package/types/bin/hbom.d.ts +3 -0
- package/types/bin/hbom.d.ts.map +1 -0
- package/types/bin/repl.d.ts.map +1 -1
- package/types/lib/audit/index.d.ts +44 -0
- package/types/lib/audit/index.d.ts.map +1 -1
- package/types/lib/audit/reporters.d.ts +16 -0
- package/types/lib/audit/reporters.d.ts.map +1 -1
- package/types/lib/audit/targets.d.ts.map +1 -1
- package/types/lib/cli/index.d.ts +16 -0
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/evinser/evinser.d.ts +4 -0
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/helpers/agentFormulationParser.d.ts.map +1 -1
- package/types/lib/helpers/analyzer.d.ts +33 -0
- package/types/lib/helpers/analyzer.d.ts.map +1 -1
- package/types/lib/helpers/analyzerScope.d.ts +11 -0
- package/types/lib/helpers/analyzerScope.d.ts.map +1 -0
- package/types/lib/helpers/asarutils.d.ts +34 -0
- package/types/lib/helpers/asarutils.d.ts.map +1 -0
- package/types/lib/helpers/auditCategories.d.ts +5 -0
- package/types/lib/helpers/auditCategories.d.ts.map +1 -1
- package/types/lib/helpers/cbomutils.d.ts +3 -2
- package/types/lib/helpers/cbomutils.d.ts.map +1 -1
- package/types/lib/helpers/chromextutils.d.ts.map +1 -1
- package/types/lib/helpers/ciParsers/githubActions.d.ts.map +1 -1
- package/types/lib/helpers/communityAiConfigParser.d.ts.map +1 -1
- package/types/lib/helpers/depsUtils.d.ts.map +1 -1
- package/types/lib/helpers/display.d.ts +1 -0
- package/types/lib/helpers/display.d.ts.map +1 -1
- package/types/lib/helpers/evidenceUtils.d.ts +8 -0
- package/types/lib/helpers/evidenceUtils.d.ts.map +1 -0
- package/types/lib/helpers/exportUtils.d.ts.map +1 -1
- package/types/lib/helpers/gtfobins.d.ts +8 -0
- package/types/lib/helpers/gtfobins.d.ts.map +1 -1
- package/types/lib/helpers/hbom.d.ts +49 -0
- package/types/lib/helpers/hbom.d.ts.map +1 -0
- package/types/lib/helpers/hbomAnalysis.d.ts +62 -0
- package/types/lib/helpers/hbomAnalysis.d.ts.map +1 -0
- package/types/lib/helpers/hbomLoader.d.ts +7 -0
- package/types/lib/helpers/hbomLoader.d.ts.map +1 -0
- package/types/lib/helpers/hostTopology.d.ts +12 -0
- package/types/lib/helpers/hostTopology.d.ts.map +1 -0
- package/types/lib/helpers/inventoryStats.d.ts +11 -0
- package/types/lib/helpers/inventoryStats.d.ts.map +1 -0
- package/types/lib/helpers/lolbas.d.ts.map +1 -1
- package/types/lib/helpers/mcpConfigParser.d.ts +1 -1
- package/types/lib/helpers/mcpConfigParser.d.ts.map +1 -1
- package/types/lib/helpers/osqueryTransform.d.ts +3 -0
- package/types/lib/helpers/osqueryTransform.d.ts.map +1 -1
- package/types/lib/helpers/plugins.d.ts +58 -0
- package/types/lib/helpers/plugins.d.ts.map +1 -0
- package/types/lib/helpers/propertySanitizer.d.ts +3 -0
- package/types/lib/helpers/propertySanitizer.d.ts.map +1 -0
- package/types/lib/helpers/protobom.d.ts +3 -4
- package/types/lib/helpers/protobom.d.ts.map +1 -1
- package/types/lib/helpers/remote/dependency-track.d.ts +10 -3
- package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -1
- package/types/lib/helpers/source.d.ts.map +1 -1
- package/types/lib/helpers/utils.d.ts +74 -8
- package/types/lib/helpers/utils.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts +5 -0
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts +3 -0
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/server/server.d.ts +2 -0
- package/types/lib/server/server.d.ts.map +1 -1
- package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
- package/types/lib/stages/postgen/auditBom.d.ts +26 -1
- package/types/lib/stages/postgen/auditBom.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts +2 -1
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
- package/types/lib/stages/pregen/envAudit.d.ts.map +1 -1
- package/data/spdx-model-v3.0.1.jsonld +0 -15999
package/lib/managers/docker.js
CHANGED
|
@@ -20,8 +20,12 @@ import {
|
|
|
20
20
|
getAllFiles,
|
|
21
21
|
getTmpDir,
|
|
22
22
|
isDryRun,
|
|
23
|
+
readEnvironmentVariable,
|
|
23
24
|
recordActivity,
|
|
25
|
+
recordDecisionActivity,
|
|
26
|
+
recordSensitiveFileRead,
|
|
24
27
|
safeExistsSync,
|
|
28
|
+
safeExtractArchive,
|
|
25
29
|
safeMkdirSync,
|
|
26
30
|
safeMkdtempSync,
|
|
27
31
|
safeRmSync,
|
|
@@ -32,6 +36,13 @@ import { getDirs, getOnlyDirs } from "./containerutils.js";
|
|
|
32
36
|
|
|
33
37
|
export const isWin = _platform() === "win32";
|
|
34
38
|
export const DOCKER_HUB_REGISTRY = "docker.io";
|
|
39
|
+
// Docker commonly stores Hub credentials under index.docker.io or
|
|
40
|
+
// registry-1.docker.io while pulls target docker.io.
|
|
41
|
+
const DOCKER_HUB_REGISTRY_ALIASES = new Set([
|
|
42
|
+
DOCKER_HUB_REGISTRY,
|
|
43
|
+
"index.docker.io",
|
|
44
|
+
"registry-1.docker.io",
|
|
45
|
+
]);
|
|
35
46
|
|
|
36
47
|
/**
|
|
37
48
|
* Encode a value as base64url (RFC 4648 §5) with padding.
|
|
@@ -42,6 +53,212 @@ export const DOCKER_HUB_REGISTRY = "docker.io";
|
|
|
42
53
|
const toBase64Url = (value) =>
|
|
43
54
|
Buffer.from(value).toString("base64").replace(/\+/g, "-").replace(/\//g, "_");
|
|
44
55
|
|
|
56
|
+
const normalizeRegistryPath = (registryPath) => {
|
|
57
|
+
if (!registryPath || registryPath === "/") {
|
|
58
|
+
return "";
|
|
59
|
+
}
|
|
60
|
+
let normalizedPath = registryPath.trim();
|
|
61
|
+
if (!normalizedPath.startsWith("/")) {
|
|
62
|
+
normalizedPath = `/${normalizedPath}`;
|
|
63
|
+
}
|
|
64
|
+
while (normalizedPath.endsWith("/")) {
|
|
65
|
+
normalizedPath = normalizedPath.slice(0, -1);
|
|
66
|
+
}
|
|
67
|
+
const lowerCasePath = normalizedPath.toLowerCase();
|
|
68
|
+
if (lowerCasePath.endsWith("/v1") || lowerCasePath.endsWith("/v2")) {
|
|
69
|
+
normalizedPath = normalizedPath.slice(0, -3);
|
|
70
|
+
}
|
|
71
|
+
return normalizedPath === "/" ? "" : normalizedPath;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const buildRegistryAuthority = (hostname, port) => {
|
|
75
|
+
if (!hostname) {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
hostname = hostname.toLowerCase();
|
|
79
|
+
if (hostname.includes(":") && !hostname.startsWith("[")) {
|
|
80
|
+
hostname = `[${hostname}]`;
|
|
81
|
+
}
|
|
82
|
+
if (port) {
|
|
83
|
+
return `${hostname}:${port}`;
|
|
84
|
+
}
|
|
85
|
+
return hostname;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const parseRawRegistryAuthority = (authority) => {
|
|
89
|
+
if (!authority?.trim()) {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
authority = authority.trim();
|
|
93
|
+
if (authority.startsWith("[")) {
|
|
94
|
+
const closingBracketIndex = authority.indexOf("]");
|
|
95
|
+
if (closingBracketIndex === -1) {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
const hostname = authority.slice(0, closingBracketIndex + 1);
|
|
99
|
+
const portSuffix = authority.slice(closingBracketIndex + 1);
|
|
100
|
+
if (!portSuffix) {
|
|
101
|
+
return buildRegistryAuthority(hostname);
|
|
102
|
+
}
|
|
103
|
+
if (!/^:\d+$/.test(portSuffix)) {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
return buildRegistryAuthority(hostname, portSuffix.slice(1));
|
|
107
|
+
}
|
|
108
|
+
const colonIndex = authority.lastIndexOf(":");
|
|
109
|
+
if (colonIndex > -1 && authority.indexOf(":") === colonIndex) {
|
|
110
|
+
const portCandidate = authority.slice(colonIndex + 1);
|
|
111
|
+
if (/^\d+$/.test(portCandidate)) {
|
|
112
|
+
return buildRegistryAuthority(
|
|
113
|
+
authority.slice(0, colonIndex),
|
|
114
|
+
portCandidate,
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return buildRegistryAuthority(authority);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const parseRegistryReference = (registry) => {
|
|
122
|
+
if (!registry?.trim()) {
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
registry = registry.trim();
|
|
126
|
+
if (registry.includes("://")) {
|
|
127
|
+
if (!URL.canParse(registry)) {
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
const registryUrl = new URL(registry);
|
|
131
|
+
const authoritySource = registry
|
|
132
|
+
.slice(registry.indexOf("://") + 3)
|
|
133
|
+
.split("/")[0];
|
|
134
|
+
return {
|
|
135
|
+
authority: parseRawRegistryAuthority(authoritySource),
|
|
136
|
+
path: normalizeRegistryPath(registryUrl.pathname),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
const slashIndex = registry.indexOf("/");
|
|
140
|
+
const authority =
|
|
141
|
+
slashIndex === -1 ? registry : registry.slice(0, slashIndex);
|
|
142
|
+
const registryPath = slashIndex === -1 ? "" : registry.slice(slashIndex);
|
|
143
|
+
if (!authority) {
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
// Raw registry references such as host:port are not absolute URLs, so we
|
|
148
|
+
// add an https scheme only to parse the authority and optional port.
|
|
149
|
+
return {
|
|
150
|
+
authority: parseRawRegistryAuthority(authority),
|
|
151
|
+
path: normalizeRegistryPath(registryPath),
|
|
152
|
+
};
|
|
153
|
+
} catch (_err) {
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const looksLikeImageReference = (value) => {
|
|
159
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
value = value.trim();
|
|
163
|
+
if (value.includes("://")) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
if (!value.includes("/")) {
|
|
167
|
+
if (value.includes(":")) {
|
|
168
|
+
const tagOrPortSuffix = value.slice(value.lastIndexOf(":") + 1);
|
|
169
|
+
if (!/^\d+$/.test(tagOrPortSuffix)) {
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
return !parseRegistryReference(value)?.authority;
|
|
173
|
+
}
|
|
174
|
+
return !(
|
|
175
|
+
value.includes(".") ||
|
|
176
|
+
value === "localhost" ||
|
|
177
|
+
value.startsWith("[")
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
const firstSegment = value.split("/")[0];
|
|
181
|
+
return !(
|
|
182
|
+
parseRegistryReference(firstSegment)?.authority &&
|
|
183
|
+
(firstSegment.includes(".") ||
|
|
184
|
+
firstSegment.includes(":") ||
|
|
185
|
+
firstSegment === "localhost" ||
|
|
186
|
+
firstSegment.startsWith("["))
|
|
187
|
+
);
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const resolveRequestedRegistryRef = (forRegistry, requestedRegistryRef) => {
|
|
191
|
+
const fallbackRegistry =
|
|
192
|
+
forRegistry || process.env.DOCKER_SERVER_ADDRESS || DOCKER_HUB_REGISTRY;
|
|
193
|
+
if (
|
|
194
|
+
typeof requestedRegistryRef !== "string" ||
|
|
195
|
+
!requestedRegistryRef.trim()
|
|
196
|
+
) {
|
|
197
|
+
return fallbackRegistry;
|
|
198
|
+
}
|
|
199
|
+
requestedRegistryRef = requestedRegistryRef.trim();
|
|
200
|
+
if (requestedRegistryRef.includes("://")) {
|
|
201
|
+
return requestedRegistryRef;
|
|
202
|
+
}
|
|
203
|
+
return looksLikeImageReference(requestedRegistryRef)
|
|
204
|
+
? fallbackRegistry
|
|
205
|
+
: requestedRegistryRef;
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const extractRequestedRegistryRefFromPath = (path, forRegistry) => {
|
|
209
|
+
if (!path?.includes("?")) {
|
|
210
|
+
return resolveRequestedRegistryRef(forRegistry, forRegistry);
|
|
211
|
+
}
|
|
212
|
+
const queryString = path.slice(path.indexOf("?") + 1);
|
|
213
|
+
const requestedImageRef = new URLSearchParams(queryString).get("fromImage");
|
|
214
|
+
return resolveRequestedRegistryRef(
|
|
215
|
+
forRegistry,
|
|
216
|
+
requestedImageRef || forRegistry,
|
|
217
|
+
);
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
const normalizeRegistryReference = (registry) => {
|
|
221
|
+
const parsedRegistry = parseRegistryReference(registry);
|
|
222
|
+
if (!parsedRegistry?.authority) {
|
|
223
|
+
return undefined;
|
|
224
|
+
}
|
|
225
|
+
return parsedRegistry.path
|
|
226
|
+
? `${parsedRegistry.authority}${parsedRegistry.path}`
|
|
227
|
+
: parsedRegistry.authority;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
const registriesMatch = (configuredRegistry, requestedRegistry) => {
|
|
231
|
+
if (!requestedRegistry) {
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
const normalizedConfiguredRegistry =
|
|
235
|
+
parseRegistryReference(configuredRegistry);
|
|
236
|
+
const normalizedRequestedRegistry = parseRegistryReference(requestedRegistry);
|
|
237
|
+
if (
|
|
238
|
+
!normalizedConfiguredRegistry?.authority ||
|
|
239
|
+
!normalizedRequestedRegistry?.authority
|
|
240
|
+
) {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
const hostMatches =
|
|
244
|
+
normalizedConfiguredRegistry.authority ===
|
|
245
|
+
normalizedRequestedRegistry.authority ||
|
|
246
|
+
(DOCKER_HUB_REGISTRY_ALIASES.has(normalizedConfiguredRegistry.authority) &&
|
|
247
|
+
DOCKER_HUB_REGISTRY_ALIASES.has(normalizedRequestedRegistry.authority));
|
|
248
|
+
if (!hostMatches) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
if (!normalizedConfiguredRegistry.path) {
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
return (
|
|
255
|
+
normalizedConfiguredRegistry.path === normalizedRequestedRegistry.path ||
|
|
256
|
+
normalizedRequestedRegistry.path.startsWith(
|
|
257
|
+
`${normalizedConfiguredRegistry.path}/`,
|
|
258
|
+
)
|
|
259
|
+
);
|
|
260
|
+
};
|
|
261
|
+
|
|
45
262
|
// Should we extract the tar image in non-strict mode
|
|
46
263
|
const NON_STRICT_TAR_EXTRACT = ["true", "1"].includes(
|
|
47
264
|
process?.env?.NON_STRICT_TAR_EXTRACT,
|
|
@@ -185,19 +402,52 @@ const REQUEST_TIMEOUT_SECS = 60000;
|
|
|
185
402
|
*
|
|
186
403
|
* @param {string} [forRegistry] Registry hostname (e.g. "registry-1.docker.io").
|
|
187
404
|
* Defaults to DOCKER_SERVER_ADDRESS env var or "docker.io".
|
|
405
|
+
* @param {string} [requestedRegistryRef] Requested registry/image reference used
|
|
406
|
+
* to scope config.json auth matching. Unqualified images default to Docker Hub.
|
|
188
407
|
* @returns {Object} Options object suitable for passing to `got`
|
|
189
408
|
*/
|
|
190
|
-
const getDefaultOptions = (forRegistry) => {
|
|
409
|
+
const getDefaultOptions = (forRegistry, requestedRegistryRef = forRegistry) => {
|
|
191
410
|
let authTokenSet = false;
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
411
|
+
const credentialSourceEvaluations = [];
|
|
412
|
+
let selectedCredentialSource;
|
|
413
|
+
const noteCredentialSource = (source, outcome, detail = undefined) => {
|
|
414
|
+
credentialSourceEvaluations.push({
|
|
415
|
+
detail,
|
|
416
|
+
outcome,
|
|
417
|
+
source,
|
|
418
|
+
});
|
|
419
|
+
if (outcome === "selected") {
|
|
420
|
+
selectedCredentialSource = source;
|
|
199
421
|
}
|
|
422
|
+
};
|
|
423
|
+
const dockerServerAddress = readEnvironmentVariable("DOCKER_SERVER_ADDRESS");
|
|
424
|
+
const dockerConfig = readEnvironmentVariable("DOCKER_CONFIG");
|
|
425
|
+
const dockerAuthConfig = readEnvironmentVariable("DOCKER_AUTH_CONFIG", {
|
|
426
|
+
sensitive: true,
|
|
427
|
+
});
|
|
428
|
+
const dockerUser = readEnvironmentVariable("DOCKER_USER", {
|
|
429
|
+
sensitive: true,
|
|
430
|
+
});
|
|
431
|
+
const dockerPassword = readEnvironmentVariable("DOCKER_PASSWORD", {
|
|
432
|
+
sensitive: true,
|
|
433
|
+
});
|
|
434
|
+
const dockerEmail = readEnvironmentVariable("DOCKER_EMAIL", {
|
|
435
|
+
sensitive: true,
|
|
436
|
+
});
|
|
437
|
+
if (!forRegistry) {
|
|
438
|
+
forRegistry = dockerServerAddress ?? DOCKER_HUB_REGISTRY;
|
|
200
439
|
}
|
|
440
|
+
requestedRegistryRef = resolveRequestedRegistryRef(
|
|
441
|
+
forRegistry,
|
|
442
|
+
requestedRegistryRef,
|
|
443
|
+
);
|
|
444
|
+
const normalizedForRegistry =
|
|
445
|
+
parseRegistryReference(forRegistry)?.authority ?? forRegistry;
|
|
446
|
+
const authDecisionTarget =
|
|
447
|
+
requestedRegistryRef ||
|
|
448
|
+
normalizedForRegistry ||
|
|
449
|
+
forRegistry ||
|
|
450
|
+
DOCKER_HUB_REGISTRY;
|
|
201
451
|
const opts = {
|
|
202
452
|
enableUnixSockets: true,
|
|
203
453
|
throwHttpErrors: true,
|
|
@@ -214,47 +464,64 @@ const getDefaultOptions = (forRegistry) => {
|
|
|
214
464
|
hooks: { beforeError: [] },
|
|
215
465
|
mutableDefaults: true,
|
|
216
466
|
};
|
|
217
|
-
const DOCKER_CONFIG =
|
|
467
|
+
const DOCKER_CONFIG = dockerConfig || join(homedir(), ".docker");
|
|
468
|
+
const dockerConfigFile = join(DOCKER_CONFIG, "config.json");
|
|
218
469
|
// Support for private registry
|
|
219
|
-
if (
|
|
470
|
+
if (dockerAuthConfig) {
|
|
220
471
|
opts.headers = {
|
|
221
|
-
"X-Registry-Auth":
|
|
472
|
+
"X-Registry-Auth": dockerAuthConfig,
|
|
222
473
|
};
|
|
223
474
|
authTokenSet = true;
|
|
475
|
+
noteCredentialSource("DOCKER_AUTH_CONFIG", "selected");
|
|
476
|
+
} else {
|
|
477
|
+
noteCredentialSource("DOCKER_AUTH_CONFIG", "skipped", "not set");
|
|
224
478
|
}
|
|
225
479
|
if (
|
|
226
480
|
!authTokenSet &&
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
481
|
+
dockerUser &&
|
|
482
|
+
dockerPassword &&
|
|
483
|
+
dockerEmail &&
|
|
484
|
+
normalizedForRegistry
|
|
231
485
|
) {
|
|
232
486
|
const authPayload = {
|
|
233
|
-
username:
|
|
234
|
-
email:
|
|
235
|
-
serveraddress:
|
|
487
|
+
username: dockerUser,
|
|
488
|
+
email: dockerEmail,
|
|
489
|
+
serveraddress: normalizedForRegistry,
|
|
236
490
|
};
|
|
237
|
-
if (
|
|
238
|
-
authPayload.IdentityToken =
|
|
491
|
+
if (dockerUser === "<token>") {
|
|
492
|
+
authPayload.IdentityToken = dockerPassword;
|
|
239
493
|
} else {
|
|
240
|
-
authPayload.password =
|
|
494
|
+
authPayload.password = dockerPassword;
|
|
241
495
|
}
|
|
242
496
|
opts.headers = {
|
|
243
497
|
"X-Registry-Auth": toBase64Url(JSON.stringify(authPayload)),
|
|
244
498
|
};
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
"utf-8",
|
|
499
|
+
authTokenSet = true;
|
|
500
|
+
noteCredentialSource(
|
|
501
|
+
"DOCKER_USER/DOCKER_PASSWORD/DOCKER_EMAIL",
|
|
502
|
+
"selected",
|
|
250
503
|
);
|
|
504
|
+
} else if (!authTokenSet) {
|
|
505
|
+
noteCredentialSource(
|
|
506
|
+
"DOCKER_USER/DOCKER_PASSWORD/DOCKER_EMAIL",
|
|
507
|
+
"skipped",
|
|
508
|
+
dockerUser || dockerPassword || dockerEmail
|
|
509
|
+
? "incomplete environment credentials"
|
|
510
|
+
: "not set",
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
if (!authTokenSet && safeExistsSync(dockerConfigFile)) {
|
|
514
|
+
const configData = readFileSync(dockerConfigFile, "utf-8");
|
|
515
|
+
recordSensitiveFileRead(dockerConfigFile, {
|
|
516
|
+
label: "Docker credential file",
|
|
517
|
+
});
|
|
251
518
|
if (configData) {
|
|
252
519
|
try {
|
|
253
520
|
const configJson = JSON.parse(configData);
|
|
254
521
|
if (configJson.auths) {
|
|
255
522
|
// Check if there are hardcoded tokens
|
|
256
523
|
for (const serverAddress of Object.keys(configJson.auths)) {
|
|
257
|
-
if (
|
|
524
|
+
if (!registriesMatch(serverAddress, requestedRegistryRef)) {
|
|
258
525
|
continue;
|
|
259
526
|
}
|
|
260
527
|
if (configJson.auths[serverAddress].auth) {
|
|
@@ -274,6 +541,11 @@ const getDefaultOptions = (forRegistry) => {
|
|
|
274
541
|
"X-Registry-Auth": toBase64Url(JSON.stringify(authPayload)),
|
|
275
542
|
};
|
|
276
543
|
authTokenSet = true;
|
|
544
|
+
noteCredentialSource(
|
|
545
|
+
"docker-config-auth",
|
|
546
|
+
"selected",
|
|
547
|
+
serverAddress,
|
|
548
|
+
);
|
|
277
549
|
break;
|
|
278
550
|
}
|
|
279
551
|
if (configJson.credsStore) {
|
|
@@ -286,6 +558,11 @@ const getDefaultOptions = (forRegistry) => {
|
|
|
286
558
|
"X-Registry-Auth": helperAuthToken,
|
|
287
559
|
};
|
|
288
560
|
authTokenSet = true;
|
|
561
|
+
noteCredentialSource(
|
|
562
|
+
`docker-credential-helper:${configJson.credsStore}`,
|
|
563
|
+
"selected",
|
|
564
|
+
serverAddress,
|
|
565
|
+
);
|
|
289
566
|
break;
|
|
290
567
|
}
|
|
291
568
|
}
|
|
@@ -293,7 +570,7 @@ const getDefaultOptions = (forRegistry) => {
|
|
|
293
570
|
} else if (configJson.credHelpers) {
|
|
294
571
|
// Support for credential helpers
|
|
295
572
|
for (const serverAddress of Object.keys(configJson.credHelpers)) {
|
|
296
|
-
if (
|
|
573
|
+
if (!registriesMatch(serverAddress, requestedRegistryRef)) {
|
|
297
574
|
continue;
|
|
298
575
|
}
|
|
299
576
|
if (configJson.credHelpers[serverAddress]) {
|
|
@@ -306,22 +583,40 @@ const getDefaultOptions = (forRegistry) => {
|
|
|
306
583
|
"X-Registry-Auth": helperAuthToken,
|
|
307
584
|
};
|
|
308
585
|
authTokenSet = true;
|
|
586
|
+
noteCredentialSource(
|
|
587
|
+
`docker-credential-helper:${configJson.credHelpers[serverAddress]}`,
|
|
588
|
+
"selected",
|
|
589
|
+
serverAddress,
|
|
590
|
+
);
|
|
309
591
|
break;
|
|
310
592
|
}
|
|
311
593
|
}
|
|
312
594
|
}
|
|
313
595
|
}
|
|
596
|
+
if (!authTokenSet) {
|
|
597
|
+
noteCredentialSource(
|
|
598
|
+
"docker-config",
|
|
599
|
+
"skipped",
|
|
600
|
+
"no matching config.json auth entry",
|
|
601
|
+
);
|
|
602
|
+
}
|
|
314
603
|
} catch (_err) {
|
|
315
604
|
// pass
|
|
605
|
+
noteCredentialSource("docker-config", "skipped", "config parse failed");
|
|
316
606
|
}
|
|
317
607
|
}
|
|
608
|
+
} else if (!authTokenSet) {
|
|
609
|
+
noteCredentialSource("docker-config", "skipped", "config.json not found");
|
|
318
610
|
}
|
|
319
611
|
const userInfo = _userInfo();
|
|
320
612
|
opts.podmanPrefixUrl = isWin ? "" : "http://unix:/run/podman/podman.sock:";
|
|
321
613
|
opts.podmanRootlessPrefixUrl = isWin
|
|
322
614
|
? ""
|
|
323
615
|
: `http://unix:/run/user/${userInfo.uid}/podman/podman.sock:`;
|
|
324
|
-
|
|
616
|
+
const dockerHost = readEnvironmentVariable("DOCKER_HOST");
|
|
617
|
+
const dockerCertPath = readEnvironmentVariable("DOCKER_CERT_PATH");
|
|
618
|
+
const dockerTlsVerify = readEnvironmentVariable("DOCKER_TLS_VERIFY");
|
|
619
|
+
if (!dockerHost) {
|
|
325
620
|
if (isPodman) {
|
|
326
621
|
opts.prefixUrl = isPodmanRootless
|
|
327
622
|
? opts.podmanRootlessPrefixUrl
|
|
@@ -345,7 +640,7 @@ const getDefaultOptions = (forRegistry) => {
|
|
|
345
640
|
}
|
|
346
641
|
}
|
|
347
642
|
} else {
|
|
348
|
-
let hostStr =
|
|
643
|
+
let hostStr = dockerHost;
|
|
349
644
|
if (hostStr.startsWith("unix:///")) {
|
|
350
645
|
hostStr = hostStr.replace("unix:///", "http://unix:/");
|
|
351
646
|
if (hostStr.includes("docker.sock")) {
|
|
@@ -354,29 +649,54 @@ const getDefaultOptions = (forRegistry) => {
|
|
|
354
649
|
}
|
|
355
650
|
}
|
|
356
651
|
opts.prefixUrl = hostStr;
|
|
357
|
-
if (
|
|
652
|
+
if (dockerCertPath) {
|
|
653
|
+
const dockerCertFile = join(dockerCertPath, "cert.pem");
|
|
654
|
+
const dockerKeyFile = join(dockerCertPath, "key.pem");
|
|
655
|
+
const dockerCertificate = readFileSync(dockerCertFile, "utf8");
|
|
656
|
+
recordSensitiveFileRead(dockerCertFile, {
|
|
657
|
+
label: "Docker client certificate",
|
|
658
|
+
});
|
|
659
|
+
const dockerKey = readFileSync(dockerKeyFile, "utf8");
|
|
660
|
+
recordSensitiveFileRead(dockerKeyFile, {
|
|
661
|
+
label: "Docker client private key",
|
|
662
|
+
});
|
|
358
663
|
opts.https = {
|
|
359
|
-
certificate:
|
|
360
|
-
|
|
361
|
-
"utf8",
|
|
362
|
-
),
|
|
363
|
-
key: readFileSync(
|
|
364
|
-
join(process.env.DOCKER_CERT_PATH, "key.pem"),
|
|
365
|
-
"utf8",
|
|
366
|
-
),
|
|
664
|
+
certificate: dockerCertificate,
|
|
665
|
+
key: dockerKey,
|
|
367
666
|
};
|
|
368
667
|
// Disable tls on empty values
|
|
369
668
|
// From the docker docs: Setting the DOCKER_TLS_VERIFY environment variable to any value other than the empty string is equivalent to setting the --tlsverify flag
|
|
370
|
-
if (
|
|
371
|
-
process.env.DOCKER_TLS_VERIFY &&
|
|
372
|
-
process.env.DOCKER_TLS_VERIFY === ""
|
|
373
|
-
) {
|
|
669
|
+
if (dockerTlsVerify === "") {
|
|
374
670
|
opts.https.rejectUnauthorized = false;
|
|
375
671
|
console.log("TLS Verification disabled for", hostStr);
|
|
376
672
|
}
|
|
377
673
|
}
|
|
378
674
|
}
|
|
379
675
|
|
|
676
|
+
if (!selectedCredentialSource) {
|
|
677
|
+
noteCredentialSource(
|
|
678
|
+
"anonymous",
|
|
679
|
+
"selected",
|
|
680
|
+
"no credential source resolved",
|
|
681
|
+
);
|
|
682
|
+
}
|
|
683
|
+
const skippedSources = credentialSourceEvaluations
|
|
684
|
+
.filter((entry) => entry.outcome !== "selected")
|
|
685
|
+
.map((entry) =>
|
|
686
|
+
entry.detail ? `${entry.source} (${entry.detail})` : entry.source,
|
|
687
|
+
);
|
|
688
|
+
recordDecisionActivity(`docker-auth:${authDecisionTarget}`, {
|
|
689
|
+
metadata: {
|
|
690
|
+
decisionType: "credential-source-selection",
|
|
691
|
+
evaluatedSources: credentialSourceEvaluations.map(
|
|
692
|
+
({ detail, outcome, source }) =>
|
|
693
|
+
detail ? `${source}:${outcome}:${detail}` : `${source}:${outcome}`,
|
|
694
|
+
),
|
|
695
|
+
selectedSource: selectedCredentialSource,
|
|
696
|
+
},
|
|
697
|
+
reason: `Selected Docker auth source '${selectedCredentialSource}' for ${authDecisionTarget}. Skipped: ${skippedSources.length ? skippedSources.join(", ") : "none"}.`,
|
|
698
|
+
});
|
|
699
|
+
|
|
380
700
|
return opts;
|
|
381
701
|
};
|
|
382
702
|
|
|
@@ -395,7 +715,20 @@ const getDefaultOptions = (forRegistry) => {
|
|
|
395
715
|
* daemon base URL, or `undefined`
|
|
396
716
|
*/
|
|
397
717
|
export const getConnection = async (options, forRegistry) => {
|
|
718
|
+
if (isContainerd || isNerdctl) {
|
|
719
|
+
return undefined;
|
|
720
|
+
}
|
|
398
721
|
if (isDryRun) {
|
|
722
|
+
try {
|
|
723
|
+
getDefaultOptions(forRegistry);
|
|
724
|
+
} catch (error) {
|
|
725
|
+
recordActivity({
|
|
726
|
+
kind: "read",
|
|
727
|
+
reason: `Dry run mode failed while tracing Docker credential inputs: ${error.message}`,
|
|
728
|
+
status: "failed",
|
|
729
|
+
target: error?.path || forRegistry || "container-daemon",
|
|
730
|
+
});
|
|
731
|
+
}
|
|
399
732
|
recordActivity({
|
|
400
733
|
kind: "network",
|
|
401
734
|
reason:
|
|
@@ -405,9 +738,6 @@ export const getConnection = async (options, forRegistry) => {
|
|
|
405
738
|
});
|
|
406
739
|
return undefined;
|
|
407
740
|
}
|
|
408
|
-
if (isContainerd || isNerdctl) {
|
|
409
|
-
return undefined;
|
|
410
|
-
}
|
|
411
741
|
if (!dockerConn) {
|
|
412
742
|
const defaultOptions = getDefaultOptions(forRegistry);
|
|
413
743
|
const podmanRootlessUrl = defaultOptions.podmanRootlessPrefixUrl;
|
|
@@ -535,7 +865,10 @@ export const makeRequest = async (path, method, forRegistry) => {
|
|
|
535
865
|
}
|
|
536
866
|
// Use the client's prefixUrl (set correctly by getConnection for
|
|
537
867
|
// docker/podman). Only pass per-request auth headers and method options.
|
|
538
|
-
const defaultOptions = getDefaultOptions(
|
|
868
|
+
const defaultOptions = getDefaultOptions(
|
|
869
|
+
forRegistry,
|
|
870
|
+
extractRequestedRegistryRefFromPath(path, forRegistry),
|
|
871
|
+
);
|
|
539
872
|
const opts = {
|
|
540
873
|
responseType: method === "GET" ? "json" : "buffer",
|
|
541
874
|
resolveBodyOnly: true,
|
|
@@ -858,13 +1191,17 @@ export const getImage = async (fullImageName) => {
|
|
|
858
1191
|
return localData;
|
|
859
1192
|
};
|
|
860
1193
|
|
|
1194
|
+
/**
|
|
1195
|
+
* @typedef {{ path: string }} TarReadEntryLike
|
|
1196
|
+
*/
|
|
1197
|
+
|
|
861
1198
|
/**
|
|
862
1199
|
* Warnings such as TAR_ENTRY_INFO are treated as errors in strict mode. While this is mostly desired, we can relax this
|
|
863
1200
|
* requirement for one particular warning related to absolute paths.
|
|
864
1201
|
* This callback function checks for absolute paths in the entry read from the archive and strips them using a custom
|
|
865
1202
|
* method.
|
|
866
1203
|
*
|
|
867
|
-
* @param
|
|
1204
|
+
* @param {TarReadEntryLike} entry ReadEntry object from node-tar
|
|
868
1205
|
*/
|
|
869
1206
|
function handleAbsolutePath(entry) {
|
|
870
1207
|
if (entry.path === "/" || win32.isAbsolute(entry.path)) {
|
|
@@ -981,34 +1318,36 @@ const EXTRACT_EXCLUDE_TYPES = new Set([
|
|
|
981
1318
|
* empty or a non-fatal error was encountered
|
|
982
1319
|
*/
|
|
983
1320
|
export const extractTar = async (fullImageName, dir, options) => {
|
|
984
|
-
if (isDryRun) {
|
|
985
|
-
recordActivity({
|
|
986
|
-
kind: "untar",
|
|
987
|
-
reason:
|
|
988
|
-
"Dry run mode blocks untar and layer extraction operations because they create files on disk.",
|
|
989
|
-
status: "blocked",
|
|
990
|
-
target: `${fullImageName} -> ${dir}`,
|
|
991
|
-
});
|
|
992
|
-
return false;
|
|
993
|
-
}
|
|
994
1321
|
try {
|
|
995
|
-
await
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1322
|
+
return await safeExtractArchive(
|
|
1323
|
+
fullImageName,
|
|
1324
|
+
dir,
|
|
1325
|
+
async () =>
|
|
1326
|
+
await stream.pipeline(
|
|
1327
|
+
createReadStream(fullImageName),
|
|
1328
|
+
x({
|
|
1329
|
+
sync: false,
|
|
1330
|
+
preserveOwner: false,
|
|
1331
|
+
noMtime: true,
|
|
1332
|
+
noChmod: true,
|
|
1333
|
+
strict: !NON_STRICT_TAR_EXTRACT,
|
|
1334
|
+
C: dir,
|
|
1335
|
+
portable: true,
|
|
1336
|
+
unlink: true,
|
|
1337
|
+
onwarn: handleTarWarning,
|
|
1338
|
+
onReadEntry: handleAbsolutePath,
|
|
1339
|
+
filter: tarFilter,
|
|
1340
|
+
}),
|
|
1341
|
+
),
|
|
1342
|
+
"untar",
|
|
1343
|
+
{
|
|
1344
|
+
blockedReason:
|
|
1345
|
+
"Dry run mode blocks untar and layer extraction operations because they create files on disk.",
|
|
1346
|
+
metadata: {
|
|
1347
|
+
archiveFormat: "tar",
|
|
1348
|
+
},
|
|
1349
|
+
},
|
|
1010
1350
|
);
|
|
1011
|
-
return true;
|
|
1012
1351
|
} catch (err) {
|
|
1013
1352
|
if (err.code === "EPERM" && err.syscall === "symlink") {
|
|
1014
1353
|
console.log(
|
|
@@ -1382,7 +1721,22 @@ export const extractFromManifest = async (
|
|
|
1382
1721
|
* Returns the location of the layers with additional packages related metadata
|
|
1383
1722
|
*/
|
|
1384
1723
|
export const exportImage = async (fullImageName, options) => {
|
|
1724
|
+
// Safely ignore local directories
|
|
1725
|
+
if (
|
|
1726
|
+
!fullImageName ||
|
|
1727
|
+
fullImageName === "." ||
|
|
1728
|
+
safeExistsSync(resolve(fullImageName))
|
|
1729
|
+
) {
|
|
1730
|
+
return undefined;
|
|
1731
|
+
}
|
|
1385
1732
|
if (isDryRun) {
|
|
1733
|
+
const imageDetails = parseImageName(fullImageName);
|
|
1734
|
+
const requestedRegistryRef = imageDetails.registry
|
|
1735
|
+
? imageDetails.repo
|
|
1736
|
+
? `${imageDetails.registry}/${imageDetails.repo}`
|
|
1737
|
+
: imageDetails.registry
|
|
1738
|
+
: DOCKER_HUB_REGISTRY;
|
|
1739
|
+
await getConnection({}, requestedRegistryRef);
|
|
1386
1740
|
recordActivity({
|
|
1387
1741
|
kind: "container",
|
|
1388
1742
|
reason:
|
|
@@ -1392,14 +1746,6 @@ export const exportImage = async (fullImageName, options) => {
|
|
|
1392
1746
|
});
|
|
1393
1747
|
return undefined;
|
|
1394
1748
|
}
|
|
1395
|
-
// Safely ignore local directories
|
|
1396
|
-
if (
|
|
1397
|
-
!fullImageName ||
|
|
1398
|
-
fullImageName === "." ||
|
|
1399
|
-
safeExistsSync(resolve(fullImageName))
|
|
1400
|
-
) {
|
|
1401
|
-
return undefined;
|
|
1402
|
-
}
|
|
1403
1749
|
// Try to get the data locally first
|
|
1404
1750
|
const localData = await getImage(fullImageName);
|
|
1405
1751
|
if (!localData) {
|
|
@@ -1694,8 +2040,9 @@ export const removeImage = async (fullImageName, force = false) => {
|
|
|
1694
2040
|
* if the helper is unavailable or returns an error
|
|
1695
2041
|
*/
|
|
1696
2042
|
export const getCredsFromHelper = (exeSuffix, serverAddress) => {
|
|
1697
|
-
|
|
1698
|
-
|
|
2043
|
+
const cacheKey = `${exeSuffix}:${normalizeRegistryReference(serverAddress) ?? serverAddress}`;
|
|
2044
|
+
if (registry_auth_keys[cacheKey]) {
|
|
2045
|
+
return registry_auth_keys[cacheKey];
|
|
1699
2046
|
}
|
|
1700
2047
|
let credHelperExe = `docker-credential-${exeSuffix}`;
|
|
1701
2048
|
if (isWin) {
|
|
@@ -1711,22 +2058,21 @@ export const getCredsFromHelper = (exeSuffix, serverAddress) => {
|
|
|
1711
2058
|
} else if (result.stdout) {
|
|
1712
2059
|
const cmdOutput = Buffer.from(result.stdout).toString();
|
|
1713
2060
|
try {
|
|
2061
|
+
const dockerUser = readEnvironmentVariable("DOCKER_USER", {
|
|
2062
|
+
sensitive: true,
|
|
2063
|
+
});
|
|
2064
|
+
const dockerPassword = readEnvironmentVariable("DOCKER_PASSWORD", {
|
|
2065
|
+
sensitive: true,
|
|
2066
|
+
});
|
|
1714
2067
|
const authPayload = JSON.parse(cmdOutput);
|
|
1715
2068
|
const fixedAuthPayload = {
|
|
1716
|
-
username:
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
process.env.DOCKER_USER,
|
|
1720
|
-
password:
|
|
1721
|
-
authPayload.password ||
|
|
1722
|
-
authPayload.Secret ||
|
|
1723
|
-
process.env.DOCKER_PASSWORD,
|
|
1724
|
-
email:
|
|
1725
|
-
authPayload.email || authPayload.username || process.env.DOCKER_USER,
|
|
2069
|
+
username: authPayload.username || authPayload.Username || dockerUser,
|
|
2070
|
+
password: authPayload.password || authPayload.Secret || dockerPassword,
|
|
2071
|
+
email: authPayload.email || authPayload.username || dockerUser,
|
|
1726
2072
|
serveraddress: serverAddress,
|
|
1727
2073
|
};
|
|
1728
2074
|
const authKey = toBase64Url(JSON.stringify(fixedAuthPayload));
|
|
1729
|
-
registry_auth_keys[
|
|
2075
|
+
registry_auth_keys[cacheKey] = authKey;
|
|
1730
2076
|
return authKey;
|
|
1731
2077
|
} catch (_err) {
|
|
1732
2078
|
return undefined;
|