@push.rocks/smartdaemon 2.11.0 → 2.12.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.
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartdaemon',
6
- version: '2.11.0',
6
+ version: '2.12.0',
7
7
  description: 'Start scripts as long running daemons and manage them.'
8
8
  };
9
9
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx5QkFBeUI7SUFDL0IsT0FBTyxFQUFFLFFBQVE7SUFDakIsV0FBVyxFQUFFLHdEQUF3RDtDQUN0RSxDQUFBIn0=
@@ -0,0 +1,78 @@
1
+ export interface ISystemdTransientScopeOptions {
2
+ /** The calling user's manager; the only manager a transient scope is started in. */
3
+ scope: 'user';
4
+ /** Absolute, normalized program path, executed directly: no shell, no PATH search. */
5
+ executable: string;
6
+ /** Literal arguments, at most 128 of at most 32768 characters each, without NUL. */
7
+ args: readonly string[];
8
+ /** Absolute, normalized directory the program starts in. */
9
+ workingDirectory: string;
10
+ /**
11
+ * The program's complete environment. Nothing of the calling process is inherited: the program
12
+ * receives exactly these variables, the manager's `XDG_RUNTIME_DIR` and systemd's
13
+ * `INVOCATION_ID`. Names match `[A-Za-z_][A-Za-z0-9_]*` (at most 128 characters); values are
14
+ * strings of at most 32768 characters without NUL; at most 256 variables. `XDG_RUNTIME_DIR`,
15
+ * `INVOCATION_ID` and names starting with `SYSTEMD_` or `DBUS_`, which configure systemd-run
16
+ * itself, are refused.
17
+ */
18
+ environment: Readonly<Record<string, string>>;
19
+ /** Literal unit description: clean text of 1 to 1024 characters, trimmed, without `\`. */
20
+ description: string;
21
+ /** A `.scope` unit name; defaults to a unique `smartdaemon-<32 hex digits>.scope`. */
22
+ unitName?: string;
23
+ /** User-manager socket directory. Defaults to a non-empty XDG_RUNTIME_DIR. */
24
+ runtimeDirectory?: string;
25
+ /** Absolute executable path supplied by trusted owning code. Defaults to `/usr/bin/systemd-run`. */
26
+ systemdRunPath?: string;
27
+ /** Absolute executable path supplied by trusted owning code. Defaults to `/usr/bin/systemctl`. */
28
+ systemctlPath?: string;
29
+ /** Bounds the manager probe and the program's direct process, each. Defaults to 120 seconds. */
30
+ commandTimeoutMs?: number;
31
+ }
32
+ export interface ISystemdTransientScopeResult {
33
+ /** The scope unit. It stays active while any process the program started runs in it. */
34
+ readonly unitName: string;
35
+ /** Exit status of the program's direct process; null when a signal ended it. */
36
+ readonly exitCode: number | null;
37
+ readonly signal: NodeJS.Signals | null;
38
+ /** UTF-8 decoded output of the program and every process that shared its stdout. */
39
+ readonly stdout: string;
40
+ /** As `stdout`, without the line systemd-run prints on starting the scope. */
41
+ readonly stderr: string;
42
+ }
43
+ export type TSystemdTransientScopeErrorCode =
44
+ /** The options are malformed, or the runtime directory is not a private directory of the caller. */
45
+ 'invalid_options'
46
+ /** The process is not running on Linux. */
47
+ | 'unsupported_platform'
48
+ /** No runtime directory is set or it does not exist, or the manager does not answer systemctl. */
49
+ | 'user_manager_unavailable'
50
+ /** systemd-run exited without reporting the scope running; the program has not run. */
51
+ | 'scope_start_failed'
52
+ /** The manager probe or the program did not finish, and close its output, in time. */
53
+ | 'timed_out'
54
+ /** The program's stdout or stderr exceeded 1 MiB. */
55
+ | 'output_limit';
56
+ export declare class SystemdTransientScopeError extends Error {
57
+ readonly code: TSystemdTransientScopeErrorCode;
58
+ /** The scope the call used; null when the options were refused. */
59
+ readonly unitName: string | null;
60
+ /** The probe's or systemd-run's stderr as far as it was read; empty when none ran. */
61
+ readonly stderr: string;
62
+ constructor(code: TSystemdTransientScopeErrorCode,
63
+ /** The scope the call used; null when the options were refused. */
64
+ unitName: string | null,
65
+ /** The probe's or systemd-run's stderr as far as it was read; empty when none ran. */
66
+ stderr: string, options?: ErrorOptions);
67
+ }
68
+ /**
69
+ * Starts a program in a new transient scope unit of the calling user's systemd manager, so it and
70
+ * every process it starts run outside the caller's own unit and survive that unit's stop, and
71
+ * waits for the program's direct process. A program that daemonizes and exits returns its result
72
+ * while its daemon keeps the scope active; the scope ends when its last process exits. The daemon
73
+ * must not keep the program's stdout or stderr open, or the call runs into its timeout.
74
+ *
75
+ * On `timed_out` and `output_limit` the direct process is killed; processes it started stay in
76
+ * the scope. A program that exits with a failure status is a result, not an error.
77
+ */
78
+ export declare const runInTransientScope: (options: ISystemdTransientScopeOptions) => Promise<ISystemdTransientScopeResult>;
@@ -0,0 +1,204 @@
1
+ import * as plugins from './smartdaemon.plugins.js';
2
+ import { isCleanText } from './systemd.definition.js';
3
+ import { captureUserEnvironment, inspectRuntimeDirectory, isSafeDirectory } from './systemd.userenvironment.js';
4
+ export class SystemdTransientScopeError extends Error {
5
+ constructor(code,
6
+ /** The scope the call used; null when the options were refused. */
7
+ unitName,
8
+ /** The probe's or systemd-run's stderr as far as it was read; empty when none ran. */
9
+ stderr, options) {
10
+ super(`Systemd transient scope failed: ${code}${unitName === null ? '' : ` (${unitName})`}.`, options);
11
+ this.code = code;
12
+ this.unitName = unitName;
13
+ this.stderr = stderr;
14
+ this.name = 'SystemdTransientScopeError';
15
+ }
16
+ }
17
+ const outputLimit = 1048576;
18
+ const reservedName = (name) => name === 'XDG_RUNTIME_DIR' || name === 'INVOCATION_ID' || name.startsWith('SYSTEMD_') || name.startsWith('DBUS_');
19
+ /** Reads every option once through its own data descriptor, so no accessor or proxy trap runs. */
20
+ const validate = (options) => {
21
+ const plain = (value, prototype) => value !== null &&
22
+ typeof value === 'object' && !plugins.util.types.isProxy(value) && Object.getPrototypeOf(value) === prototype;
23
+ if (!plain(options, Object.prototype))
24
+ return undefined;
25
+ const required = ['scope', 'executable', 'args', 'workingDirectory', 'environment', 'description'];
26
+ const optional = ['unitName', 'runtimeDirectory', 'systemdRunPath', 'systemctlPath', 'commandTimeoutMs'];
27
+ const values = new Map();
28
+ for (const key of Reflect.ownKeys(options)) {
29
+ const descriptor = Object.getOwnPropertyDescriptor(options, key);
30
+ if (typeof key !== 'string' || ![...required, ...optional].includes(key) || !descriptor?.enumerable ||
31
+ !('value' in descriptor))
32
+ return undefined;
33
+ if (descriptor.value !== undefined)
34
+ values.set(key, descriptor.value);
35
+ }
36
+ if (!required.every((key) => values.has(key)) || values.get('scope') !== 'user')
37
+ return undefined;
38
+ const path = (value) => isSafeDirectory(value);
39
+ const bounded = (value) => typeof value === 'string' && value.length <= 32768 && !value.includes('\0');
40
+ const executable = values.get('executable');
41
+ const workingDirectory = values.get('workingDirectory');
42
+ const description = values.get('description');
43
+ if (!path(executable) || !(workingDirectory === '/' || path(workingDirectory)) ||
44
+ typeof description !== 'string' || description.length < 1 || description.length > 1024 ||
45
+ description.trim() !== description || description.includes('\\') || !isCleanText(description))
46
+ return undefined;
47
+ const argsValue = values.get('args');
48
+ if (!plain(argsValue, Array.prototype) || !Array.isArray(argsValue) || argsValue.length > 128 ||
49
+ Reflect.ownKeys(argsValue).length !== argsValue.length + 1)
50
+ return undefined;
51
+ const args = [];
52
+ for (let index = 0; index < argsValue.length; index++) {
53
+ const descriptor = Object.getOwnPropertyDescriptor(argsValue, String(index));
54
+ if (!descriptor || !('value' in descriptor) || !bounded(descriptor.value))
55
+ return undefined;
56
+ args.push(descriptor.value);
57
+ }
58
+ const variables = values.get('environment');
59
+ if (!plain(variables, Object.prototype))
60
+ return undefined;
61
+ const names = Reflect.ownKeys(variables);
62
+ if (names.length > 256)
63
+ return undefined;
64
+ const environment = new Map();
65
+ for (const name of names) {
66
+ const descriptor = Object.getOwnPropertyDescriptor(variables, name);
67
+ if (typeof name !== 'string' || !/^[A-Za-z_][A-Za-z0-9_]{0,127}$/.test(name) || reservedName(name) ||
68
+ !descriptor?.enumerable || !('value' in descriptor) || !bounded(descriptor.value))
69
+ return undefined;
70
+ environment.set(name, descriptor.value);
71
+ }
72
+ const unitName = values.get('unitName') ?? `smartdaemon-${plugins.crypto.randomUUID().replaceAll('-', '')}.scope`;
73
+ const runtimeDirectory = values.get('runtimeDirectory');
74
+ const systemdRunPath = values.get('systemdRunPath') ?? '/usr/bin/systemd-run';
75
+ const systemctlPath = values.get('systemctlPath') ?? '/usr/bin/systemctl';
76
+ const timeoutMs = values.get('commandTimeoutMs') ?? 120000;
77
+ if (typeof unitName !== 'string' || !/^[a-zA-Z0-9][a-zA-Z0-9_.:-]{0,230}\.scope$/.test(unitName) ||
78
+ (runtimeDirectory !== undefined && !path(runtimeDirectory)) || !path(systemdRunPath) || !path(systemctlPath) ||
79
+ !Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 600000)
80
+ return undefined;
81
+ return {
82
+ executable, args, workingDirectory, environment, description, unitName, runtimeDirectory, systemdRunPath,
83
+ systemctlPath, timeoutMs: timeoutMs,
84
+ };
85
+ };
86
+ /**
87
+ * Runs a program with stdin on /dev/null and bounded output. It settles once the process has exited
88
+ * and its stdout and stderr have closed; on the deadline or an output overflow it kills the process
89
+ * if it still runs and releases both pipes, so a descendant holding them keeps no handle open here.
90
+ */
91
+ const runProcess = (file, args, env, timeoutMs) => new Promise((resolve) => {
92
+ const child = plugins.childProcess.spawn(file, args, {
93
+ cwd: '/', env, stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true,
94
+ });
95
+ const output = { stdout: [], stderr: [] };
96
+ const sizes = { stdout: 0, stderr: 0 };
97
+ let settled = false;
98
+ const text = (chunks) => Buffer.concat(chunks).toString('utf8');
99
+ const abandon = (kind) => {
100
+ if (settled)
101
+ return;
102
+ settled = true;
103
+ clearTimeout(timer);
104
+ if (child.exitCode === null && child.signalCode === null)
105
+ child.kill('SIGKILL');
106
+ child.stdout.destroy();
107
+ child.stderr.destroy();
108
+ resolve({ kind, stderr: text(output.stderr) });
109
+ };
110
+ const timer = setTimeout(() => abandon('timed_out'), timeoutMs);
111
+ for (const stream of ['stdout', 'stderr']) {
112
+ child[stream].on('data', (chunk) => {
113
+ sizes[stream] += chunk.length;
114
+ if (sizes[stream] > outputLimit)
115
+ abandon('output_limit');
116
+ else
117
+ output[stream].push(chunk);
118
+ });
119
+ }
120
+ child.on('error', (error) => {
121
+ if (settled || child.pid !== undefined)
122
+ return;
123
+ settled = true;
124
+ clearTimeout(timer);
125
+ resolve({ kind: 'spawn_failed', error });
126
+ });
127
+ child.on('close', (code, signal) => {
128
+ if (settled)
129
+ return;
130
+ settled = true;
131
+ clearTimeout(timer);
132
+ resolve({ kind: 'exited', code, signal, stdout: text(output.stdout), stderr: text(output.stderr) });
133
+ });
134
+ });
135
+ /**
136
+ * The first stderr line systemd-run prints once the scope runs, before it executes the program:
137
+ * systemd 255 and later print `Running as unit: NAME` with an optional `; invocation ID: ID`,
138
+ * systemd 254 prints `Running scope as unit: NAME`. Returns the rest of stderr, or undefined.
139
+ */
140
+ const programStderr = (stderr, unitName) => {
141
+ const newline = stderr.indexOf('\n');
142
+ if (newline < 0)
143
+ return undefined;
144
+ const line = stderr.slice(0, newline);
145
+ const started = line === `Running as unit: ${unitName}` || line === `Running scope as unit: ${unitName}` ||
146
+ (line.startsWith(`Running as unit: ${unitName}; invocation ID: `) &&
147
+ /^[0-9a-f]{32}$/.test(line.slice(`Running as unit: ${unitName}; invocation ID: `.length)));
148
+ return started ? stderr.slice(newline + 1) : undefined;
149
+ };
150
+ /**
151
+ * Starts a program in a new transient scope unit of the calling user's systemd manager, so it and
152
+ * every process it starts run outside the caller's own unit and survive that unit's stop, and
153
+ * waits for the program's direct process. A program that daemonizes and exits returns its result
154
+ * while its daemon keeps the scope active; the scope ends when its last process exits. The daemon
155
+ * must not keep the program's stdout or stderr open, or the call runs into its timeout.
156
+ *
157
+ * On `timed_out` and `output_limit` the direct process is killed; processes it started stay in
158
+ * the scope. A program that exits with a failure status is a result, not an error.
159
+ */
160
+ export const runInTransientScope = async (options) => {
161
+ const validated = validate(options);
162
+ if (validated === undefined)
163
+ throw new SystemdTransientScopeError('invalid_options', null, '');
164
+ const { unitName } = validated;
165
+ const fail = (code, stderr = '', cause) => {
166
+ throw new SystemdTransientScopeError(code, unitName, stderr, cause === undefined ? undefined : { cause });
167
+ };
168
+ if (process.platform !== 'linux')
169
+ fail('unsupported_platform');
170
+ const runtimeDirectory = validated.runtimeDirectory ?? captureUserEnvironment(undefined).runtimeDirectory;
171
+ if (runtimeDirectory === undefined)
172
+ fail('user_manager_unavailable');
173
+ if (!isSafeDirectory(runtimeDirectory))
174
+ fail('invalid_options');
175
+ const admission = await inspectRuntimeDirectory(runtimeDirectory);
176
+ if (admission === 'absent')
177
+ fail('user_manager_unavailable');
178
+ if (admission !== 'private')
179
+ fail('invalid_options');
180
+ const probe = await runProcess(validated.systemctlPath, ['--user', '--no-ask-password', '--no-pager', 'show', '--property=Version'], { PATH: '/usr/bin:/bin', LANG: 'C', LC_ALL: 'C', XDG_RUNTIME_DIR: runtimeDirectory }, validated.timeoutMs);
181
+ if (probe.kind === 'timed_out')
182
+ fail('timed_out', probe.stderr);
183
+ if (probe.kind !== 'exited' || probe.code !== 0 || !probe.stdout.startsWith('Version=')) {
184
+ fail('user_manager_unavailable', probe.kind === 'spawn_failed' ? '' : probe.stderr, probe.kind === 'spawn_failed' ? probe.error : undefined);
185
+ }
186
+ // systemd-run registers its own process as the scope, then executes the program in place with
187
+ // its environment, so that environment is the program's own plus INVOCATION_ID.
188
+ const outcome = await runProcess(validated.systemdRunPath, [
189
+ '--user', '--scope', '--collect', '--no-ask-password', '--expand-environment=no',
190
+ `--unit=${unitName}`, `--description=${validated.description}`,
191
+ `--working-directory=${validated.workingDirectory}`, '--', validated.executable, ...validated.args,
192
+ ], { ...Object.fromEntries(validated.environment), XDG_RUNTIME_DIR: runtimeDirectory }, validated.timeoutMs);
193
+ if (outcome.kind === 'spawn_failed')
194
+ return fail('scope_start_failed', '', outcome.error);
195
+ if (outcome.kind !== 'exited')
196
+ return fail(outcome.kind, outcome.stderr);
197
+ const stderr = programStderr(outcome.stderr, unitName);
198
+ if (stderr === undefined)
199
+ return fail('scope_start_failed', outcome.stderr);
200
+ return Object.freeze({
201
+ unitName, exitCode: outcome.code, signal: outcome.signal, stdout: outcome.stdout, stderr,
202
+ });
203
+ };
204
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zeXN0ZW1kdHJhbnNpZW50c2NvcGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLnN5c3RlbWR0cmFuc2llbnRzY29wZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLDBCQUEwQixDQUFDO0FBQ3BELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN0RCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsdUJBQXVCLEVBQUUsZUFBZSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUE0RGhILE1BQU0sT0FBTywwQkFBMkIsU0FBUSxLQUFLO0lBQ25ELFlBQ2tCLElBQXFDO0lBQ3JELG1FQUFtRTtJQUNuRCxRQUF1QjtJQUN2QyxzRkFBc0Y7SUFDdEUsTUFBYyxFQUM5QixPQUFzQjtRQUV0QixLQUFLLENBQUMsbUNBQW1DLElBQUksR0FBRyxRQUFRLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssUUFBUSxHQUFHLEdBQUcsRUFBRSxPQUFPLENBQUMsQ0FBQztRQVB2RixTQUFJLEdBQUosSUFBSSxDQUFpQztRQUVyQyxhQUFRLEdBQVIsUUFBUSxDQUFlO1FBRXZCLFdBQU0sR0FBTixNQUFNLENBQVE7UUFJOUIsSUFBSSxDQUFDLElBQUksR0FBRyw0QkFBNEIsQ0FBQztJQUMzQyxDQUFDO0NBQ0Y7QUFFRCxNQUFNLFdBQVcsR0FBRyxPQUFPLENBQUM7QUFDNUIsTUFBTSxZQUFZLEdBQUcsQ0FBQyxJQUFZLEVBQUUsRUFBRSxDQUNwQyxJQUFJLEtBQUssaUJBQWlCLElBQUksSUFBSSxLQUFLLGVBQWUsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQyxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUM7QUFlcEgsa0dBQWtHO0FBQ2xHLE1BQU0sUUFBUSxHQUFHLENBQUMsT0FBZ0IsRUFB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
@@ -1,5 +1,5 @@
1
1
  import * as plugins from './smartdaemon.plugins.js';
