@agentsoc/beacon 0.0.4 → 0.0.5

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 CHANGED
@@ -98,7 +98,7 @@ Install the background service daemon (systemd on Linux, launchd on macOS):
98
98
  sudo beacon install
99
99
  ```
100
100
 
101
- On macOS the plist is written under `/Library/LaunchDaemons/`, and on Linux the unit file goes under `/etc/systemd/system/`—both require root, so use `sudo`. If `sudo` cannot find `beacon` (for example with nvm), run `sudo env "PATH=$PATH" beacon install` or invoke the CLI with the full path to the global binary.
101
+ On macOS the plist is written under `/Library/LaunchDaemons/`, and on Linux the unit file goes under `/etc/systemd/system/`—both require root, so use `sudo`. The service is configured to **run as your login user** (via `SUDO_USER` when you use `sudo`), so it uses the same config directory as `beacon config`—not root’s home. If `sudo` cannot find `beacon` (for example with nvm), run `sudo env "PATH=$PATH" beacon install` or invoke the CLI with the full path to the global binary.
102
102
 
103
103
  ### Status and stats
104
104
 
@@ -110,7 +110,7 @@ beacon status
110
110
 
111
111
  Use `beacon status --json` for machine-readable output (includes `validateKeyUrl` on errors).
112
112
 
113
- After successful batches, the CLI updates **`stats.json`** next to your config (same config directory as `config.json`—for example `~/Library/Application Support/agentsoc-beacon/` on macOS). The file tracks `logsForwarded`, `batchesSucceeded`, `batchesFailed`, optional `lastError`, and `updatedAt`. If the beacon runs as another user (e.g. root), that user’s config directory holds the stats file.
113
+ After successful batches, the CLI updates **`stats.json`** next to your config (same config directory as `config.json`—for example `~/Library/Application Support/agentsoc-beacon/` on macOS). The file tracks `logsForwarded`, `batchesSucceeded`, `batchesFailed`, optional `lastError`, and `updatedAt`. The background service runs as the installing user (see Install Service above), so stats stay alongside your user config.
114
114
 
115
115
  The marketing site’s product demo terminal runs through **`beacon status`** so visitors can see a sample of this output.
116
116
 
@@ -1 +1 @@
1
- {"version":3,"file":"service-install.d.ts","sourceRoot":"","sources":["../src/service-install.ts"],"names":[],"mappings":"AA2GA,wBAAsB,cAAc,kBAuEnC"}
1
+ {"version":3,"file":"service-install.d.ts","sourceRoot":"","sources":["../src/service-install.ts"],"names":[],"mappings":"AA4IA,wBAAsB,cAAc,kBA4EnC"}
@@ -1,5 +1,6 @@
1
1
  import { constants as fsConstants } from 'node:fs';
2
2
  import fs from 'node:fs/promises';
3
+ import os from 'node:os';
3
4
  import path from 'node:path';
4
5
  import { execFileSync, execSync } from 'node:child_process';
5
6
  import { BEACON_CONFIG_REQUIRED_MESSAGE, loadConfig } from './config.js';
@@ -82,6 +83,35 @@ function launchctlBootoutSystem(plistPath, label) {
82
83
  // not loaded yet
83
84
  }
84
85
  }
86
+ /**
87
+ * Config and stats paths use os.homedir(). A LaunchDaemon/systemd unit runs as root by
88
+ * default, which points at /var/root (macOS) or /root — not the user who ran `beacon config`.
89
+ * Prefer SUDO_USER from `sudo`; otherwise the current login user when not root.
90
+ */
91
+ function resolveDaemonRunAsUsername() {
92
+ const sudoUser = process.env.SUDO_USER?.trim();
93
+ if (sudoUser) {
94
+ return sudoUser;
95
+ }
96
+ const uid = typeof process.getuid === 'function' ? process.getuid() : -1;
97
+ if (uid !== 0) {
98
+ try {
99
+ return os.userInfo().username;
100
+ }
101
+ catch {
102
+ // fall through
103
+ }
104
+ }
105
+ throw new Error('Cannot determine which user account should run the beacon daemon. ' +
106
+ 'Config is stored under that user\'s home directory. ' +
107
+ 'Run install from your normal account with sudo, e.g. `sudo beacon install`, not from a root-only shell.');
108
+ }
109
+ function escapePlistString(s) {
110
+ return s
111
+ .replace(/&/g, '&')
112
+ .replace(/</g, '&lt;')
113
+ .replace(/>/g, '&gt;');
114
+ }
85
115
  function launchctlBootstrapSystem(plistPath) {
86
116
  try {
87
117
  execFileSync('launchctl', ['bootstrap', 'system', plistPath], {
@@ -107,12 +137,14 @@ export async function installService() {
107
137
  const cliPath = path.resolve(process.argv[1]);
108
138
  const command = `${runner} ${cliPath} run`;
109
139
  if (process.platform === 'linux') {
140
+ const runAs = resolveDaemonRunAsUsername();
110
141
  const serviceUnit = `[Unit]
111
142
  Description=AgentSOC Syslog Beacon
112
143
  After=network.target
113
144
 
114
145
  [Service]
115
146
  Type=simple
147
+ User=${runAs}
116
148
  ExecStart=${command}
117
149
  Restart=always
118
150
  RestartSec=10
@@ -131,6 +163,7 @@ WantedBy=multi-user.target
131
163
  }
132
164
  else if (process.platform === 'darwin') {
133
165
  const label = 'com.agentsoc.syslog-beacon';
166
+ const runAs = escapePlistString(resolveDaemonRunAsUsername());
134
167
  const launchdRunner = resolveLaunchdRunner();
135
168
  const plist = `<?xml version="1.0" encoding="UTF-8"?>
136
169
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -138,6 +171,8 @@ WantedBy=multi-user.target
138
171
  <dict>
139
172
  <key>Label</key>
140
173
  <string>${label}</string>
174
+ <key>UserName</key>
175
+ <string>${runAs}</string>
141
176
  <key>ProgramArguments</key>
142
177
  <array>
143
178
  <string>${launchdRunner}</string>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentsoc/beacon",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "Lightweight, background-running log forwarder (beacon) for AgentSOC",
5
5
  "type": "module",
6
6
  "bin": {