mirror of
https://github.com/Kaelio/ktx.git
synced 2026-07-04 10:52:13 +02:00
fix(setup): unblock clean Linux installs and add enabled_tables allowlist
- Pin managed Python runtime to 3.13 via `uv venv --python 3.13` so installs don't pick the system 3.12 on Ubuntu 24.04 and fail at wheel install. - Sanitize NO_PROXY/no_proxy for the daemon child process — drop IPv6 CIDR entries that httpx rejects with InvalidURL (OrbStack injects these by default). - Add `enabled_tables` allowlist on warehouse connections (zod schema + live-database introspection filter) to scope ingest to specific tables. - Add `getting-started/troubleshooting-linux` docs page covering the Python 3.13 prerequisite, IPv6 proxy gotcha, and a minimal working recipe; link it from the quickstart troubleshooting table and the llms-docs map. - Make docs-site origin overridable via `KTX_DOCS_ORIGIN` so local builds can serve under host.docker.internal.
This commit is contained in:
parent
c513d61dca
commit
2403f58eff
12 changed files with 307 additions and 8 deletions
|
|
@ -4,6 +4,7 @@ import { join } from 'node:path';
|
|||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import {
|
||||
readManagedPythonDaemonStatus,
|
||||
sanitizeProxyEnv,
|
||||
startManagedPythonDaemon,
|
||||
stopAllManagedPythonDaemons,
|
||||
stopManagedPythonDaemon,
|
||||
|
|
@ -404,3 +405,38 @@ describe('managed Python daemon lifecycle', () => {
|
|||
expect(await readFile(layout(tempDir).daemonStatePath, 'utf8')).toContain('"pid": 4242');
|
||||
});
|
||||
});
|
||||
|
||||
describe('sanitizeProxyEnv', () => {
|
||||
it('removes IPv6 CIDR entries from NO_PROXY that crash httpx', () => {
|
||||
const cleaned = sanitizeProxyEnv({
|
||||
NO_PROXY: 'localhost,127.0.0.1,fd07:b51a:cc66:f0::/64,*.orb.internal',
|
||||
no_proxy: 'localhost,127.0.0.1,fd07:b51a:cc66:f0::/64,*.orb.internal',
|
||||
});
|
||||
expect(cleaned.NO_PROXY).toBe('localhost,127.0.0.1,*.orb.internal');
|
||||
expect(cleaned.no_proxy).toBe('localhost,127.0.0.1,*.orb.internal');
|
||||
});
|
||||
|
||||
it('deletes NO_PROXY entirely when every entry is unparseable', () => {
|
||||
const cleaned = sanitizeProxyEnv({ NO_PROXY: 'fd07::/64,::1' });
|
||||
expect(cleaned.NO_PROXY).toBeUndefined();
|
||||
});
|
||||
|
||||
it('preserves IPv4 addresses, IPv4 CIDRs, hostnames, and wildcards', () => {
|
||||
const cleaned = sanitizeProxyEnv({
|
||||
NO_PROXY: '127.0.0.0/8,10.0.0.1,localhost,*.example.com',
|
||||
});
|
||||
expect(cleaned.NO_PROXY).toBe('127.0.0.0/8,10.0.0.1,localhost,*.example.com');
|
||||
});
|
||||
|
||||
it('leaves other env vars untouched', () => {
|
||||
const cleaned = sanitizeProxyEnv({ PATH: '/usr/bin', NO_PROXY: '::1', FOO: 'bar' });
|
||||
expect(cleaned.PATH).toBe('/usr/bin');
|
||||
expect(cleaned.FOO).toBe('bar');
|
||||
expect(cleaned.NO_PROXY).toBeUndefined();
|
||||
});
|
||||
|
||||
it('does nothing when NO_PROXY is not set', () => {
|
||||
const cleaned = sanitizeProxyEnv({ PATH: '/usr/bin' });
|
||||
expect(cleaned).toEqual({ PATH: '/usr/bin' });
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -697,7 +697,7 @@ export async function startManagedPythonDaemon(
|
|||
detached: true,
|
||||
stdio: ['ignore', stdout.fd, stderr.fd],
|
||||
env: {
|
||||
...process.env,
|
||||
...sanitizeProxyEnv(process.env),
|
||||
KTX_DAEMON_VERSION: options.cliVersion,
|
||||
},
|
||||
},
|
||||
|
|
@ -807,3 +807,32 @@ export async function stopAllManagedPythonDaemons(
|
|||
scanErrors: discovery.scanErrors,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter NO_PROXY/no_proxy values to remove entries httpx cannot parse.
|
||||
*
|
||||
* httpx (used by the Python daemon via huggingface_hub / sentence-transformers)
|
||||
* treats each comma-separated NO_PROXY entry as a URL pattern. Raw IPv6 CIDR
|
||||
* blocks like `fd07:b51a:cc66:f0::/64` raise `InvalidURL` and crash the daemon.
|
||||
* OrbStack and similar Docker setups inject such entries by default.
|
||||
*
|
||||
* We drop any entry containing `::` (the unambiguous IPv6 marker) but keep
|
||||
* IPv4 addresses, IPv4 CIDRs, hostnames, and wildcard hosts intact.
|
||||
*/
|
||||
export function sanitizeProxyEnv(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
|
||||
const result: NodeJS.ProcessEnv = { ...env };
|
||||
for (const key of ['NO_PROXY', 'no_proxy']) {
|
||||
const value = result[key];
|
||||
if (typeof value !== 'string' || value.length === 0) continue;
|
||||
const kept = value
|
||||
.split(',')
|
||||
.map((entry) => entry.trim())
|
||||
.filter((entry) => entry.length > 0 && !entry.includes('::'));
|
||||
if (kept.length === 0) {
|
||||
delete result[key];
|
||||
} else {
|
||||
result[key] = kept.join(',');
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ describe('installManagedPythonRuntime', () => {
|
|||
expect(result.status).toBe('installed');
|
||||
expect(commands).toEqual([
|
||||
{ command: 'uv', args: ['--version'] },
|
||||
{ command: 'uv', args: ['venv', result.layout.venvDir] },
|
||||
{ command: 'uv', args: ['venv', result.layout.venvDir, '--python', '3.13'] },
|
||||
{
|
||||
command: 'uv',
|
||||
args: ['pip', 'install', '--python', result.layout.pythonPath, result.asset.wheelPath],
|
||||
|
|
|
|||
|
|
@ -12,6 +12,16 @@ const execFileAsync = promisify(execFile);
|
|||
export const runtimeFeatureSchema = z.enum(['core', 'local-embeddings']);
|
||||
export type KtxRuntimeFeature = z.infer<typeof runtimeFeatureSchema>;
|
||||
|
||||
/**
|
||||
* Python version the managed runtime venv must be built with. KTX's bundled
|
||||
* wheels declare `requires-python = ">=3.13"`; without an explicit `--python`
|
||||
* flag, `uv venv` may pick a too-old system Python (Ubuntu 24.04 ships 3.12)
|
||||
* and the subsequent `uv pip install` fails late with a confusing "package
|
||||
* requires Python >=3.13" error. Pinning here pushes uv to auto-download the
|
||||
* right interpreter via its python-management feature.
|
||||
*/
|
||||
export const MANAGED_RUNTIME_PYTHON_VERSION = '3.13';
|
||||
|
||||
const runtimeAssetManifestSchema = z.object({
|
||||
schemaVersion: z.literal(1),
|
||||
distributionName: z.literal('kaelio-ktx'),
|
||||
|
|
@ -334,7 +344,7 @@ export async function installManagedPythonRuntime(
|
|||
exec,
|
||||
logPath: layout.installLogPath,
|
||||
command: 'uv',
|
||||
args: ['venv', layout.venvDir],
|
||||
args: ['venv', layout.venvDir, '--python', MANAGED_RUNTIME_PYTHON_VERSION],
|
||||
env: uvEnv,
|
||||
});
|
||||
const wheelSpec = features.includes('local-embeddings') ? `${asset.wheelPath}[local-embeddings]` : asset.wheelPath;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue