typekro 0.27.0 → 0.28.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.
Files changed (211) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/core/containers/build.d.ts +2 -46
  3. package/dist/core/containers/build.d.ts.map +1 -1
  4. package/dist/core/containers/build.js +219 -134
  5. package/dist/core/containers/build.js.map +1 -1
  6. package/dist/core/containers/errors.d.ts +4 -0
  7. package/dist/core/containers/errors.d.ts.map +1 -1
  8. package/dist/core/containers/errors.js +14 -1
  9. package/dist/core/containers/errors.js.map +1 -1
  10. package/dist/core/containers/exec.d.ts +6 -23
  11. package/dist/core/containers/exec.d.ts.map +1 -1
  12. package/dist/core/containers/exec.js +94 -78
  13. package/dist/core/containers/exec.js.map +1 -1
  14. package/dist/core/containers/image.d.ts +11 -7
  15. package/dist/core/containers/image.d.ts.map +1 -1
  16. package/dist/core/containers/image.js +102 -13
  17. package/dist/core/containers/image.js.map +1 -1
  18. package/dist/core/containers/index.d.ts +5 -1
  19. package/dist/core/containers/index.d.ts.map +1 -1
  20. package/dist/core/containers/index.js +3 -0
  21. package/dist/core/containers/index.js.map +1 -1
  22. package/dist/core/containers/registries/credentials.d.ts +30 -0
  23. package/dist/core/containers/registries/credentials.d.ts.map +1 -0
  24. package/dist/core/containers/registries/credentials.js +87 -0
  25. package/dist/core/containers/registries/credentials.js.map +1 -0
  26. package/dist/core/containers/registries/docker-session.d.ts +14 -0
  27. package/dist/core/containers/registries/docker-session.d.ts.map +1 -0
  28. package/dist/core/containers/registries/docker-session.js +164 -0
  29. package/dist/core/containers/registries/docker-session.js.map +1 -0
  30. package/dist/core/containers/registries/ecr.d.ts +2 -3
  31. package/dist/core/containers/registries/ecr.d.ts.map +1 -1
  32. package/dist/core/containers/registries/ecr.js +13 -22
  33. package/dist/core/containers/registries/ecr.js.map +1 -1
  34. package/dist/core/containers/registries/harbor.d.ts +7 -0
  35. package/dist/core/containers/registries/harbor.d.ts.map +1 -0
  36. package/dist/core/containers/registries/harbor.js +9 -0
  37. package/dist/core/containers/registries/harbor.js.map +1 -0
  38. package/dist/core/containers/registries/index.d.ts.map +1 -1
  39. package/dist/core/containers/registries/index.js +5 -0
  40. package/dist/core/containers/registries/index.js.map +1 -1
  41. package/dist/core/containers/registries/oci.d.ts +13 -0
  42. package/dist/core/containers/registries/oci.d.ts.map +1 -0
  43. package/dist/core/containers/registries/oci.js +68 -0
  44. package/dist/core/containers/registries/oci.js.map +1 -0
  45. package/dist/core/containers/registries/orbstack.d.ts +2 -3
  46. package/dist/core/containers/registries/orbstack.d.ts.map +1 -1
  47. package/dist/core/containers/registries/orbstack.js +8 -8
  48. package/dist/core/containers/registries/orbstack.js.map +1 -1
  49. package/dist/core/containers/registries/types.d.ts +75 -49
  50. package/dist/core/containers/registries/types.d.ts.map +1 -1
  51. package/dist/core/containers/registries/types.js +1 -9
  52. package/dist/core/containers/registries/types.js.map +1 -1
  53. package/dist/core/deployment/direct-factory.d.ts.map +1 -1
  54. package/dist/core/deployment/direct-factory.js +15 -8
  55. package/dist/core/deployment/direct-factory.js.map +1 -1
  56. package/dist/core/deployment/engine.d.ts.map +1 -1
  57. package/dist/core/deployment/engine.js +46 -5
  58. package/dist/core/deployment/engine.js.map +1 -1
  59. package/dist/core/deployment/kro-factory.d.ts +7 -7
  60. package/dist/core/deployment/kro-factory.d.ts.map +1 -1
  61. package/dist/core/deployment/kro-factory.js +148 -60
  62. package/dist/core/deployment/kro-factory.js.map +1 -1
  63. package/dist/core/deployment/kro-instance-safety.d.ts +7 -0
  64. package/dist/core/deployment/kro-instance-safety.d.ts.map +1 -1
  65. package/dist/core/deployment/kro-instance-safety.js +15 -0
  66. package/dist/core/deployment/kro-instance-safety.js.map +1 -1
  67. package/dist/core/deployment/kro-namespace-teardown.d.ts +7 -5
  68. package/dist/core/deployment/kro-namespace-teardown.d.ts.map +1 -1
  69. package/dist/core/deployment/kro-namespace-teardown.js +29 -10
  70. package/dist/core/deployment/kro-namespace-teardown.js.map +1 -1
  71. package/dist/core/deployment/kro-readiness.d.ts +1 -0
  72. package/dist/core/deployment/kro-readiness.d.ts.map +1 -1
  73. package/dist/core/deployment/kro-readiness.js +22 -1
  74. package/dist/core/deployment/kro-readiness.js.map +1 -1
  75. package/dist/core/deployment/rollback-manager.d.ts +13 -0
  76. package/dist/core/deployment/rollback-manager.d.ts.map +1 -1
  77. package/dist/core/deployment/rollback-manager.js +8 -0
  78. package/dist/core/deployment/rollback-manager.js.map +1 -1
  79. package/dist/core/serialization/core.js +3 -1
  80. package/dist/core/serialization/core.js.map +1 -1
  81. package/dist/core/serialization/schema.d.ts +2 -2
  82. package/dist/core/serialization/schema.d.ts.map +1 -1
  83. package/dist/core/serialization/schema.js +57 -4
  84. package/dist/core/serialization/schema.js.map +1 -1
  85. package/dist/core/types/serialization.d.ts +9 -0
  86. package/dist/core/types/serialization.d.ts.map +1 -1
  87. package/dist/factories/apisix/types.js +11 -11
  88. package/dist/factories/apisix/types.js.map +1 -1
  89. package/dist/factories/caddy/types.js +2 -2
  90. package/dist/factories/caddy/types.js.map +1 -1
  91. package/dist/factories/cert-manager/types.js +6 -6
  92. package/dist/factories/cert-manager/types.js.map +1 -1
  93. package/dist/factories/cilium/compositions/cilium-bootstrap.js +6 -6
  94. package/dist/factories/cilium/compositions/cilium-bootstrap.js.map +1 -1
  95. package/dist/factories/clickhouse/compositions/clickhouse-cluster.js +1 -1
  96. package/dist/factories/clickhouse/compositions/clickhouse-cluster.js.map +1 -1
  97. package/dist/factories/clickhouse/types.js +8 -8
  98. package/dist/factories/clickhouse/types.js.map +1 -1
  99. package/dist/factories/clickstack/types.js +5 -5
  100. package/dist/factories/clickstack/types.js.map +1 -1
  101. package/dist/factories/cnpg/types.js +6 -6
  102. package/dist/factories/cnpg/types.js.map +1 -1
  103. package/dist/factories/dagster/types.js +14 -14
  104. package/dist/factories/dagster/types.js.map +1 -1
  105. package/dist/factories/external-dns/types.js +3 -3
  106. package/dist/factories/external-dns/types.js.map +1 -1
  107. package/dist/factories/harbor/compositions/harbor-installation.d.ts +610 -0
  108. package/dist/factories/harbor/compositions/harbor-installation.d.ts.map +1 -0
  109. package/dist/factories/harbor/compositions/harbor-installation.js +348 -0
  110. package/dist/factories/harbor/compositions/harbor-installation.js.map +1 -0
  111. package/dist/factories/harbor/compositions/index.d.ts +2 -0
  112. package/dist/factories/harbor/compositions/index.d.ts.map +1 -0
  113. package/dist/factories/harbor/compositions/index.js +2 -0
  114. package/dist/factories/harbor/compositions/index.js.map +1 -0
  115. package/dist/factories/harbor/index.d.ts +7 -0
  116. package/dist/factories/harbor/index.d.ts.map +1 -0
  117. package/dist/factories/harbor/index.js +7 -0
  118. package/dist/factories/harbor/index.js.map +1 -0
  119. package/dist/factories/harbor/provider/harbor-api.d.ts +123 -0
  120. package/dist/factories/harbor/provider/harbor-api.d.ts.map +1 -0
  121. package/dist/factories/harbor/provider/harbor-api.js +595 -0
  122. package/dist/factories/harbor/provider/harbor-api.js.map +1 -0
  123. package/dist/factories/harbor/provider/index.d.ts +4 -0
  124. package/dist/factories/harbor/provider/index.d.ts.map +1 -0
  125. package/dist/factories/harbor/provider/index.js +4 -0
  126. package/dist/factories/harbor/provider/index.js.map +1 -0
  127. package/dist/factories/harbor/provider/kubernetes-secret-store.d.ts +12 -0
  128. package/dist/factories/harbor/provider/kubernetes-secret-store.d.ts.map +1 -0
  129. package/dist/factories/harbor/provider/kubernetes-secret-store.js +81 -0
  130. package/dist/factories/harbor/provider/kubernetes-secret-store.js.map +1 -0
  131. package/dist/factories/harbor/provider/rook-s3-binding.d.ts +30 -0
  132. package/dist/factories/harbor/provider/rook-s3-binding.d.ts.map +1 -0
  133. package/dist/factories/harbor/provider/rook-s3-binding.js +74 -0
  134. package/dist/factories/harbor/provider/rook-s3-binding.js.map +1 -0
  135. package/dist/factories/harbor/resources/helm.d.ts +12 -0
  136. package/dist/factories/harbor/resources/helm.d.ts.map +1 -0
  137. package/dist/factories/harbor/resources/helm.js +46 -0
  138. package/dist/factories/harbor/resources/helm.js.map +1 -0
  139. package/dist/factories/harbor/resources/index.d.ts +2 -0
  140. package/dist/factories/harbor/resources/index.d.ts.map +1 -0
  141. package/dist/factories/harbor/resources/index.js +2 -0
  142. package/dist/factories/harbor/resources/index.js.map +1 -0
  143. package/dist/factories/harbor/types.d.ts +319 -0
  144. package/dist/factories/harbor/types.d.ts.map +1 -0
  145. package/dist/factories/harbor/types.js +252 -0
  146. package/dist/factories/harbor/types.js.map +1 -0
  147. package/dist/factories/harbor/utils/helm-values-mapper.d.ts +8 -0
  148. package/dist/factories/harbor/utils/helm-values-mapper.d.ts.map +1 -0
  149. package/dist/factories/harbor/utils/helm-values-mapper.js +322 -0
  150. package/dist/factories/harbor/utils/helm-values-mapper.js.map +1 -0
  151. package/dist/factories/harbor/utils/index.d.ts +2 -0
  152. package/dist/factories/harbor/utils/index.d.ts.map +1 -0
  153. package/dist/factories/harbor/utils/index.js +2 -0
  154. package/dist/factories/harbor/utils/index.js.map +1 -0
  155. package/dist/factories/helm/helm-release.d.ts +10 -0
  156. package/dist/factories/helm/helm-release.d.ts.map +1 -1
  157. package/dist/factories/helm/helm-release.js +30 -2
  158. package/dist/factories/helm/helm-release.js.map +1 -1
  159. package/dist/factories/helm/readiness-evaluators.d.ts.map +1 -1
  160. package/dist/factories/helm/readiness-evaluators.js +26 -1
  161. package/dist/factories/helm/readiness-evaluators.js.map +1 -1
  162. package/dist/factories/helm/types.d.ts +5 -0
  163. package/dist/factories/helm/types.d.ts.map +1 -1
  164. package/dist/factories/index.d.ts +1 -0
  165. package/dist/factories/index.d.ts.map +1 -1
  166. package/dist/factories/index.js +4 -0
  167. package/dist/factories/index.js.map +1 -1
  168. package/dist/factories/inngest/types.js +8 -8
  169. package/dist/factories/inngest/types.js.map +1 -1
  170. package/dist/factories/kubernetes/networking/network-policy.d.ts.map +1 -1
  171. package/dist/factories/kubernetes/networking/network-policy.js +34 -1
  172. package/dist/factories/kubernetes/networking/network-policy.js.map +1 -1
  173. package/dist/factories/ory/types.js +40 -40
  174. package/dist/factories/ory/types.js.map +1 -1
  175. package/dist/factories/rook/compositions/index.d.ts +1 -0
  176. package/dist/factories/rook/compositions/index.d.ts.map +1 -1
  177. package/dist/factories/rook/compositions/index.js +1 -0
  178. package/dist/factories/rook/compositions/index.js.map +1 -1
  179. package/dist/factories/rook/compositions/rook-ceph-operator-installation.d.ts +2 -0
  180. package/dist/factories/rook/compositions/rook-ceph-operator-installation.d.ts.map +1 -1
  181. package/dist/factories/rook/compositions/rook-ceph-operator-installation.js +17 -0
  182. package/dist/factories/rook/compositions/rook-ceph-operator-installation.js.map +1 -1
  183. package/dist/factories/rook/compositions/rook-ceph-platform.d.ts +181 -0
  184. package/dist/factories/rook/compositions/rook-ceph-platform.d.ts.map +1 -0
  185. package/dist/factories/rook/compositions/rook-ceph-platform.js +388 -0
  186. package/dist/factories/rook/compositions/rook-ceph-platform.js.map +1 -0
  187. package/dist/factories/rook/resources/bucket-storage-class.d.ts.map +1 -1
  188. package/dist/factories/rook/resources/bucket-storage-class.js +4 -1
  189. package/dist/factories/rook/resources/bucket-storage-class.js.map +1 -1
  190. package/dist/factories/rook/resources/ceph-object-store.d.ts.map +1 -1
  191. package/dist/factories/rook/resources/ceph-object-store.js +2 -0
  192. package/dist/factories/rook/resources/ceph-object-store.js.map +1 -1
  193. package/dist/factories/rook/resources/helm.d.ts +4 -0
  194. package/dist/factories/rook/resources/helm.d.ts.map +1 -1
  195. package/dist/factories/rook/resources/helm.js +22 -0
  196. package/dist/factories/rook/resources/helm.js.map +1 -1
  197. package/dist/factories/rook/types.d.ts +180 -1
  198. package/dist/factories/rook/types.d.ts.map +1 -1
  199. package/dist/factories/rook/types.js +100 -9
  200. package/dist/factories/rook/types.js.map +1 -1
  201. package/dist/factories/rook/utils/helm-values-mapper.d.ts +34 -1
  202. package/dist/factories/rook/utils/helm-values-mapper.d.ts.map +1 -1
  203. package/dist/factories/rook/utils/helm-values-mapper.js +207 -0
  204. package/dist/factories/rook/utils/helm-values-mapper.js.map +1 -1
  205. package/dist/factories/searxng/types.js +2 -2
  206. package/dist/factories/searxng/types.js.map +1 -1
  207. package/dist/factories/valkey/types.js +4 -4
  208. package/dist/factories/valkey/types.js.map +1 -1
  209. package/dist/factories/webapp/types.js +8 -8
  210. package/dist/factories/webapp/types.js.map +1 -1
  211. package/package.json +6 -1
