mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix(docker): repair copied AI venv paths (#390)
AI feature installs now keep copied Python venv metadata (bin/pip shebang, bin/activate, pyvenv.cfg) pointed at /data/ai/venv, so scripts no longer silently fall back to the baked, read-only /opt/venv after the venv is bootstrapped into /data. Fixes #127 (AI tools incompatible with PUID/PGID). The entrypoint repairs both fresh bootstraps and already-stamped runtime venvs (self-heals existing deployments on next restart, no reinstall needed), with regression coverage for literal path replacement and binary file safety. Independently reviewed and verified: traced chown/gosu ordering in entrypoint.sh to confirm no permission regression, reproduced the exact issue #127 scenario (custom PUID + manual venv activation) in a live container both before and after the fix, and ran the PR's own test suite locally (16/16 passing). Co-authored-by: SyntaxSawdust
This commit is contained in:
co-authored by
SyntaxSawdust
parent
a0d1c70172
commit
7e01d3637e
@@ -1,5 +1,5 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { chmodSync, mkdirSync, mkdtempSync, rmSync } from "node:fs";
|
||||
import { chmodSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { dirname, join, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
@@ -72,3 +72,32 @@ describe("entrypoint-lib.sh ensure_writable", () => {
|
||||
expect(stderr).toContain("chown");
|
||||
});
|
||||
});
|
||||
|
||||
describe("entrypoint-lib.sh rewrite_venv_paths", () => {
|
||||
it("rewrites copied venv text entrypoints literally without touching binary files", () => {
|
||||
const optVenv = join(root, "opt&venv");
|
||||
const aiVenv = join(root, "data|ai", "venv&runtime");
|
||||
const binDir = join(aiVenv, "bin");
|
||||
mkdirSync(binDir, { recursive: true });
|
||||
|
||||
const pip = join(binDir, "pip");
|
||||
const activate = join(binDir, "activate");
|
||||
const pyvenv = join(aiVenv, "pyvenv.cfg");
|
||||
const binary = join(binDir, "python3");
|
||||
|
||||
writeFileSync(pip, `#!${optVenv}/bin/python3\nprint('pip')\n`);
|
||||
writeFileSync(activate, `VIRTUAL_ENV=${optVenv}\nexport VIRTUAL_ENV\n`);
|
||||
writeFileSync(pyvenv, `command = python3 -m venv ${optVenv}\n`);
|
||||
writeFileSync(binary, Buffer.from([0x00, ...Buffer.from(optVenv), 0x00]));
|
||||
|
||||
const result = runLib(`rewrite_venv_paths '${aiVenv}' '${optVenv}' '${aiVenv}'`);
|
||||
expect(result.status, result.stderr).toBe(0);
|
||||
|
||||
for (const file of [pip, activate, pyvenv]) {
|
||||
const content = readFileSync(file, "utf-8");
|
||||
expect(content).toContain(aiVenv);
|
||||
expect(content).not.toContain(optVenv);
|
||||
}
|
||||
expect(readFileSync(binary)).toEqual(Buffer.from([0x00, ...Buffer.from(optVenv), 0x00]));
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user