@shield-agent/kya 0.33.6 → 0.35.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/.cursor-plugin/plugin.json +2 -2
- package/.mcp.json +1 -1
- package/LIMITATIONS.md +2 -1
- package/README.md +39 -640
- package/amp/settings.example.json +1 -1
- package/assets/report-blocked.png +0 -0
- package/assets/report-certify.png +0 -0
- package/assets/report-overview.png +0 -0
- package/assets/screenshot-features.json +18 -0
- package/claude/claude_desktop_config.example.json +1 -1
- package/cline/cline_mcp_settings.example.json +1 -1
- package/copilot/mcp-config.example.json +1 -1
- package/dist/alerts/config.d.ts +22 -0
- package/dist/alerts/config.d.ts.map +1 -0
- package/dist/alerts/config.js +59 -0
- package/dist/alerts/config.js.map +1 -0
- package/dist/alerts/constants.d.ts +5 -0
- package/dist/alerts/constants.d.ts.map +1 -0
- package/dist/alerts/constants.js +5 -0
- package/dist/alerts/constants.js.map +1 -0
- package/dist/alerts/desktop.d.ts +19 -0
- package/dist/alerts/desktop.d.ts.map +1 -0
- package/dist/alerts/desktop.js +57 -0
- package/dist/alerts/desktop.js.map +1 -0
- package/dist/alerts/incident-alert.d.ts +42 -0
- package/dist/alerts/incident-alert.d.ts.map +1 -0
- package/dist/alerts/incident-alert.js +84 -0
- package/dist/alerts/incident-alert.js.map +1 -0
- package/dist/alerts/scan.d.ts +37 -0
- package/dist/alerts/scan.d.ts.map +1 -0
- package/dist/alerts/scan.js +188 -0
- package/dist/alerts/scan.js.map +1 -0
- package/dist/alerts/state.d.ts +55 -0
- package/dist/alerts/state.d.ts.map +1 -0
- package/dist/alerts/state.js +178 -0
- package/dist/alerts/state.js.map +1 -0
- package/dist/alerts/triage-input.d.ts +36 -0
- package/dist/alerts/triage-input.d.ts.map +1 -0
- package/dist/alerts/triage-input.js +159 -0
- package/dist/alerts/triage-input.js.map +1 -0
- package/dist/alerts/triage-model.d.ts +42 -0
- package/dist/alerts/triage-model.d.ts.map +1 -0
- package/dist/alerts/triage-model.js +126 -0
- package/dist/alerts/triage-model.js.map +1 -0
- package/dist/alerts/triage-prompt.d.ts +23 -0
- package/dist/alerts/triage-prompt.d.ts.map +1 -0
- package/dist/alerts/triage-prompt.js +53 -0
- package/dist/alerts/triage-prompt.js.map +1 -0
- package/dist/alerts/triage-schema.json +52 -0
- package/dist/alerts/triage-setup.d.ts +77 -0
- package/dist/alerts/triage-setup.d.ts.map +1 -0
- package/dist/alerts/triage-setup.js +290 -0
- package/dist/alerts/triage-setup.js.map +1 -0
- package/dist/alerts/triage-status.d.ts +26 -0
- package/dist/alerts/triage-status.d.ts.map +1 -0
- package/dist/alerts/triage-status.js +61 -0
- package/dist/alerts/triage-status.js.map +1 -0
- package/dist/alerts/triage-tokenizer.d.ts +29 -0
- package/dist/alerts/triage-tokenizer.d.ts.map +1 -0
- package/dist/alerts/triage-tokenizer.js +82 -0
- package/dist/alerts/triage-tokenizer.js.map +1 -0
- package/dist/card-png.d.ts +3 -0
- package/dist/card-png.d.ts.map +1 -0
- package/dist/card-png.js +54 -0
- package/dist/card-png.js.map +1 -0
- package/dist/card.d.ts +62 -0
- package/dist/card.d.ts.map +1 -0
- package/dist/card.js +154 -0
- package/dist/card.js.map +1 -0
- package/dist/certify/evaluate.d.ts +11 -1
- package/dist/certify/evaluate.d.ts.map +1 -1
- package/dist/certify/evaluate.js +8 -1
- package/dist/certify/evaluate.js.map +1 -1
- package/dist/certify/render.d.ts.map +1 -1
- package/dist/certify/render.js +10 -1
- package/dist/certify/render.js.map +1 -1
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +234 -49
- package/dist/cli.js.map +1 -1
- package/dist/commands/alerts.d.ts +16 -0
- package/dist/commands/alerts.d.ts.map +1 -0
- package/dist/commands/alerts.js +112 -0
- package/dist/commands/alerts.js.map +1 -0
- package/dist/commands/connect.d.ts.map +1 -1
- package/dist/commands/connect.js +4 -3
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +12 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/hook.d.ts.map +1 -1
- package/dist/commands/hook.js +94 -8
- package/dist/commands/hook.js.map +1 -1
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +2 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/notify-flush.d.ts.map +1 -1
- package/dist/commands/notify-flush.js +3 -0
- package/dist/commands/notify-flush.js.map +1 -1
- package/dist/commands/receipt-serve.d.ts +1 -1
- package/dist/commands/receipt-serve.d.ts.map +1 -1
- package/dist/commands/receipt-serve.js +3 -2
- package/dist/commands/receipt-serve.js.map +1 -1
- package/dist/commands/receipt.d.ts +19 -0
- package/dist/commands/receipt.d.ts.map +1 -1
- package/dist/commands/receipt.js +21 -1
- package/dist/commands/receipt.js.map +1 -1
- package/dist/commands/serve-mcp.d.ts +2 -0
- package/dist/commands/serve-mcp.d.ts.map +1 -1
- package/dist/commands/serve-mcp.js +2 -0
- package/dist/commands/serve-mcp.js.map +1 -1
- package/dist/commands/start.d.ts +50 -2
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +233 -27
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/team.d.ts +19 -2
- package/dist/commands/team.d.ts.map +1 -1
- package/dist/commands/team.js +93 -13
- package/dist/commands/team.js.map +1 -1
- package/dist/commands/uninstall.d.ts +20 -0
- package/dist/commands/uninstall.d.ts.map +1 -0
- package/dist/commands/uninstall.js +378 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/commands/wire-hooks.d.ts +16 -2
- package/dist/commands/wire-hooks.d.ts.map +1 -1
- package/dist/commands/wire-hooks.js +86 -21
- package/dist/commands/wire-hooks.js.map +1 -1
- package/dist/cta.d.ts +3 -1
- package/dist/cta.d.ts.map +1 -1
- package/dist/cta.js +11 -6
- package/dist/cta.js.map +1 -1
- package/dist/fs-atomic.d.ts.map +1 -1
- package/dist/fs-atomic.js +9 -2
- package/dist/fs-atomic.js.map +1 -1
- package/dist/guard-demo.d.ts +23 -0
- package/dist/guard-demo.d.ts.map +1 -0
- package/dist/guard-demo.js +34 -0
- package/dist/guard-demo.js.map +1 -0
- package/dist/guard-entry.d.ts +2 -0
- package/dist/guard-entry.d.ts.map +1 -0
- package/dist/guard-entry.js +50 -0
- package/dist/guard-entry.js.map +1 -0
- package/dist/guard-lite.d.ts +27 -0
- package/dist/guard-lite.d.ts.map +1 -0
- package/dist/guard-lite.js +274 -0
- package/dist/guard-lite.js.map +1 -0
- package/dist/guard-pack.d.ts +7 -2
- package/dist/guard-pack.d.ts.map +1 -1
- package/dist/guard-pack.js +202 -4
- package/dist/guard-pack.js.map +1 -1
- package/dist/hook-health.d.ts +7 -0
- package/dist/hook-health.d.ts.map +1 -0
- package/dist/hook-health.js +105 -0
- package/dist/hook-health.js.map +1 -0
- package/dist/investigate/detectors.d.ts +6 -0
- package/dist/investigate/detectors.d.ts.map +1 -1
- package/dist/investigate/detectors.js +10 -0
- package/dist/investigate/detectors.js.map +1 -1
- package/dist/manifest.d.ts +106 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +454 -0
- package/dist/manifest.js.map +1 -0
- package/dist/mcp/http.d.ts +1 -0
- package/dist/mcp/http.d.ts.map +1 -1
- package/dist/mcp/http.js +1 -0
- package/dist/mcp/http.js.map +1 -1
- package/dist/mcp/protocol.d.ts +2 -0
- package/dist/mcp/protocol.d.ts.map +1 -1
- package/dist/mcp/protocol.js +5 -1
- package/dist/mcp/protocol.js.map +1 -1
- package/dist/mcp/stdio.d.ts +1 -0
- package/dist/mcp/stdio.d.ts.map +1 -1
- package/dist/mcp/stdio.js +1 -0
- package/dist/mcp/stdio.js.map +1 -1
- package/dist/never-list-input.d.ts +2 -0
- package/dist/never-list-input.d.ts.map +1 -1
- package/dist/never-list-input.js +30 -30
- package/dist/never-list-input.js.map +1 -1
- package/dist/notify/dispatch.d.ts +1 -1
- package/dist/notify/dispatch.d.ts.map +1 -1
- package/dist/notify/dispatch.js +4 -1
- package/dist/notify/dispatch.js.map +1 -1
- package/dist/notify/incident-templates.d.ts +23 -0
- package/dist/notify/incident-templates.d.ts.map +1 -0
- package/dist/notify/incident-templates.js +128 -0
- package/dist/notify/incident-templates.js.map +1 -0
- package/dist/notify/index.d.ts +12 -0
- package/dist/notify/index.d.ts.map +1 -1
- package/dist/notify/index.js +50 -3
- package/dist/notify/index.js.map +1 -1
- package/dist/notify/templates.d.ts +6 -0
- package/dist/notify/templates.d.ts.map +1 -1
- package/dist/notify/templates.js +12 -2
- package/dist/notify/templates.js.map +1 -1
- package/dist/offline-evaluate.d.ts.map +1 -1
- package/dist/offline-evaluate.js +2 -1
- package/dist/offline-evaluate.js.map +1 -1
- package/dist/parse-args.js +1 -1
- package/dist/parse-args.js.map +1 -1
- package/dist/receipt/changes.d.ts +2 -1
- package/dist/receipt/changes.d.ts.map +1 -1
- package/dist/receipt/changes.js +9 -0
- package/dist/receipt/changes.js.map +1 -1
- package/dist/receipt/dashboard.d.ts +14 -1
- package/dist/receipt/dashboard.d.ts.map +1 -1
- package/dist/receipt/dashboard.js +20 -2
- package/dist/receipt/dashboard.js.map +1 -1
- package/dist/receipt/live-server.d.ts +19 -0
- package/dist/receipt/live-server.d.ts.map +1 -1
- package/dist/receipt/live-server.js +119 -0
- package/dist/receipt/live-server.js.map +1 -1
- package/dist/receipt/receipt-css.d.ts.map +1 -1
- package/dist/receipt/receipt-css.js +45 -0
- package/dist/receipt/receipt-css.js.map +1 -1
- package/dist/receipt/render-receipt.d.ts +17 -0
- package/dist/receipt/render-receipt.d.ts.map +1 -1
- package/dist/receipt/render-receipt.js +479 -80
- package/dist/receipt/render-receipt.js.map +1 -1
- package/dist/receipt/search.d.ts.map +1 -1
- package/dist/receipt/search.js +2 -0
- package/dist/receipt/search.js.map +1 -1
- package/dist/receipt/semantic-setup.d.ts +4 -0
- package/dist/receipt/semantic-setup.d.ts.map +1 -1
- package/dist/receipt/semantic-setup.js +10 -1
- package/dist/receipt/semantic-setup.js.map +1 -1
- package/dist/receipt/share.d.ts +15 -0
- package/dist/receipt/share.d.ts.map +1 -1
- package/dist/receipt/share.js +34 -1
- package/dist/receipt/share.js.map +1 -1
- package/dist/telemetry.d.ts +17 -2
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +67 -7
- package/dist/telemetry.js.map +1 -1
- package/dist/trail.d.ts +45 -0
- package/dist/trail.d.ts.map +1 -1
- package/dist/trail.js +38 -0
- package/dist/trail.js.map +1 -1
- package/dist/write-journal.d.ts +39 -0
- package/dist/write-journal.d.ts.map +1 -0
- package/dist/write-journal.js +107 -0
- package/dist/write-journal.js.map +1 -0
- package/droid/README.md +1 -1
- package/droid/mcp.example.json +1 -1
- package/gemini/settings.example.json +1 -1
- package/grok/README.md +2 -2
- package/kilo/kilo.example.json +1 -1
- package/kimi/mcp.example.json +1 -1
- package/kiro/mcp.example.json +1 -1
- package/manifest.json +2 -2
- package/mastracode/mcp.example.json +1 -1
- package/mcp.json +1 -1
- package/openai/codex.config.example.toml +1 -1
- package/opencode/opencode.example.json +1 -1
- package/package.json +9 -3
- package/qwen/settings.example.json +1 -1
- package/server.json +3 -3
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"amp.mcpServers": {
|
|
3
3
|
"shield-kya": {
|
|
4
4
|
"command": "npx",
|
|
5
|
-
"args": ["--no-install", "@shield-agent/kya@0.
|
|
5
|
+
"args": ["--no-install", "@shield-agent/kya@0.35.3", "serve-mcp", "--stdio"],
|
|
6
6
|
"env": {
|
|
7
7
|
"KYA_BASE_URL": "https://shield-agent.com",
|
|
8
8
|
"KYA_API_KEY": "${KYA_API_KEY}",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "Links every screenshot, video or demo listed in channel-copy.json to the features.json ids it shows. Rule R9 of scripts/check-feature-coverage.mjs: a PR that changes one of these feature rows must retake the picture, or add stillValid.<id> = { rowSha, note } here (rowSha is printed by the failing check). Docs: docs/operations/kya-published-refs.md in the monorepo.",
|
|
3
|
+
"screenshots": {
|
|
4
|
+
"assets/logo.svg": { "features": [] },
|
|
5
|
+
"assets/activity-receipt.png": { "features": ["kya-receipt"] },
|
|
6
|
+
"assets/report-activity.png": { "features": ["kya-receipt"] },
|
|
7
|
+
"assets/report-blocked.png": { "features": ["kya-start", "kya-receipt"] },
|
|
8
|
+
"assets/report-certify.png": { "features": ["kya-certify", "kya-receipt"] },
|
|
9
|
+
"assets/report-changes.png": { "features": ["kya-diff-preview", "kya-receipt"] },
|
|
10
|
+
"assets/report-gateway-backends.png": { "features": ["kya-gate"] },
|
|
11
|
+
"assets/report-gateway-listeners.png": { "features": ["kya-gate"] },
|
|
12
|
+
"assets/report-gateway-playground.png": { "features": ["kya-gate"] },
|
|
13
|
+
"assets/report-gateway-policies.png": { "features": ["kya-gate", "kya-gate-deny"] },
|
|
14
|
+
"assets/report-gateway-routes.png": { "features": ["kya-gate"] },
|
|
15
|
+
"assets/report-gateway.png": { "features": ["kya-gate"] },
|
|
16
|
+
"assets/report-overview.png": { "features": ["kya-receipt", "kya-certify"] }
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"mcpServers": {
|
|
3
3
|
"shield-kya": {
|
|
4
4
|
"command": "npx",
|
|
5
|
-
"args": ["--no-install", "@shield-agent/kya@0.
|
|
5
|
+
"args": ["--no-install", "@shield-agent/kya@0.35.3", "serve-mcp", "--stdio"],
|
|
6
6
|
"env": {
|
|
7
7
|
"KYA_BASE_URL": "https://shield-agent.com",
|
|
8
8
|
"KYA_API_KEY": "${KYA_API_KEY}",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"mcpServers": {
|
|
3
3
|
"shield-kya": {
|
|
4
4
|
"command": "npx",
|
|
5
|
-
"args": ["--no-install", "@shield-agent/kya@0.
|
|
5
|
+
"args": ["--no-install", "@shield-agent/kya@0.35.3", "serve-mcp", "--stdio"],
|
|
6
6
|
"env": {
|
|
7
7
|
"KYA_BASE_URL": "https://shield-agent.com",
|
|
8
8
|
"KYA_API_KEY": "${KYA_API_KEY}",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"mcpServers": {
|
|
3
3
|
"shield-kya": {
|
|
4
4
|
"command": "npx",
|
|
5
|
-
"args": ["--no-install", "@shield-agent/kya@0.
|
|
5
|
+
"args": ["--no-install", "@shield-agent/kya@0.35.3", "serve-mcp", "--stdio"],
|
|
6
6
|
"env": {
|
|
7
7
|
"KYA_BASE_URL": "https://shield-agent.com",
|
|
8
8
|
"KYA_API_KEY": "${KYA_API_KEY}",
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Severity } from "../investigate/detectors.js";
|
|
2
|
+
export declare const SEVERITIES: readonly Severity[];
|
|
3
|
+
export declare const DEFAULT_MIN_SEVERITY: Severity;
|
|
4
|
+
export declare const DEFAULT_WINDOW_MINUTES = 120;
|
|
5
|
+
/** Upper bound so a typo cannot make every flush read a huge window. */
|
|
6
|
+
export declare const MAX_WINDOW_MINUTES: number;
|
|
7
|
+
export interface AlertsConfig {
|
|
8
|
+
readonly enabled: boolean;
|
|
9
|
+
readonly minSeverity: Severity;
|
|
10
|
+
readonly windowMinutes: number;
|
|
11
|
+
/** Desktop notification for each new incident alert. `alerts.desktop: false` or KYA_ALERTS_DESKTOP=off turns it off. */
|
|
12
|
+
readonly desktop: boolean;
|
|
13
|
+
/** Where `enabled` came from. */
|
|
14
|
+
readonly source: "env" | "config" | "default";
|
|
15
|
+
}
|
|
16
|
+
export declare function severityRank(s: Severity): number;
|
|
17
|
+
export declare function isSeverity(v: unknown): v is Severity;
|
|
18
|
+
/** The user-level `alerts` object, defensively parsed. Never throws. */
|
|
19
|
+
export declare function resolveAlertsConfig(env?: NodeJS.ProcessEnv): AlertsConfig;
|
|
20
|
+
/** `kya alerts on|off`: write `alerts.enabled` to the user-level config, keep the other keys. */
|
|
21
|
+
export declare function writeAlertsEnabled(env: NodeJS.ProcessEnv, enabled: boolean): void;
|
|
22
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/alerts/config.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAE5D,eAAO,MAAM,UAAU,EAAE,SAAS,QAAQ,EAA0C,CAAC;AACrF,eAAO,MAAM,oBAAoB,EAAE,QAAiB,CAAC;AACrD,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,wEAAwE;AACxE,eAAO,MAAM,kBAAkB,QAAc,CAAC;AAE9C,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,wHAAwH;IACxH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,iCAAiC;IACjC,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG,QAAQ,GAAG,SAAS,CAAC;CAC/C;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,CAEhD;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,QAAQ,CAEpD;AAUD,wEAAwE;AACxE,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,YAAY,CAqBtF;AAED,iGAAiG;AACjG,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAKjF"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Incident alert settings. User level only: they come from <KYA_HOME|home>/.kya/config.json
|
|
3
|
+
* and the KYA_ALERTS env switch. A project `.kya/config.json` is never read here, so a repo
|
|
4
|
+
* cannot turn alerts off, lower the floor, or add a receiver. Advisory: local KYA never blocks on this.
|
|
5
|
+
*/
|
|
6
|
+
import { kyaHome, readFileConfig, writeFileConfig } from "../config.js";
|
|
7
|
+
export const SEVERITIES = ["low", "medium", "high", "critical"];
|
|
8
|
+
export const DEFAULT_MIN_SEVERITY = "high";
|
|
9
|
+
export const DEFAULT_WINDOW_MINUTES = 120;
|
|
10
|
+
/** Upper bound so a typo cannot make every flush read a huge window. */
|
|
11
|
+
export const MAX_WINDOW_MINUTES = 7 * 24 * 60;
|
|
12
|
+
export function severityRank(s) {
|
|
13
|
+
return SEVERITIES.indexOf(s);
|
|
14
|
+
}
|
|
15
|
+
export function isSeverity(v) {
|
|
16
|
+
return typeof v === "string" && SEVERITIES.includes(v);
|
|
17
|
+
}
|
|
18
|
+
/** KYA_ALERTS=on|off (also 1/true, 0/false). Anything else: no override. */
|
|
19
|
+
function envSwitch(env) {
|
|
20
|
+
const v = env.KYA_ALERTS?.trim().toLowerCase();
|
|
21
|
+
if (v === "on" || v === "1" || v === "true")
|
|
22
|
+
return true;
|
|
23
|
+
if (v === "off" || v === "0" || v === "false")
|
|
24
|
+
return false;
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
/** The user-level `alerts` object, defensively parsed. Never throws. */
|
|
28
|
+
export function resolveAlertsConfig(env = process.env) {
|
|
29
|
+
let raw = {};
|
|
30
|
+
try {
|
|
31
|
+
const a = readFileConfig(kyaHome(env)).alerts;
|
|
32
|
+
if (a && typeof a === "object" && !Array.isArray(a))
|
|
33
|
+
raw = a;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
/* unreadable config: defaults */
|
|
37
|
+
}
|
|
38
|
+
const minSeverity = isSeverity(raw["minSeverity"]) ? raw["minSeverity"] : DEFAULT_MIN_SEVERITY;
|
|
39
|
+
const w = raw["windowMinutes"];
|
|
40
|
+
const windowMinutes = typeof w === "number" && Number.isFinite(w) && w > 0
|
|
41
|
+
? Math.min(Math.floor(w), MAX_WINDOW_MINUTES)
|
|
42
|
+
: DEFAULT_WINDOW_MINUTES;
|
|
43
|
+
const desktop = raw["desktop"] !== false && !/^(off|0|false)$/i.test(env.KYA_ALERTS_DESKTOP?.trim() ?? "");
|
|
44
|
+
const override = envSwitch(env);
|
|
45
|
+
if (override !== undefined)
|
|
46
|
+
return { enabled: override, minSeverity, windowMinutes, desktop, source: "env" };
|
|
47
|
+
if (typeof raw["enabled"] === "boolean") {
|
|
48
|
+
return { enabled: raw["enabled"], minSeverity, windowMinutes, desktop, source: "config" };
|
|
49
|
+
}
|
|
50
|
+
return { enabled: false, minSeverity, windowMinutes, desktop, source: "default" };
|
|
51
|
+
}
|
|
52
|
+
/** `kya alerts on|off`: write `alerts.enabled` to the user-level config, keep the other keys. */
|
|
53
|
+
export function writeAlertsEnabled(env, enabled) {
|
|
54
|
+
const home = kyaHome(env);
|
|
55
|
+
const prev = readFileConfig(home).alerts;
|
|
56
|
+
const base = prev && typeof prev === "object" && !Array.isArray(prev) ? prev : {};
|
|
57
|
+
writeFileConfig(home, { alerts: { ...base, enabled } });
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/alerts/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGxE,MAAM,CAAC,MAAM,UAAU,GAAwB,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;AACrF,MAAM,CAAC,MAAM,oBAAoB,GAAa,MAAM,CAAC;AACrD,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAC1C,wEAAwE;AACxE,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;AAY9C,MAAM,UAAU,YAAY,CAAC,CAAW;IACtC,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,CAAU;IACnC,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAK,UAAgC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAChF,CAAC;AAED,4EAA4E;AAC5E,SAAS,SAAS,CAAC,GAAsB;IACvC,MAAM,CAAC,GAAG,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC/C,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IACzD,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,OAAO;QAAE,OAAO,KAAK,CAAC;IAC5D,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,mBAAmB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACtE,IAAI,GAAG,GAA4B,EAAE,CAAC;IACtC,IAAI,CAAC;QACH,MAAM,CAAC,GAAI,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,CAA0B,CAAC,MAAM,CAAC;QACxE,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;YAAE,GAAG,GAAG,CAA4B,CAAC;IAC1F,CAAC;IAAC,MAAM,CAAC;QACP,iCAAiC;IACnC,CAAC;IACD,MAAM,WAAW,GAAG,UAAU,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC;IAC/F,MAAM,CAAC,GAAG,GAAG,CAAC,eAAe,CAAC,CAAC;IAC/B,MAAM,aAAa,GACjB,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QAClD,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC;QAC7C,CAAC,CAAC,sBAAsB,CAAC;IAC7B,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,CAAC,KAAK,KAAK,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3G,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC7G,IAAI,OAAO,GAAG,CAAC,SAAS,CAAC,KAAK,SAAS,EAAE,CAAC;QACxC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAC5F,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;AACpF,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,kBAAkB,CAAC,GAAsB,EAAE,OAAgB;IACzE,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1B,MAAM,IAAI,GAAI,cAAc,CAAC,IAAI,CAA0B,CAAC,MAAM,CAAC;IACnE,MAAM,IAAI,GAAG,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,IAAgC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/G,eAAe,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,EAAW,CAAC,CAAC;AACnE,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Light constants shared by the hook path (notify) and the alert modules. No imports on purpose. */
|
|
2
|
+
export declare const INCIDENT_EVENT = "incident.opened";
|
|
3
|
+
export declare const INCIDENT_KIND = "kya.incident.opened";
|
|
4
|
+
export declare const ADVISORY_LINE = "Local KYA is advisory.";
|
|
5
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/alerts/constants.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,eAAO,MAAM,cAAc,oBAAoB,CAAC;AAChD,eAAO,MAAM,aAAa,wBAAwB,CAAC;AACnD,eAAO,MAAM,aAAa,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Light constants shared by the hook path (notify) and the alert modules. No imports on purpose. */
|
|
2
|
+
export const INCIDENT_EVENT = "incident.opened";
|
|
3
|
+
export const INCIDENT_KIND = "kya.incident.opened";
|
|
4
|
+
export const ADVISORY_LINE = "Local KYA is advisory.";
|
|
5
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/alerts/constants.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,MAAM,CAAC,MAAM,cAAc,GAAG,iBAAiB,CAAC;AAChD,MAAM,CAAC,MAAM,aAAa,GAAG,qBAAqB,CAAC;AACnD,MAAM,CAAC,MAAM,aAAa,GAAG,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { IncidentAlert } from "./incident-alert.js";
|
|
2
|
+
export declare const DESKTOP_TITLE = "KYA security alert";
|
|
3
|
+
export interface DesktopCommand {
|
|
4
|
+
readonly file: string;
|
|
5
|
+
readonly args: readonly string[];
|
|
6
|
+
readonly env?: Readonly<Record<string, string>>;
|
|
7
|
+
}
|
|
8
|
+
export declare function desktopCommand(platform: NodeJS.Platform, title: string, body: string): DesktopCommand | undefined;
|
|
9
|
+
/** `severity: <level>. Detectors: <ids>.` Only fixed words and safe ids. */
|
|
10
|
+
export declare function desktopBody(alert: Pick<IncidentAlert, "severity" | "detectorIds" | "test">): string;
|
|
11
|
+
export type DesktopRunner = (cmd: DesktopCommand, env: NodeJS.ProcessEnv) => Promise<boolean>;
|
|
12
|
+
export interface DesktopDeps {
|
|
13
|
+
/** Test seam: the platform. */
|
|
14
|
+
readonly platform?: NodeJS.Platform;
|
|
15
|
+
/** Test seam: runs the command. */
|
|
16
|
+
readonly run?: DesktopRunner;
|
|
17
|
+
}
|
|
18
|
+
export declare function desktopNotify(alert: IncidentAlert, env: NodeJS.ProcessEnv, deps?: DesktopDeps): Promise<boolean>;
|
|
19
|
+
//# sourceMappingURL=desktop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"desktop.d.ts","sourceRoot":"","sources":["../../src/alerts/desktop.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,eAAO,MAAM,aAAa,uBAAuB,CAAC;AAalD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACjD;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAejH;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,UAAU,GAAG,aAAa,GAAG,MAAM,CAAC,GAAG,MAAM,CAInG;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAY9F,MAAM,WAAW,WAAW;IAC1B,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IACpC,mCAAmC;IACnC,QAAQ,CAAC,GAAG,CAAC,EAAE,aAAa,CAAC;CAC9B;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAQ1H"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Desktop notification for a new incident alert. macOS: osascript. Linux: notify-send when it exists.
|
|
3
|
+
* Windows: a PowerShell toast. The text is static: a fixed title, the severity and the detector ids
|
|
4
|
+
* (ids pass the safe-id check in triage-input.ts). No summary, tool name or path from the trail is shown.
|
|
5
|
+
* Arguments go to the program as argv (execFile, no shell). Windows reads the text from two environment
|
|
6
|
+
* variables, because PowerShell has no argv-safe way to pass text to a script block.
|
|
7
|
+
* Advisory and fail open: a missing notifier or a failure returns false and changes nothing else.
|
|
8
|
+
*/
|
|
9
|
+
import { execFile } from "node:child_process";
|
|
10
|
+
export const DESKTOP_TITLE = "KYA security alert";
|
|
11
|
+
const TIMEOUT_MS = 5_000;
|
|
12
|
+
const OSA_SCRIPT = ["on run argv", "display notification (item 1 of argv) with title (item 2 of argv)", "end run"];
|
|
13
|
+
const WIN_SCRIPT = [
|
|
14
|
+
"[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null",
|
|
15
|
+
"$x = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02)",
|
|
16
|
+
"$t = $x.GetElementsByTagName('text')",
|
|
17
|
+
"$t.Item(0).AppendChild($x.CreateTextNode($env:KYA_TOAST_TITLE)) | Out-Null",
|
|
18
|
+
"$t.Item(1).AppendChild($x.CreateTextNode($env:KYA_TOAST_BODY)) | Out-Null",
|
|
19
|
+
"[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('KYA').Show([Windows.UI.Notifications.ToastNotification]::new($x))",
|
|
20
|
+
].join("; ");
|
|
21
|
+
export function desktopCommand(platform, title, body) {
|
|
22
|
+
switch (platform) {
|
|
23
|
+
case "darwin":
|
|
24
|
+
return { file: "osascript", args: [...OSA_SCRIPT.flatMap((l) => ["-e", l]), body, title] };
|
|
25
|
+
case "linux":
|
|
26
|
+
return { file: "notify-send", args: ["--app-name", "KYA", "--", title, body] };
|
|
27
|
+
case "win32":
|
|
28
|
+
return {
|
|
29
|
+
file: "powershell.exe",
|
|
30
|
+
args: ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", WIN_SCRIPT],
|
|
31
|
+
env: { KYA_TOAST_TITLE: title, KYA_TOAST_BODY: body },
|
|
32
|
+
};
|
|
33
|
+
default:
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** `severity: <level>. Detectors: <ids>.` Only fixed words and safe ids. */
|
|
38
|
+
export function desktopBody(alert) {
|
|
39
|
+
const safe = alert.detectorIds.filter((d) => /^[a-z0-9-]{1,40}$/.test(d));
|
|
40
|
+
const ids = safe.length > 0 ? safe.join(", ") : "none";
|
|
41
|
+
return `${alert.test ? "Test. " : ""}Severity: ${alert.severity}. Detectors: ${ids}. Open kya report.`;
|
|
42
|
+
}
|
|
43
|
+
const defaultRun = (cmd, env) => new Promise((resolve) => {
|
|
44
|
+
execFile(cmd.file, [...cmd.args], { env: { ...env, ...cmd.env }, timeout: TIMEOUT_MS, windowsHide: true, shell: false }, (err) => resolve(!err));
|
|
45
|
+
});
|
|
46
|
+
export async function desktopNotify(alert, env, deps = {}) {
|
|
47
|
+
try {
|
|
48
|
+
const cmd = desktopCommand(deps.platform ?? process.platform, DESKTOP_TITLE, desktopBody(alert));
|
|
49
|
+
if (!cmd)
|
|
50
|
+
return false;
|
|
51
|
+
return await (deps.run ?? defaultRun)(cmd, env);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=desktop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"desktop.js","sourceRoot":"","sources":["../../src/alerts/desktop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The alert body for one detected incident. Built from the privacy-safe triage input (redacted,
|
|
3
|
+
* clipped summaries, counts, detector ids) and static detector text. The incident id, title and
|
|
4
|
+
* fix brief header can hold a session id or a raw tool key, so none of them is copied here.
|
|
5
|
+
* No raw args, argument hashes, target paths, diff previews, session ids or home folders.
|
|
6
|
+
*/
|
|
7
|
+
import type { Severity } from "../investigate/detectors.js";
|
|
8
|
+
import { type Incident } from "../investigate/index.js";
|
|
9
|
+
import type { TrailEvent } from "../trail.js";
|
|
10
|
+
import type { IncidentTriage } from "./triage-model.js";
|
|
11
|
+
export { ADVISORY_LINE, INCIDENT_EVENT, INCIDENT_KIND } from "./constants.js";
|
|
12
|
+
export declare const MAX_ALERT_SUMMARIES = 3;
|
|
13
|
+
export interface IncidentAlert {
|
|
14
|
+
readonly ref: string;
|
|
15
|
+
readonly title: string;
|
|
16
|
+
readonly severity: Severity;
|
|
17
|
+
readonly detectorIds: readonly string[];
|
|
18
|
+
readonly findingCount: number;
|
|
19
|
+
/** Verdict counts; absent when the triage input was not available. */
|
|
20
|
+
readonly counts?: {
|
|
21
|
+
readonly allow: number;
|
|
22
|
+
readonly hold: number;
|
|
23
|
+
readonly deny: number;
|
|
24
|
+
};
|
|
25
|
+
readonly firstTs: string;
|
|
26
|
+
readonly lastTs: string;
|
|
27
|
+
readonly tools: readonly string[];
|
|
28
|
+
readonly summaries: readonly string[];
|
|
29
|
+
/** First step of the suggested change, static text per detector. Empty when none. */
|
|
30
|
+
readonly fix: string;
|
|
31
|
+
/** Local model triage (optional, advisory). Absent when the model is not installed or failed. Never changes severity. */
|
|
32
|
+
readonly triage?: IncidentTriage;
|
|
33
|
+
readonly advisory: string;
|
|
34
|
+
readonly test: boolean;
|
|
35
|
+
}
|
|
36
|
+
/** First non-empty line under "## Suggested change" in a fix brief (static detector text). */
|
|
37
|
+
export declare function fixBriefFirstLine(brief: string | undefined): string;
|
|
38
|
+
export declare function incidentTitle(detectorIds: readonly string[]): string;
|
|
39
|
+
export declare function buildIncidentAlert(incident: Incident, events: readonly TrailEvent[], brief?: string): IncidentAlert;
|
|
40
|
+
/** The synthetic incident `kya alerts test` sends. Marked as a test in the title and the `test` flag. */
|
|
41
|
+
export declare function buildTestIncidentAlert(now?: Date): IncidentAlert;
|
|
42
|
+
//# sourceMappingURL=incident-alert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"incident-alert.d.ts","sourceRoot":"","sources":["../../src/alerts/incident-alert.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAkC,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAIxD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC9E,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,sEAAsE;IACtE,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3F,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,qFAAqF;IACrF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,yHAAyH;IACzH,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB;AAED,8FAA8F;AAC9F,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAWnE;AAED,wBAAgB,aAAa,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAWpE;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,SAAS,UAAU,EAAE,EAC7B,KAAK,CAAC,EAAE,MAAM,GACb,aAAa,CA2Bf;AAED,yGAAyG;AACzG,wBAAgB,sBAAsB,CAAC,GAAG,GAAE,IAAiB,GAAG,aAAa,CAiB5E"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { detectorTitle } from "../investigate/index.js";
|
|
2
|
+
import { buildTriageInput } from "./triage-input.js";
|
|
3
|
+
import { incidentRef } from "./state.js";
|
|
4
|
+
import { ADVISORY_LINE } from "./constants.js";
|
|
5
|
+
export { ADVISORY_LINE, INCIDENT_EVENT, INCIDENT_KIND } from "./constants.js";
|
|
6
|
+
export const MAX_ALERT_SUMMARIES = 3;
|
|
7
|
+
/** First non-empty line under "## Suggested change" in a fix brief (static detector text). */
|
|
8
|
+
export function fixBriefFirstLine(brief) {
|
|
9
|
+
if (!brief)
|
|
10
|
+
return "";
|
|
11
|
+
const lines = brief.split("\n");
|
|
12
|
+
const at = lines.findIndex((l) => l.trim() === "## Suggested change");
|
|
13
|
+
if (at === -1)
|
|
14
|
+
return "";
|
|
15
|
+
for (const line of lines.slice(at + 1)) {
|
|
16
|
+
const t = line.trim();
|
|
17
|
+
if (t.startsWith("## "))
|
|
18
|
+
return "";
|
|
19
|
+
if (t)
|
|
20
|
+
return t.slice(0, 240);
|
|
21
|
+
}
|
|
22
|
+
return "";
|
|
23
|
+
}
|
|
24
|
+
export function incidentTitle(detectorIds) {
|
|
25
|
+
const first = detectorIds[0];
|
|
26
|
+
let name = "Security incident";
|
|
27
|
+
if (first !== undefined) {
|
|
28
|
+
try {
|
|
29
|
+
name = detectorTitle(first) ?? name;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
/* unknown id: generic name */
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return `KYA incident: ${name}`;
|
|
36
|
+
}
|
|
37
|
+
export function buildIncidentAlert(incident, events, brief) {
|
|
38
|
+
// The builder may return nothing or a reduced input when its secret check trips: then send the minimum.
|
|
39
|
+
let triage;
|
|
40
|
+
try {
|
|
41
|
+
triage = buildTriageInput(incident, events);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
triage = null;
|
|
45
|
+
}
|
|
46
|
+
const detectorIds = triage && triage.detectorIds.length > 0
|
|
47
|
+
? [...triage.detectorIds]
|
|
48
|
+
: [...new Set(incident.findings.map((f) => f.detectorId))].sort();
|
|
49
|
+
return {
|
|
50
|
+
ref: incidentRef(incident.id),
|
|
51
|
+
title: incidentTitle(detectorIds),
|
|
52
|
+
severity: incident.severity,
|
|
53
|
+
detectorIds,
|
|
54
|
+
findingCount: incident.findingCount,
|
|
55
|
+
...(triage ? { counts: { ...triage.counts } } : {}),
|
|
56
|
+
firstTs: incident.firstTs,
|
|
57
|
+
lastTs: incident.lastTs,
|
|
58
|
+
tools: triage ? triage.toolIds.slice(0, MAX_ALERT_SUMMARIES) : [],
|
|
59
|
+
summaries: triage ? triage.summaries.slice(0, MAX_ALERT_SUMMARIES) : [],
|
|
60
|
+
fix: fixBriefFirstLine(brief),
|
|
61
|
+
advisory: ADVISORY_LINE,
|
|
62
|
+
test: false,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/** The synthetic incident `kya alerts test` sends. Marked as a test in the title and the `test` flag. */
|
|
66
|
+
export function buildTestIncidentAlert(now = new Date()) {
|
|
67
|
+
const ts = now.toISOString();
|
|
68
|
+
return {
|
|
69
|
+
ref: "test",
|
|
70
|
+
title: "[TEST] KYA incident: Never-list tool attempted repeatedly",
|
|
71
|
+
severity: "high",
|
|
72
|
+
detectorIds: ["never-repeat"],
|
|
73
|
+
findingCount: 1,
|
|
74
|
+
counts: { allow: 0, hold: 0, deny: 3 },
|
|
75
|
+
firstTs: ts,
|
|
76
|
+
lastTs: ts,
|
|
77
|
+
tools: ["kya.test"],
|
|
78
|
+
summaries: ["This is a test alert from kya alerts test. No action needed."],
|
|
79
|
+
fix: "This is a test. Nothing happened on your machine.",
|
|
80
|
+
advisory: ADVISORY_LINE,
|
|
81
|
+
test: true,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=incident-alert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"incident-alert.js","sourceRoot":"","sources":["../../src/alerts/incident-alert.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type Incident, type Severity } from "../investigate/index.js";
|
|
2
|
+
import type { NotifyDeps } from "../notify/sender.js";
|
|
3
|
+
import { type TrailEvent } from "../trail.js";
|
|
4
|
+
import { type DesktopDeps } from "./desktop.js";
|
|
5
|
+
import { type IncidentAlert } from "./incident-alert.js";
|
|
6
|
+
import { type TriageInput } from "./triage-input.js";
|
|
7
|
+
import type { IncidentTriage } from "./triage-model.js";
|
|
8
|
+
export interface AlertScanDeps extends NotifyDeps {
|
|
9
|
+
/** Test seam: the clock. */
|
|
10
|
+
readonly now?: () => Date;
|
|
11
|
+
/** Test seam: triage of one incident input. Default: the local model when it is installed. */
|
|
12
|
+
readonly triage?: (input: TriageInput) => Promise<IncidentTriage | undefined>;
|
|
13
|
+
/** Test seam: the desktop notifier. */
|
|
14
|
+
readonly desktop?: DesktopDeps;
|
|
15
|
+
/** Test seam: shorter triage timeout. */
|
|
16
|
+
readonly triageTimeoutMs?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface AlertScanResult {
|
|
19
|
+
/** Incidents that passed the floor and the dedupe check and were sent. */
|
|
20
|
+
readonly alerted: readonly IncidentAlert[];
|
|
21
|
+
readonly delivered: number;
|
|
22
|
+
}
|
|
23
|
+
/** Model load plus one inference. Longer than this and the alert goes out without triage. */
|
|
24
|
+
export declare const TRIAGE_TIMEOUT_MS = 8000;
|
|
25
|
+
/** One scan opens at most this many desktop notifications (an incident storm must not flood the screen). */
|
|
26
|
+
export declare const MAX_DESKTOP_PER_SCAN = 3;
|
|
27
|
+
/** Events may be at most this far in the future (clock skew). Later ones are forged or broken. */
|
|
28
|
+
export declare const MAX_FUTURE_MS: number;
|
|
29
|
+
/** Events inside the window. A ts that does not parse, or lies more than 5 minutes ahead, is dropped. */
|
|
30
|
+
export declare function windowEvents(events: readonly TrailEvent[], now: Date, windowMinutes: number): TrailEvent[];
|
|
31
|
+
/** Pure core: events in, incidents at or above the floor out. */
|
|
32
|
+
export declare function incidentsAboveFloor(events: readonly TrailEvent[], minSeverity: Severity): {
|
|
33
|
+
incidents: Incident[];
|
|
34
|
+
briefs: ReadonlyMap<string, string>;
|
|
35
|
+
};
|
|
36
|
+
export declare function runAlertScan(_cwd: string, env: NodeJS.ProcessEnv, deps?: AlertScanDeps): Promise<AlertScanResult>;
|
|
37
|
+
//# sourceMappingURL=scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/alerts/scan.ts"],"names":[],"mappings":"AAaA,OAAO,EAAoB,KAAK,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEzF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAE/D,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAS7E,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C,4BAA4B;IAC5B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,8FAA8F;IAC9F,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAAC;IAC9E,uCAAuC;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC;IAC/B,yCAAyC;IACzC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,eAAe;IAC9B,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;IAC3C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAID,6FAA6F;AAC7F,eAAO,MAAM,iBAAiB,OAAQ,CAAC;AACvC,4GAA4G;AAC5G,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAmDtC,kGAAkG;AAClG,eAAO,MAAM,aAAa,QAAa,CAAC;AAExC,yGAAyG;AACzG,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,GAAG,UAAU,EAAE,CAO1G;AAED,iEAAiE;AACjE,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,UAAU,EAAE,EAC7B,WAAW,EAAE,QAAQ,GACpB;IAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;IAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAMhE;AAeD,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC,eAAe,CAAC,CAgF1B"}
|