@panguard-ai/panguard-guard 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/cli/index.d.ts +9 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +128 -29
- package/dist/cli/index.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +46 -14
- package/dist/config.js.map +1 -1
- package/dist/daemon/index.js +20 -18
- package/dist/daemon/index.js.map +1 -1
- package/dist/dashboard/dashboard.html +2428 -205
- package/dist/dashboard/index.d.ts +104 -0
- package/dist/dashboard/index.d.ts.map +1 -1
- package/dist/dashboard/index.js +710 -58
- package/dist/dashboard/index.js.map +1 -1
- package/dist/engines/atr-engine.d.ts +24 -2
- package/dist/engines/atr-engine.d.ts.map +1 -1
- package/dist/engines/atr-engine.js +80 -20
- package/dist/engines/atr-engine.js.map +1 -1
- package/dist/event-processor.js +6 -4
- package/dist/event-processor.js.map +1 -1
- package/dist/guard-engine.d.ts +41 -1
- package/dist/guard-engine.d.ts.map +1 -1
- package/dist/guard-engine.js +124 -19
- package/dist/guard-engine.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/investigation/index.js +3 -3
- package/dist/investigation/index.js.map +1 -1
- package/dist/llm-detect.d.ts +19 -0
- package/dist/llm-detect.d.ts.map +1 -1
- package/dist/llm-detect.js +72 -5
- package/dist/llm-detect.js.map +1 -1
- package/dist/memory/baseline.d.ts.map +1 -1
- package/dist/memory/baseline.js +4 -7
- package/dist/memory/baseline.js.map +1 -1
- package/dist/net/validate-outbound-url.d.ts +33 -0
- package/dist/net/validate-outbound-url.d.ts.map +1 -0
- package/dist/net/validate-outbound-url.js +95 -0
- package/dist/net/validate-outbound-url.js.map +1 -0
- package/dist/notify/webhook.d.ts.map +1 -1
- package/dist/notify/webhook.js +10 -0
- package/dist/notify/webhook.js.map +1 -1
- package/dist/redact.d.ts +35 -0
- package/dist/redact.d.ts.map +1 -0
- package/dist/redact.js +39 -0
- package/dist/redact.js.map +1 -0
- package/dist/response/file-quarantine.d.ts +2 -0
- package/dist/response/file-quarantine.d.ts.map +1 -1
- package/dist/response/file-quarantine.js +35 -9
- package/dist/response/file-quarantine.js.map +1 -1
- package/dist/rule-loader.d.ts +14 -1
- package/dist/rule-loader.d.ts.map +1 -1
- package/dist/rule-loader.js +62 -4
- package/dist/rule-loader.js.map +1 -1
- package/dist/rule-sync.d.ts +22 -0
- package/dist/rule-sync.d.ts.map +1 -1
- package/dist/rule-sync.js +152 -66
- package/dist/rule-sync.js.map +1 -1
- package/dist/threat-cloud/index.d.ts +11 -14
- package/dist/threat-cloud/index.d.ts.map +1 -1
- package/dist/threat-cloud/index.js +24 -24
- package/dist/threat-cloud/index.js.map +1 -1
- package/dist/threat-cloud/tc-key-provisioner.d.ts.map +1 -1
- package/dist/threat-cloud/tc-key-provisioner.js +19 -1
- package/dist/threat-cloud/tc-key-provisioner.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +12 -12
|
@@ -15,6 +15,13 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import type { DashboardStatus, DashboardEvent, ThreatMapEntry, GuardConfig, ThreatVerdict } from '../types.js';
|
|
17
17
|
import { DashboardRelayClient } from './relay-client.js';
|
|
18
|
+
/**
|
|
19
|
+
* Remove the persisted dashboard launch token. Exported so `pga guard stop` /
|
|
20
|
+
* `pga guard uninstall` can guarantee the secret never outlives the daemon even
|
|
21
|
+
* when the process is killed without a graceful `stop()` (e.g. SIGTERM mid-run).
|
|
22
|
+
* Best-effort: a missing file or permission error is not fatal.
|
|
23
|
+
*/
|
|
24
|
+
export declare function removeDashboardToken(): void;
|
|
18
25
|
/** Relay configuration for connecting to a remote Manager */
|
|
19
26
|
export interface DashboardRelayOptions {
|
|
20
27
|
readonly managerUrl: string;
|
|
@@ -33,6 +40,7 @@ export declare class DashboardServer {
|
|
|
33
40
|
private readonly maxRecentEvents;
|
|
34
41
|
private readonly port;
|
|
35
42
|
private getConfig;
|
|
43
|
+
private configApplier;
|
|
36
44
|
private getRulesProvider;
|
|
37
45
|
private readonly authToken;
|
|
38
46
|
private rateLimits;
|
|
@@ -40,6 +48,16 @@ export declare class DashboardServer {
|
|
|
40
48
|
private readonly relayConfig;
|
|
41
49
|
constructor(port: number, relayConfig?: DashboardRelayOptions);
|
|
42
50
|
setConfigGetter(getter: () => GuardConfig): void;
|
|
51
|
+
/**
|
|
52
|
+
* Wire the engine's live-config applier. When a config-writing handler (e.g.
|
|
53
|
+
* the Threat Cloud / mode POST) persists a new config to disk, it ALSO calls
|
|
54
|
+
* this so the engine mutates its in-memory `this.config` + `this.mode` and
|
|
55
|
+
* re-arms enforcement for the new mode. Without it, the daemon kept serving
|
|
56
|
+
* the stale config it was constructed with: GET /api/config and /api/status
|
|
57
|
+
* returned the old value, enforcement kept the old mode, and the UI control
|
|
58
|
+
* snapped back — the change looked rejected even though disk was updated.
|
|
59
|
+
*/
|
|
60
|
+
setConfigApplier(applier: (cfg: GuardConfig) => void): void;
|
|
43
61
|
/**
|
|
44
62
|
* Wire a callback that returns the live set of ATR rules currently loaded by
|
|
45
63
|
* the engine. Used by SARIF / Evidence Pack export so the auditor sees the
|
|
@@ -59,9 +77,20 @@ export declare class DashboardServer {
|
|
|
59
77
|
addVerdict(verdict: ThreatVerdict): void;
|
|
60
78
|
addThreatMapEntry(entry: ThreatMapEntry): void;
|
|
61
79
|
getAuthToken(): string;
|
|
80
|
+
/**
|
|
81
|
+
* Persist the launch token to ~/.panguard-guard/dashboard-token with 0o600 so
|
|
82
|
+
* a separate `pga up` invocation (rerun, already-running daemon, headless,
|
|
83
|
+
* copied URL) can construct the authenticated launch URL. The token is the
|
|
84
|
+
* launch secret that mints the auth cookie, so it is written owner-only and
|
|
85
|
+
* never logged — same handling as the cookie. Best-effort: a write failure
|
|
86
|
+
* just means the CLI falls back to printing guidance instead of a live URL.
|
|
87
|
+
*/
|
|
88
|
+
private persistAuthToken;
|
|
62
89
|
private handleRequest;
|
|
63
90
|
private checkRateLimit;
|
|
64
91
|
private serveIndex;
|
|
92
|
+
/** Parse the one-time launch token from a `GET /?token=...` request URL. */
|
|
93
|
+
private extractLaunchToken;
|
|
65
94
|
/**
|
|
66
95
|
* Compose the status envelope returned by /api/status.
|
|
67
96
|
* Adds a `license` field so the SPA can gate Pilot-only UI without making
|
|
@@ -69,6 +98,26 @@ export declare class DashboardServer {
|
|
|
69
98
|
* (cliTier overrides licenseKey) or defaults to community.
|
|
70
99
|
*/
|
|
71
100
|
private buildStatusResponse;
|
|
101
|
+
/**
|
|
102
|
+
* Real per-layer health, derived from live engine state — NOT hard-coded.
|
|
103
|
+
* The dashboard's "Layer A/B Active" used to be static green in the HTML, so it
|
|
104
|
+
* stayed green even with zero rules loaded or the engine stopped. This computes
|
|
105
|
+
* the truth: Layer A (deterministic pattern) is active only when rules are
|
|
106
|
+
* actually loaded AND the engine is running; Layer B (deterministic heuristic +
|
|
107
|
+
* baseline) tracks the running state; Layer C (optional semantic) reflects
|
|
108
|
+
* whether the user has configured a BYO LLM (config.ai) — it is advisory and
|
|
109
|
+
* off-by-default, so "off" is a healthy state, not a fault.
|
|
110
|
+
*/
|
|
111
|
+
private computeLayers;
|
|
112
|
+
/**
|
|
113
|
+
* Honest enforcement posture. The dashboard used to print PROTECTED whenever
|
|
114
|
+
* mode === 'protection', even with an all-off enforcement policy that takes no
|
|
115
|
+
* action — the exact "says PROTECTED, prevents nothing" overclaim the audit
|
|
116
|
+
* flagged. This reports what the daemon will ACTUALLY do: 'protected' only when
|
|
117
|
+
* protection mode is on AND at least one response action is armed; otherwise
|
|
118
|
+
* 'monitoring' (detect + notify, no automatic OS response).
|
|
119
|
+
*/
|
|
120
|
+
private computeEnforcement;
|
|
72
121
|
private normalizeLicenseTier;
|
|
73
122
|
/**
|
|
74
123
|
* SARIF 2.1.0 stub export. Production wiring to the migrator's evidence
|
|
@@ -107,13 +156,68 @@ export declare class DashboardServer {
|
|
|
107
156
|
private jsonResponse;
|
|
108
157
|
private handleSkillsApi;
|
|
109
158
|
private handleAiConfigGet;
|
|
159
|
+
/**
|
|
160
|
+
* True when `host` is a private/internal/loopback/link-local IPv4 address (or
|
|
161
|
+
* `localhost`). Self-contained so the SSRF check stays in this file.
|
|
162
|
+
*/
|
|
163
|
+
private static isPrivateHost;
|
|
110
164
|
private static isValidEndpointUrl;
|
|
165
|
+
/**
|
|
166
|
+
* If `host` is an IPv6-mapped IPv4 address, return the embedded dotted-quad
|
|
167
|
+
* IPv4; otherwise null. Accepts the URL bracket form ([...]), the
|
|
168
|
+
* dotted-quad tail (::ffff:1.2.3.4) and the hex tail (::ffff:0102:0304).
|
|
169
|
+
*/
|
|
170
|
+
private static extractMappedIpv4;
|
|
111
171
|
private handleRulesApi;
|
|
112
172
|
private handleThreatCloudGet;
|
|
113
173
|
private handleThreatCloudPost;
|
|
114
174
|
private handleLoadedRulesApi;
|
|
115
175
|
private handleProxyVerdictsApi;
|
|
116
176
|
private handleInstalledSkillsApi;
|
|
177
|
+
/**
|
|
178
|
+
* Read a JSON request body (≤10KB) for the action POST endpoints. Resolves to
|
|
179
|
+
* the parsed object, or null after having already written the error response
|
|
180
|
+
* (payload too large / invalid JSON / stream error) — callers just return on null.
|
|
181
|
+
*/
|
|
182
|
+
private readJsonBody;
|
|
183
|
+
/**
|
|
184
|
+
* POST /api/skills/quarantine — move a flagged file-based skill into quarantine.
|
|
185
|
+
* Resolves the skill name under ~/.claude/skills/, contains it against path
|
|
186
|
+
* traversal, confirms it exists, then uses the existing FileQuarantine (atomic
|
|
187
|
+
* move + 0o700 perms + restorable manifest). MCP-server config entries are not
|
|
188
|
+
* file-based and cannot be quarantined this way.
|
|
189
|
+
*/
|
|
190
|
+
private handleQuarantinePost;
|
|
191
|
+
/**
|
|
192
|
+
* POST /api/skills/whitelist — mark a skill safe (false positive) by adding it
|
|
193
|
+
* to the local skill-whitelist.json the installed-skills view reads. Atomic
|
|
194
|
+
* write (tmp + rename), owner-only perms.
|
|
195
|
+
*/
|
|
196
|
+
private handleWhitelistPost;
|
|
197
|
+
/**
|
|
198
|
+
* POST /api/skills/unwhitelist — remove a skill from the local whitelist, so a
|
|
199
|
+
* mistaken "Mark safe" is reversible from the dashboard (the whitelist used to
|
|
200
|
+
* be append-only with no in-product undo). Atomic write, owner-only perms.
|
|
201
|
+
*/
|
|
202
|
+
private handleUnwhitelistPost;
|
|
203
|
+
/**
|
|
204
|
+
* GET /api/skills/quarantined — the list of currently quarantined files, so the
|
|
205
|
+
* user can SEE what's quarantined and restore it. The quarantine confirm dialog
|
|
206
|
+
* promises restorability; this + /api/skills/restore make that promise real.
|
|
207
|
+
*/
|
|
208
|
+
private handleQuarantinedListApi;
|
|
209
|
+
/**
|
|
210
|
+
* POST /api/skills/restore — restore a quarantined file to its original path,
|
|
211
|
+
* honoring the reversibility the UI promises. Body: { id }.
|
|
212
|
+
*/
|
|
213
|
+
private handleRestorePost;
|
|
214
|
+
/**
|
|
215
|
+
* GET /api/rule-update — surface the daily notify-only rule-update check that
|
|
216
|
+
* rule-sync writes to <dataDir>/rule-update.json. The backend computed this
|
|
217
|
+
* signal ("newer detection rules published") but nothing read it, so the most
|
|
218
|
+
* actionable security update was invisible. Notify-only: never auto-applies.
|
|
219
|
+
*/
|
|
220
|
+
private handleRuleUpdateApi;
|
|
117
221
|
private handleAgentsApi;
|
|
118
222
|
private sendToClient;
|
|
119
223
|
private broadcast;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dashboard/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dashboard/index.ts"],"names":[],"mappings":"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"}
|