@@ -1,108 +1,124 @@
1
- /**
2
- * Docker CLI Execution Helper
3
- *
4
- * Wraps Bun.spawn for Docker commands with streaming output,
5
- * timeout support, and actionable error messages.
6
- */
1
+ import { spawn } from 'node:child_process';
7
2
  import { getComponentLogger } from '../logging/index.js';
8
3
  import { ContainerBuildError } from './errors.js';
9
4
  const logger = getComponentLogger('container-exec');
10
- /** Valid Docker build-arg key pattern. */
11
5
  const VALID_BUILD_ARG_KEY = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
12
- /**
13
- * Validate that build arg keys are safe Docker ARG names.
14
- * Prevents flag injection via malicious keys like "--platform".
15
- */
6
+ const MAX_CAPTURED_OUTPUT_CHARS = 1_048_576;
7
+ const FORCE_KILL_GRACE_MS = 1_000;
16
8
  export function validateBuildArgs(buildArgs) {
17
9
  for (const [key, value] of Object.entries(buildArgs)) {
18
10
  if (!VALID_BUILD_ARG_KEY.test(key)) {
19
- throw new ContainerBuildError(`Invalid build arg key: "${key}". Must match ${VALID_BUILD_ARG_KEY.source}`, 'INVALID_BUILD_ARG', ['Build arg keys must be valid Docker ARG names (alphanumeric + underscore, starting with letter/underscore).']);
11
+ throw new ContainerBuildError(`Invalid build arg key: "${key}". Must match ${VALID_BUILD_ARG_KEY.source}`, 'INVALID_BUILD_ARG', ['Build arg keys must be valid Docker ARG names.']);
20
12
  }
21
- if (typeof value === 'string' && value.includes('\n')) {
22
- throw new ContainerBuildError(`Build arg value for "${key}" contains newlines, which may break Docker --build-arg parsing.`, 'INVALID_BUILD_ARG', ['Remove newlines from build arg values.']);
13
+ if (value.includes('\n')) {
14
+ throw new ContainerBuildError(`Build arg value for "${key}" contains newlines.`, 'INVALID_BUILD_ARG', ['Remove newlines from build arg values.']);
23
15
  }
24
16
  }
25
17
  }
26
- /**
27
- * Execute a Docker CLI command.
28
- *
29
- * Streams output to the logger in real-time unless `quiet` is set.
30
- * Throws ContainerBuildError on non-zero exit or timeout.
31
- */
18
+ function redact(value, sensitiveValues) {
19
+ return sensitiveValues.reduce((current, sensitive) => (sensitive ? current.split(sensitive).join('***') : current), value);
20
+ }
21
+ function redactedDockerArgs(args) {
22
+ return args.map((arg, index) => {
23
+ if (args[index - 1] === '--build-arg' && arg.includes('=')) {
24
+ return `${arg.slice(0, arg.indexOf('='))}=***`;
25
+ }
26
+ if (args[index - 1] === '--password')
27
+ return '***';
28
+ return arg;
29
+ });
30
+ }
31
+ function appendBounded(current, chunk) {
32
+ const combined = current + chunk;
33
+ return combined.length <= MAX_CAPTURED_OUTPUT_CHARS
34
+ ? combined
35
+ : combined.slice(-MAX_CAPTURED_OUTPUT_CHARS);
36
+ }
37
+ /** Execute Docker through a Node-compatible process boundary with timeout and cancellation. */
32
38
  export async function execDocker(args, options = {}) {
33
- const { stdin, quiet = false, timeout = 300_000 } = options;
34
- // Redact --build-arg values in logs to prevent secret leakage
35
- const redactedArgs = args.map((arg, i) => args[i - 1] === '--build-arg' && arg.includes('=')
36
- ? `${arg.split('=')[0]}=***`
37
- : arg);
38
- logger.debug('Executing docker command', { args: ['docker', ...redactedArgs] });
39
- const proc = Bun.spawn(['docker', ...args], {
40
- stdout: 'pipe',
41
- stderr: 'pipe',
42
- stdin: stdin ? 'pipe' : undefined,
39
+ const { stdin, quiet = false, timeout = 300_000, signal, environment = {}, sensitiveValues = [], } = options;
40
+ if (signal?.aborted)
41
+ throw ContainerBuildError.cancelled();
42
+ const safeArgs = redactedDockerArgs(args);
43
+ logger.debug('Executing docker command', { args: ['docker', ...safeArgs] });
44
+ const child = spawn('docker', args, {
45
+ env: { ...process.env, ...environment },
46
+ stdio: ['pipe', 'pipe', 'pipe'],
43
47
  });
44
- if (stdin && proc.stdin) {
45
- proc.stdin.write(stdin);
46
- proc.stdin.end();
47
- }
48
- // Start reading streams immediately (before awaiting exit) to prevent
49
- // resource leaks if the process is killed by timeout.
50
- const stdoutPromise = new Response(proc.stdout).text().catch(() => '');
51
- const stderrPromise = new Response(proc.stderr).text().catch(() => '');
52
- // Race exit against timeout. The timeout promise has a .catch() no-op to
53
- // prevent unhandled rejections if the timeout fires at the exact moment
54
- // the process exits (race condition at the boundary).
55
- let timeoutTimer;
56
- const timeoutPromise = new Promise((_, reject) => {
57
- timeoutTimer = setTimeout(() => {
58
- proc.kill();
59
- reject(new ContainerBuildError(`Docker command timed out after ${timeout}ms: docker ${redactedArgs.join(' ')}`, 'BUILD_TIMEOUT', ['Increase the timeout option.', 'Check network connectivity for pulls.']));
60
- }, timeout);
48
+ let stdout = '';
49
+ let stderr = '';
50
+ child.stdout.setEncoding('utf8');
51
+ child.stderr.setEncoding('utf8');
52
+ child.stdout.on('data', (chunk) => {
53
+ stdout = appendBounded(stdout, chunk);
61
54
  });
62
- timeoutPromise.catch(() => { });
63
- const exitCode = await Promise.race([proc.exited, timeoutPromise]).finally(() => {
64
- if (timeoutTimer !== undefined)
65
- clearTimeout(timeoutTimer);
55
+ child.stderr.on('data', (chunk) => {
56
+ stderr = appendBounded(stderr, chunk);
66
57
  });
67
- const stdout = await stdoutPromise;
68
- const stderr = await stderrPromise;
69
- if (!quiet && stdout.trim()) {
70
- for (const line of stdout.trim().split('\n').slice(-20)) {
58
+ child.stdin.on('error', (error) => {
59
+ if (error.code !== 'EPIPE')
60
+ logger.debug('Docker stdin closed unexpectedly', { error: error.message });
61
+ });
62
+ if (stdin !== undefined)
63
+ child.stdin.end(stdin);
64
+ else
65
+ child.stdin.end();
66
+ let timedOut = false;
67
+ let cancelled = false;
68
+ let forceKillHandle;
69
+ const terminate = () => {
70
+ child.kill('SIGTERM');
71
+ forceKillHandle ??= setTimeout(() => child.kill('SIGKILL'), FORCE_KILL_GRACE_MS);
72
+ };
73
+ const timeoutHandle = setTimeout(() => {
74
+ timedOut = true;
75
+ terminate();
76
+ }, timeout);
77
+ const abort = () => {
78
+ cancelled = true;
79
+ terminate();
80
+ };
81
+ signal?.addEventListener('abort', abort, { once: true });
82
+ const exitCode = await new Promise((resolve, reject) => {
83
+ child.once('error', reject);
84
+ child.once('close', (code) => resolve(code ?? 1));
85
+ }).finally(() => {
86
+ clearTimeout(timeoutHandle);
87
+ if (forceKillHandle)
88
+ clearTimeout(forceKillHandle);
89
+ signal?.removeEventListener('abort', abort);
90
+ });
91
+ if (cancelled)
92
+ throw ContainerBuildError.cancelled();
93
+ if (timedOut) {
94
+ throw ContainerBuildError.timeout(timeout, `docker ${safeArgs.join(' ')}`);
95
+ }
96
+ const safeStdout = redact(stdout, sensitiveValues);
97
+ const safeStderr = redact(stderr, sensitiveValues);
98
+ if (!quiet && safeStdout.trim()) {
99
+ for (const line of safeStdout.trim().split('\n').slice(-20))
71
100
  logger.info(line);
72
- }
73
101
  }
74
102
  if (exitCode !== 0) {
75
103
  if (!quiet) {
76
- for (const line of stderr.trim().split('\n')) {
104
+ for (const line of safeStderr.trim().split('\n').slice(-40))
77
105
  logger.error(line);
78
- }
79
106
  }
80
- throw ContainerBuildError.buildFailed(exitCode, stderr);
107
+ throw ContainerBuildError.commandFailed(exitCode, safeArgs, safeStderr);
81
108
  }
82
- return { exitCode, stdout, stderr };
109
+ return { exitCode, stdout: safeStdout, stderr: safeStderr };
83
110
  }
84
- /**
85
- * Check if Docker is available and the daemon is running.
86
- */
87
- export async function checkDockerAvailable() {
111
+ export async function checkDockerAvailable(signal) {
88
112
  try {
89
- const proc = Bun.spawn(['docker', 'version', '--format', '{{.Server.Version}}'], {
90
- stdout: 'pipe',
91
- stderr: 'pipe',
113
+ const result = await execDocker(['version', '--format', '{{.Server.Version}}'], {
114
+ quiet: true,
115
+ timeout: 15_000,
116
+ ...(signal ? { signal } : {}),
92
117
  });
93
- // Read both streams concurrently before awaiting exit
94
- const stdoutPromise = new Response(proc.stdout).text().catch(() => '');
95
- const stderrPromise = new Response(proc.stderr).text().catch(() => '');
96
- const exitCode = await proc.exited;
97
- const stdout = await stdoutPromise;
98
- const stderr = await stderrPromise;
99
- if (exitCode !== 0) {
100
- throw ContainerBuildError.dockerNotAvailable(stderr.trim());
101
- }
102
- logger.debug('Docker available', { version: stdout.trim() });
118
+ logger.debug('Docker available', { version: result.stdout.trim() });
103
119
  }
104
120
  catch (error) {
105
- if (error instanceof ContainerBuildError)
121
+ if (error instanceof ContainerBuildError && error.code === 'BUILD_CANCELLED')
106
122
  throw error;
107
123
  throw ContainerBuildError.dockerNotAvailable(error instanceof Error ? error.message : String(error));
108
124
  }
@@ -1 +1 @@
1
- {"version":3,"file":"exec.js","sourceRoot":"","sources":["../../../src/core/containers/exec.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"exec.js","sourceRoot":"","sources":["../../../src/core/containers/exec.ts"],"names":[],"mappings":"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"}
@@ -10,8 +10,9 @@
10
10
  * that: you `await` it. It is NOT a deferred reference — resolve images in (async) setup code before
11
11
  * composing, then feed the resulting literals into resources or chart values.
12
12
  *
13
- * Memoization: the build is keyed by container identity (`id ?? imageName`) and cached, so awaiting
14
- * the same container many times (e.g. several deployments sharing one image) builds it exactly ONCE.
13
+ * Memoization: the build is keyed by the effective content, target, registry, and build options, so
14
+ * awaiting the same container many times builds it once while a changed context or registry cannot
15
+ * accidentally reuse a different image.
15
16
  *
16
17
  * @example
17
18
  * ```typescript
@@ -28,16 +29,19 @@
28
29
  import type { ContainerBuildOptions, ContainerBuildResult } from './registries/types.js';
29
30
  /** A built container image, resolved to a literal — both the full URI and its split parts. */
30
31
  export interface ContainerImage {
31
- /** Full image URI, e.g. `123.dkr.ecr.us-east-1.amazonaws.com/app:sha-abc`. */
32
+ /** Immutable digest URI for remote images, or the local tagged URI. */
32
33
  readonly imageUri: string;
33
- /** The URI without the tag, e.g. `123.dkr.ecr.us-east-1.amazonaws.com/app`. */
34
+ /** Human-readable tagged URI retained for inspection and retention policy. */
35
+ readonly taggedImageUri: string;
34
36
  readonly repository: string;
35
- /** The tag, e.g. `sha-abc`. */
36
37
  readonly tag: string;
38
+ /** Registry-verified digest. Omitted for local, non-pushed images. */
39
+ readonly digest?: string;
40
+ readonly platforms: readonly string[];
37
41
  }
38
- /** Options for {@link container}: the {@link ContainerBuildOptions} plus an optional stable identity. */
42
+ /** Options for {@link container}: the {@link ContainerBuildOptions} plus an optional diagnostic identity. */
39
43
  export interface ContainerOptions extends ContainerBuildOptions {
40
- /** Stable identity for build memoization; defaults to `imageName`. Set when two containers share one. */
44
+ /** Stable diagnostic identity included in, but never substituted for, the complete cache key. */
41
45
  id?: string;
42
46
  }
43
47
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../../src/core/containers/image.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,KAAK,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAEzF,8FAA8F;AAC9F,MAAM,WAAW,cAAc;IAC7B,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,+EAA+E;IAC/E,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,+BAA+B;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,yGAAyG;AACzG,MAAM,WAAW,gBAAiB,SAAQ,qBAAqB;IAC7D,yGAAyG;IACzG,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAQ9E;AAKD,uGAAuG;AACvG,KAAK,OAAO,GAAG,CAAC,OAAO,EAAE,qBAAqB,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;AASjF;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,gBAAgB,EACzB,KAAK,GAAE,OAAwB,GAC9B,OAAO,CAAC,cAAc,CAAC,CAQzB;AAED,sGAAsG;AACtG,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
1
+ {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../../src/core/containers/image.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAOH,OAAO,KAAK,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAEzF,8FAA8F;AAC9F,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,8EAA8E;IAC9E,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,sEAAsE;IACtE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAED,6GAA6G;AAC7G,MAAM,WAAW,gBAAiB,SAAQ,qBAAqB;IAC7D,iGAAiG;IACjG,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAQ9E;AAOD,uGAAuG;AACvG,KAAK,OAAO,GAAG,CAAC,OAAO,EAAE,qBAAqB,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAiGjF;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,gBAAgB,EACzB,KAAK,GAAE,OAAwB,GAC9B,OAAO,CAAC,cAAc,CAAC,CAazB;AAED,sGAAsG;AACtG,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
@@ -10,8 +10,9 @@
10
10
  * that: you `await` it. It is NOT a deferred reference — resolve images in (async) setup code before
11
11
  * composing, then feed the resulting literals into resources or chart values.
12
12
  *
13
- * Memoization: the build is keyed by container identity (`id ?? imageName`) and cached, so awaiting
14
- * the same container many times (e.g. several deployments sharing one image) builds it exactly ONCE.
13
+ * Memoization: the build is keyed by the effective content, target, registry, and build options, so
14
+ * awaiting the same container many times builds it once while a changed context or registry cannot
15
+ * accidentally reuse a different image.
15
16
  *
16
17
  * @example
17
18
  * ```typescript
@@ -25,7 +26,10 @@
25
26
  * // or for a Helm chart's split image values: { repository: img.repository, tag: img.tag }
26
27
  * ```
27
28
  */
28
- import { buildContainer } from './build.js';
29
+ import { createHash } from 'node:crypto';
30
+ import { existsSync } from 'node:fs';
31
+ import { join, resolve } from 'node:path';
32
+ import { buildContainer, computeContentHash } from './build.js';
29
33
  /**
30
34
  * Split a full image URI into `{ repository, tag }`. Handles digest form (`repo@sha256:…`) and tag
31
35
  * form (`repo:tag`), registry-port-colon aware (a colon in `host:port/...` is not the tag separator).
@@ -40,13 +44,92 @@ export function splitImageUri(uri) {
40
44
  ? { repository: uri.slice(0, colon), tag: uri.slice(colon + 1) }
41
45
  : { repository: uri, tag: 'latest' };
42
46
  }
43
- /** Build memoization, keyed by container identity (`id ?? imageName`) — builds each image once. */
47
+ /** Build memoization, keyed by effective content/options — builds each exact image once. */
44
48
  const buildCache = new Map();
49
+ const objectIdentities = new WeakMap();
50
+ let nextObjectIdentity = 1;
45
51
  async function buildAndShape(options, build) {
46
52
  const { id: _id, ...buildOptions } = options;
47
53
  const result = await build({ ...buildOptions, tag: buildOptions.tag ?? 'content-hash' });
48
- const { repository, tag } = splitImageUri(result.imageUri);
49
- return { imageUri: result.imageUri, repository, tag };
54
+ return {
55
+ imageUri: result.imageUri,
56
+ taggedImageUri: result.taggedImageUri,
57
+ repository: result.repository,
58
+ tag: result.tag,
59
+ ...(result.digest ? { digest: result.digest } : {}),
60
+ platforms: result.platforms,
61
+ };
62
+ }
63
+ function objectIdentity(value) {
64
+ if (!value)
65
+ return undefined;
66
+ let identity = objectIdentities.get(value);
67
+ if (!identity) {
68
+ identity = nextObjectIdentity++;
69
+ objectIdentities.set(value, identity);
70
+ }
71
+ return identity;
72
+ }
73
+ function sortedRecord(value) {
74
+ return value
75
+ ? Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)))
76
+ : undefined;
77
+ }
78
+ function registryIdentity(registry) {
79
+ switch (registry.type) {
80
+ case 'oci':
81
+ return {
82
+ type: registry.type,
83
+ registry: registry.registry,
84
+ repositoryPrefix: registry.repositoryPrefix,
85
+ dockerConfigPath: registry.dockerConfigPath,
86
+ tls: registry.tls,
87
+ credentialProvider: objectIdentity(registry.credentialProvider),
88
+ };
89
+ case 'ecr':
90
+ return {
91
+ type: registry.type,
92
+ accountId: registry.accountId,
93
+ region: registry.region,
94
+ createRepository: registry.createRepository,
95
+ credentials: objectIdentity(registry.credentials),
96
+ };
97
+ case 'custom':
98
+ return { type: registry.type, handler: objectIdentity(registry.handler) };
99
+ default:
100
+ return registry;
101
+ }
102
+ }
103
+ async function resolvedBuildOptions(options, build) {
104
+ const context = resolve(options.context);
105
+ const dockerfile = options.dockerfile ?? 'Dockerfile';
106
+ let tag = options.tag ?? 'content-hash';
107
+ if (tag === 'content-hash' &&
108
+ build === buildContainer &&
109
+ existsSync(context) &&
110
+ existsSync(join(context, dockerfile))) {
111
+ tag = await computeContentHash(context, join(context, dockerfile));
112
+ }
113
+ return { ...options, context, dockerfile, tag };
114
+ }
115
+ function buildCacheKey(options, build) {
116
+ const identity = {
117
+ id: options.id,
118
+ context: options.context,
119
+ dockerfile: options.dockerfile,
120
+ imageName: options.imageName,
121
+ tag: options.tag,
122
+ platform: options.platform,
123
+ platforms: options.platforms ? [...options.platforms] : undefined,
124
+ buildArgs: sortedRecord(options.buildArgs),
125
+ target: options.target,
126
+ timeout: options.timeout,
127
+ signal: objectIdentity(options.signal),
128
+ extraDockerArgs: options.extraDockerArgs ? [...options.extraDockerArgs] : undefined,
129
+ registry: registryIdentity(options.registry),
130
+ builder: objectIdentity(build),
131
+ };
132
+ return createHash('sha256').update(JSON.stringify(identity)).digest('hex');
50
133
  }
51
134
  /**
52
135
  * Build a container image (delegating to {@link buildContainer}) and resolve to its shaped result.
@@ -54,13 +137,19 @@ async function buildAndShape(options, build) {
54
137
  * pass only `options`.
55
138
  */
56
139
  export function container(options, build = buildContainer) {
57
- const key = options.id ?? options.imageName;
58
- let pending = buildCache.get(key);
59
- if (!pending) {
60
- pending = buildAndShape(options, build);
61
- buildCache.set(key, pending);
62
- }
63
- return pending;
140
+ return resolvedBuildOptions(options, build).then((resolved) => {
141
+ const key = buildCacheKey(resolved, build);
142
+ let pending = buildCache.get(key);
143
+ if (!pending) {
144
+ pending = buildAndShape(resolved, build);
145
+ buildCache.set(key, pending);
146
+ pending.catch(() => {
147
+ if (buildCache.get(key) === pending)
148
+ buildCache.delete(key);
149
+ });
150
+ }
151
+ return pending;
152
+ });
64
153
  }
65
154
  /** Clear the build memoization cache. Intended for tests/long-lived processes that need a rebuild. */
66
155
  export function clearContainerCache() {
@@ -1 +1 @@
1
- {"version":3,"file":"image.js","sourceRoot":"","sources":["../../../src/core/containers/image.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAmB5C;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,EAAE,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,EAAE,KAAK,CAAC,CAAC;QAAE,OAAO,EAAE,UAAU,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;IAC/E,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACnC,OAAO,KAAK,GAAG,KAAK;QAClB,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE;QAChE,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;AACzC,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,GAAG,IAAI,GAAG,EAAmC,CAAC;AAK9D,KAAK,UAAU,aAAa,CAAC,OAAyB,EAAE,KAAc;IACpE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,YAAY,EAAE,GAAG,OAAO,CAAC;IAC7C,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,EAAE,GAAG,YAAY,EAAE,GAAG,EAAE,YAAY,CAAC,GAAG,IAAI,cAAc,EAAE,CAAC,CAAC;IACzF,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC;AACxD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CACvB,OAAyB,EACzB,QAAiB,cAAc;IAE/B,MAAM,GAAG,GAAG,OAAO,CAAC,EAAE,IAAI,OAAO,CAAC,SAAS,CAAC;IAC5C,IAAI,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,GAAG,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACxC,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,mBAAmB;IACjC,UAAU,CAAC,KAAK,EAAE,CAAC;AACrB,CAAC"}
1
+ {"version":3,"file":"image.js","sourceRoot":"","sources":["../../../src/core/containers/image.ts"],"names":[],"mappings":"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"}
@@ -21,5 +21,9 @@
21
21
  export { buildContainer } from './build.js';
22
22
  export { ContainerBuildError } from './errors.js';
23
23
  export { type ContainerImage, type ContainerOptions, clearContainerCache, container, splitImageUri, } from './image.js';
24
- export type { ContainerBuildOptions, ContainerBuildResult, EcrRegistryConfig, OrbstackRegistryConfig, RegistryConfig, } from './registries/types.js';
24
+ export type { ContainerBuildProgress, ContainerBuildOptions, ContainerBuildResult, CustomRegistryConfig, EcrRegistryConfig, HarborRegistryConfig, OciRegistryConfig, OciRegistryCredential, OciRegistryCredentialProvider, OciRegistryTlsConfig, OrbstackRegistryConfig, RegistryConfig, RegistryHandler, RegistrySession, } from './registries/types.js';
25
+ export { kubernetesSecretRegistryCredentials } from './registries/credentials.js';
26
+ export type { KubernetesRegistrySecretReader, KubernetesSecretRegistryCredentialOptions, } from './registries/credentials.js';
27
+ export { harbor } from './registries/harbor.js';
28
+ export { ociRegistry } from './registries/oci.js';
25
29
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/containers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,mBAAmB,EACnB,SAAS,EACT,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,qBAAqB,EACrB,oBAAoB,EACpB,iBAAiB,EACjB,sBAAsB,EACtB,cAAc,GACf,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/containers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,mBAAmB,EACnB,SAAS,EACT,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EACjB,qBAAqB,EACrB,6BAA6B,EAC7B,oBAAoB,EACpB,sBAAsB,EACtB,cAAc,EACd,eAAe,EACf,eAAe,GAChB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,mCAAmC,EAAE,MAAM,6BAA6B,CAAC;AAClF,YAAY,EACV,8BAA8B,EAC9B,yCAAyC,GAC1C,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC"}
@@ -21,4 +21,7 @@
21
21
  export { buildContainer } from './build.js';
22
22
  export { ContainerBuildError } from './errors.js';
23
23
  export { clearContainerCache, container, splitImageUri, } from './image.js';
24
+ export { kubernetesSecretRegistryCredentials } from './registries/credentials.js';
25
+ export { harbor } from './registries/harbor.js';
26
+ export { ociRegistry } from './registries/oci.js';
24
27
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/containers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAGL,mBAAmB,EACnB,SAAS,EACT,aAAa,GACd,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/containers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAGL,mBAAmB,EACnB,SAAS,EACT,aAAa,GACd,MAAM,YAAY,CAAC;AAiBpB,OAAO,EAAE,mCAAmC,EAAE,MAAM,6BAA6B,CAAC;AAKlF,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,30 @@
1
+ import type { OciRegistryCredentialProvider } from './types.js';
2
+ export interface KubernetesSecretRegistryCredentialOptions {
3
+ namespace: string;
4
+ name: string;
5
+ /** Registry host used when resolving a kubernetes.io/dockerconfigjson entry. */
6
+ registry?: string;
7
+ /** Non-secret username paired with passwordKey. Mutually exclusive with usernameKey. */
8
+ username?: string;
9
+ usernameKey?: string;
10
+ passwordKey?: string;
11
+ dockerConfigJsonKey?: string;
12
+ context?: string;
13
+ kubeconfigPath?: string;
14
+ /** Optional embedding/test seam. Production defaults to the selected Kubernetes client. */
15
+ secretReader?: KubernetesRegistrySecretReader;
16
+ }
17
+ export type KubernetesRegistrySecretReader = (request: {
18
+ readonly namespace: string;
19
+ readonly name: string;
20
+ readonly context?: string;
21
+ readonly kubeconfigPath?: string;
22
+ }) => Promise<Readonly<Record<string, string>>>;
23
+ /**
24
+ * Resolve an OCI credential from a selected Kubernetes Secret at execution time.
25
+ *
26
+ * The returned closure retains only Secret coordinates; decoded values exist only during the
27
+ * registry session and are never written to TypeKro state or generated resources.
28
+ */
29
+ export declare function kubernetesSecretRegistryCredentials(options: KubernetesSecretRegistryCredentialOptions): OciRegistryCredentialProvider;
30
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../../../src/core/containers/registries/credentials.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAyB,6BAA6B,EAAE,MAAM,YAAY,CAAC;AAEvF,MAAM,WAAW,yCAAyC;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wFAAwF;IACxF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2FAA2F;IAC3F,YAAY,CAAC,EAAE,8BAA8B,CAAC;CAC/C;AAED,MAAM,MAAM,8BAA8B,GAAG,CAAC,OAAO,EAAE;IACrD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC,KAAK,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;AAoDhD;;;;;GAKG;AACH,wBAAgB,mCAAmC,CACjD,OAAO,EAAE,yCAAyC,GACjD,6BAA6B,CAwC/B"}
@@ -0,0 +1,87 @@
1
+ import { Buffer } from 'node:buffer';
2
+ import { createKubernetesClientProvider, } from '../../kubernetes/client-provider.js';
3
+ import { ContainerBuildError } from '../errors.js';
4
+ function decodeSecretValue(value, key) {
5
+ if (!value) {
6
+ throw new ContainerBuildError(`Registry credential Secret is missing key "${key}".`, 'REGISTRY_SECRET_INVALID', ['Verify the Secret name, namespace, and configured key names.']);
7
+ }
8
+ return Buffer.from(value, 'base64').toString('utf8');
9
+ }
10
+ function registryHost(value) {
11
+ const withScheme = value.includes('://') ? value : `https://${value}`;
12
+ return new URL(withScheme).host;
13
+ }
14
+ function credentialFromDockerConfig(encodedConfig, registry) {
15
+ const decoded = Buffer.from(encodedConfig, 'base64').toString('utf8');
16
+ const parsed = JSON.parse(decoded);
17
+ const entries = Object.entries(parsed.auths ?? {});
18
+ const selected = registry
19
+ ? entries.find(([name]) => registryHost(name) === registryHost(registry))
20
+ : entries.length === 1
21
+ ? entries[0]
22
+ : undefined;
23
+ if (!selected) {
24
+ throw new ContainerBuildError('Docker config Secret does not contain an unambiguous credential for the registry.', 'REGISTRY_SECRET_INVALID', ['Set the registry option or use explicit usernameKey and passwordKey values.']);
25
+ }
26
+ const entry = selected[1];
27
+ if (entry.username && entry.password)
28
+ return entry;
29
+ const auth = entry.auth ? Buffer.from(entry.auth, 'base64').toString('utf8') : '';
30
+ const separator = auth.indexOf(':');
31
+ if (separator <= 0) {
32
+ throw new ContainerBuildError('Docker config Secret credential is missing username/password material.', 'REGISTRY_SECRET_INVALID');
33
+ }
34
+ return { username: auth.slice(0, separator), password: auth.slice(separator + 1) };
35
+ }
36
+ /**
37
+ * Resolve an OCI credential from a selected Kubernetes Secret at execution time.
38
+ *
39
+ * The returned closure retains only Secret coordinates; decoded values exist only during the
40
+ * registry session and are never written to TypeKro state or generated resources.
41
+ */
42
+ export function kubernetesSecretRegistryCredentials(options) {
43
+ if (options.username !== undefined && options.usernameKey !== undefined) {
44
+ throw new ContainerBuildError('Registry credential options must select either username or usernameKey, not both.', 'REGISTRY_SECRET_INVALID');
45
+ }
46
+ if (options.username !== undefined && options.username.trim().length === 0) {
47
+ throw new ContainerBuildError('Registry credential username must not be empty.', 'REGISTRY_SECRET_INVALID');
48
+ }
49
+ return async (signal) => {
50
+ if (signal?.aborted)
51
+ throw ContainerBuildError.cancelled();
52
+ const request = {
53
+ namespace: options.namespace,
54
+ name: options.name,
55
+ ...(options.context ? { context: options.context } : {}),
56
+ ...(options.kubeconfigPath ? { kubeconfigPath: options.kubeconfigPath } : {}),
57
+ };
58
+ const data = options.secretReader
59
+ ? await options.secretReader(request)
60
+ : await readKubernetesSecret(request);
61
+ if (signal?.aborted)
62
+ throw ContainerBuildError.cancelled();
63
+ const dockerConfigKey = options.dockerConfigJsonKey ?? '.dockerconfigjson';
64
+ if (data[dockerConfigKey]) {
65
+ return credentialFromDockerConfig(data[dockerConfigKey], options.registry);
66
+ }
67
+ const passwordKey = options.passwordKey ?? 'password';
68
+ return {
69
+ username: options.username ??
70
+ decodeSecretValue(data[options.usernameKey ?? 'username'], options.usernameKey ?? 'username'),
71
+ password: decodeSecretValue(data[passwordKey], passwordKey),
72
+ };
73
+ };
74
+ }
75
+ async function readKubernetesSecret(request) {
76
+ const config = {
77
+ ...(request.context ? { context: request.context } : {}),
78
+ ...(request.kubeconfigPath ? { kubeconfigPath: request.kubeconfigPath } : {}),
79
+ };
80
+ const provider = createKubernetesClientProvider(config);
81
+ const secret = await provider.getCoreV1Api().readNamespacedSecret({
82
+ namespace: request.namespace,
83
+ name: request.name,
84
+ });
85
+ return secret.data ?? {};
86
+ }
87
+ //# sourceMappingURL=credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../../../src/core/containers/registries/credentials.ts"],"names":[],"mappings":"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"}