@kindgi/cli 0.1.5 → 0.1.6-rc.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 +4 -1
- package/dist/build/defaults.d.ts.map +1 -1
- package/dist/build/defaults.js +6 -0
- package/dist/build/defaults.js.map +1 -1
- package/dist/build/java-image.d.ts +6 -0
- package/dist/build/java-image.d.ts.map +1 -1
- package/dist/build/java-image.js +4 -1
- package/dist/build/java-image.js.map +1 -1
- package/dist/build/runners.d.ts +2 -0
- package/dist/build/runners.d.ts.map +1 -1
- package/dist/build/scala-image.d.ts +6 -0
- package/dist/build/scala-image.d.ts.map +1 -1
- package/dist/build/scala-image.js +4 -1
- package/dist/build/scala-image.js.map +1 -1
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +23 -7
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/approvals.d.ts.map +1 -1
- package/dist/commands/approvals.js +23 -3
- package/dist/commands/approvals.js.map +1 -1
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +32 -3
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/deploy.js +1 -1
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +128 -17
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/doctor.d.ts +4 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +41 -6
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +53 -7
- package/dist/commands/env.js.map +1 -1
- package/dist/commands/eval-runs.d.ts.map +1 -1
- package/dist/commands/eval-runs.js +27 -2
- package/dist/commands/eval-runs.js.map +1 -1
- package/dist/commands/eval-suites.d.ts.map +1 -1
- package/dist/commands/eval-suites.js +16 -6
- package/dist/commands/eval-suites.js.map +1 -1
- package/dist/commands/flows.d.ts.map +1 -1
- package/dist/commands/flows.js +23 -5
- package/dist/commands/flows.js.map +1 -1
- package/dist/commands/helpers.d.ts +10 -0
- package/dist/commands/helpers.d.ts.map +1 -1
- package/dist/commands/helpers.js +35 -0
- package/dist/commands/helpers.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +29 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +8 -1
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/memory.d.ts.map +1 -1
- package/dist/commands/memory.js +4 -4
- package/dist/commands/memory.js.map +1 -1
- package/dist/commands/proposals.d.ts.map +1 -1
- package/dist/commands/proposals.js +30 -10
- package/dist/commands/proposals.js.map +1 -1
- package/dist/commands/provenance.d.ts.map +1 -1
- package/dist/commands/provenance.js +3 -3
- package/dist/commands/provenance.js.map +1 -1
- package/dist/commands/providers.d.ts.map +1 -1
- package/dist/commands/providers.js +19 -2
- package/dist/commands/providers.js.map +1 -1
- package/dist/commands/run-waits.d.ts +28 -2
- package/dist/commands/run-waits.d.ts.map +1 -1
- package/dist/commands/run-waits.js +22 -3
- package/dist/commands/run-waits.js.map +1 -1
- package/dist/commands/runs.d.ts.map +1 -1
- package/dist/commands/runs.js +5 -1
- package/dist/commands/runs.js.map +1 -1
- package/dist/commands/schedules.d.ts.map +1 -1
- package/dist/commands/schedules.js +9 -4
- package/dist/commands/schedules.js.map +1 -1
- package/dist/commands/secrets-copy.d.ts +3 -0
- package/dist/commands/secrets-copy.d.ts.map +1 -0
- package/dist/commands/secrets-copy.js +164 -0
- package/dist/commands/secrets-copy.js.map +1 -0
- package/dist/commands/secrets.d.ts.map +1 -1
- package/dist/commands/secrets.js +19 -8
- package/dist/commands/secrets.js.map +1 -1
- package/dist/commands/service-accounts.d.ts.map +1 -1
- package/dist/commands/service-accounts.js +1 -1
- package/dist/commands/service-accounts.js.map +1 -1
- package/dist/commands/sso.d.ts +2 -1
- package/dist/commands/sso.d.ts.map +1 -1
- package/dist/commands/sso.js +11 -72
- package/dist/commands/sso.js.map +1 -1
- package/dist/commands/tokens.d.ts +1 -1
- package/dist/commands/tokens.d.ts.map +1 -1
- package/dist/commands/tokens.js +7 -6
- package/dist/commands/tokens.js.map +1 -1
- package/dist/commands/tools.d.ts.map +1 -1
- package/dist/commands/tools.js +10 -5
- package/dist/commands/tools.js.map +1 -1
- package/dist/dev/defaults.d.ts +10 -0
- package/dist/dev/defaults.d.ts.map +1 -1
- package/dist/dev/defaults.js +126 -16
- package/dist/dev/defaults.js.map +1 -1
- package/dist/dev/pack-env.d.ts +27 -1
- package/dist/dev/pack-env.d.ts.map +1 -1
- package/dist/dev/pack-env.js +27 -4
- package/dist/dev/pack-env.js.map +1 -1
- package/dist/dev/pack-service.d.ts +8 -0
- package/dist/dev/pack-service.d.ts.map +1 -1
- package/dist/dev/pack-service.js +2 -0
- package/dist/dev/pack-service.js.map +1 -1
- package/dist/dev/paths.d.ts +6 -0
- package/dist/dev/paths.d.ts.map +1 -1
- package/dist/dev/paths.js +8 -0
- package/dist/dev/paths.js.map +1 -1
- package/dist/dev/runners.d.ts +24 -0
- package/dist/dev/runners.d.ts.map +1 -1
- package/dist/dev/runtime-image.d.ts +1 -1
- package/dist/dev/runtime-image.d.ts.map +1 -1
- package/dist/dev/runtime-image.js +1 -1
- package/dist/dev/runtime-image.js.map +1 -1
- package/dist/dev/sandbox/bwrap.d.ts +19 -0
- package/dist/dev/sandbox/bwrap.d.ts.map +1 -0
- package/dist/dev/sandbox/bwrap.js +164 -0
- package/dist/dev/sandbox/bwrap.js.map +1 -0
- package/dist/dev/sandbox/detect.d.ts +26 -0
- package/dist/dev/sandbox/detect.d.ts.map +1 -0
- package/dist/dev/sandbox/detect.js +84 -0
- package/dist/dev/sandbox/detect.js.map +1 -0
- package/dist/dev/sandbox/index.d.ts +44 -0
- package/dist/dev/sandbox/index.d.ts.map +1 -0
- package/dist/dev/sandbox/index.js +81 -0
- package/dist/dev/sandbox/index.js.map +1 -0
- package/dist/dev/sandbox/notices.d.ts +23 -0
- package/dist/dev/sandbox/notices.d.ts.map +1 -0
- package/dist/dev/sandbox/notices.js +95 -0
- package/dist/dev/sandbox/notices.js.map +1 -0
- package/dist/dev/sandbox/policy.d.ts +80 -0
- package/dist/dev/sandbox/policy.d.ts.map +1 -0
- package/dist/dev/sandbox/policy.js +313 -0
- package/dist/dev/sandbox/policy.js.map +1 -0
- package/dist/dev/sandbox/seatbelt.d.ts +3 -0
- package/dist/dev/sandbox/seatbelt.d.ts.map +1 -0
- package/dist/dev/sandbox/seatbelt.js +131 -0
- package/dist/dev/sandbox/seatbelt.js.map +1 -0
- package/dist/dev/sandbox/settings.d.ts +30 -0
- package/dist/dev/sandbox/settings.d.ts.map +1 -0
- package/dist/dev/sandbox/settings.js +97 -0
- package/dist/dev/sandbox/settings.js.map +1 -0
- package/dist/env/provider-keys.d.ts +35 -0
- package/dist/env/provider-keys.d.ts.map +1 -0
- package/dist/env/provider-keys.js +108 -0
- package/dist/env/provider-keys.js.map +1 -0
- package/dist/init/agent-access.d.ts +119 -0
- package/dist/init/agent-access.d.ts.map +1 -0
- package/dist/init/agent-access.js +339 -0
- package/dist/init/agent-access.js.map +1 -0
- package/dist/init/augment-scaffolder.d.ts +2 -0
- package/dist/init/augment-scaffolder.d.ts.map +1 -1
- package/dist/init/augment-scaffolder.js +11 -1
- package/dist/init/augment-scaffolder.js.map +1 -1
- package/dist/init/gitignore-patcher.d.ts.map +1 -1
- package/dist/init/gitignore-patcher.js +5 -3
- package/dist/init/gitignore-patcher.js.map +1 -1
- package/dist/init/java-augment.d.ts +2 -0
- package/dist/init/java-augment.d.ts.map +1 -1
- package/dist/init/java-augment.js +10 -0
- package/dist/init/java-augment.js.map +1 -1
- package/dist/init/python-augment.d.ts +2 -0
- package/dist/init/python-augment.d.ts.map +1 -1
- package/dist/init/python-augment.js +10 -0
- package/dist/init/python-augment.js.map +1 -1
- package/dist/init/scala-augment.d.ts +2 -0
- package/dist/init/scala-augment.d.ts.map +1 -1
- package/dist/init/scala-augment.js +12 -2
- package/dist/init/scala-augment.js.map +1 -1
- package/dist/sdk-skills/kindgi-authoring-agents/SKILL.md +1 -1
- package/dist/sdk-skills/kindgi-authoring-flows/SKILL.md +1 -1
- package/dist/sdk-skills/kindgi-authoring-guardrails/SKILL.md +1 -1
- package/dist/sdk-skills/kindgi-authoring-mcp-servers/SKILL.md +8 -7
- package/dist/sdk-skills/kindgi-authoring-providers/SKILL.md +22 -16
- package/dist/sdk-skills/kindgi-authoring-tools/SKILL.md +14 -3
- package/dist/sdk-skills/kindgi-framework-feedback/SKILL.md +1 -1
- package/dist/sdk-skills/kindgi-getting-started/SKILL.md +24 -2
- package/dist/sdk-skills/kindgi-java-authoring-agents/SKILL.md +3 -3
- package/dist/sdk-skills/kindgi-java-authoring-flows/SKILL.md +1 -1
- package/dist/sdk-skills/kindgi-java-authoring-guardrails/SKILL.md +1 -1
- package/dist/sdk-skills/kindgi-java-authoring-tools/SKILL.md +35 -12
- package/dist/sdk-skills/kindgi-java-getting-started/SKILL.md +29 -5
- package/dist/sdk-skills/kindgi-python-authoring-agents/SKILL.md +1 -1
- package/dist/sdk-skills/kindgi-python-authoring-flows/SKILL.md +1 -1
- package/dist/sdk-skills/kindgi-python-authoring-guardrails/SKILL.md +1 -1
- package/dist/sdk-skills/kindgi-python-authoring-tools/SKILL.md +35 -9
- package/dist/sdk-skills/kindgi-python-getting-started/SKILL.md +28 -4
- package/dist/sdk-skills/kindgi-scala-authoring-agents/SKILL.md +3 -3
- package/dist/sdk-skills/kindgi-scala-authoring-flows/SKILL.md +1 -1
- package/dist/sdk-skills/kindgi-scala-authoring-guardrails/SKILL.md +1 -1
- package/dist/sdk-skills/kindgi-scala-authoring-tools/SKILL.md +35 -12
- package/dist/sdk-skills/kindgi-scala-getting-started/SKILL.md +29 -5
- package/dist/templates/java/README.md.tmpl +1 -1
- package/dist/templates/minimal/README.md.tmpl +1 -1
- package/dist/templates/python/README.md.tmpl +1 -1
- package/dist/templates/sample/README.md.tmpl +1 -1
- package/dist/templates/sample/tools/fetch-httpbin/index.ts.tmpl +2 -1
- package/dist/templates/scala/README.md.tmpl +1 -1
- package/package.json +13 -13
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (C) 2026 Kindgi Inc.
|
|
3
|
+
/**
|
|
4
|
+
* What `kindgi dev` says about the sandbox at start, and whether it starts:
|
|
5
|
+
*
|
|
6
|
+
* - on, and this machine can: one line naming it, then each path or
|
|
7
|
+
* socket `dev.sandbox` opens;
|
|
8
|
+
* - on, and it can't: a warning, loud and once, with why and what would
|
|
9
|
+
* fix it; the pack service runs without;
|
|
10
|
+
* - required, and it can't: a refusal, before anything starts;
|
|
11
|
+
* - off: one line saying so.
|
|
12
|
+
*
|
|
13
|
+
* On, with more than one Kindgi configuration in the app, it refuses: the
|
|
14
|
+
* code it runs can't change the one in use, but bubblewrap can't stop it
|
|
15
|
+
* adding another by a name looked up first, which the next start would
|
|
16
|
+
* load outside the sandbox.
|
|
17
|
+
*/
|
|
18
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
19
|
+
import { join } from 'node:path';
|
|
20
|
+
import { KINDGI_CONFIG_FILENAMES } from '@kindgi/handler-runtime';
|
|
21
|
+
import { DEV_SANDBOX_DOCS } from './detect.js';
|
|
22
|
+
import { sandboxLabel } from './index.js';
|
|
23
|
+
import { DEV_SANDBOX_VAR, devSandboxSettings } from './settings.js';
|
|
24
|
+
export async function resolveDevSandbox(opts) {
|
|
25
|
+
const settings = devSandboxSettings(opts.config, opts.env, {
|
|
26
|
+
packDir: opts.packDir,
|
|
27
|
+
home: opts.home,
|
|
28
|
+
});
|
|
29
|
+
if (settings.kind === 'invalid')
|
|
30
|
+
return { kind: 'error', message: settings.message };
|
|
31
|
+
const { mode, source, allowRead, allowUnixSockets } = settings.value;
|
|
32
|
+
if (mode === 'off') {
|
|
33
|
+
const why = source === 'env' ? `${DEV_SANDBOX_VAR}=off` : '`dev.sandbox: false` in the config';
|
|
34
|
+
return {
|
|
35
|
+
kind: 'ok',
|
|
36
|
+
sandbox: undefined,
|
|
37
|
+
lines: [
|
|
38
|
+
`⚠ dev sandbox: off (${why}): your tools' code can read your files and keys as you can`,
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const availability = await opts.detect();
|
|
43
|
+
if (availability.kind === 'unavailable') {
|
|
44
|
+
if (mode === 'required') {
|
|
45
|
+
return {
|
|
46
|
+
kind: 'error',
|
|
47
|
+
message: `the dev sandbox is required (${DEV_SANDBOX_VAR}=required), and can't run here: ${availability.reason}. ${availability.fix}`,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
kind: 'ok',
|
|
52
|
+
sandbox: undefined,
|
|
53
|
+
lines: [
|
|
54
|
+
'⚠ Your tools run without the dev sandbox on this system: they can read your files and keys.',
|
|
55
|
+
` Why: ${availability.reason}. ${availability.fix}`,
|
|
56
|
+
` More: ${DEV_SANDBOX_DOCS}. To refuse to run without it: ${DEV_SANDBOX_VAR}=required; to drop this warning: ${DEV_SANDBOX_VAR}=off.`,
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const configs = kindgiConfigFiles(opts.packDir);
|
|
61
|
+
if (configs.length > 1) {
|
|
62
|
+
return {
|
|
63
|
+
kind: 'error',
|
|
64
|
+
message: `more than one Kindgi configuration in ${opts.packDir}: ${configs.join(', ')}. With the dev sandbox on, kindgi dev starts with one only: the code it runs can't change it, but could add another by a name looked up first. Keep the one you use and remove the others.`,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const sandbox = {
|
|
68
|
+
engine: availability.engine,
|
|
69
|
+
settings: settings.value,
|
|
70
|
+
home: opts.home,
|
|
71
|
+
};
|
|
72
|
+
return {
|
|
73
|
+
kind: 'ok',
|
|
74
|
+
sandbox,
|
|
75
|
+
lines: [
|
|
76
|
+
`✓ dev sandbox: ${sandboxLabel(availability.engine)}: your tools' code can't read your keys or files outside the app, write outside it, or reach Docker; it still has the network and the app's own files`,
|
|
77
|
+
...allowRead.map((p) => ` also reads ${p} (dev.sandbox.allowRead)`),
|
|
78
|
+
...allowUnixSockets.map((p) => ` also connects to ${p} (dev.sandbox.allowUnixSockets)`),
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/** The Kindgi configuration files in the app: `kindgi.config.*`, `kindgi.config.json`, a `pyproject.toml` with `[tool.kindgi]`. */
|
|
83
|
+
export function kindgiConfigFiles(packDir) {
|
|
84
|
+
const found = [...KINDGI_CONFIG_FILENAMES, 'kindgi.config.json'].filter((name) => existsSync(join(packDir, name)));
|
|
85
|
+
const pyproject = join(packDir, 'pyproject.toml');
|
|
86
|
+
try {
|
|
87
|
+
if (/^\[tool\.kindgi[\].]/m.test(readFileSync(pyproject, 'utf8')))
|
|
88
|
+
found.push('pyproject.toml');
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// No pyproject.toml.
|
|
92
|
+
}
|
|
93
|
+
return found;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=notices.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notices.js","sourceRoot":"","sources":["../../../src/dev/sandbox/notices.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { type PackCode } from '../pack-code.js';
|
|
2
|
+
import type { DevSandboxSettings } from './settings.js';
|
|
3
|
+
export interface SandboxPolicy {
|
|
4
|
+
/** The app (the pack root), real path. */
|
|
5
|
+
readonly app: string;
|
|
6
|
+
/** The home folder, real path. */
|
|
7
|
+
readonly home: string;
|
|
8
|
+
/** Real paths the service reads, outside the app. */
|
|
9
|
+
readonly readRoots: readonly string[];
|
|
10
|
+
/** Roots left out because they hold the home folder. */
|
|
11
|
+
readonly skipped: readonly string[];
|
|
12
|
+
/** UNIX sockets it may connect to (`dev.sandbox.allowUnixSockets`). */
|
|
13
|
+
readonly allowUnixSockets: readonly string[];
|
|
14
|
+
/** Its own temp folder, real path (its `TMPDIR` on macOS). */
|
|
15
|
+
readonly tmpDir: string;
|
|
16
|
+
/** Folders inside the app's closed `.kindgi` it may write (the indexer's output). */
|
|
17
|
+
readonly writable: readonly string[];
|
|
18
|
+
/**
|
|
19
|
+
* The app's Kindgi configuration files, by every name `kindgi dev` looks
|
|
20
|
+
* for, whether or not they exist: never written from inside.
|
|
21
|
+
*/
|
|
22
|
+
readonly readOnly: readonly string[];
|
|
23
|
+
/**
|
|
24
|
+
* Symbolic links a path it runs from resolves through, outside the app
|
|
25
|
+
* and the read roots (a uv-managed Python's `cpython-3.11-…` link to its
|
|
26
|
+
* `cpython-3.11.16-…` folder, in the home folder): opened one by one
|
|
27
|
+
* (macOS), or made again inside (Linux).
|
|
28
|
+
*/
|
|
29
|
+
readonly links: readonly {
|
|
30
|
+
readonly path: string;
|
|
31
|
+
readonly target: string;
|
|
32
|
+
}[];
|
|
33
|
+
}
|
|
34
|
+
/** Every name `kindgi dev` reads a pack's configuration from, at the app's root. */
|
|
35
|
+
export declare const CONFIG_FILE_NAMES: readonly string[];
|
|
36
|
+
export interface SandboxPolicyOptions {
|
|
37
|
+
readonly packDir: string;
|
|
38
|
+
readonly home: string;
|
|
39
|
+
readonly code: PackCode;
|
|
40
|
+
readonly settings: DevSandboxSettings;
|
|
41
|
+
readonly tmpDir: string;
|
|
42
|
+
/** The pack service's environment, for asking the Python interpreter. */
|
|
43
|
+
readonly env: Readonly<Record<string, string>>;
|
|
44
|
+
/** Node: the binary and the entrypoint (the pack service's, or the indexer's). */
|
|
45
|
+
readonly node: {
|
|
46
|
+
readonly execPath: string;
|
|
47
|
+
readonly entry: string;
|
|
48
|
+
};
|
|
49
|
+
/** Folders inside the app's `.kindgi` it may write. */
|
|
50
|
+
readonly writable?: readonly string[];
|
|
51
|
+
/** Test seam: what the Python interpreter says about itself. */
|
|
52
|
+
readonly queryPython?: (python: readonly string[], cwd: string, env: Readonly<Record<string, string>>) => Promise<PythonPaths>;
|
|
53
|
+
}
|
|
54
|
+
export interface PythonPaths {
|
|
55
|
+
readonly path: readonly string[];
|
|
56
|
+
readonly prefix: string;
|
|
57
|
+
readonly basePrefix: string;
|
|
58
|
+
readonly executable: string;
|
|
59
|
+
}
|
|
60
|
+
export declare function sandboxPolicy(opts: SandboxPolicyOptions): Promise<SandboxPolicy>;
|
|
61
|
+
/**
|
|
62
|
+
* The symbolic links met while resolving `path`, in order: each one's own
|
|
63
|
+
* path (its folder resolved) and its target as written.
|
|
64
|
+
*/
|
|
65
|
+
export declare function symlinksOf(path: string): {
|
|
66
|
+
readonly path: string;
|
|
67
|
+
readonly target: string;
|
|
68
|
+
}[];
|
|
69
|
+
/**
|
|
70
|
+
* The real folders of the packages that dependencies of `starts` link to
|
|
71
|
+
* outside `covered` (a checkout's workspace packages, `link:` ones), and
|
|
72
|
+
* theirs in turn: each package's own folder, never a parent. A link into
|
|
73
|
+
* a covered folder (a `node_modules`) isn't followed: it's open already.
|
|
74
|
+
*/
|
|
75
|
+
export declare function linkedPackages(starts: readonly string[], covered: readonly string[]): string[];
|
|
76
|
+
/** The classpath in a JVM pack's `@argfile` (`-cp "<entries>"`), each entry's real path. */
|
|
77
|
+
export declare function classpathEntries(argsFile: string): Promise<string[]>;
|
|
78
|
+
/** Ask the pack's interpreter where it reads from. */
|
|
79
|
+
export declare function queryPythonReal(python: readonly string[], cwd: string, env: Readonly<Record<string, string>>): Promise<PythonPaths>;
|
|
80
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../../src/dev/sandbox/policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (C) 2026 Kindgi Inc.
|
|
3
|
+
/**
|
|
4
|
+
* What the sandboxed pack service may read, worked out at every start
|
|
5
|
+
* from what that start runs:
|
|
6
|
+
*
|
|
7
|
+
* - the app (the pack root), read and write;
|
|
8
|
+
* - every `node_modules` from the app up to `/` (a workspace's hoisted
|
|
9
|
+
* dependencies);
|
|
10
|
+
* - the runtime: Node's install and the pack service's own package; the
|
|
11
|
+
* Python interpreter's `sys.path`, prefix and base prefix (a venv, a
|
|
12
|
+
* uv-managed Python under `~/.local/share/uv`); the JDK and every
|
|
13
|
+
* classpath entry (jars in `~/.m2/repository`, coursier's cache);
|
|
14
|
+
* - `dev.sandbox.allowRead`;
|
|
15
|
+
* - a linked package's own folder: where a dependency's link points
|
|
16
|
+
* outside all of the above (a checkout's workspace packages, `link:`
|
|
17
|
+
* ones), and theirs in turn.
|
|
18
|
+
*
|
|
19
|
+
* A root that is `/`, the home folder, or a folder holding the home
|
|
20
|
+
* folder is left out (`skipped`): it would open everything the sandbox
|
|
21
|
+
* closes.
|
|
22
|
+
*
|
|
23
|
+
* The app's Kindgi configuration (`kindgi.config.*`, `pyproject.toml`) is
|
|
24
|
+
* read-only inside: `kindgi dev` itself loads it, and it says how wide the
|
|
25
|
+
* sandbox is.
|
|
26
|
+
*/
|
|
27
|
+
import { execFile } from 'node:child_process';
|
|
28
|
+
import { existsSync, lstatSync, readFileSync, readlinkSync, realpathSync } from 'node:fs';
|
|
29
|
+
import { readFile } from 'node:fs/promises';
|
|
30
|
+
import { delimiter, dirname, isAbsolute, join, parse, resolve, sep } from 'node:path';
|
|
31
|
+
import { isJvmPackCode, javaArgsFile } from '../pack-code.js';
|
|
32
|
+
/** Every name `kindgi dev` reads a pack's configuration from, at the app's root. */
|
|
33
|
+
export const CONFIG_FILE_NAMES = [
|
|
34
|
+
'kindgi.config.ts',
|
|
35
|
+
'kindgi.config.mts',
|
|
36
|
+
'kindgi.config.cts',
|
|
37
|
+
'kindgi.config.js',
|
|
38
|
+
'kindgi.config.mjs',
|
|
39
|
+
'kindgi.config.cjs',
|
|
40
|
+
'kindgi.config.json',
|
|
41
|
+
'pyproject.toml',
|
|
42
|
+
];
|
|
43
|
+
export async function sandboxPolicy(opts) {
|
|
44
|
+
const app = real(opts.packDir);
|
|
45
|
+
const home = real(opts.home);
|
|
46
|
+
const runtime = await runtimeRoots(opts);
|
|
47
|
+
const base = [...nodeModulesUpFrom(app), ...runtime.roots, ...opts.settings.allowRead];
|
|
48
|
+
const linked = linkedPackages([app, ...runtime.packages], [app, ...base.map(real)]);
|
|
49
|
+
const { readRoots, skipped } = partitionRoots([...base, ...linked], app, home);
|
|
50
|
+
const inside = (p) => [app, ...readRoots].some((r) => p === r || p.startsWith(r + sep));
|
|
51
|
+
const links = new Map();
|
|
52
|
+
for (const path of [...runtime.paths, ...base]) {
|
|
53
|
+
for (const link of symlinksOf(path))
|
|
54
|
+
if (!inside(link.path))
|
|
55
|
+
links.set(link.path, link.target);
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
app,
|
|
59
|
+
home,
|
|
60
|
+
readRoots,
|
|
61
|
+
skipped,
|
|
62
|
+
allowUnixSockets: opts.settings.allowUnixSockets,
|
|
63
|
+
tmpDir: opts.tmpDir,
|
|
64
|
+
writable: (opts.writable ?? []).map(real),
|
|
65
|
+
readOnly: CONFIG_FILE_NAMES.map((name) => join(app, name)),
|
|
66
|
+
links: [...links].map(([path, target]) => ({ path, target })),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/** How many links one path's resolution follows, at most (a loop stops there). */
|
|
70
|
+
const MAX_HOPS = 40;
|
|
71
|
+
/**
|
|
72
|
+
* The symbolic links met while resolving `path`, in order: each one's own
|
|
73
|
+
* path (its folder resolved) and its target as written.
|
|
74
|
+
*/
|
|
75
|
+
export function symlinksOf(path) {
|
|
76
|
+
if (!isAbsolute(path))
|
|
77
|
+
return [];
|
|
78
|
+
const found = [];
|
|
79
|
+
let pending = path.split(sep).filter((c) => c !== '');
|
|
80
|
+
let at = parse(path).root;
|
|
81
|
+
let hops = 0;
|
|
82
|
+
while (pending.length > 0 && hops < MAX_HOPS) {
|
|
83
|
+
const name = pending.shift();
|
|
84
|
+
if (name === '.')
|
|
85
|
+
continue;
|
|
86
|
+
if (name === '..') {
|
|
87
|
+
at = dirname(at);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const next = join(at, name);
|
|
91
|
+
let target;
|
|
92
|
+
try {
|
|
93
|
+
if (lstatSync(next).isSymbolicLink())
|
|
94
|
+
target = readlinkSync(next);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return found;
|
|
98
|
+
}
|
|
99
|
+
if (target === undefined) {
|
|
100
|
+
at = next;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
hops += 1;
|
|
104
|
+
found.push({ path: next, target });
|
|
105
|
+
const rest = target.split(sep).filter((c) => c !== '');
|
|
106
|
+
if (isAbsolute(target))
|
|
107
|
+
at = parse(target).root;
|
|
108
|
+
pending = [...rest, ...pending];
|
|
109
|
+
}
|
|
110
|
+
return found;
|
|
111
|
+
}
|
|
112
|
+
/** How many linked packages the search follows, at most. */
|
|
113
|
+
const MAX_LINKED = 500;
|
|
114
|
+
/**
|
|
115
|
+
* The real folders of the packages that dependencies of `starts` link to
|
|
116
|
+
* outside `covered` (a checkout's workspace packages, `link:` ones), and
|
|
117
|
+
* theirs in turn: each package's own folder, never a parent. A link into
|
|
118
|
+
* a covered folder (a `node_modules`) isn't followed: it's open already.
|
|
119
|
+
*/
|
|
120
|
+
export function linkedPackages(starts, covered) {
|
|
121
|
+
const isCovered = (p) => covered.some((c) => p === c || p.startsWith(c + sep));
|
|
122
|
+
const found = new Set();
|
|
123
|
+
const queue = [...starts];
|
|
124
|
+
const seen = new Set();
|
|
125
|
+
while (queue.length > 0 && found.size < MAX_LINKED) {
|
|
126
|
+
const dir = queue.shift();
|
|
127
|
+
if (seen.has(dir))
|
|
128
|
+
continue;
|
|
129
|
+
seen.add(dir);
|
|
130
|
+
for (const name of dependencyNames(dir)) {
|
|
131
|
+
const link = join(dir, 'node_modules', ...name.split('/'));
|
|
132
|
+
let isLink = false;
|
|
133
|
+
try {
|
|
134
|
+
isLink = lstatSync(link).isSymbolicLink();
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (!isLink)
|
|
140
|
+
continue;
|
|
141
|
+
const target = real(link);
|
|
142
|
+
if (isCovered(target) || !existsSync(join(target, 'package.json')))
|
|
143
|
+
continue;
|
|
144
|
+
found.add(target);
|
|
145
|
+
queue.push(target);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return [...found];
|
|
149
|
+
}
|
|
150
|
+
/** The names a package depends on at run time (`dependencies`, `optionalDependencies`). */
|
|
151
|
+
function dependencyNames(dir) {
|
|
152
|
+
try {
|
|
153
|
+
const manifest = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8'));
|
|
154
|
+
return [
|
|
155
|
+
...Object.keys(manifest.dependencies ?? {}),
|
|
156
|
+
...Object.keys(manifest.optionalDependencies ?? {}),
|
|
157
|
+
];
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
return [];
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* What the pack's runtime reads: Node's install, the Python interpreter's
|
|
165
|
+
* paths, the JDK and the classpath; and, for Node, the package whose
|
|
166
|
+
* entrypoint runs (whose links are followed).
|
|
167
|
+
*/
|
|
168
|
+
async function runtimeRoots(opts) {
|
|
169
|
+
const { code } = opts;
|
|
170
|
+
if (code.language === 'node') {
|
|
171
|
+
const node = nodeRoots(opts.node.execPath, opts.node.entry);
|
|
172
|
+
return { ...node, paths: [opts.node.execPath, opts.node.entry] };
|
|
173
|
+
}
|
|
174
|
+
if (code.language === 'python') {
|
|
175
|
+
const query = opts.queryPython ?? queryPythonReal;
|
|
176
|
+
const py = await query(code.python, opts.packDir, opts.env);
|
|
177
|
+
const program = code.python[0];
|
|
178
|
+
return {
|
|
179
|
+
roots: [...py.path, py.prefix, py.basePrefix, dirname(dirname(real(py.executable)))],
|
|
180
|
+
packages: [],
|
|
181
|
+
paths: [
|
|
182
|
+
py.executable,
|
|
183
|
+
...(program !== undefined && isAbsolute(program) ? [program] : []),
|
|
184
|
+
...(program !== undefined && !isAbsolute(program) && program.includes(sep)
|
|
185
|
+
? [resolve(opts.packDir, program)]
|
|
186
|
+
: []),
|
|
187
|
+
...py.path,
|
|
188
|
+
py.prefix,
|
|
189
|
+
py.basePrefix,
|
|
190
|
+
],
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
if (isJvmPackCode(code)) {
|
|
194
|
+
const jdk = jdkRoot(code.javaHome, code.java, opts.env.PATH);
|
|
195
|
+
const classpath = await classpathEntries(javaArgsFile(code));
|
|
196
|
+
return {
|
|
197
|
+
roots: [jdk, ...classpath],
|
|
198
|
+
packages: [],
|
|
199
|
+
paths: [...(code.javaHome !== undefined ? [code.javaHome] : []), code.java, ...classpath],
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
return { roots: [], packages: [], paths: [] };
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* The candidates that exist, as real paths: outside the app (it's open
|
|
206
|
+
* anyway), and not holding the home folder (those are `skipped`).
|
|
207
|
+
*/
|
|
208
|
+
function partitionRoots(candidates, app, home) {
|
|
209
|
+
const readRoots = new Set();
|
|
210
|
+
const skipped = new Set();
|
|
211
|
+
for (const candidate of candidates) {
|
|
212
|
+
if (candidate === '' || !isAbsolute(candidate) || !existsSync(candidate))
|
|
213
|
+
continue;
|
|
214
|
+
const root = real(candidate);
|
|
215
|
+
if (root === app || root.startsWith(app + sep))
|
|
216
|
+
continue;
|
|
217
|
+
(holds(root, home) ? skipped : readRoots).add(root);
|
|
218
|
+
}
|
|
219
|
+
return { readRoots: withoutNested([...readRoots]), skipped: [...skipped] };
|
|
220
|
+
}
|
|
221
|
+
/** Whether `root` is `/`, `home`, or a folder above it. */
|
|
222
|
+
function holds(root, home) {
|
|
223
|
+
return root === parse(root).root || home === root || home.startsWith(root + sep);
|
|
224
|
+
}
|
|
225
|
+
/** Drop a root inside another (the outer one covers it). */
|
|
226
|
+
function withoutNested(roots) {
|
|
227
|
+
return roots.filter((r) => !roots.some((o) => o !== r && r.startsWith(o + sep)));
|
|
228
|
+
}
|
|
229
|
+
function real(path) {
|
|
230
|
+
try {
|
|
231
|
+
return realpathSync(path);
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
return path;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/** `<dir>/node_modules` for the app and each folder above it, where one exists. */
|
|
238
|
+
function nodeModulesUpFrom(dir) {
|
|
239
|
+
const found = [];
|
|
240
|
+
let at = dir;
|
|
241
|
+
for (;;) {
|
|
242
|
+
const candidate = join(at, 'node_modules');
|
|
243
|
+
if (existsSync(candidate))
|
|
244
|
+
found.push(candidate);
|
|
245
|
+
const up = dirname(at);
|
|
246
|
+
if (up === at)
|
|
247
|
+
return found;
|
|
248
|
+
at = up;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
/** Node's install, and the entrypoint's package with the `node_modules` above it. */
|
|
252
|
+
function nodeRoots(execPath, entry) {
|
|
253
|
+
const entryReal = real(entry);
|
|
254
|
+
let packageRoot = dirname(entryReal);
|
|
255
|
+
while (!existsSync(join(packageRoot, 'package.json')) && dirname(packageRoot) !== packageRoot) {
|
|
256
|
+
packageRoot = dirname(packageRoot);
|
|
257
|
+
}
|
|
258
|
+
return {
|
|
259
|
+
roots: [dirname(dirname(real(execPath))), packageRoot, ...nodeModulesUpFrom(packageRoot)],
|
|
260
|
+
packages: [packageRoot],
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
/** The JDK's home: `javaHome`, else the `java` on `PATH`'s, two folders up from its real path. */
|
|
264
|
+
function jdkRoot(javaHome, java, path) {
|
|
265
|
+
if (javaHome !== undefined)
|
|
266
|
+
return real(javaHome);
|
|
267
|
+
const binary = isAbsolute(java)
|
|
268
|
+
? java
|
|
269
|
+
: (path ?? '')
|
|
270
|
+
.split(delimiter)
|
|
271
|
+
.map((d) => join(d, java))
|
|
272
|
+
.find((p) => existsSync(p));
|
|
273
|
+
return binary === undefined ? '' : dirname(dirname(real(binary)));
|
|
274
|
+
}
|
|
275
|
+
/** The classpath in a JVM pack's `@argfile` (`-cp "<entries>"`), each entry's real path. */
|
|
276
|
+
export async function classpathEntries(argsFile) {
|
|
277
|
+
const text = await readFile(argsFile, 'utf8').catch(() => '');
|
|
278
|
+
const match = /-cp\s+"((?:[^"\\]|\\.)*)"/.exec(text);
|
|
279
|
+
if (match?.[1] === undefined)
|
|
280
|
+
return [];
|
|
281
|
+
const value = match[1].replace(/\\(.)/g, '$1');
|
|
282
|
+
return value
|
|
283
|
+
.split(delimiter)
|
|
284
|
+
.filter((e) => e !== '')
|
|
285
|
+
.map((e) => (e.endsWith(`${sep}*`) ? e.slice(0, -2) : e));
|
|
286
|
+
}
|
|
287
|
+
const PYTHON_PATHS = 'import json, sys; print(json.dumps({"path": sys.path, "prefix": sys.prefix, "base": sys.base_prefix, "exe": sys.executable}))';
|
|
288
|
+
/** Ask the pack's interpreter where it reads from. */
|
|
289
|
+
export function queryPythonReal(python, cwd, env) {
|
|
290
|
+
const [program, ...args] = python;
|
|
291
|
+
return new Promise((resolvePaths, reject) => {
|
|
292
|
+
execFile(program ?? 'python3', [...args, '-c', PYTHON_PATHS], { cwd, env, timeout: 30_000, maxBuffer: 1024 * 1024 }, (err, stdout) => {
|
|
293
|
+
if (err !== null) {
|
|
294
|
+
reject(new Error(`could not ask the pack's Python where it reads from: ${err.message}`));
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
try {
|
|
298
|
+
const line = stdout.trim().split('\n').pop() ?? '';
|
|
299
|
+
const parsed = JSON.parse(line);
|
|
300
|
+
resolvePaths({
|
|
301
|
+
path: parsed.path,
|
|
302
|
+
prefix: parsed.prefix,
|
|
303
|
+
basePrefix: parsed.base,
|
|
304
|
+
executable: parsed.exe,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
catch (cause) {
|
|
308
|
+
reject(new Error(`the pack's Python answered something else: ${cause.message}`));
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../../src/dev/sandbox/policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seatbelt.d.ts","sourceRoot":"","sources":["../../../src/dev/sandbox/seatbelt.ts"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAmBjD,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAqF7D"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (C) 2026 Kindgi Inc.
|
|
3
|
+
/**
|
|
4
|
+
* The pack service's Seatbelt profile on macOS (`sandbox-exec -f`).
|
|
5
|
+
* Seatbelt applies the last rule that matches, so the order is the
|
|
6
|
+
* policy:
|
|
7
|
+
*
|
|
8
|
+
* 1. allow by default (processes, the network, the system), but no
|
|
9
|
+
* writes anywhere: a binary it replaced (`/opt/homebrew/bin/git`, an
|
|
10
|
+
* app in `/Applications`) would run unsandboxed later;
|
|
11
|
+
* 2. close the home folder and the shared temp folders (keys, cloud
|
|
12
|
+
* credentials, registry tokens, other projects, other tools' temp
|
|
13
|
+
* files), then open the service's own temp folder and the `/dev`
|
|
14
|
+
* nodes a runtime writes;
|
|
15
|
+
* 3. open what it runs: the app (read and write), the runtime and the
|
|
16
|
+
* dependencies (read), and stat-only the folders above them (a
|
|
17
|
+
* runtime resolves real paths through them);
|
|
18
|
+
* 4. close the secrets inside all of that again: `.env*`, `.kindgi`
|
|
19
|
+
* (but the dev outputs it runs, and the indexer's output folder),
|
|
20
|
+
* `.git`, `kindgi.env`, `pack.env`, `.kindgirc.json`, `.npmrc`,
|
|
21
|
+
* `.pypirc`, `.netrc`; and keep the app's Kindgi configuration
|
|
22
|
+
* unwritable (`kindgi dev` loads it, and it says how wide this is);
|
|
23
|
+
* 5. no UNIX sockets (the Docker socket, ssh-agent, a database's) but
|
|
24
|
+
* DNS's (`mDNSResponder`) and `dev.sandbox.allowUnixSockets`;
|
|
25
|
+
* 6. no Apple Events, LaunchServices (`open -a Terminal <a file it
|
|
26
|
+
* wrote>` would run it outside) or the keychain.
|
|
27
|
+
*/
|
|
28
|
+
import { dirname, join, parse } from 'node:path';
|
|
29
|
+
import { devBundleMapPath, devDistDir, devIndexPath, devJvmDir, devStagedIndexPath, devStagedPackIndexPath, } from '../paths.js';
|
|
30
|
+
/** A path as an SBPL string literal. */
|
|
31
|
+
function str(path) {
|
|
32
|
+
return `"${path.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
|
|
33
|
+
}
|
|
34
|
+
/** Every folder above `path`, up to `/`. */
|
|
35
|
+
function ancestors(path) {
|
|
36
|
+
const found = [];
|
|
37
|
+
let at = path;
|
|
38
|
+
const root = parse(path).root;
|
|
39
|
+
while (at !== root) {
|
|
40
|
+
at = dirname(at);
|
|
41
|
+
found.push(at);
|
|
42
|
+
}
|
|
43
|
+
return found;
|
|
44
|
+
}
|
|
45
|
+
export function seatbeltProfile(policy) {
|
|
46
|
+
const { app, home, tmpDir } = policy;
|
|
47
|
+
const roots = policy.readRoots;
|
|
48
|
+
const statOnly = [
|
|
49
|
+
...new Set([
|
|
50
|
+
...[app, ...roots, tmpDir, ...policy.links.map((l) => l.path)].flatMap(ancestors),
|
|
51
|
+
join(app, '.kindgi'),
|
|
52
|
+
join(app, '.kindgi', 'dev'),
|
|
53
|
+
]),
|
|
54
|
+
];
|
|
55
|
+
const devOutputs = [
|
|
56
|
+
`(subpath ${str(devDistDir(app))})`,
|
|
57
|
+
`(subpath ${str(devJvmDir(app, 'java'))})`,
|
|
58
|
+
`(subpath ${str(devJvmDir(app, 'scala'))})`,
|
|
59
|
+
...[
|
|
60
|
+
devIndexPath(app),
|
|
61
|
+
devStagedIndexPath(app),
|
|
62
|
+
devStagedPackIndexPath(app),
|
|
63
|
+
devBundleMapPath(app),
|
|
64
|
+
].map((p) => `(literal ${str(p)})`),
|
|
65
|
+
];
|
|
66
|
+
const writable = policy.writable.map((d) => `(subpath ${str(d)})`);
|
|
67
|
+
const readOnly = policy.readOnly.map((f) => `(literal ${str(f)})`);
|
|
68
|
+
const sockets = [
|
|
69
|
+
'(path-literal "/private/var/run/mDNSResponder")',
|
|
70
|
+
...policy.allowUnixSockets.map((p) => `(path-literal ${str(p)})`),
|
|
71
|
+
];
|
|
72
|
+
return [
|
|
73
|
+
'; The pack service under `kindgi dev`: written by kindgi dev at every start. Do not edit.',
|
|
74
|
+
'(version 1)',
|
|
75
|
+
'(allow default)',
|
|
76
|
+
'; No writes anywhere but where opened below.',
|
|
77
|
+
'(deny file-write*)',
|
|
78
|
+
'',
|
|
79
|
+
'; Closed: the home folder and the shared temp folders.',
|
|
80
|
+
`(deny file-read* file-write* (subpath ${str(home)}) (subpath "/private/var/folders") (subpath "/private/tmp"))`,
|
|
81
|
+
"; Its own temp folder; the JVM's perf data; Darwin's per-user caches.",
|
|
82
|
+
`(allow file-read* file-write* (subpath ${str(tmpDir)}))`,
|
|
83
|
+
'(allow file-read* file-write* (regex #"^/private/var/folders/[^/]+/[^/]+/T/hsperfdata_"))',
|
|
84
|
+
'(allow file-read* (regex #"^/private/var/folders/[^/]+/[^/]+/C/"))',
|
|
85
|
+
'; The /dev nodes a runtime writes.',
|
|
86
|
+
'(allow file-write* (literal "/dev/null") (literal "/dev/zero") (literal "/dev/tty") (literal "/dev/dtracehelper") (regex #"^/dev/fd/"))',
|
|
87
|
+
'',
|
|
88
|
+
'; Open: the folders above what it runs, to look up (not to list or read).',
|
|
89
|
+
`(allow file-read-metadata ${statOnly.map((p) => `(literal ${str(p)})`).join(' ')})`,
|
|
90
|
+
'; Open: the runtime and the dependencies (read), the app (read and write).',
|
|
91
|
+
...(roots.length > 0
|
|
92
|
+
? [`(allow file-read* ${roots.map((r) => `(subpath ${str(r)})`).join(' ')})`]
|
|
93
|
+
: []),
|
|
94
|
+
`(allow file-read* file-write* (subpath ${str(app)}))`,
|
|
95
|
+
...(policy.links.length > 0
|
|
96
|
+
? [
|
|
97
|
+
'; The links what it runs resolves through (a uv-managed Python), each link only.',
|
|
98
|
+
`(allow file-read* ${policy.links.map((l) => `(literal ${str(l.path)})`).join(' ')})`,
|
|
99
|
+
]
|
|
100
|
+
: []),
|
|
101
|
+
'',
|
|
102
|
+
'; Closed again, wherever they are: secrets.',
|
|
103
|
+
'(deny file-read* file-write*',
|
|
104
|
+
' (regex #"/\\.env[^/]*$")',
|
|
105
|
+
' (regex #"/(kindgi\\.env|pack\\.env|\\.kindgirc\\.json|\\.npmrc|\\.pypirc|\\.netrc)$")',
|
|
106
|
+
' (regex #"/\\.git(/|$)")',
|
|
107
|
+
' (regex #"/\\.kindgi(/|$)"))',
|
|
108
|
+
'; but the dev outputs the service runs.',
|
|
109
|
+
`(allow file-read* ${devOutputs.join(' ')})`,
|
|
110
|
+
...(writable.length > 0
|
|
111
|
+
? [
|
|
112
|
+
"; and the indexer's output folder.",
|
|
113
|
+
`(allow file-read* file-write* ${writable.join(' ')})`,
|
|
114
|
+
]
|
|
115
|
+
: []),
|
|
116
|
+
"; Kindgi's configuration: kindgi dev loads it, and it says how wide this sandbox is.",
|
|
117
|
+
`(deny file-write* ${readOnly.join(' ')})`,
|
|
118
|
+
'',
|
|
119
|
+
"; No UNIX sockets (the Docker socket, ssh-agent, a database's), but DNS's and the allowed ones.",
|
|
120
|
+
'(deny network-outbound (remote unix-socket))',
|
|
121
|
+
`(allow network-outbound ${sockets.map((s) => `(remote unix-socket ${s})`).join(' ')})`,
|
|
122
|
+
'',
|
|
123
|
+
'; No Apple Events, or LaunchServices (opening an app, a file with one).',
|
|
124
|
+
'(deny appleevent-send)',
|
|
125
|
+
'(deny mach-lookup (global-name "com.apple.coreservices.launchservicesd") (global-name-regex #"^com\\.apple\\.lsd\\.") (global-name "com.apple.coreservices.appleevents"))',
|
|
126
|
+
"; The keychain: securityd's file keychains, secd's (but trustd, which checks TLS certificates).",
|
|
127
|
+
'(deny mach-lookup (global-name "com.apple.SecurityServer") (global-name-regex #"^com\\.apple\\.securityd\\.") (global-name-regex #"^com\\.apple\\.security\\."))',
|
|
128
|
+
'',
|
|
129
|
+
].join('\n');
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=seatbelt.js.map
|