@agentsoc/beacon 0.0.2 → 0.0.3
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 +27 -10
- package/dist/beacon-context.d.ts +14 -0
- package/dist/beacon-context.d.ts.map +1 -0
- package/dist/beacon-context.js +49 -0
- package/dist/beacon-update-info.d.ts +23 -0
- package/dist/beacon-update-info.d.ts.map +1 -0
- package/dist/beacon-update-info.js +62 -0
- package/dist/beacon-version.d.ts +5 -0
- package/dist/beacon-version.d.ts.map +1 -0
- package/dist/beacon-version.js +45 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +164 -31
- package/dist/config.d.ts +45 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +94 -0
- package/dist/enrich.d.ts +9 -0
- package/dist/enrich.d.ts.map +1 -0
- package/dist/forwarder.d.ts +20 -0
- package/dist/forwarder.d.ts.map +1 -0
- package/dist/run-beacon.d.ts +5 -0
- package/dist/run-beacon.d.ts.map +1 -0
- package/dist/service-install.d.ts +2 -0
- package/dist/service-install.d.ts.map +1 -0
- package/dist/service-install.js +4 -3
- package/dist/service-status.d.ts +11 -0
- package/dist/service-status.d.ts.map +1 -0
- package/dist/stats.d.ts +15 -0
- package/dist/stats.d.ts.map +1 -0
- package/dist/tail.d.ts +10 -0
- package/dist/tail.d.ts.map +1 -0
- package/package.json +22 -2
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ npm install -g .
|
|
|
39
39
|
Then use `beacon` / `syslog-beacon` like a normal global install:
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
|
-
beacon config --
|
|
42
|
+
beacon config --key <key> [--env production|development]
|
|
43
43
|
beacon run
|
|
44
44
|
```
|
|
45
45
|
|
|
@@ -52,21 +52,22 @@ The CLI provides the following commands:
|
|
|
52
52
|
Configure the AgentSOC connection (saves to a local configuration file):
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
|
-
beacon config --
|
|
55
|
+
beacon config --key <key> [--env production|development]
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
**
|
|
58
|
+
**Parameters:**
|
|
59
59
|
|
|
60
|
-
- `--
|
|
61
|
-
- `--
|
|
60
|
+
- `--key, -k <key>`: AgentSOC API Key (required; e.g., `sk_1234567890abcdef`)
|
|
61
|
+
- `--env, -e <env>`: `production` (default) or `development` — selects default URLs for **log ingest** and for **`beacon status`** (platform API). Production: ingest `https://ingest.agentsoc.com/api/v1/webhooks/syslog`, platform `https://api.agentsoc.com`. Development: ingest `http://localhost:8110/api/v1/webhooks/syslog`, platform `http://localhost:8100`.
|
|
62
62
|
|
|
63
|
-
**
|
|
63
|
+
**Examples:**
|
|
64
64
|
|
|
65
65
|
```bash
|
|
66
|
-
beacon config --
|
|
66
|
+
beacon config --key sk_1234567890abcdef
|
|
67
|
+
beacon config --key sk_1234567890abcdef --env development
|
|
67
68
|
```
|
|
68
69
|
|
|
69
|
-
**Note:** If you run `bun run src/cli.ts config` without
|
|
70
|
+
**Note:** If you run `bun run src/cli.ts config` without `--key`, you'll receive usage help. URLs are not set in `config.json` (use `--env` or `AGENTSOC_ENV`). At runtime you can override **ingest** with `AGENTSOC_INGEST_URL` and the **platform API** (for `beacon status` only) with `AGENTSOC_PLATFORM_URL` or `AGENTSOC_PLATFORM_API_BASE_URL`.
|
|
70
71
|
|
|
71
72
|
### Run Foreground Daemon
|
|
72
73
|
|
|
@@ -87,16 +88,32 @@ beacon run [options]
|
|
|
87
88
|
beacon run --batch-size 50 --flush-ms 5000
|
|
88
89
|
```
|
|
89
90
|
|
|
90
|
-
_Note: You can
|
|
91
|
+
_Note: You can use `AGENTSOC_API_KEY` instead of saving a key in config. Use `AGENTSOC_ENV` (`production` / `development`) to override the saved environment for a single run. `AGENTSOC_INGEST_URL` overrides log shipping only. For `beacon status`, the CLI calls `GET {platform}/api/v1/siem/beacon/validate/key` (default platform from env above); override the platform origin with `AGENTSOC_PLATFORM_URL` or `AGENTSOC_PLATFORM_API_BASE_URL` if ingest and API live on different hosts._
|
|
91
92
|
|
|
92
93
|
### Install Service
|
|
93
94
|
|
|
94
95
|
Install the background service daemon (systemd on Linux, launchd on macOS):
|
|
95
96
|
|
|
96
97
|
```bash
|
|
97
|
-
beacon install
|
|
98
|
+
sudo beacon install
|
|
99
|
+
```
|
|
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.
|
|
102
|
+
|
|
103
|
+
### Status and stats
|
|
104
|
+
|
|
105
|
+
Show whether the systemd/launchd service is present, resolve **organization name and API key label** via the platform API (`GET /api/v1/siem/beacon/validate/key` using your ingest key), and print forwarding counters from the local stats file:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
beacon status
|
|
98
109
|
```
|
|
99
110
|
|
|
111
|
+
Use `beacon status --json` for machine-readable output (includes `validateKeyUrl` on errors).
|
|
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.
|
|
114
|
+
|
|
115
|
+
The marketing site’s product demo terminal runs through **`beacon status`** so visitors can see a sample of this output.
|
|
116
|
+
|
|
100
117
|
## Development
|
|
101
118
|
|
|
102
119
|
- Start the daemon using npm script: `npm start` or `bun run start`
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface BeaconContextOk {
|
|
2
|
+
ok: true;
|
|
3
|
+
organizationName: string | null;
|
|
4
|
+
organizationSlug: string | null;
|
|
5
|
+
apiKeyName: string;
|
|
6
|
+
}
|
|
7
|
+
export interface BeaconContextErr {
|
|
8
|
+
ok: false;
|
|
9
|
+
message: string;
|
|
10
|
+
}
|
|
11
|
+
export type BeaconContextResult = BeaconContextOk | BeaconContextErr;
|
|
12
|
+
/** Calls platform `GET /api/v1/siem/beacon/validate/key` with the ingest API key. */
|
|
13
|
+
export declare function fetchBeaconContext(validateKeyUrl: string, apiKey: string): Promise<BeaconContextResult>;
|
|
14
|
+
//# sourceMappingURL=beacon-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beacon-context.d.ts","sourceRoot":"","sources":["../src/beacon-context.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,IAAI,CAAC;IACT,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,KAAK,CAAC;IACV,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,mBAAmB,GAAG,eAAe,GAAG,gBAAgB,CAAC;AAWrE,qFAAqF;AACrF,wBAAsB,kBAAkB,CACtC,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,mBAAmB,CAAC,CAgD9B"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** Calls platform `GET /api/v1/siem/beacon/validate/key` with the ingest API key. */
|
|
2
|
+
export async function fetchBeaconContext(validateKeyUrl, apiKey) {
|
|
3
|
+
const controller = new AbortController();
|
|
4
|
+
const t = setTimeout(() => controller.abort(), 12_000);
|
|
5
|
+
try {
|
|
6
|
+
const res = await fetch(validateKeyUrl, {
|
|
7
|
+
method: "GET",
|
|
8
|
+
headers: { "X-API-Key": apiKey },
|
|
9
|
+
signal: controller.signal,
|
|
10
|
+
});
|
|
11
|
+
const text = await res.text();
|
|
12
|
+
let body;
|
|
13
|
+
try {
|
|
14
|
+
body = text ? JSON.parse(text) : null;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return { ok: false, message: "Invalid response from platform API" };
|
|
18
|
+
}
|
|
19
|
+
if (!res.ok) {
|
|
20
|
+
const err = body;
|
|
21
|
+
const msg = err && typeof err.error === "string"
|
|
22
|
+
? err.error
|
|
23
|
+
: `HTTP ${res.status}`;
|
|
24
|
+
return { ok: false, message: msg };
|
|
25
|
+
}
|
|
26
|
+
const data = body;
|
|
27
|
+
if (!data?.success || !data.apiKey?.name) {
|
|
28
|
+
return { ok: false, message: "Unexpected response from platform API" };
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
ok: true,
|
|
32
|
+
organizationName: data.organization?.name ?? null,
|
|
33
|
+
organizationSlug: data.organization?.slug ?? null,
|
|
34
|
+
apiKeyName: data.apiKey.name,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
if (e instanceof Error && e.name === "AbortError") {
|
|
39
|
+
return { ok: false, message: "Request timed out" };
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
ok: false,
|
|
43
|
+
message: e instanceof Error ? e.message : String(e),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
clearTimeout(t);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type BeaconUpdateInfo = {
|
|
2
|
+
success: boolean;
|
|
3
|
+
package: string;
|
|
4
|
+
latestVersion: string | null;
|
|
5
|
+
registryResolved: boolean;
|
|
6
|
+
install: {
|
|
7
|
+
npm: string;
|
|
8
|
+
bun: string;
|
|
9
|
+
pnpm: string;
|
|
10
|
+
};
|
|
11
|
+
docsUrl: string;
|
|
12
|
+
installScriptUrl: string;
|
|
13
|
+
};
|
|
14
|
+
export type BeaconUpdateFetchResult = {
|
|
15
|
+
ok: true;
|
|
16
|
+
info: BeaconUpdateInfo;
|
|
17
|
+
} | {
|
|
18
|
+
ok: false;
|
|
19
|
+
message: string;
|
|
20
|
+
};
|
|
21
|
+
/** Latest @agentsoc/beacon version from the public npm registry (no AgentSOC API). */
|
|
22
|
+
export declare function fetchBeaconUpdateFromNpm(): Promise<BeaconUpdateFetchResult>;
|
|
23
|
+
//# sourceMappingURL=beacon-update-info.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beacon-update-info.d.ts","sourceRoot":"","sources":["../src/beacon-update-info.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAC/B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,gBAAgB,CAAA;CAAE,GACpC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAsBnC,sFAAsF;AACtF,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,uBAAuB,CAAC,CAyCjF"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const BEACON_PACKAGE = "@agentsoc/beacon";
|
|
2
|
+
const NPM_REGISTRY_URL = `https://registry.npmjs.org/${encodeURIComponent(BEACON_PACKAGE)}`;
|
|
3
|
+
const DOC_URL = "https://agentsoc.com/products/agentsoc-beacon";
|
|
4
|
+
const INSTALL_SCRIPT_URL = "https://agentsoc.com/connectors/beacon.sh";
|
|
5
|
+
function buildInfo(latestVersion, registryResolved) {
|
|
6
|
+
return {
|
|
7
|
+
success: true,
|
|
8
|
+
package: BEACON_PACKAGE,
|
|
9
|
+
latestVersion,
|
|
10
|
+
registryResolved,
|
|
11
|
+
install: {
|
|
12
|
+
npm: `npm install -g ${BEACON_PACKAGE}@latest`,
|
|
13
|
+
bun: `bun add -g ${BEACON_PACKAGE}@latest`,
|
|
14
|
+
pnpm: `pnpm add -g ${BEACON_PACKAGE}@latest`,
|
|
15
|
+
},
|
|
16
|
+
docsUrl: DOC_URL,
|
|
17
|
+
installScriptUrl: INSTALL_SCRIPT_URL,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** Latest @agentsoc/beacon version from the public npm registry (no AgentSOC API). */
|
|
21
|
+
export async function fetchBeaconUpdateFromNpm() {
|
|
22
|
+
const controller = new AbortController();
|
|
23
|
+
const t = setTimeout(() => controller.abort(), 12_000);
|
|
24
|
+
try {
|
|
25
|
+
const res = await fetch(NPM_REGISTRY_URL, {
|
|
26
|
+
headers: { Accept: "application/json" },
|
|
27
|
+
signal: controller.signal,
|
|
28
|
+
});
|
|
29
|
+
const text = await res.text();
|
|
30
|
+
let body;
|
|
31
|
+
try {
|
|
32
|
+
body = text ? JSON.parse(text) : null;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return { ok: false, message: "Invalid JSON from registry.npmjs.org" };
|
|
36
|
+
}
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
return {
|
|
39
|
+
ok: false,
|
|
40
|
+
message: `registry.npmjs.org returned HTTP ${res.status}`,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const data = body;
|
|
44
|
+
const latest = data["dist-tags"]?.latest?.trim() ?? null;
|
|
45
|
+
return {
|
|
46
|
+
ok: true,
|
|
47
|
+
info: buildInfo(latest, true),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
if (e instanceof Error && e.name === "AbortError") {
|
|
52
|
+
return { ok: false, message: "Request timed out" };
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
ok: false,
|
|
56
|
+
message: e instanceof Error ? e.message : String(e),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
clearTimeout(t);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Resolve @agentsoc/beacon version from the installed package.json (works for global npm install). */
|
|
2
|
+
export declare function readBeaconCliVersion(): string;
|
|
3
|
+
/** Simple semver compare for numeric x.y.z (ignores prerelease tail for ordering). */
|
|
4
|
+
export declare function semverLessThan(a: string, b: string): boolean;
|
|
5
|
+
//# sourceMappingURL=beacon-version.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beacon-version.d.ts","sourceRoot":"","sources":["../src/beacon-version.ts"],"names":[],"mappings":"AAIA,uGAAuG;AACvG,wBAAgB,oBAAoB,IAAI,MAAM,CAsB7C;AAOD,sFAAsF;AACtF,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAW5D"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
/** Resolve @agentsoc/beacon version from the installed package.json (works for global npm install). */
|
|
5
|
+
export function readBeaconCliVersion() {
|
|
6
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
for (let i = 0; i < 8; i++) {
|
|
8
|
+
const pkgPath = join(dir, "package.json");
|
|
9
|
+
if (existsSync(pkgPath)) {
|
|
10
|
+
try {
|
|
11
|
+
const j = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
12
|
+
if (j.name === "@agentsoc/beacon" && typeof j.version === "string") {
|
|
13
|
+
return j.version;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
/* try parent */
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const parent = dirname(dir);
|
|
21
|
+
if (parent === dir)
|
|
22
|
+
break;
|
|
23
|
+
dir = parent;
|
|
24
|
+
}
|
|
25
|
+
return "0.0.0";
|
|
26
|
+
}
|
|
27
|
+
function stripPrerelease(v) {
|
|
28
|
+
const i = v.indexOf("-");
|
|
29
|
+
return i === -1 ? v : v.slice(0, i);
|
|
30
|
+
}
|
|
31
|
+
/** Simple semver compare for numeric x.y.z (ignores prerelease tail for ordering). */
|
|
32
|
+
export function semverLessThan(a, b) {
|
|
33
|
+
const pa = stripPrerelease(a).split(".").map((x) => parseInt(x, 10) || 0);
|
|
34
|
+
const pb = stripPrerelease(b).split(".").map((x) => parseInt(x, 10) || 0);
|
|
35
|
+
const n = Math.max(pa.length, pb.length);
|
|
36
|
+
for (let i = 0; i < n; i++) {
|
|
37
|
+
const da = pa[i] ?? 0;
|
|
38
|
+
const db = pb[i] ?? 0;
|
|
39
|
+
if (da < db)
|
|
40
|
+
return true;
|
|
41
|
+
if (da > db)
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
CHANGED
|
@@ -1,37 +1,56 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
2
3
|
import { Command } from "commander";
|
|
3
|
-
import { loadConfig, saveConfig } from "./config.js";
|
|
4
|
+
import { BEACON_CONFIG_REQUIRED_MESSAGE, coerceBeaconEnvironment, loadConfig, parseBeaconEnvironment, resolveBeaconApiKey, resolveSiemBeaconValidateKeyUrl, resolveIngestUrl, saveConfig, } from "./config.js";
|
|
5
|
+
import { fetchBeaconContext } from "./beacon-context.js";
|
|
6
|
+
import { fetchBeaconUpdateFromNpm } from "./beacon-update-info.js";
|
|
7
|
+
import { readBeaconCliVersion, semverLessThan } from "./beacon-version.js";
|
|
4
8
|
import { runBeacon } from "./run-beacon.js";
|
|
5
9
|
import { installService } from "./service-install.js";
|
|
6
10
|
import { probeServiceStatus } from "./service-status.js";
|
|
7
11
|
import { getStatsFilePath, readStats } from "./stats.js";
|
|
12
|
+
const BEACON_VERSION = readBeaconCliVersion();
|
|
8
13
|
const program = new Command();
|
|
9
14
|
program
|
|
10
15
|
.name("beacon")
|
|
11
16
|
.description("AgentSOC Syslog Beacon - Lightweight background log forwarder")
|
|
12
|
-
.version(
|
|
17
|
+
.version(BEACON_VERSION, "-v, --version");
|
|
13
18
|
program
|
|
14
19
|
.command("config")
|
|
15
20
|
.description("Configure the AgentSOC connection")
|
|
16
|
-
.option("-
|
|
21
|
+
.option("-e, --env <env>", "Environment: production (default) or development")
|
|
17
22
|
.option("-k, --key <key>", "AgentSOC API Key")
|
|
18
23
|
.action(async (options) => {
|
|
19
|
-
if (!options.
|
|
20
|
-
console.log("\n[beacon] Missing required
|
|
21
|
-
console.log("Usage: beacon config --
|
|
24
|
+
if (!options.key) {
|
|
25
|
+
console.log("\n[beacon] Missing required option.\n");
|
|
26
|
+
console.log("Usage: beacon config --key <key> [--env production|development]\n");
|
|
22
27
|
console.log("Examples:");
|
|
23
|
-
console.log("
|
|
24
|
-
console.log(" beacon config --
|
|
28
|
+
console.log(" beacon config --key sk_1234567890abcdef");
|
|
29
|
+
console.log(" beacon config --key sk_1234567890abcdef --env development\n");
|
|
25
30
|
console.log("Options:");
|
|
26
|
-
console.log(" -
|
|
27
|
-
console.log(" -
|
|
31
|
+
console.log(" -k, --key <key> AgentSOC API Key (required)");
|
|
32
|
+
console.log(" -e, --env <env> production (default) or development; sets ingest + platform API defaults\n");
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
const existing = await loadConfig();
|
|
36
|
+
let environment;
|
|
37
|
+
try {
|
|
38
|
+
environment =
|
|
39
|
+
options.env !== undefined
|
|
40
|
+
? parseBeaconEnvironment(options.env)
|
|
41
|
+
: (coerceBeaconEnvironment(existing.environment) ?? "production");
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
console.error("[beacon]", e instanceof Error ? e.message : String(e));
|
|
28
45
|
process.exit(1);
|
|
29
46
|
}
|
|
30
47
|
await saveConfig({
|
|
31
|
-
ingestUrl: options.url,
|
|
32
48
|
apiKey: options.key,
|
|
49
|
+
environment,
|
|
50
|
+
agentId: existing.agentId,
|
|
33
51
|
});
|
|
34
52
|
console.log("[beacon] Config saved.");
|
|
53
|
+
console.log(`[beacon] Environment: ${environment}`);
|
|
35
54
|
});
|
|
36
55
|
program
|
|
37
56
|
.command("install")
|
|
@@ -48,35 +67,149 @@ program
|
|
|
48
67
|
program
|
|
49
68
|
.command("status")
|
|
50
69
|
.description("Show service state and forwarding statistics")
|
|
51
|
-
.
|
|
70
|
+
.option("--json", "Print machine-readable JSON on stdout")
|
|
71
|
+
.action(async (opts) => {
|
|
52
72
|
const svc = probeServiceStatus();
|
|
53
73
|
const stats = await readStats();
|
|
54
74
|
const statsPath = getStatsFilePath();
|
|
55
|
-
|
|
56
|
-
|
|
75
|
+
const cfg = await loadConfig();
|
|
76
|
+
const apiKey = resolveBeaconApiKey(cfg);
|
|
77
|
+
const validateKeyUrl = resolveSiemBeaconValidateKeyUrl(cfg);
|
|
78
|
+
const context = apiKey
|
|
79
|
+
? await fetchBeaconContext(validateKeyUrl, apiKey)
|
|
80
|
+
: ({
|
|
81
|
+
ok: false,
|
|
82
|
+
message: BEACON_CONFIG_REQUIRED_MESSAGE,
|
|
83
|
+
});
|
|
84
|
+
if (opts.json) {
|
|
85
|
+
console.log(JSON.stringify({
|
|
86
|
+
service: svc,
|
|
87
|
+
stats,
|
|
88
|
+
statsPath,
|
|
89
|
+
validateKeyUrl,
|
|
90
|
+
context: context.ok
|
|
91
|
+
? {
|
|
92
|
+
organizationName: context.organizationName,
|
|
93
|
+
organizationSlug: context.organizationSlug,
|
|
94
|
+
apiKeyName: context.apiKeyName,
|
|
95
|
+
}
|
|
96
|
+
: { error: context.message },
|
|
97
|
+
}, null, 2));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const labelW = 26;
|
|
101
|
+
const line = (label, value) => {
|
|
102
|
+
console.log(` ${label.padEnd(labelW)}${value}`);
|
|
103
|
+
};
|
|
104
|
+
console.log("\n AgentSOC Beacon — Status\n");
|
|
105
|
+
console.log(" Account");
|
|
106
|
+
if (context.ok) {
|
|
107
|
+
line("Organization", context.organizationName ??
|
|
108
|
+
"(name unavailable — check platform API / database)");
|
|
109
|
+
line("API key", context.apiKeyName);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
line("Connection", context.message);
|
|
113
|
+
}
|
|
114
|
+
console.log("\n Service");
|
|
115
|
+
line(`Daemon (${svc.manager})`, svc.installed ? svc.stateLabel : "not installed");
|
|
57
116
|
if (svc.active === true)
|
|
58
|
-
|
|
117
|
+
line("Running", "yes");
|
|
59
118
|
else if (svc.active === false)
|
|
60
|
-
|
|
119
|
+
line("Running", "no");
|
|
61
120
|
else
|
|
62
|
-
|
|
121
|
+
line("Running", "n/a");
|
|
63
122
|
if (svc.detail)
|
|
64
|
-
|
|
65
|
-
console.log("\n Forwarding (
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
console.log(` Failed batches: ${stats.batchesFailed}`);
|
|
123
|
+
line("Note", svc.detail);
|
|
124
|
+
console.log("\n Forwarding (this machine)");
|
|
125
|
+
line("Log entries forwarded", String(stats.logsForwarded));
|
|
126
|
+
line("Successful batches", String(stats.batchesSucceeded));
|
|
127
|
+
line("Failed batches", String(stats.batchesFailed));
|
|
70
128
|
if (stats.updatedAt && stats.updatedAt !== new Date(0).toISOString()) {
|
|
71
|
-
|
|
129
|
+
line("Last stats update", stats.updatedAt);
|
|
72
130
|
}
|
|
73
131
|
else {
|
|
74
|
-
|
|
132
|
+
line("Last stats update", "(none yet)");
|
|
75
133
|
}
|
|
76
134
|
if (stats.lastError) {
|
|
77
|
-
|
|
135
|
+
line("Last error", stats.lastError);
|
|
136
|
+
}
|
|
137
|
+
console.log();
|
|
138
|
+
});
|
|
139
|
+
program
|
|
140
|
+
.command("update")
|
|
141
|
+
.description("Check for a newer Beacon CLI and optionally install it")
|
|
142
|
+
.option("--json", "Print machine-readable JSON on stdout")
|
|
143
|
+
.option("-y, --yes", "Run npm install -g @agentsoc/beacon@latest (non-interactive upgrade)")
|
|
144
|
+
.action(async (opts) => {
|
|
145
|
+
const current = BEACON_VERSION;
|
|
146
|
+
const fetched = await fetchBeaconUpdateFromNpm();
|
|
147
|
+
if (opts.json) {
|
|
148
|
+
const latest = fetched.ok ? fetched.info.latestVersion : null;
|
|
149
|
+
const outdated = latest != null &&
|
|
150
|
+
latest.length > 0 &&
|
|
151
|
+
semverLessThan(current, latest);
|
|
152
|
+
console.log(JSON.stringify({
|
|
153
|
+
currentVersion: current,
|
|
154
|
+
registry: "https://registry.npmjs.org/@agentsoc%2fbeacon",
|
|
155
|
+
remote: fetched.ok ? fetched.info : null,
|
|
156
|
+
error: fetched.ok ? undefined : fetched.message,
|
|
157
|
+
updateAvailable: fetched.ok ? outdated : null,
|
|
158
|
+
}, null, 2));
|
|
159
|
+
if (!fetched.ok)
|
|
160
|
+
process.exit(1);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (!fetched.ok) {
|
|
164
|
+
console.error(`[beacon] Could not reach npm registry: ${fetched.message}`);
|
|
165
|
+
console.error("[beacon] You can still run: npm install -g @agentsoc/beacon@latest");
|
|
166
|
+
process.exit(1);
|
|
167
|
+
}
|
|
168
|
+
const { info } = fetched;
|
|
169
|
+
const latest = info.latestVersion;
|
|
170
|
+
console.log("\n AgentSOC Beacon — Update check\n");
|
|
171
|
+
console.log(` This install ${current}`);
|
|
172
|
+
if (latest) {
|
|
173
|
+
console.log(` Latest on registry ${latest}`);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
console.log(" Latest on registry (unavailable — unexpected npm response)");
|
|
177
|
+
}
|
|
178
|
+
const canCompare = Boolean(latest && latest.length > 0);
|
|
179
|
+
const outdated = canCompare && semverLessThan(current, latest);
|
|
180
|
+
if (canCompare && !outdated) {
|
|
181
|
+
console.log("\n You are on the latest published version.\n");
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (canCompare && outdated) {
|
|
185
|
+
console.log("\n A newer version is available.\n");
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
console.log("\n Compare versions manually, or reinstall with:\n");
|
|
189
|
+
}
|
|
190
|
+
console.log(` ${info.install.npm}`);
|
|
191
|
+
console.log(` ${info.install.bun}`);
|
|
192
|
+
console.log(` ${info.install.pnpm}`);
|
|
193
|
+
if (info.docsUrl) {
|
|
194
|
+
console.log(`\n Docs: ${info.docsUrl}`);
|
|
195
|
+
}
|
|
196
|
+
if (opts.yes) {
|
|
197
|
+
if (!outdated && canCompare) {
|
|
198
|
+
console.log("\n[beacon] Already up to date — skipping install.\n");
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
console.log("\n[beacon] Running npm install -g @agentsoc/beacon@latest …\n");
|
|
202
|
+
const npm = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
203
|
+
try {
|
|
204
|
+
execFileSync(npm, ["install", "-g", "@agentsoc/beacon@latest"], { stdio: "inherit", env: process.env });
|
|
205
|
+
console.log("\n[beacon] Update finished. Run `beacon --version` to verify.\n");
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
process.exit(1);
|
|
209
|
+
}
|
|
210
|
+
return;
|
|
78
211
|
}
|
|
79
|
-
console.log("\n
|
|
212
|
+
console.log("\n To upgrade now, run the same command with --yes\n");
|
|
80
213
|
});
|
|
81
214
|
program
|
|
82
215
|
.command("run")
|
|
@@ -85,10 +218,10 @@ program
|
|
|
85
218
|
.option("--flush-ms <n>", "Flush interval in ms", "2000")
|
|
86
219
|
.action(async (options) => {
|
|
87
220
|
const config = await loadConfig();
|
|
88
|
-
const apiKey =
|
|
89
|
-
const ingestUrl =
|
|
90
|
-
if (!apiKey
|
|
91
|
-
console.error(
|
|
221
|
+
const apiKey = resolveBeaconApiKey(config);
|
|
222
|
+
const ingestUrl = resolveIngestUrl(config);
|
|
223
|
+
if (!apiKey) {
|
|
224
|
+
console.error(`[beacon] ${BEACON_CONFIG_REQUIRED_MESSAGE}`);
|
|
92
225
|
process.exit(1);
|
|
93
226
|
}
|
|
94
227
|
console.log("[beacon] Starting in foreground...");
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export declare const INGEST_URL_PRODUCTION = "https://ingest.agentsoc.com/api/v1/webhooks/syslog";
|
|
2
|
+
export declare const INGEST_URL_DEVELOPMENT = "http://localhost:8110/api/v1/webhooks/syslog";
|
|
3
|
+
/** Platform API (for `beacon status` key validation — not log ingest). */
|
|
4
|
+
export declare const PLATFORM_API_PRODUCTION = "https://api.agentsoc.com";
|
|
5
|
+
export declare const PLATFORM_API_DEVELOPMENT = "http://localhost:8100";
|
|
6
|
+
/** Path on the platform API for SIEM ingest key validation (`beacon status`). */
|
|
7
|
+
export declare const SIEM_BEACON_VALIDATE_KEY_PATH = "/api/v1/siem/beacon/validate/key";
|
|
8
|
+
export type BeaconEnvironment = "production" | "development";
|
|
9
|
+
/** API key from saved config or process environment (trimmed). */
|
|
10
|
+
export declare function resolveBeaconApiKey(config: BeaconConfig): string | undefined;
|
|
11
|
+
/** Shown when run/install needs a key and none is configured. */
|
|
12
|
+
export declare const BEACON_CONFIG_REQUIRED_MESSAGE = "Beacon is not configured. Run: beacon config --key <your-api-key> [--env production|development]. Or set AGENTSOC_API_KEY in your environment.";
|
|
13
|
+
export interface BeaconConfig {
|
|
14
|
+
apiKey?: string;
|
|
15
|
+
/** @deprecated Resolved from environment; not set by the CLI */
|
|
16
|
+
ingestUrl?: string;
|
|
17
|
+
/** Defaults to production when omitted */
|
|
18
|
+
environment?: BeaconEnvironment;
|
|
19
|
+
agentId?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function parseBeaconEnvironment(input: string): BeaconEnvironment;
|
|
22
|
+
export declare function coerceBeaconEnvironment(value: unknown): BeaconEnvironment | undefined;
|
|
23
|
+
export declare function ingestUrlForEnvironment(env: BeaconEnvironment): string;
|
|
24
|
+
export declare function effectiveEnvironment(config: BeaconConfig): BeaconEnvironment;
|
|
25
|
+
/**
|
|
26
|
+
* Ingest URL used at runtime. Optional AGENTSOC_INGEST_URL overrides (legacy
|
|
27
|
+
* / advanced); otherwise derived from AGENTSOC_ENV or saved environment.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveIngestUrl(config: BeaconConfig): string;
|
|
30
|
+
/**
|
|
31
|
+
* Platform API origin (no trailing slash).
|
|
32
|
+
* Override with `AGENTSOC_PLATFORM_URL` or `AGENTSOC_PLATFORM_API_BASE_URL`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function resolvePlatformApiBase(config: BeaconConfig): string;
|
|
35
|
+
/**
|
|
36
|
+
* Full URL for `GET …/siem/beacon/validate/key` (organization + API key label for `beacon status`).
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolveSiemBeaconValidateKeyUrl(config: BeaconConfig): string;
|
|
39
|
+
/** @deprecated Use {@link resolveSiemBeaconValidateKeyUrl} */
|
|
40
|
+
export declare function resolveBeaconContextUrl(config: BeaconConfig): string;
|
|
41
|
+
export declare function getConfigDir(): string;
|
|
42
|
+
export declare function getConfigFile(): string;
|
|
43
|
+
export declare function loadConfig(): Promise<BeaconConfig>;
|
|
44
|
+
export declare function saveConfig(config: BeaconConfig): Promise<void>;
|
|
45
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,qBAAqB,uDACoB,CAAC;AAEvD,eAAO,MAAM,sBAAsB,iDACa,CAAC;AAEjD,0EAA0E;AAC1E,eAAO,MAAM,uBAAuB,6BAA6B,CAAC;AAElE,eAAO,MAAM,wBAAwB,0BAA0B,CAAC;AAEhE,iFAAiF;AACjF,eAAO,MAAM,6BAA6B,qCACN,CAAC;AAErC,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,aAAa,CAAC;AAE7D,kEAAkE;AAClE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAK5E;AAED,iEAAiE;AACjE,eAAO,MAAM,8BAA8B,mJACuG,CAAC;AAEnJ,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,CAOvE;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,GACb,iBAAiB,GAAG,SAAS,CAU/B;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,iBAAiB,GAAG,MAAM,CAItE;AAmBD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,GAAG,iBAAiB,CAM5E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAI7D;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAMnE;AAED;;GAEG;AACH,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,YAAY,GACnB,MAAM,CAER;AAED,8DAA8D;AAC9D,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAEpE;AAED,wBAAgB,YAAY,IAAI,MAAM,CAarC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,YAAY,CAAC,CAQxD;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAepE"}
|
package/dist/config.js
CHANGED
|
@@ -1,6 +1,100 @@
|
|
|
1
1
|
import os from "node:os";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
|
+
export const INGEST_URL_PRODUCTION = "https://ingest.agentsoc.com/api/v1/webhooks/syslog";
|
|
5
|
+
export const INGEST_URL_DEVELOPMENT = "http://localhost:8110/api/v1/webhooks/syslog";
|
|
6
|
+
/** Platform API (for `beacon status` key validation — not log ingest). */
|
|
7
|
+
export const PLATFORM_API_PRODUCTION = "https://api.agentsoc.com";
|
|
8
|
+
export const PLATFORM_API_DEVELOPMENT = "http://localhost:8100";
|
|
9
|
+
/** Path on the platform API for SIEM ingest key validation (`beacon status`). */
|
|
10
|
+
export const SIEM_BEACON_VALIDATE_KEY_PATH = "/api/v1/siem/beacon/validate/key";
|
|
11
|
+
/** API key from saved config or process environment (trimmed). */
|
|
12
|
+
export function resolveBeaconApiKey(config) {
|
|
13
|
+
const fromEnv = process.env.AGENTSOC_API_KEY?.trim();
|
|
14
|
+
if (fromEnv)
|
|
15
|
+
return fromEnv;
|
|
16
|
+
const fromFile = config.apiKey?.trim();
|
|
17
|
+
return fromFile || undefined;
|
|
18
|
+
}
|
|
19
|
+
/** Shown when run/install needs a key and none is configured. */
|
|
20
|
+
export const BEACON_CONFIG_REQUIRED_MESSAGE = "Beacon is not configured. Run: beacon config --key <your-api-key> [--env production|development]. Or set AGENTSOC_API_KEY in your environment.";
|
|
21
|
+
export function parseBeaconEnvironment(input) {
|
|
22
|
+
const s = input.toLowerCase().trim();
|
|
23
|
+
if (s === "production" || s === "prod")
|
|
24
|
+
return "production";
|
|
25
|
+
if (s === "development" || s === "dev")
|
|
26
|
+
return "development";
|
|
27
|
+
throw new Error(`Invalid environment "${input}". Use production or development (prod / dev).`);
|
|
28
|
+
}
|
|
29
|
+
export function coerceBeaconEnvironment(value) {
|
|
30
|
+
if (value === "production" || value === "development")
|
|
31
|
+
return value;
|
|
32
|
+
if (typeof value === "string") {
|
|
33
|
+
try {
|
|
34
|
+
return parseBeaconEnvironment(value);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
export function ingestUrlForEnvironment(env) {
|
|
43
|
+
return env === "development"
|
|
44
|
+
? INGEST_URL_DEVELOPMENT
|
|
45
|
+
: INGEST_URL_PRODUCTION;
|
|
46
|
+
}
|
|
47
|
+
function platformApiBaseForEnvironment(env) {
|
|
48
|
+
return env === "development" ? PLATFORM_API_DEVELOPMENT : PLATFORM_API_PRODUCTION;
|
|
49
|
+
}
|
|
50
|
+
function environmentFromProcessEnv() {
|
|
51
|
+
const raw = process.env.AGENTSOC_ENV?.trim();
|
|
52
|
+
if (!raw)
|
|
53
|
+
return undefined;
|
|
54
|
+
try {
|
|
55
|
+
return parseBeaconEnvironment(raw);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
console.warn(`[beacon] Ignoring invalid AGENTSOC_ENV="${raw}" (use production or development).`);
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export function effectiveEnvironment(config) {
|
|
63
|
+
return (environmentFromProcessEnv() ??
|
|
64
|
+
coerceBeaconEnvironment(config.environment) ??
|
|
65
|
+
"production");
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Ingest URL used at runtime. Optional AGENTSOC_INGEST_URL overrides (legacy
|
|
69
|
+
* / advanced); otherwise derived from AGENTSOC_ENV or saved environment.
|
|
70
|
+
*/
|
|
71
|
+
export function resolveIngestUrl(config) {
|
|
72
|
+
const override = process.env.AGENTSOC_INGEST_URL?.trim();
|
|
73
|
+
if (override)
|
|
74
|
+
return override;
|
|
75
|
+
return ingestUrlForEnvironment(effectiveEnvironment(config));
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Platform API origin (no trailing slash).
|
|
79
|
+
* Override with `AGENTSOC_PLATFORM_URL` or `AGENTSOC_PLATFORM_API_BASE_URL`.
|
|
80
|
+
*/
|
|
81
|
+
export function resolvePlatformApiBase(config) {
|
|
82
|
+
const override = process.env.AGENTSOC_PLATFORM_URL?.trim() ||
|
|
83
|
+
process.env.AGENTSOC_PLATFORM_API_BASE_URL?.trim();
|
|
84
|
+
if (override)
|
|
85
|
+
return override.replace(/\/$/, "");
|
|
86
|
+
return platformApiBaseForEnvironment(effectiveEnvironment(config));
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Full URL for `GET …/siem/beacon/validate/key` (organization + API key label for `beacon status`).
|
|
90
|
+
*/
|
|
91
|
+
export function resolveSiemBeaconValidateKeyUrl(config) {
|
|
92
|
+
return `${resolvePlatformApiBase(config)}${SIEM_BEACON_VALIDATE_KEY_PATH}`;
|
|
93
|
+
}
|
|
94
|
+
/** @deprecated Use {@link resolveSiemBeaconValidateKeyUrl} */
|
|
95
|
+
export function resolveBeaconContextUrl(config) {
|
|
96
|
+
return resolveSiemBeaconValidateKeyUrl(config);
|
|
97
|
+
}
|
|
4
98
|
export function getConfigDir() {
|
|
5
99
|
const home = os.homedir();
|
|
6
100
|
if (process.platform === "win32") {
|
package/dist/enrich.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enrich.d.ts","sourceRoot":"","sources":["../src/enrich.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,QAAQ,CAAC,CA8BrD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { HostInfo } from "./enrich.js";
|
|
2
|
+
export interface ForwarderOptions {
|
|
3
|
+
ingestUrl: string;
|
|
4
|
+
apiKey: string;
|
|
5
|
+
batchSize?: number;
|
|
6
|
+
flushMs?: number;
|
|
7
|
+
host: HostInfo;
|
|
8
|
+
}
|
|
9
|
+
export declare class Forwarder {
|
|
10
|
+
private opts;
|
|
11
|
+
private buffer;
|
|
12
|
+
private timer;
|
|
13
|
+
private readonly batchSize;
|
|
14
|
+
private readonly flushMs;
|
|
15
|
+
constructor(opts: ForwarderOptions);
|
|
16
|
+
pushLog(line: string): void;
|
|
17
|
+
private flush;
|
|
18
|
+
stop(): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=forwarder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forwarder.d.ts","sourceRoot":"","sources":["../src/forwarder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,QAAQ,CAAC;CAChB;AA6ED,qBAAa,SAAS;IAMR,OAAO,CAAC,IAAI;IALxB,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAEb,IAAI,EAAE,gBAAgB;IAKnC,OAAO,CAAC,IAAI,EAAE,MAAM;YAoCb,KAAK;IA4CN,IAAI;CAKlB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-beacon.d.ts","sourceRoot":"","sources":["../src/run-beacon.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAG7D,wBAAsB,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC;;GAiBnE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-install.d.ts","sourceRoot":"","sources":["../src/service-install.ts"],"names":[],"mappings":"AAKA,wBAAsB,cAAc,kBAgEnC"}
|
package/dist/service-install.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { execSync } from 'node:child_process';
|
|
4
|
-
import { loadConfig } from './config.js';
|
|
4
|
+
import { BEACON_CONFIG_REQUIRED_MESSAGE, loadConfig } from './config.js';
|
|
5
5
|
export async function installService() {
|
|
6
6
|
const config = await loadConfig();
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
// Service units do not inherit the install shell's env — key must be saved in config.
|
|
8
|
+
if (!config.apiKey?.trim()) {
|
|
9
|
+
throw new Error(BEACON_CONFIG_REQUIRED_MESSAGE);
|
|
9
10
|
}
|
|
10
11
|
const isBun = process.execPath.endsWith('bun') || process.execPath.endsWith('bun.exe');
|
|
11
12
|
const runner = isBun ? process.execPath : 'node';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type ServiceManager = "systemd" | "launchd" | "none";
|
|
2
|
+
export interface ServiceStatus {
|
|
3
|
+
manager: ServiceManager;
|
|
4
|
+
installed: boolean;
|
|
5
|
+
active: boolean | null;
|
|
6
|
+
/** Human-readable state from the platform (e.g. active, inactive, running) */
|
|
7
|
+
stateLabel: string;
|
|
8
|
+
detail?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function probeServiceStatus(): ServiceStatus;
|
|
11
|
+
//# sourceMappingURL=service-status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-status.d.ts","sourceRoot":"","sources":["../src/service-status.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;AAE5D,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,cAAc,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IACvB,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAOD,wBAAgB,kBAAkB,IAAI,aAAa,CA4FlD"}
|
package/dist/stats.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
declare const STATS_VERSION: 1;
|
|
2
|
+
export interface BeaconStatsFile {
|
|
3
|
+
version: typeof STATS_VERSION;
|
|
4
|
+
updatedAt: string;
|
|
5
|
+
logsForwarded: number;
|
|
6
|
+
batchesSucceeded: number;
|
|
7
|
+
batchesFailed: number;
|
|
8
|
+
lastError?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function getStatsFilePath(): string;
|
|
11
|
+
export declare function readStats(): Promise<BeaconStatsFile>;
|
|
12
|
+
export declare function recordSuccessfulBatch(logCount: number): Promise<void>;
|
|
13
|
+
export declare function recordFailedBatch(message: string): Promise<void>;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=stats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../src/stats.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,aAAa,EAAG,CAAU,CAAC;AAEjC,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,aAAa,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAUD,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,eAAe,CAAC,CAa1D;AAWD,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAc3E;AAED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAetE"}
|
package/dist/tail.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tail.d.ts","sourceRoot":"","sources":["../src/tail.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;AAEjD,qBAAa,YAAY;IAIX,OAAO,CAAC,KAAK;IAHzB,OAAO,CAAC,QAAQ,CAAC,CAAe;IAChC,OAAO,CAAC,SAAS,CAAC,CAAe;gBAEb,KAAK,EAAE,WAAW;IAE/B,KAAK;IAkDL,IAAI;CAQZ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentsoc/beacon",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Lightweight, background-running log forwarder (beacon) for AgentSOC",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,11 +8,31 @@
|
|
|
8
8
|
"syslog-beacon": "./dist/cli.js"
|
|
9
9
|
},
|
|
10
10
|
"main": "./dist/cli.js",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": "./dist/cli.js",
|
|
13
|
+
"./package.json": "./package.json",
|
|
14
|
+
"./config": {
|
|
15
|
+
"types": "./dist/config.d.ts",
|
|
16
|
+
"import": "./dist/config.js"
|
|
17
|
+
},
|
|
18
|
+
"./stats": {
|
|
19
|
+
"types": "./dist/stats.d.ts",
|
|
20
|
+
"import": "./dist/stats.js"
|
|
21
|
+
},
|
|
22
|
+
"./service-status": {
|
|
23
|
+
"types": "./dist/service-status.d.ts",
|
|
24
|
+
"import": "./dist/service-status.js"
|
|
25
|
+
},
|
|
26
|
+
"./service-install": {
|
|
27
|
+
"types": "./dist/service-install.d.ts",
|
|
28
|
+
"import": "./dist/service-install.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
11
31
|
"files": [
|
|
12
32
|
"dist"
|
|
13
33
|
],
|
|
14
34
|
"scripts": {
|
|
15
|
-
"build": "bun run --cwd ../../.. bun build --target
|
|
35
|
+
"build": "bun run --cwd ../../.. bun build --target node --entry-points ./apps/connectors/syslog-beacon-cli/src/cli.ts --outdir ./apps/connectors/syslog-beacon-cli/dist --minify",
|
|
16
36
|
"build:simple": "tsc",
|
|
17
37
|
"start": "bun run src/cli.ts run",
|
|
18
38
|
"install-service": "bun run src/cli.ts install"
|