2
- import { captureUserEnvironment, isSafeDirectory, isUserManagerEnvironment, } from './systemd.userenvironment.js';
2
+ import { captureUserEnvironment, inspectRuntimeDirectory, isSafeDirectory, isUserManagerEnvironment, } from './systemd.userenvironment.js';
3
3
  import { environmentByteLimit, environmentVariableLimit, isCleanText } from './systemd.definition.js';
4
4
  export class SystemdUnitError extends Error {
5
5
  constructor(code) {
@@ -275,19 +275,7 @@ export class SystemdUnit {
275
275
  return undefined;
276
276
  if (!isUserManagerEnvironment(environment))
277
277
  throw new SystemdUnitError('invalid_options');
278
- const runtimeDirectory = environment.runtimeDirectory;
279
- try {
280
- const uid = process.getuid?.();
281
- if (process.platform !== 'linux' || uid === undefined || process.geteuid?.() !== uid ||
282
- await plugins.fs.realpath(runtimeDirectory) !== runtimeDirectory) {
283
- throw new SystemdUnitError('invalid_options');
284
- }
285
- const info = await plugins.fs.lstat(runtimeDirectory);
286
- if (!info.isDirectory() || info.isSymbolicLink() || info.uid !== uid ||
287
- (info.mode & 0o077) !== 0)
288
- throw new SystemdUnitError('invalid_options');
289
- }
290
- catch {
278
+ if (await inspectRuntimeDirectory(environment.runtimeDirectory) !== 'private') {
291
279
  throw new SystemdUnitError('invalid_options');
292
280
  }
293
281
  return environment;
@@ -319,4 +307,4 @@ export class SystemdUnit {
319
307
  });
320
308
  }
321
309
  }
322
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zeXN0ZW1kdW5pdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2NsYXNzZXMuc3lzdGVtZHVuaXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSwwQkFBMEIsQ0FBQztBQUNwRCxPQUFPLEVBR0wsc0JBQXNCLEVBQ3RCLGVBQWUsRUFDZix3QkFBd0IsR0FDekIsTUFBTSw4QkFBOEIsQ0FBQztBQUN0QyxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsd0JBQXdCLEVBQUUsV0FBVyxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUErRXRHLE1BQU0sT0FBTyxnQkFBaUIsU0FBUSxLQUFLO0lBQ3pDLFlBQTRCLElBQTREO1FBQ3RGLEtBQUssQ0FBQyxrQ0FBa0MsSUFBSSxHQUFHLENBQUMsQ0FBQztRQUR2QixTQUFJLEdBQUosSUFBSSxDQUF3RDtRQUV0RixJQUFJLENBQUMsSUFBSSxHQUFHLGtCQUFrQixDQUFDO0lBQ2pDLENBQUM7Q0FDRjtBQUVELGtHQUFrRztBQUNsRyxNQUFNLGFBQWEsR0FBRyxJQUFJLEdBQUcsQ0FBaUI7SUFDNUMsQ0FBQyxHQUFHLEVBQUUsZUFBZSxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsY0FBYyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsYUFBYSxDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsWUFBWSxDQUFDO0lBQzVGLENBQUMsR0FBRyxFQUFFLFdBQVcsQ0FBQyxFQUFFLENBQUMsS0FBSyxFQUFFLFNBQVMsQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFFLFFBQVEsQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQztDQUNuRixDQUFDLENBQUM7QUFFSCxxR0FBcUc7QUFDckcsTUFBTSxhQUFhLEdBQUcsQ0FBQyxJQUFZLEVBQW1DLEVBQUU7SUFDdEUsSUFBSSxJQUFJLEtBQUssVUFBVTtRQUFFLE9B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
310
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zeXN0ZW1kdW5pdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2NsYXNzZXMuc3lzdGVtZHVuaXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSwwQkFBMEIsQ0FBQztBQUNwRCxPQUFPLEVBR0wsc0JBQXNCLEVBQ3RCLHVCQUF1QixFQUN2QixlQUFlLEVBQ2Ysd0JBQXdCLEdBQ3pCLE1BQU0sOEJBQThCLENBQUM7QUFDdEMsT0FBTyxFQUFFLG9CQUFvQixFQUFFLHdCQUF3QixFQUFFLFdBQVcsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBK0V0RyxNQUFNLE9BQU8sZ0JBQWlCLFNBQVEsS0FBSztJQUN6QyxZQUE0QixJQUE0RDtRQUN0RixLQUFLLENBQUMsa0NBQWtDLElBQUksR0FBRyxDQUFDLENBQUM7UUFEdkIsU0FBSSxHQUFKLElBQUksQ0FBd0Q7UUFFdEYsSUFBSSxDQUFDLElBQUksR0FBRyxrQkFBa0IsQ0FBQztJQUNqQyxDQUFDO0NBQ0Y7QUFFRCxrR0FBa0c7QUFDbEcsTUFBTSxhQUFhLEdBQUcsSUFBSSxHQUFHLENBQWlCO0lBQzVDLENBQUMsR0FBRyxFQUFFLGVBQWUsQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLGNBQWMsQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFFLGFBQWEsQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFFLFlBQVksQ0FBQztJQUM1RixDQUFDLEdBQUcsRUFBRSxXQUFXLENBQUMsRUFBRSxDQUFDLEtBQUssRUFBRSxTQUFTLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBRSxRQUFRLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUM7Q0FDbkYsQ0FBQyxDQUFDO0FBRUgscUdBQXFHO0FBQ3JHLE1BQU0sYUFBYSxHQUFHLENBQUMsSUFBWSxFQUFtQyxFQUFFO0lBQ3RFLElBQUksSUFBSSxLQUFL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
@@ -3,3 +3,4 @@ export * from './smartdaemon.classes.service.js';
3
3
  export * from './classes.systemdunit.js';
4
4
  export * from './classes.systemdservicedefinition.js';
5
5
  export * from './classes.systemdunitfile.js';
6
+ export * from './classes.systemdtransientscope.js';
package/dist_ts/index.js CHANGED
@@ -3,4 +3,5 @@ export * from './smartdaemon.classes.service.js';
3
3
  export * from './classes.systemdunit.js';
4
4
  export * from './classes.systemdservicedefinition.js';
5
5
  export * from './classes.systemdunitfile.js';
6
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLHNDQUFzQyxDQUFDO0FBQ3JELGNBQWMsa0NBQWtDLENBQUM7QUFDakQsY0FBYywwQkFBMEIsQ0FBQztBQUN6QyxjQUFjLHVDQUF1QyxDQUFDO0FBQ3RELGNBQWMsOEJBQThCLENBQUMifQ==
6
+ export * from './classes.systemdtransientscope.js';
7
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLHNDQUFzQyxDQUFDO0FBQ3JELGNBQWMsa0NBQWtDLENBQUM7QUFDakQsY0FBYywwQkFBMEIsQ0FBQztBQUN6QyxjQUFjLHVDQUF1QyxDQUFDO0FBQ3RELGNBQWMsOEJBQThCLENBQUM7QUFDN0MsY0FBYyxvQ0FBb0MsQ0FBQyJ9
@@ -31,3 +31,9 @@ export declare const captureUserEnvironment: (runtimeDirectoryOption: string | u
31
31
  * XDG config/data roots to systemctl, so all of them must be well formed before the first call.
32
32
  */
33
33
  export declare const isUserManagerEnvironment: (environment: ISystemdUserEnvironment) => environment is TSystemdUserManagerEnvironment;
34
+ /**
35
+ * Admits a user-manager runtime directory: on Linux, for a process whose uid is its effective uid,
36
+ * the path must be its own real path and a directory owned by that uid without group or other
37
+ * permissions. `absent` is a directory that does not exist; every other refusal is `unsafe`.
38
+ */
39
+ export declare const inspectRuntimeDirectory: (runtimeDirectory: string) => Promise<"private" | "absent" | "unsafe">;
@@ -30,4 +30,24 @@ export const captureUserEnvironment = (runtimeDirectoryOption) => {
30
30
  export const isUserManagerEnvironment = (environment) => isSafeDirectory(environment.runtimeDirectory) && isSafeDirectory(environment.homeDirectory) &&
31
31
  (environment.configDirectory === undefined || isSafeDirectory(environment.configDirectory)) &&
32
32
  (environment.dataDirectory === undefined || isSafeDirectory(environment.dataDirectory));
33
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3lzdGVtZC51c2VyZW52aXJvbm1lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zeXN0ZW1kLnVzZXJlbnZpcm9ubWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLDBCQUEwQixDQUFDO0FBeUJwRCw4RkFBOEY7QUFDOUYsTUFBTSxDQUFDLE1BQU0sZUFBZSxHQUFHLENBQUMsS0FBYyxFQUFtQixFQUFFLENBQ2pFLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxLQUFLLEtBQUssR0FBRyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQztJQUM1RSxPQUFPLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsS0FBSyxLQUFLLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQztJQUMvRCxLQUFLLENBQUMsTUFBTSxJQUFJLElBQUksSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUV6RDs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSxzQkFBc0IsR0FBRyxDQUNwQyxzQkFBMEMsRUFDakIsRUFBRTtJQUMzQixJQUFJLGFBQWlDLENBQUM7SUFDdEMsSUFBSSxDQUFDO1FBQ0gsYUFBYSxHQUFHLE9BQU8sQ0FBQyxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsT0FBTyxDQUFDO0lBQ2hELENBQUM7SUFBQyxNQUFNLENBQUM7UUFDUCw0RkFBNEY7UUFDNUYsK0VBQStFO0lBQ2pGLENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUM7UUFDbkIsYUFBYTtRQUNiLGVBQWUsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLGVBQWUsSUFBSSxTQUFTO1FBQ3pELGFBQWEsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLGFBQWEsSUFBSSxTQUFTO1FBQ3JELGdCQUFnQixFQUFFLHNCQUFzQixJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxlQUFlLElBQUksU0FBUyxDQUFDO0tBQ3ZGLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQztBQUVGOzs7R0FHRztBQUNILE1BQU0sQ0FBQyxNQUFNLHdCQUF3QixHQUFHLENBQ3RDLFdBQW9DLEVBQ1csRUFBRSxDQUNqRCxlQUFlLENBQUMsV0FBVyxDQUFDLGdCQUFnQixDQUFDLElBQUksZUFBZSxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUM7SUFDM0YsQ0FBQyxXQUFXLENBQUMsZUFBZSxLQUFLLFNBQVMsSUFBSSxlQUFlLENBQUMsV0FBVyxDQUFDLGVBQWUsQ0FBQyxDQUFDO0lBQzNGLENBQUMsV0FBVyxDQUFDLGFBQWEsS0FBSyxTQUFTLElBQUksZUFBZSxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDIn0=
33
+ /**
34
+ * Admits a user-manager runtime directory: on Linux, for a process whose uid is its effective uid,
35
+ * the path must be its own real path and a directory owned by that uid without group or other
36
+ * permissions. `absent` is a directory that does not exist; every other refusal is `unsafe`.
37
+ */
38
+ export const inspectRuntimeDirectory = async (runtimeDirectory) => {
39
+ const uid = process.getuid?.();
40
+ if (process.platform !== 'linux' || uid === undefined || process.geteuid?.() !== uid)
41
+ return 'unsafe';
42
+ try {
43
+ if (await plugins.fs.realpath(runtimeDirectory) !== runtimeDirectory)
44
+ return 'unsafe';
45
+ const info = await plugins.fs.lstat(runtimeDirectory);
46
+ return info.isDirectory() && !info.isSymbolicLink() && info.uid === uid && (info.mode & 0o077) === 0
47
+ ? 'private' : 'unsafe';
48
+ }
49
+ catch (error) {
50
+ return error.code === 'ENOENT' ? 'absent' : 'unsafe';
51
+ }
52
+ };
53
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3lzdGVtZC51c2VyZW52aXJvbm1lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zeXN0ZW1kLnVzZXJlbnZpcm9ubWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLDBCQUEwQixDQUFDO0FBeUJwRCw4RkFBOEY7QUFDOUYsTUFBTSxDQUFDLE1BQU0sZUFBZSxHQUFHLENBQUMsS0FBYyxFQUFtQixFQUFFLENBQ2pFLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxLQUFLLEtBQUssR0FBRyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQztJQUM1RSxPQUFPLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsS0FBSyxLQUFLLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQztJQUMvRCxLQUFLLENBQUMsTUFBTSxJQUFJLElBQUksSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUV6RDs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSxzQkFBc0IsR0FBRyxDQUNwQyxzQkFBMEMsRUFDakIsRUFBRTtJQUMzQixJQUFJLGFBQWlDLENBQUM7SUFDdEMsSUFBSSxDQUFDO1FBQ0gsYUFBYSxHQUFHLE9BQU8sQ0FBQyxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsT0FBTyxDQUFDO0lBQ2hELENBQUM7SUFBQyxNQUFNLENBQUM7UUFDUCw0RkFBNEY7UUFDNUYsK0VBQStFO0lBQ2pGLENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUM7UUFDbkIsYUFBYTtRQUNiLGVBQWUsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLGVBQWUsSUFBSSxTQUFTO1FBQ3pELGFBQWEsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLGFBQWEsSUFBSSxTQUFTO1FBQ3JELGdCQUFnQixFQUFFLHNCQUFzQixJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxlQUFlLElBQUksU0FBUyxDQUFDO0tBQ3ZGLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQztBQUVGOzs7R0FHRztBQUNILE1BQU0sQ0FBQyxNQUFNLHdCQUF3QixHQUFHLENBQ3RDLFdBQW9DLEVBQ1csRUFBRSxDQUNqRCxlQUFlLENBQUMsV0FBVyxDQUFDLGdCQUFnQixDQUFDLElBQUksZUFBZSxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUM7SUFDM0YsQ0FBQyxXQUFXLENBQUMsZUFBZSxLQUFLLFNBQVMsSUFBSSxlQUFlLENBQUMsV0FBVyxDQUFDLGVBQWUsQ0FBQyxDQUFDO0lBQzNGLENBQUMsV0FBVyxDQUFDLGFBQWEsS0FBSyxTQUFTLElBQUksZUFBZSxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDO0FBRTFGOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsTUFBTSx1QkFBdUIsR0FBRyxLQUFLLEVBQzFDLGdCQUF3QixFQUNrQixFQUFFO0lBQzVDLE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDO0lBQy9CLElBQUksT0FBTyxDQUFDLFFBQVEsS0FBSyxPQUFPLElBQUksR0FBRyxLQUFLLFNBQVMsSUFBSSxPQUFPLENBQUMsT0FBTyxFQUFFLEVBQUUsS0FBSyxHQUFHO1FBQUUsT0FBTyxRQUFRLENBQUM7SUFDdEcsSUFBSSxDQUFDO1FBQ0gsSUFBSSxNQUFNLE9BQU8sQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLGdCQUFnQixDQUFDLEtBQUssZ0JBQWdCO1lBQUUsT0FBTyxRQUFRLENBQUM7UUFDdEYsTUFBTSxJQUFJLEdBQUcsTUFBTSxPQUFPLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ3RELE9BQU8sSUFBSSxDQUFDLFdBQVcsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRSxJQUFJLElBQUksQ0FBQyxHQUFHLEtBQUssR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDO1lBQ2xHLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQztJQUMzQixDQUFDO0lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztRQUNmLE9BQVEsS0FBK0IsQ0FBQyxJQUFJLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQztJQUNsRixDQUFDO0FBQ0gsQ0FBQyxDQUFDIn0=
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@push.rocks/smartdaemon",
3
- "version": "2.11.0",
3
+ "version": "2.12.0",
4
4
  "private": false,
5
5
  "description": "Start scripts as long running daemons and manage them.",
6
6
  "main": "dist_ts/index.js",
package/readme.md CHANGED
@@ -605,6 +605,77 @@ other process in the unit survives, so the main process must own their shutdown
605
605
  deliberate retention (as with `Delegate=yes` workloads). A successful systemd start still requires application readiness
606
606
  verification, and a completed stop alone does not prove database drain.
607
607
 
608
+ ### Starting a program in its own transient scope
609
+
610
+ A service that launches a long-lived program keeps that program in its own
611
+ control group, so stopping the service ends the program too, even when the
612
+ program detached itself with `setsid`. `runInTransientScope()` starts a program in
613
+ a new transient scope unit of the calling user's systemd manager instead
614
+ (`systemd-run --user --scope`): the program and every process it starts run in
615
+ that scope and outlive the caller's unit. The call waits for the program's direct
616
+ process and returns its result; a program that daemonizes and exits returns while
617
+ its daemon keeps the scope active, and the scope ends when its last process exits.
618
+
619
+ ```typescript
620
+ import { runInTransientScope, SystemdTransientScopeError } from '@push.rocks/smartdaemon';
621
+
622
+ try {
623
+ const result = await runInTransientScope({
624
+ scope: 'user',
625
+ description: 'Codex app-server daemon',
626
+ executable: '/home/owner/.local/bin/codex',
627
+ args: ['app-server', 'daemon', 'start'],
628
+ workingDirectory: '/home/owner',
629
+ environment: { HOME: '/home/owner', CODEX_HOME: '/home/owner/.codex', PATH: '/usr/bin:/bin' },
630
+ });
631
+ console.log(result.unitName, result.exitCode, result.stdout);
632
+ } catch (error) {
633
+ if (error instanceof SystemdTransientScopeError && error.code === 'user_manager_unavailable') {
634
+ // No user manager: the caller decides how to run the program without one.
635
+ }
636
+ throw error;
637
+ }
638
+ ```
639
+
640
+ The result holds the scope's `unitName`, the direct process's `exitCode` (or the
641
+ `signal` that ended it), and its `stdout` and `stderr`, UTF-8 decoded. A failure
642
+ status is a result, not an error. The program is executed directly from an
643
+ absolute `executable` with literal `args`, with no shell, PATH search or `$`
644
+ expansion (systemd 258 expands `$` in a scope's command line unless told not to,
645
+ and the call always passes `--expand-environment=no`), in the absolute
646
+ `workingDirectory`, with stdin on `/dev/null`. Its
647
+ environment is exactly `environment` plus the manager's `XDG_RUNTIME_DIR` and
648
+ systemd's `INVOCATION_ID`: nothing of the calling process is inherited, so pass
649
+ every variable the program needs. `XDG_RUNTIME_DIR`, `INVOCATION_ID` and names
650
+ starting with `SYSTEMD_` or `DBUS_`, which would configure systemd-run itself, are
651
+ refused. `unitName` names the scope (a `.scope` name) and defaults to a unique
652
+ `smartdaemon-<32 hex digits>.scope`; a scope of that name that is still active
653
+ refuses a second start. The literal `description` is the unit's description.
654
+
655
+ Failures throw `SystemdTransientScopeError` with the scope's `unitName` (null for
656
+ refused options), the `stderr` read so far and one of these codes:
657
+
658
+ | Code | Meaning |
659
+ | --- | --- |
660
+ | `invalid_options` | Malformed options, or a runtime directory that is not a private directory of the caller |
661
+ | `unsupported_platform` | The process is not running on Linux |
662
+ | `user_manager_unavailable` | No `XDG_RUNTIME_DIR` (or `runtimeDirectory`), a runtime directory that does not exist, or a manager that does not answer `systemctl --user` |
663
+ | `scope_start_failed` | systemd-run exited without reporting the scope running; the program has not run |
664
+ | `timed_out` | The manager probe or the program did not finish and close its output within `commandTimeoutMs` |
665
+ | `output_limit` | The program's stdout or stderr exceeded 1 MiB |
666
+
667
+ The call completes once the direct process has exited and its stdout and stderr
668
+ have closed, so a daemon must not keep them open (Codex, for example, redirects
669
+ its daemon's output); otherwise the call runs into its timeout. On `timed_out` and
670
+ `output_limit` the direct process is killed and the processes it started stay in
671
+ the scope. `commandTimeoutMs` (default 120000, maximum 600000) bounds the probe
672
+ and the program each. Trusted owning code can set `runtimeDirectory` and the
673
+ absolute `systemdRunPath` and `systemctlPath`. systemd-run reports the started
674
+ scope as its first stderr line, which systemd 254 and later print; an older
675
+ systemd-run, which lacks `--expand-environment`, fails with `scope_start_failed`.
676
+ If the program cannot be executed after the scope started, systemd-run reports
677
+ that as the program's exit status 1.
678
+
608
679
  ### SmartDaemonService Class
609
680
 
610
681
  ```typescript
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartdaemon',
6
- version: '2.11.0',
6
+ version: '2.12.0',
7
7
  description: 'Start scripts as long running daemons and manage them.'
8
8
  }
@@ -0,0 +1,272 @@
1
+ import * as plugins from './smartdaemon.plugins.js';
2
+ import { isCleanText } from './systemd.definition.js';
3
+ import { captureUserEnvironment, inspectRuntimeDirectory, isSafeDirectory } from './systemd.userenvironment.js';
4
+
5
+ export interface ISystemdTransientScopeOptions {
6
+ /** The calling user's manager; the only manager a transient scope is started in. */
7
+ scope: 'user';
8
+ /** Absolute, normalized program path, executed directly: no shell, no PATH search. */
9
+ executable: string;
10
+ /** Literal arguments, at most 128 of at most 32768 characters each, without NUL. */
11
+ args: readonly string[];
12
+ /** Absolute, normalized directory the program starts in. */
13
+ workingDirectory: string;
14
+ /**
15
+ * The program's complete environment. Nothing of the calling process is inherited: the program
16
+ * receives exactly these variables, the manager's `XDG_RUNTIME_DIR` and systemd's
17
+ * `INVOCATION_ID`. Names match `[A-Za-z_][A-Za-z0-9_]*` (at most 128 characters); values are
18
+ * strings of at most 32768 characters without NUL; at most 256 variables. `XDG_RUNTIME_DIR`,
19
+ * `INVOCATION_ID` and names starting with `SYSTEMD_` or `DBUS_`, which configure systemd-run
20
+ * itself, are refused.
21
+ */
22
+ environment: Readonly<Record<string, string>>;
23
+ /** Literal unit description: clean text of 1 to 1024 characters, trimmed, without `\`. */
24
+ description: string;
25
+ /** A `.scope` unit name; defaults to a unique `smartdaemon-<32 hex digits>.scope`. */
26
+ unitName?: string;
27
+ /** User-manager socket directory. Defaults to a non-empty XDG_RUNTIME_DIR. */
28
+ runtimeDirectory?: string;
29
+ /** Absolute executable path supplied by trusted owning code. Defaults to `/usr/bin/systemd-run`. */
30
+ systemdRunPath?: string;
31
+ /** Absolute executable path supplied by trusted owning code. Defaults to `/usr/bin/systemctl`. */
32
+ systemctlPath?: string;
33
+ /** Bounds the manager probe and the program's direct process, each. Defaults to 120 seconds. */
34
+ commandTimeoutMs?: number;
35
+ }
36
+
37
+ export interface ISystemdTransientScopeResult {
38
+ /** The scope unit. It stays active while any process the program started runs in it. */
39
+ readonly unitName: string;
40
+ /** Exit status of the program's direct process; null when a signal ended it. */
41
+ readonly exitCode: number | null;
42
+ readonly signal: NodeJS.Signals | null;
43
+ /** UTF-8 decoded output of the program and every process that shared its stdout. */
44
+ readonly stdout: string;
45
+ /** As `stdout`, without the line systemd-run prints on starting the scope. */
46
+ readonly stderr: string;
47
+ }
48
+
49
+ export type TSystemdTransientScopeErrorCode =
50
+ /** The options are malformed, or the runtime directory is not a private directory of the caller. */
51
+ | 'invalid_options'
52
+ /** The process is not running on Linux. */
53
+ | 'unsupported_platform'
54
+ /** No runtime directory is set or it does not exist, or the manager does not answer systemctl. */
55
+ | 'user_manager_unavailable'
56
+ /** systemd-run exited without reporting the scope running; the program has not run. */
57
+ | 'scope_start_failed'
58
+ /** The manager probe or the program did not finish, and close its output, in time. */
59
+ | 'timed_out'
60
+ /** The program's stdout or stderr exceeded 1 MiB. */
61
+ | 'output_limit';
62
+
63
+ export class SystemdTransientScopeError extends Error {
64
+ constructor(
65
+ public readonly code: TSystemdTransientScopeErrorCode,
66
+ /** The scope the call used; null when the options were refused. */
67
+ public readonly unitName: string | null,
68
+ /** The probe's or systemd-run's stderr as far as it was read; empty when none ran. */
69
+ public readonly stderr: string,
70
+ options?: ErrorOptions,
71
+ ) {
72
+ super(`Systemd transient scope failed: ${code}${unitName === null ? '' : ` (${unitName})`}.`, options);
73
+ this.name = 'SystemdTransientScopeError';
74
+ }
75
+ }
76
+
77
+ const outputLimit = 1048576;
78
+ const reservedName = (name: string) =>
79
+ name === 'XDG_RUNTIME_DIR' || name === 'INVOCATION_ID' || name.startsWith('SYSTEMD_') || name.startsWith('DBUS_');
80
+
81
+ interface IValidatedOptions {
82
+ readonly executable: string;
83
+ readonly args: readonly string[];
84
+ readonly workingDirectory: string;
85
+ readonly environment: ReadonlyMap<string, string>;
86
+ readonly description: string;
87
+ readonly unitName: string;
88
+ readonly runtimeDirectory?: string;
89
+ readonly systemdRunPath: string;
90
+ readonly systemctlPath: string;
91
+ readonly timeoutMs: number;
92
+ }
93
+
94
+ /** Reads every option once through its own data descriptor, so no accessor or proxy trap runs. */
95
+ const validate = (options: unknown): IValidatedOptions | undefined => {
96
+ const plain = (value: unknown, prototype: object): value is object => value !== null &&
97
+ typeof value === 'object' && !plugins.util.types.isProxy(value) && Object.getPrototypeOf(value) === prototype;
98
+ if (!plain(options, Object.prototype)) return undefined;
99
+ const required = ['scope', 'executable', 'args', 'workingDirectory', 'environment', 'description'];
100
+ const optional = ['unitName', 'runtimeDirectory', 'systemdRunPath', 'systemctlPath', 'commandTimeoutMs'];
101
+ const values = new Map<string, unknown>();
102
+ for (const key of Reflect.ownKeys(options)) {
103
+ const descriptor = Object.getOwnPropertyDescriptor(options, key);
104
+ if (typeof key !== 'string' || ![...required, ...optional].includes(key) || !descriptor?.enumerable ||
105
+ !('value' in descriptor)) return undefined;
106
+ if (descriptor.value !== undefined) values.set(key, descriptor.value);
107
+ }
108
+ if (!required.every((key) => values.has(key)) || values.get('scope') !== 'user') return undefined;
109
+ const path = (value: unknown): value is string => isSafeDirectory(value);
110
+ const bounded = (value: unknown): value is string =>
111
+ typeof value === 'string' && value.length <= 32768 && !value.includes('\0');
112
+
113
+ const executable = values.get('executable');
114
+ const workingDirectory = values.get('workingDirectory');
115
+ const description = values.get('description');
116
+ if (!path(executable) || !(workingDirectory === '/' || path(workingDirectory)) ||
117
+ typeof description !== 'string' || description.length < 1 || description.length > 1024 ||
118
+ description.trim() !== description || description.includes('\\') || !isCleanText(description)) return undefined;
119
+
120
+ const argsValue = values.get('args');
121
+ if (!plain(argsValue, Array.prototype) || !Array.isArray(argsValue) || argsValue.length > 128 ||
122
+ Reflect.ownKeys(argsValue).length !== argsValue.length + 1) return undefined;
123
+ const args: string[] = [];
124
+ for (let index = 0; index < argsValue.length; index++) {
125
+ const descriptor = Object.getOwnPropertyDescriptor(argsValue, String(index));
126
+ if (!descriptor || !('value' in descriptor) || !bounded(descriptor.value)) return undefined;
127
+ args.push(descriptor.value);
128
+ }
129
+
130
+ const variables = values.get('environment');
131
+ if (!plain(variables, Object.prototype)) return undefined;
132
+ const names = Reflect.ownKeys(variables);
133
+ if (names.length > 256) return undefined;
134
+ const environment = new Map<string, string>();
135
+ for (const name of names) {
136
+ const descriptor = Object.getOwnPropertyDescriptor(variables, name);
137
+ if (typeof name !== 'string' || !/^[A-Za-z_][A-Za-z0-9_]{0,127}$/.test(name) || reservedName(name) ||
138
+ !descriptor?.enumerable || !('value' in descriptor) || !bounded(descriptor.value)) return undefined;
139
+ environment.set(name, descriptor.value);
140
+ }
141
+
142
+ const unitName = values.get('unitName') ?? `smartdaemon-${plugins.crypto.randomUUID().replaceAll('-', '')}.scope`;
143
+ const runtimeDirectory = values.get('runtimeDirectory');
144
+ const systemdRunPath = values.get('systemdRunPath') ?? '/usr/bin/systemd-run';
145
+ const systemctlPath = values.get('systemctlPath') ?? '/usr/bin/systemctl';
146
+ const timeoutMs = values.get('commandTimeoutMs') ?? 120000;
147
+ if (typeof unitName !== 'string' || !/^[a-zA-Z0-9][a-zA-Z0-9_.:-]{0,230}\.scope$/.test(unitName) ||
148
+ (runtimeDirectory !== undefined && !path(runtimeDirectory)) || !path(systemdRunPath) || !path(systemctlPath) ||
149
+ !Number.isSafeInteger(timeoutMs) || (timeoutMs as number) < 1 || (timeoutMs as number) > 600000) return undefined;
150
+ return {
151
+ executable, args, workingDirectory, environment, description, unitName, runtimeDirectory, systemdRunPath,
152
+ systemctlPath, timeoutMs: timeoutMs as number,
153
+ };
154
+ };
155
+
156
+ type TProcessOutcome =
157
+ | { readonly kind: 'exited'; readonly code: number | null; readonly signal: NodeJS.Signals | null;
158
+ readonly stdout: string; readonly stderr: string }
159
+ | { readonly kind: 'spawn_failed'; readonly error: Error }
160
+ | { readonly kind: 'timed_out' | 'output_limit'; readonly stderr: string };
161
+
162
+ /**
163
+ * Runs a program with stdin on /dev/null and bounded output. It settles once the process has exited
164
+ * and its stdout and stderr have closed; on the deadline or an output overflow it kills the process
165
+ * if it still runs and releases both pipes, so a descendant holding them keeps no handle open here.
166
+ */
167
+ const runProcess = (file: string, args: readonly string[], env: Record<string, string>, timeoutMs: number) =>
168
+ new Promise<TProcessOutcome>((resolve) => {
169
+ const child = plugins.childProcess.spawn(file, args, {
170
+ cwd: '/', env, stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true,
171
+ });
172
+ const output = { stdout: [] as Buffer[], stderr: [] as Buffer[] };
173
+ const sizes = { stdout: 0, stderr: 0 };
174
+ let settled = false;
175
+ const text = (chunks: Buffer[]) => Buffer.concat(chunks).toString('utf8');
176
+ const abandon = (kind: 'timed_out' | 'output_limit') => {
177
+ if (settled) return;
178
+ settled = true;
179
+ clearTimeout(timer);
180
+ if (child.exitCode === null && child.signalCode === null) child.kill('SIGKILL');
181
+ child.stdout.destroy();
182
+ child.stderr.destroy();
183
+ resolve({ kind, stderr: text(output.stderr) });
184
+ };
185
+ const timer = setTimeout(() => abandon('timed_out'), timeoutMs);
186
+ for (const stream of ['stdout', 'stderr'] as const) {
187
+ child[stream].on('data', (chunk: Buffer) => {
188
+ sizes[stream] += chunk.length;
189
+ if (sizes[stream] > outputLimit) abandon('output_limit');
190
+ else output[stream].push(chunk);
191
+ });
192
+ }
193
+ child.on('error', (error) => {
194
+ if (settled || child.pid !== undefined) return;
195
+ settled = true;
196
+ clearTimeout(timer);
197
+ resolve({ kind: 'spawn_failed', error });
198
+ });
199
+ child.on('close', (code, signal) => {
200
+ if (settled) return;
201
+ settled = true;
202
+ clearTimeout(timer);
203
+ resolve({ kind: 'exited', code, signal, stdout: text(output.stdout), stderr: text(output.stderr) });
204
+ });
205
+ });
206
+
207
+ /**
208
+ * The first stderr line systemd-run prints once the scope runs, before it executes the program:
209
+ * systemd 255 and later print `Running as unit: NAME` with an optional `; invocation ID: ID`,
210
+ * systemd 254 prints `Running scope as unit: NAME`. Returns the rest of stderr, or undefined.
211
+ */
212
+ const programStderr = (stderr: string, unitName: string): string | undefined => {
213
+ const newline = stderr.indexOf('\n');
214
+ if (newline < 0) return undefined;
215
+ const line = stderr.slice(0, newline);
216
+ const started = line === `Running as unit: ${unitName}` || line === `Running scope as unit: ${unitName}` ||
217
+ (line.startsWith(`Running as unit: ${unitName}; invocation ID: `) &&
218
+ /^[0-9a-f]{32}$/.test(line.slice(`Running as unit: ${unitName}; invocation ID: `.length)));
219
+ return started ? stderr.slice(newline + 1) : undefined;
220
+ };
221
+
222
+ /**
223
+ * Starts a program in a new transient scope unit of the calling user's systemd manager, so it and
224
+ * every process it starts run outside the caller's own unit and survive that unit's stop, and
225
+ * waits for the program's direct process. A program that daemonizes and exits returns its result
226
+ * while its daemon keeps the scope active; the scope ends when its last process exits. The daemon
227
+ * must not keep the program's stdout or stderr open, or the call runs into its timeout.
228
+ *
229
+ * On `timed_out` and `output_limit` the direct process is killed; processes it started stay in
230
+ * the scope. A program that exits with a failure status is a result, not an error.
231
+ */
232
+ export const runInTransientScope = async (
233
+ options: ISystemdTransientScopeOptions,
234
+ ): Promise<ISystemdTransientScopeResult> => {
235
+ const validated = validate(options);
236
+ if (validated === undefined) throw new SystemdTransientScopeError('invalid_options', null, '');
237
+ const { unitName } = validated;
238
+ const fail = (code: TSystemdTransientScopeErrorCode, stderr = '', cause?: unknown): never => {
239
+ throw new SystemdTransientScopeError(code, unitName, stderr, cause === undefined ? undefined : { cause });
240
+ };
241
+ if (process.platform !== 'linux') fail('unsupported_platform');
242
+ const runtimeDirectory = validated.runtimeDirectory ?? captureUserEnvironment(undefined).runtimeDirectory;
243
+ if (runtimeDirectory === undefined) fail('user_manager_unavailable');
244
+ if (!isSafeDirectory(runtimeDirectory)) fail('invalid_options');
245
+ const admission = await inspectRuntimeDirectory(runtimeDirectory!);
246
+ if (admission === 'absent') fail('user_manager_unavailable');
247
+ if (admission !== 'private') fail('invalid_options');
248
+
249
+ const probe = await runProcess(validated.systemctlPath,
250
+ ['--user', '--no-ask-password', '--no-pager', 'show', '--property=Version'],
251
+ { PATH: '/usr/bin:/bin', LANG: 'C', LC_ALL: 'C', XDG_RUNTIME_DIR: runtimeDirectory! }, validated.timeoutMs);
252
+ if (probe.kind === 'timed_out') fail('timed_out', probe.stderr);
253
+ if (probe.kind !== 'exited' || probe.code !== 0 || !probe.stdout.startsWith('Version=')) {
254
+ fail('user_manager_unavailable', probe.kind === 'spawn_failed' ? '' : probe.stderr,
255
+ probe.kind === 'spawn_failed' ? probe.error : undefined);
256
+ }
257
+
258
+ // systemd-run registers its own process as the scope, then executes the program in place with
259
+ // its environment, so that environment is the program's own plus INVOCATION_ID.
260
+ const outcome = await runProcess(validated.systemdRunPath, [
261
+ '--user', '--scope', '--collect', '--no-ask-password', '--expand-environment=no',
262
+ `--unit=${unitName}`, `--description=${validated.description}`,
263
+ `--working-directory=${validated.workingDirectory}`, '--', validated.executable, ...validated.args,
264
+ ], { ...Object.fromEntries(validated.environment), XDG_RUNTIME_DIR: runtimeDirectory! }, validated.timeoutMs);
265
+ if (outcome.kind === 'spawn_failed') return fail('scope_start_failed', '', outcome.error);
266
+ if (outcome.kind !== 'exited') return fail(outcome.kind, outcome.stderr);
267
+ const stderr = programStderr(outcome.stderr, unitName);
268
+ if (stderr === undefined) return fail('scope_start_failed', outcome.stderr);
269
+ return Object.freeze({
270
+ unitName, exitCode: outcome.code, signal: outcome.signal, stdout: outcome.stdout, stderr,
271
+ });
272
+ };
@@ -3,6 +3,7 @@ import {
3
3
  type ISystemdUserEnvironment,
4
4
  type TSystemdUserManagerEnvironment,
5
5
  captureUserEnvironment,
6
+ inspectRuntimeDirectory,
6
7
  isSafeDirectory,
7
8
  isUserManagerEnvironment,
8
9
  } from './systemd.userenvironment.js';
@@ -371,17 +372,7 @@ export class SystemdUnit {
371
372
  const environment = this.userEnvironment;
372
373
  if (environment === undefined) return undefined;
373
374
  if (!isUserManagerEnvironment(environment)) throw new SystemdUnitError('invalid_options');
374
- const runtimeDirectory = environment.runtimeDirectory;
375
- try {
376
- const uid = process.getuid?.();
377
- if (process.platform !== 'linux' || uid === undefined || process.geteuid?.() !== uid ||
378
- await plugins.fs.realpath(runtimeDirectory) !== runtimeDirectory) {
379
- throw new SystemdUnitError('invalid_options');
380
- }
381
- const info = await plugins.fs.lstat(runtimeDirectory);
382
- if (!info.isDirectory() || info.isSymbolicLink() || info.uid !== uid ||
383
- (info.mode & 0o077) !== 0) throw new SystemdUnitError('invalid_options');
384
- } catch {
375
+ if (await inspectRuntimeDirectory(environment.runtimeDirectory) !== 'private') {
385
376
  throw new SystemdUnitError('invalid_options');
386
377
  }
387
378
  return environment;
package/ts/index.ts CHANGED
@@ -3,3 +3,4 @@ export * from './smartdaemon.classes.service.js';
3
3
  export * from './classes.systemdunit.js';
4
4
  export * from './classes.systemdservicedefinition.js';
5
5
  export * from './classes.systemdunitfile.js';
6
+ export * from './classes.systemdtransientscope.js';
@@ -61,3 +61,23 @@ export const isUserManagerEnvironment = (
61
61
  isSafeDirectory(environment.runtimeDirectory) && isSafeDirectory(environment.homeDirectory) &&
62
62
  (environment.configDirectory === undefined || isSafeDirectory(environment.configDirectory)) &&
63
63
  (environment.dataDirectory === undefined || isSafeDirectory(environment.dataDirectory));
64
+
65
+ /**
66
+ * Admits a user-manager runtime directory: on Linux, for a process whose uid is its effective uid,
67
+ * the path must be its own real path and a directory owned by that uid without group or other
68
+ * permissions. `absent` is a directory that does not exist; every other refusal is `unsafe`.
69
+ */
70
+ export const inspectRuntimeDirectory = async (
71
+ runtimeDirectory: string,
72
+ ): Promise<'private' | 'absent' | 'unsafe'> => {
73
+ const uid = process.getuid?.();
74
+ if (process.platform !== 'linux' || uid === undefined || process.geteuid?.() !== uid) return 'unsafe';
75
+ try {
76
+ if (await plugins.fs.realpath(runtimeDirectory) !== runtimeDirectory) return 'unsafe';
77
+ const info = await plugins.fs.lstat(runtimeDirectory);
78
+ return info.isDirectory() && !info.isSymbolicLink() && info.uid === uid && (info.mode & 0o077) === 0
79
+ ? 'private' : 'unsafe';
80
+ } catch (error) {
81
+ return (error as NodeJS.ErrnoException).code === 'ENOENT' ? 'absent' : 'unsafe';
82
+ }
83
+ };