pinokiod 8.0.1 → 8.0.2

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.
@@ -1,6 +1,7 @@
1
1
  const semver = require('semver')
2
2
 
3
3
  const CONDA_PIN_VERSION = "26.3.2"
4
+ const CONDA_RUNTIME_MARKER = ".pinokio-runtime-v1"
4
5
  const PYTHON_PIN_VERSION = "3.10.20"
5
6
  const PYTHON_INSTALL_SPEC = `python=${PYTHON_PIN_VERSION}`
6
7
  const WINDOWS_PYTHON_SSL_FIX_SPEC = `${PYTHON_INSTALL_SPEC}=*_1_cpython`
@@ -28,6 +29,7 @@ const isExpectedPythonPinned = (platform, version, build) => {
28
29
 
29
30
  module.exports = {
30
31
  CONDA_PIN_VERSION,
32
+ CONDA_RUNTIME_MARKER,
31
33
  PYTHON_INSTALL_SPEC,
32
34
  WINDOWS_PYTHON_SSL_FIX_SPEC,
33
35
  isExpectedPythonPinned,
@@ -1,10 +1,10 @@
1
1
  const fs = require('fs')
2
- const path = require('path')
3
2
  const { glob } = require('glob')
4
3
  const semver = require('semver')
5
4
  const { buildCondaListFromMeta, managedCondaRuns } = require('./conda-meta')
6
5
  const {
7
6
  CONDA_PIN_VERSION,
7
+ CONDA_RUNTIME_MARKER,
8
8
  PYTHON_INSTALL_SPEC,
9
9
  WINDOWS_PYTHON_SSL_FIX_SPEC,
10
10
  isExpectedPythonPinned,
@@ -14,61 +14,6 @@ const MINIFORGE_RELEASE = "26.3.2-3"
14
14
  const MINIFORGE_BASE_URL = `https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_RELEASE}`
15
15
  const CONDA_ROOT_DIR = "miniforge"
16
16
  const LEGACY_CONDA_ROOT_DIR = "miniconda"
17
- const WINDOWS_OPENSSL_HOOKS = {
18
- activate: {
19
- "openssl_activate-win.bat": [
20
- "@echo off",
21
- 'if "%SSL_CERT_FILE%"=="" (',
22
- ' set "SSL_CERT_FILE=%CONDA_PREFIX%\\Library\\ssl\\cacert.pem"',
23
- ' set "__CONDA_OPENSSL_CERT_FILE_SET=1"',
24
- ")",
25
- "",
26
- ].join("\r\n"),
27
- "openssl_activate-win.ps1": [
28
- "if (-not $Env:SSL_CERT_FILE) {",
29
- ' $Env:SSL_CERT_FILE = "$Env:CONDA_PREFIX\\Library\\ssl\\cacert.pem"',
30
- ' $Env:__CONDA_OPENSSL_CERT_FILE_SET = "1"',
31
- "}",
32
- "",
33
- ].join("\r\n"),
34
- "openssl_activate-win.sh": [
35
- 'if [[ "${SSL_CERT_FILE:-}" == "" ]]; then',
36
- ' export SSL_CERT_FILE="${CONDA_PREFIX}\\\\Library\\\\ssl\\\\cacert.pem"',
37
- ' export __CONDA_OPENSSL_CERT_FILE_SET="1"',
38
- "fi",
39
- "",
40
- ].join("\n"),
41
- },
42
- deactivate: {
43
- "openssl_deactivate-win.bat": [
44
- "@echo off",
45
- 'if "%__CONDA_OPENSSL_CERT_FILE_SET%" == "1" (',
46
- " set SSL_CERT_FILE=",
47
- " set __CONDA_OPENSSL_CERT_FILE_SET=",
48
- ")",
49
- "",
50
- ].join("\r\n"),
51
- "openssl_deactivate-win.ps1": [
52
- 'if ($Env:__CONDA_OPENSSL_CERT_FILE_SET -eq "1") {',
53
- " Remove-Item -Path Env:\\SSL_CERT_FILE",
54
- " Remove-Item -Path Env:\\__CONDA_OPENSSL_CERT_FILE_SET",
55
- "}",
56
- "",
57
- ].join("\r\n"),
58
- "openssl_deactivate-win.sh": [
59
- 'if [[ "${__CONDA_OPENSSL_CERT_FILE_SET:-}" == "1" ]]; then',
60
- " unset SSL_CERT_FILE",
61
- " unset __CONDA_OPENSSL_CERT_FILE_SET",
62
- "fi",
63
- "",
64
- ].join("\n"),
65
- },
66
- }
67
- const LEGACY_SSL_CERT_DIR_HOOK_FILES = [
68
- "zz_pinokio_unset_ssl_cert_dir-win.bat",
69
- "zz_pinokio_unset_ssl_cert_dir-win.ps1",
70
- "zz_pinokio_unset_ssl_cert_dir-win.sh",
71
- ]
72
17
 
73
18
  class Conda {
74
19
  description = "Pinokio uses Conda to install various useful programs in an isolated manner."
@@ -103,6 +48,9 @@ class Conda {
103
48
  async hasCondaMeta() {
104
49
  return await this.kernel.exists(`bin/${CONDA_ROOT_DIR}/conda-meta`)
105
50
  }
51
+ async hasRuntimeMarker() {
52
+ return await this.kernel.exists(`bin/${CONDA_ROOT_DIR}/${CONDA_RUNTIME_MARKER}`)
53
+ }
106
54
  env() {
107
55
  let base = {
108
56
  CONDA_PREFIX: this.kernel.bin.path(CONDA_ROOT_DIR),
@@ -124,43 +72,6 @@ class Conda {
124
72
  }
125
73
  return base
126
74
  }
127
- async ensureWindowsOpenSslHooks() {
128
- if (this.kernel.platform !== "win32") {
129
- return
130
- }
131
- const condaRootDirs = []
132
- for (const rootDir of [CONDA_ROOT_DIR, LEGACY_CONDA_ROOT_DIR]) {
133
- if (await this.kernel.exists(`bin/${rootDir}/conda-meta`)) {
134
- condaRootDirs.push(rootDir)
135
- }
136
- }
137
- if (condaRootDirs.length === 0) {
138
- return
139
- }
140
- for (const rootDir of condaRootDirs) {
141
- const activateDir = this.kernel.bin.path(`${rootDir}/etc/conda/activate.d`)
142
- const deactivateDir = this.kernel.bin.path(`${rootDir}/etc/conda/deactivate.d`)
143
- for (const hookDir of [activateDir, deactivateDir]) {
144
- for (const filename of LEGACY_SSL_CERT_DIR_HOOK_FILES) {
145
- await fs.promises.rm(path.resolve(hookDir, filename), { force: true }).catch(() => {})
146
- }
147
- }
148
- for (const [filename, content] of Object.entries(WINDOWS_OPENSSL_HOOKS.activate)) {
149
- const hookPath = path.resolve(activateDir, filename)
150
- const exists = await fs.promises.access(hookPath).then(() => true).catch(() => false)
151
- if (exists) {
152
- await fs.promises.writeFile(hookPath, content)
153
- }
154
- }
155
- for (const [filename, content] of Object.entries(WINDOWS_OPENSSL_HOOKS.deactivate)) {
156
- const hookPath = path.resolve(deactivateDir, filename)
157
- const exists = await fs.promises.access(hookPath).then(() => true).catch(() => false)
158
- if (exists) {
159
- await fs.promises.writeFile(hookPath, content)
160
- }
161
- }
162
- }
163
- }
164
75
  async init() {
165
76
  if (this.kernel.homedir) {
166
77
  console.log("condarc init")
@@ -182,10 +93,12 @@ report_errors: false`)
182
93
  await fs.promises.writeFile(this.kernel.path(`bin/${CONDA_ROOT_DIR}/conda-meta/pinned`), this.pinnedPackages())
183
94
  await this.ensureCompatibilityAlias()
184
95
  }
185
- await this.ensureWindowsOpenSslHooks()
186
96
  }
187
97
  }
188
98
  async check() {
99
+ if (!(await this.hasRuntimeMarker())) {
100
+ return false
101
+ }
189
102
  let res = await buildCondaListFromMeta(this.kernel.bin.path(CONDA_ROOT_DIR))
190
103
 
191
104
  let lines = res.response.split(/[\r\n]+/)
@@ -330,10 +243,10 @@ report_errors: false`)
330
243
  this.kernel.bin.path(CONDA_ROOT_DIR, "python3.exe"),
331
244
  )
332
245
  }
333
- await this.ensureWindowsOpenSslHooks()
334
246
  await this.ensureCompatibilityAlias()
335
- ondata({ raw: `Install finished\r\n` })
336
247
  await this.kernel.bin.rm(installer, ondata)
248
+ await fs.promises.writeFile(this.kernel.bin.path(CONDA_ROOT_DIR, CONDA_RUNTIME_MARKER), "")
249
+ ondata({ raw: `Install finished\r\n` })
337
250
  }
338
251
  async removeInstallPath(target) {
339
252
  try {
@@ -23,6 +23,7 @@ const Cuda = require("./cuda")
23
23
  const Torch = require("./torch")
24
24
  const { buildCondaListFromMeta, managedCondaRuns } = require('./conda-meta')
25
25
  const {
26
+ CONDA_RUNTIME_MARKER,
26
27
  isExpectedPythonPinned,
27
28
  } = require('./conda-pins')
28
29
  const { glob } = require('glob')
@@ -349,6 +350,10 @@ class Bin {
349
350
  let conda_builds = {}
350
351
  this.correct_conda = false
351
352
 
353
+ const runtimeMarkerExists = await fs.promises.access(
354
+ this.kernel.bin.path("miniforge", CONDA_RUNTIME_MARKER)
355
+ ).then(() => true).catch(() => false)
356
+
352
357
  //////////////////////////////////////////////////////////////////
353
358
  // exception handling
354
359
  // if importlib_metadata || uvicorn || fastapi exist in the base environment, this.correct_conda = false
@@ -375,7 +380,7 @@ class Bin {
375
380
 
376
381
  let to_reset_exists = false
377
382
 
378
- if (to_reset_exists) {
383
+ if (!runtimeMarkerExists || to_reset_exists) {
379
384
  this.correct_conda = false
380
385
  } else {
381
386
  let res = await buildCondaListFromMeta(this.kernel.bin.path("miniforge"))
@@ -448,9 +453,6 @@ class Bin {
448
453
  break
449
454
  }
450
455
  }
451
- if (this.mod && this.mod.conda && this.mod.conda.ensureWindowsOpenSslHooks) {
452
- await this.mod.conda.ensureWindowsOpenSslHooks()
453
- }
454
456
  }
455
457
 
456
458
  if (this.platform === "darwin") {
package/kernel/shell.js CHANGED
@@ -294,6 +294,14 @@ class Shell {
294
294
  setDefaultEnvValue(this.env, "HF_TOKEN_PATH", path.resolve(this.kernel.homedir, "cache", "HF_AUTH", "token"))
295
295
 
296
296
  if (this.platform === "win32") {
297
+ const managedSslDir = path.resolve(this.kernel.homedir, "bin", "miniforge", "Library", "ssl")
298
+ const managedCertFile = path.resolve(managedSslDir, "cacert.pem")
299
+ const managedCertFileExists = await fs.promises.access(managedCertFile).then(() => true).catch(() => false)
300
+ if (managedCertFileExists) {
301
+ setDefaultEnvValue(this.env, "SSL_CERT_FILE", managedCertFile)
302
+ setDefaultEnvValue(this.env, "SSL_CERT_DIR", managedSslDir)
303
+ }
304
+
297
305
  // Hugging Face file symlinks regularly fail on non-admin Windows setups.
298
306
  // Default to no-symlink cache mode unless the user/app explicitly overrides it.
299
307
  setDefaultEnvValue(this.env, "HF_HUB_DISABLE_SYMLINKS", "1")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "8.0.1",
3
+ "version": "8.0.2",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -5,8 +5,11 @@ const os = require('node:os')
5
5
  const path = require('node:path')
6
6
  const test = require('node:test')
7
7
 
8
+ const Bin = require('../kernel/bin')
8
9
  const Conda = require('../kernel/bin/conda')
9
10
  const {
11
+ CONDA_PIN_VERSION,
12
+ CONDA_RUNTIME_MARKER,
10
13
  PYTHON_INSTALL_SPEC,
11
14
  WINDOWS_PYTHON_SSL_FIX_SPEC,
12
15
  isExpectedPythonPinned,
@@ -42,11 +45,18 @@ async function writeCondaMeta(root, name, version, build = 'py_0') {
42
45
  }
43
46
 
44
47
  async function writeHealthyCondaMeta(root, platform = 'win32') {
45
- await writeCondaMeta(root, 'conda', '26.3.2', 'py310')
48
+ await writeCondaMeta(root, 'conda', CONDA_PIN_VERSION, 'py310')
46
49
  await writeCondaMeta(root, 'conda-libmamba-solver', '25.4.0', 'pyhd3eb1b0_0')
47
50
  await writeCondaMeta(root, 'python', '3.10.20', platform === 'win32' ? 'h4de0772_1_cpython' : 'cpython')
48
51
  }
49
52
 
53
+ async function writeRuntimeMarker(root) {
54
+ const marker = path.join(root, 'bin', 'miniforge', CONDA_RUNTIME_MARKER)
55
+ await fs.mkdir(path.dirname(marker), { recursive: true })
56
+ await fs.writeFile(marker, '')
57
+ return marker
58
+ }
59
+
50
60
  async function writeFakeManagedConda(root, platform = 'win32') {
51
61
  const condaPath = platform === 'win32'
52
62
  ? path.join(root, 'bin', 'miniforge', 'Scripts', 'conda.exe')
@@ -78,86 +88,17 @@ function createConda(kernel) {
78
88
  return conda
79
89
  }
80
90
 
81
- const EXPECTED_WINDOWS_OPENSSL_HOOKS = {
82
- [path.join('activate.d', 'openssl_activate-win.bat')]: [
83
- '@echo off',
84
- 'if "%SSL_CERT_FILE%"=="" (',
85
- ' set "SSL_CERT_FILE=%CONDA_PREFIX%\\Library\\ssl\\cacert.pem"',
86
- ' set "__CONDA_OPENSSL_CERT_FILE_SET=1"',
87
- ')',
88
- '',
89
- ].join('\r\n'),
90
- [path.join('activate.d', 'openssl_activate-win.ps1')]: [
91
- 'if (-not $Env:SSL_CERT_FILE) {',
92
- ' $Env:SSL_CERT_FILE = "$Env:CONDA_PREFIX\\Library\\ssl\\cacert.pem"',
93
- ' $Env:__CONDA_OPENSSL_CERT_FILE_SET = "1"',
94
- '}',
95
- '',
96
- ].join('\r\n'),
97
- [path.join('activate.d', 'openssl_activate-win.sh')]: [
98
- 'if [[ "${SSL_CERT_FILE:-}" == "" ]]; then',
99
- ' export SSL_CERT_FILE="${CONDA_PREFIX}\\\\Library\\\\ssl\\\\cacert.pem"',
100
- ' export __CONDA_OPENSSL_CERT_FILE_SET="1"',
101
- 'fi',
102
- '',
103
- ].join('\n'),
104
- [path.join('deactivate.d', 'openssl_deactivate-win.bat')]: [
105
- '@echo off',
106
- 'if "%__CONDA_OPENSSL_CERT_FILE_SET%" == "1" (',
107
- ' set SSL_CERT_FILE=',
108
- ' set __CONDA_OPENSSL_CERT_FILE_SET=',
109
- ')',
110
- '',
111
- ].join('\r\n'),
112
- [path.join('deactivate.d', 'openssl_deactivate-win.ps1')]: [
113
- 'if ($Env:__CONDA_OPENSSL_CERT_FILE_SET -eq "1") {',
114
- ' Remove-Item -Path Env:\\SSL_CERT_FILE',
115
- ' Remove-Item -Path Env:\\__CONDA_OPENSSL_CERT_FILE_SET',
116
- '}',
117
- '',
118
- ].join('\r\n'),
119
- [path.join('deactivate.d', 'openssl_deactivate-win.sh')]: [
120
- 'if [[ "${__CONDA_OPENSSL_CERT_FILE_SET:-}" == "1" ]]; then',
121
- ' unset SSL_CERT_FILE',
122
- ' unset __CONDA_OPENSSL_CERT_FILE_SET',
123
- 'fi',
124
- '',
125
- ].join('\n'),
126
- }
127
-
128
- async function seedWindowsOpenSslHooks(root, condaRootName) {
129
- const condaHookRoot = path.join(root, 'bin', condaRootName, 'etc', 'conda')
130
- for (const hookRelativePath of Object.keys(EXPECTED_WINDOWS_OPENSSL_HOOKS)) {
131
- const hookPath = path.join(condaHookRoot, hookRelativePath)
132
- await fs.mkdir(path.dirname(hookPath), { recursive: true })
133
- await fs.writeFile(hookPath, 'upstream hook with SSL_CERT_DIR\n')
134
- }
135
- for (const hookDirName of ['activate.d', 'deactivate.d']) {
136
- for (const filename of [
137
- 'zz_pinokio_unset_ssl_cert_dir-win.bat',
138
- 'zz_pinokio_unset_ssl_cert_dir-win.ps1',
139
- 'zz_pinokio_unset_ssl_cert_dir-win.sh',
140
- ]) {
141
- await fs.writeFile(path.join(condaHookRoot, hookDirName, filename), 'legacy hook\n')
142
- }
143
- }
144
- }
145
-
146
- async function assertWindowsOpenSslHooksPatched(root, condaRootName) {
147
- const condaHookRoot = path.join(root, 'bin', condaRootName, 'etc', 'conda')
148
- for (const [hookRelativePath, expectedContent] of Object.entries(EXPECTED_WINDOWS_OPENSSL_HOOKS)) {
149
- const hookPath = path.join(condaHookRoot, hookRelativePath)
150
- assert.equal(await fs.readFile(hookPath, 'utf8'), expectedContent)
151
- }
152
- for (const hookDirName of ['activate.d', 'deactivate.d']) {
153
- for (const filename of [
154
- 'zz_pinokio_unset_ssl_cert_dir-win.bat',
155
- 'zz_pinokio_unset_ssl_cert_dir-win.ps1',
156
- 'zz_pinokio_unset_ssl_cert_dir-win.sh',
157
- ]) {
158
- assert.equal(await pathExists(path.join(condaHookRoot, hookDirName, filename)), false)
159
- }
91
+ function createBin(root, platform = 'win32') {
92
+ const kernel = {
93
+ homedir: root,
94
+ platform,
95
+ path: (...parts) => path.join(root, ...parts),
160
96
  }
97
+ const bin = new Bin(kernel)
98
+ bin.platform = platform
99
+ bin.installed = {}
100
+ kernel.bin = bin
101
+ return bin
161
102
  }
162
103
 
163
104
  test('Conda uses Miniforge assets and writes conda-forge-only config', async () => {
@@ -181,29 +122,9 @@ test('Conda uses Miniforge assets and writes conda-forge-only config', async ()
181
122
  assert.equal(await pathExists(path.join(root, 'bin', 'miniforge')), false)
182
123
  })
183
124
 
184
- test('Conda init patches Windows OpenSSL hooks and removes legacy SSL_CERT_DIR hooks', async () => {
185
- const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-openssl-hooks-'))
186
- await fs.mkdir(path.join(root, 'bin', 'miniforge', 'conda-meta'), { recursive: true })
187
- await seedWindowsOpenSslHooks(root, 'miniforge')
188
- const conda = createConda(createKernel(root))
189
-
190
- await conda.init()
191
-
192
- await assertWindowsOpenSslHooksPatched(root, 'miniforge')
193
- })
194
-
195
- test('Conda init patches Windows OpenSSL hooks for legacy Miniconda roots', async () => {
196
- const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-legacy-openssl-hooks-'))
197
- await fs.mkdir(path.join(root, 'bin', 'miniconda', 'conda-meta'), { recursive: true })
198
- await seedWindowsOpenSslHooks(root, 'miniconda')
199
- const conda = createConda(createKernel(root))
200
-
201
- await conda.init()
202
-
203
- await assertWindowsOpenSslHooksPatched(root, 'miniconda')
204
- })
205
-
206
- test('Conda pins Python 3.10.20 consistently across platforms', async () => {
125
+ test('Conda pins the managed Conda and Python versions consistently', async () => {
126
+ assert.equal(CONDA_PIN_VERSION, '26.3.2')
127
+ assert.equal(CONDA_RUNTIME_MARKER, '.pinokio-runtime-v1')
207
128
  assert.equal(PYTHON_INSTALL_SPEC, 'python=3.10.20')
208
129
  assert.equal(WINDOWS_PYTHON_SSL_FIX_SPEC, 'python=3.10.20=*_1_cpython')
209
130
 
@@ -215,6 +136,48 @@ test('Conda pins Python 3.10.20 consistently across platforms', async () => {
215
136
  assert.equal(isExpectedPythonPinned('win32', '3.10.20', 'h4de0772_1_cpython'), true)
216
137
  })
217
138
 
139
+ test('Conda init does not mark an existing runtime as rebuilt', async () => {
140
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-marker-init-'))
141
+ await createMiniforge(root)
142
+ await fs.mkdir(path.join(root, 'bin', 'miniforge', 'conda-meta'), { recursive: true })
143
+
144
+ await createConda(createKernel(root, 'darwin')).init()
145
+
146
+ assert.equal(await pathExists(path.join(root, 'bin', 'miniforge', CONDA_RUNTIME_MARKER)), false)
147
+ assert.equal(
148
+ await fs.readFile(path.join(root, 'bin', 'miniforge', 'conda-meta', 'pinned'), 'utf8'),
149
+ 'conda ==26.3.2'
150
+ )
151
+ })
152
+
153
+ test('Conda init leaves Windows OpenSSL activation hooks untouched', async () => {
154
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-hooks-untouched-'))
155
+ const hookRoot = path.join(root, 'bin', 'miniforge', 'etc', 'conda')
156
+ const hookFiles = [
157
+ path.join('activate.d', 'openssl_activate-win.bat'),
158
+ path.join('activate.d', 'openssl_activate-win.ps1'),
159
+ path.join('activate.d', 'openssl_activate-win.sh'),
160
+ path.join('deactivate.d', 'openssl_deactivate-win.bat'),
161
+ path.join('deactivate.d', 'openssl_deactivate-win.ps1'),
162
+ path.join('deactivate.d', 'openssl_deactivate-win.sh'),
163
+ ]
164
+ await fs.mkdir(path.join(root, 'bin', 'miniforge', 'conda-meta'), { recursive: true })
165
+ for (const relativePath of hookFiles) {
166
+ const hookPath = path.join(hookRoot, relativePath)
167
+ await fs.mkdir(path.dirname(hookPath), { recursive: true })
168
+ await fs.writeFile(hookPath, `upstream ${relativePath}\n`)
169
+ }
170
+
171
+ await createConda(createKernel(root, 'win32')).init()
172
+
173
+ for (const relativePath of hookFiles) {
174
+ assert.equal(
175
+ await fs.readFile(path.join(hookRoot, relativePath), 'utf8'),
176
+ `upstream ${relativePath}\n`
177
+ )
178
+ }
179
+ })
180
+
218
181
  test('Conda install requests the Python 3.10.20 pin on macOS/Linux', async () => {
219
182
  const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-python-pin-darwin-'))
220
183
  const kernel = createKernel(root, 'darwin')
@@ -239,6 +202,11 @@ test('Conda install requests the Python 3.10.20 pin on macOS/Linux', async () =>
239
202
  condaInstall.message[1],
240
203
  'conda install -y --override-channels -c conda-forge "python=3.10.20" "conda-libmamba-solver>=25.4.0"'
241
204
  )
205
+ assert.equal(
206
+ await fs.readFile(path.join(root, 'bin', 'miniforge', 'conda-meta', 'pinned'), 'utf8'),
207
+ 'conda ==26.3.2'
208
+ )
209
+ assert.equal(await pathExists(path.join(root, 'bin', 'miniforge', CONDA_RUNTIME_MARKER)), true)
242
210
  })
243
211
 
244
212
  test('Conda install keeps the Windows Python 3.10.20 SSL-fixed build pin', async () => {
@@ -267,6 +235,40 @@ test('Conda install keeps the Windows Python 3.10.20 SSL-fixed build pin', async
267
235
  condaInstall.message[1],
268
236
  'conda install -y --override-channels -c conda-forge "python=3.10.20=*_1_cpython" "conda-libmamba-solver>=25.4.0"'
269
237
  )
238
+ assert.equal(await pathExists(path.join(root, 'bin', 'miniforge', CONDA_RUNTIME_MARKER)), true)
239
+ })
240
+
241
+ test('Conda install replaces the stale runtime and rebuilds declared Conda modules', async () => {
242
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-full-reset-'))
243
+ const staleRoot = await createMiniforge(root)
244
+ const staleMarker = path.join(staleRoot, 'stale-runtime.txt')
245
+ await fs.writeFile(staleMarker, 'remove me\n')
246
+ const kernel = createKernel(root, 'darwin')
247
+ const calls = []
248
+
249
+ kernel.bin.mods = [
250
+ { name: 'uv', mod: { cmd: () => 'uv=0.11.23' } },
251
+ { name: 'node', mod: { cmd: () => 'nodejs=22.21.1 pnpm' } },
252
+ ]
253
+ kernel.bin.download = async () => {}
254
+ kernel.bin.rm = async () => {}
255
+ kernel.bin.exec = async (payload) => {
256
+ calls.push(payload)
257
+ if (payload && payload.conda && payload.conda.skip) {
258
+ await fs.mkdir(path.join(root, 'bin', 'miniforge', 'conda-meta'), { recursive: true })
259
+ }
260
+ }
261
+
262
+ await createConda(kernel)._install({ dependencies: ['uv', 'node'] }, () => {})
263
+
264
+ assert.equal(await pathExists(staleMarker), false)
265
+ const condaInstall = calls.find((call) => Array.isArray(call.message))
266
+ assert.ok(condaInstall)
267
+ assert.equal(
268
+ condaInstall.message[1],
269
+ 'conda install -y --override-channels -c conda-forge "python=3.10.20" "conda-libmamba-solver>=25.4.0" uv=0.11.23 nodejs=22.21.1 pnpm'
270
+ )
271
+ assert.equal(await pathExists(path.join(root, 'bin', 'miniforge', CONDA_RUNTIME_MARKER)), true)
270
272
  })
271
273
 
272
274
  test('Conda install replaces legacy miniconda with a compatibility alias to miniforge', async () => {
@@ -327,6 +329,15 @@ test('Conda installed stays false when metadata check already marked Conda inval
327
329
  test('Conda check rejects metadata-only Windows installs', async () => {
328
330
  const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-smoke-missing-'))
329
331
  await writeHealthyCondaMeta(root, 'win32')
332
+ await writeRuntimeMarker(root)
333
+
334
+ assert.equal(await createConda(createKernel(root, 'win32')).check(), false)
335
+ })
336
+
337
+ test('Conda check rejects an otherwise healthy runtime without the runtime marker', async () => {
338
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-marker-stale-'))
339
+ await writeHealthyCondaMeta(root, 'win32')
340
+ await writeFakeManagedConda(root, 'win32')
330
341
 
331
342
  assert.equal(await createConda(createKernel(root, 'win32')).check(), false)
332
343
  })
@@ -335,13 +346,31 @@ test('Conda check accepts a runnable managed Windows conda executable', async ()
335
346
  const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-smoke-runnable-'))
336
347
  await writeHealthyCondaMeta(root, 'win32')
337
348
  await writeFakeManagedConda(root, 'win32')
349
+ await writeRuntimeMarker(root)
338
350
 
339
351
  assert.equal(await createConda(createKernel(root, 'win32')).check(), true)
340
352
  })
341
353
 
354
+ test('Bin readiness rejects a runtime without the marker and accepts it once marked', async () => {
355
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-bin-conda-marker-'))
356
+ await writeHealthyCondaMeta(root, 'win32')
357
+ await writeFakeManagedConda(root, 'win32')
358
+ const bin = createBin(root, 'win32')
359
+
360
+ await bin.tryList()
361
+ assert.equal(bin.correct_conda, false)
362
+
363
+ await writeRuntimeMarker(root)
364
+
365
+ await bin.tryList()
366
+ assert.equal(bin.correct_conda, true)
367
+ })
368
+
342
369
  test('Conda install keeps the old runtime when the replacement installer download fails', async () => {
343
370
  const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-download-fails-'))
344
- const miniconda = await createLegacyMiniconda(root)
371
+ const miniforge = await createMiniforge(root)
372
+ const oldRuntimeFile = path.join(miniforge, 'old-runtime.txt')
373
+ await fs.writeFile(oldRuntimeFile, 'keep me\n')
345
374
  const kernel = createKernel(root)
346
375
 
347
376
  kernel.bin.download = async () => {
@@ -352,8 +381,31 @@ test('Conda install keeps the old runtime when the replacement installer downloa
352
381
  createConda(kernel)._install({ dependencies: [] }, () => {}),
353
382
  /download failed/
354
383
  )
355
- assert.equal(await pathExists(miniconda), true)
356
- assert.equal(await pathExists(path.join(root, 'bin', 'miniforge')), false)
384
+ assert.equal(await pathExists(oldRuntimeFile), true)
385
+ assert.equal(await pathExists(path.join(miniforge, CONDA_RUNTIME_MARKER)), false)
386
+ })
387
+
388
+ test('Conda install leaves the runtime unmarked when bootstrap fails after replacement', async () => {
389
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-bootstrap-fails-'))
390
+ await createMiniforge(root)
391
+ const kernel = createKernel(root, 'darwin')
392
+
393
+ kernel.bin.mods = []
394
+ kernel.bin.download = async () => {}
395
+ kernel.bin.rm = async () => {}
396
+ kernel.bin.exec = async (payload) => {
397
+ if (payload && payload.conda && payload.conda.skip) {
398
+ await fs.mkdir(path.join(root, 'bin', 'miniforge', 'conda-meta'), { recursive: true })
399
+ return
400
+ }
401
+ throw new Error('bootstrap failed')
402
+ }
403
+
404
+ await assert.rejects(
405
+ createConda(kernel)._install({ dependencies: [] }, () => {}),
406
+ /bootstrap failed/
407
+ )
408
+ assert.equal(await pathExists(path.join(root, 'bin', 'miniforge', CONDA_RUNTIME_MARKER)), false)
357
409
  })
358
410
 
359
411
  test('Conda install reports manual recovery when the old runtime cannot be removed', async () => {
@@ -197,6 +197,48 @@ test('Shell.init_env keeps Windows Hugging Face symlink defaults scoped to win32
197
197
  assert.equal(winShell.env.HF_HUB_DISABLE_SYMLINKS_WARNING, '1')
198
198
  })
199
199
 
200
+ test('Shell.init_env gives Windows uv a valid managed certificate directory without overriding apps', async () => {
201
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-shell-ssl-win-'))
202
+ const managedSslDir = path.join(root, 'bin', 'miniforge', 'Library', 'ssl')
203
+ const managedCertFile = path.join(managedSslDir, 'cacert.pem')
204
+ await fs.mkdir(path.join(root, 'api'), { recursive: true })
205
+ await fs.mkdir(managedSslDir, { recursive: true })
206
+ await fs.writeFile(path.join(root, 'ENVIRONMENT'), 'PINOKIO_TEST_ENV=1\n')
207
+ await fs.writeFile(managedCertFile, 'test certificate bundle\n')
208
+
209
+ const defaultShell = createShell(createKernel(root))
210
+ defaultShell.platform = 'win32'
211
+ await defaultShell.init_env({
212
+ path: process.cwd(),
213
+ env: {}
214
+ })
215
+ assert.equal(defaultShell.env.SSL_CERT_FILE, managedCertFile)
216
+ assert.equal(defaultShell.env.SSL_CERT_DIR, managedSslDir)
217
+
218
+ const customCertFile = path.join(root, 'custom', 'certs.pem')
219
+ const customCertDir = path.join(root, 'custom', 'certs')
220
+ const overrideShell = createShell(createKernel(root))
221
+ overrideShell.platform = 'win32'
222
+ await overrideShell.init_env({
223
+ path: process.cwd(),
224
+ env: {
225
+ SSL_CERT_FILE: customCertFile,
226
+ SSL_CERT_DIR: customCertDir
227
+ }
228
+ })
229
+ assert.equal(overrideShell.env.SSL_CERT_FILE, customCertFile)
230
+ assert.equal(overrideShell.env.SSL_CERT_DIR, customCertDir)
231
+
232
+ const darwinShell = createShell(createKernel(root))
233
+ darwinShell.platform = 'darwin'
234
+ await darwinShell.init_env({
235
+ path: process.cwd(),
236
+ env: {}
237
+ })
238
+ assert.equal(darwinShell.env.SSL_CERT_FILE, undefined)
239
+ assert.equal(darwinShell.env.SSL_CERT_DIR, undefined)
240
+ })
241
+
200
242
  test('redactEnvArgs summarizes protected argv env values', () => {
201
243
  const redacted = ShellRunTemplate.redactEnvArgs({
202
244
  PINOKIO_ARG_0: 'line one\nline two',