@remcp/remcp 0.2.207 → 0.2.208
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 +14 -1
- package/package.json +1 -1
- package/src/cli/service.mjs +23 -17
package/README.md
CHANGED
|
@@ -63,7 +63,20 @@ Two things it deliberately does not do:
|
|
|
63
63
|
a non-interactive command cannot type one. Nothing in this mode grants root by itself.
|
|
64
64
|
|
|
65
65
|
While it is on, `get_runtime_info` reports `policy.unrestricted: true`, so the model can see it and
|
|
66
|
-
say so instead of assuming the guardrails are still there.
|
|
66
|
+
say so instead of assuming the guardrails are still there. The same response includes
|
|
67
|
+
`osPrivilegeBoundary`, reporting effective user and `NoNewPrivs` on Linux, the user boundary on
|
|
68
|
+
macOS, and the actual Windows process integrity level detected via `whoami.exe /groups`.
|
|
69
|
+
If that command is unavailable, Windows elevation remains `unknown`; process integrity
|
|
70
|
+
is not equivalent to blanket administrator access.
|
|
71
|
+
|
|
72
|
+
The owner-managed Linux `remcp-agent.service` does not set `NoNewPrivileges=true`: sudo/polkit
|
|
73
|
+
may request normal OS approval instead of being blocked by systemd. `remcp update` also removes
|
|
74
|
+
this legacy line from older user units. A systemd `daemon-reload` does not change an already
|
|
75
|
+
running process; activating the new privilege boundary requires an agent restart, which can stop
|
|
76
|
+
running terminal sessions and child processes. This does **not** enable passwordless root.
|
|
77
|
+
On macOS, launchd runs as the signed-in user, and TCC controls Full Disk Access and Accessibility.
|
|
78
|
+
On Windows, the interactive scheduled task requests the highest privileges available to its
|
|
79
|
+
principal; UAC and the actual process token remain authoritative.
|
|
67
80
|
|
|
68
81
|
## macOS folder permissions
|
|
69
82
|
|
package/package.json
CHANGED
package/src/cli/service.mjs
CHANGED
|
@@ -62,7 +62,7 @@ function writeLinuxServiceLauncher(cliPath = globalCliPath(), nodePath = process
|
|
|
62
62
|
|
|
63
63
|
export function installLinuxService(cliPath = globalCliPath(), nodePath = process.execPath) {
|
|
64
64
|
const launcherFile = writeLinuxServiceLauncher(cliPath, nodePath);
|
|
65
|
-
const unit = `[Unit]\nDescription=ReMCP device agent\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nExecStart=${quoteSystemd(launcherFile)} start --service\nRestart=always\nRestartSec=3\
|
|
65
|
+
const unit = `[Unit]\nDescription=ReMCP device agent\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nExecStart=${quoteSystemd(launcherFile)} start --service\nRestart=always\nRestartSec=3\n\n[Install]\nWantedBy=default.target\n`;
|
|
66
66
|
fs.mkdirSync(path.dirname(linuxServiceFile), { recursive: true });
|
|
67
67
|
fs.writeFileSync(linuxServiceFile, unit);
|
|
68
68
|
run('systemctl', ['--user', 'daemon-reload']);
|
|
@@ -279,23 +279,29 @@ export function ensureServiceIfRecorded(config) {
|
|
|
279
279
|
const launcherFile = writeLinuxServiceLauncher(cliPath, nodePath);
|
|
280
280
|
const unit = fs.readFileSync(fd, 'utf8');
|
|
281
281
|
const expected = `ExecStart=${quoteSystemd(launcherFile)} start --service`;
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
282
|
+
// Legacy versions added NoNewPrivileges=true to the user agent unit.
|
|
283
|
+
// Drop that line when repairing so ordinary OS-authenticated sudo/polkit
|
|
284
|
+
// can work for the owner's session. ReMCP never becomes root by itself.
|
|
285
|
+
// Do not modify unrelated systemd services or owner-managed drop-ins.
|
|
286
|
+
let repaired = unit.replace(/^NoNewPrivileges=true\r?\n/gm, '');
|
|
287
|
+
if (!repaired.includes(expected)) {
|
|
288
|
+
repaired = /^ExecStart=/m.test(repaired)
|
|
289
|
+
? repaired.replace(/^ExecStart=.*$/m, expected) : '';
|
|
290
|
+
}
|
|
291
|
+
if (!repaired) {
|
|
292
|
+
reinstall = true;
|
|
293
|
+
} else if (repaired !== unit) {
|
|
294
|
+
const data = Buffer.from(repaired, 'utf8');
|
|
295
|
+
fs.ftruncateSync(fd, 0);
|
|
296
|
+
let offset = 0;
|
|
297
|
+
while (offset < data.length) {
|
|
298
|
+
const written = fs.writeSync(fd, data, offset, data.length - offset, offset);
|
|
299
|
+
if (!written) throw new Error('Could not finish rewriting the systemd unit');
|
|
300
|
+
offset += written;
|
|
298
301
|
}
|
|
302
|
+
fs.ftruncateSync(fd, data.length);
|
|
303
|
+
fs.fsyncSync(fd);
|
|
304
|
+
run('systemctl', ['--user', 'daemon-reload']);
|
|
299
305
|
}
|
|
300
306
|
} finally {
|
|
301
307
|
fs.closeSync(fd);
|