@panguard-ai/panguard 1.5.3 → 1.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/auth-guard.d.ts +58 -2
- package/dist/cli/auth-guard.d.ts.map +1 -1
- package/dist/cli/auth-guard.js +96 -2
- package/dist/cli/auth-guard.js.map +1 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +45 -6
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.js +25 -31
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/login.d.ts +19 -3
- package/dist/cli/commands/login.d.ts.map +1 -1
- package/dist/cli/commands/login.js +181 -9
- package/dist/cli/commands/login.js.map +1 -1
- package/dist/cli/commands/logout.d.ts +13 -3
- package/dist/cli/commands/logout.d.ts.map +1 -1
- package/dist/cli/commands/logout.js +63 -8
- package/dist/cli/commands/logout.js.map +1 -1
- package/dist/cli/commands/report.d.ts +27 -2
- package/dist/cli/commands/report.d.ts.map +1 -1
- package/dist/cli/commands/report.js +698 -45
- package/dist/cli/commands/report.js.map +1 -1
- package/dist/cli/commands/scan.d.ts.map +1 -1
- package/dist/cli/commands/scan.js +42 -3
- package/dist/cli/commands/scan.js.map +1 -1
- package/dist/cli/commands/sensor.d.ts +17 -0
- package/dist/cli/commands/sensor.d.ts.map +1 -0
- package/dist/cli/commands/sensor.js +183 -0
- package/dist/cli/commands/sensor.js.map +1 -0
- package/dist/cli/commands/setup.d.ts.map +1 -1
- package/dist/cli/commands/setup.js +8 -5
- package/dist/cli/commands/setup.js.map +1 -1
- package/dist/cli/commands/status.js +22 -5
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/up.d.ts.map +1 -1
- package/dist/cli/commands/up.js +53 -2
- package/dist/cli/commands/up.js.map +1 -1
- package/dist/cli/commands/whoami.d.ts +30 -2
- package/dist/cli/commands/whoami.d.ts.map +1 -1
- package/dist/cli/commands/whoami.js +109 -16
- package/dist/cli/commands/whoami.js.map +1 -1
- package/dist/cli/device-flow.d.ts +72 -0
- package/dist/cli/device-flow.d.ts.map +1 -0
- package/dist/cli/device-flow.js +126 -0
- package/dist/cli/device-flow.js.map +1 -0
- package/dist/cli/index.js +14 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/interactive/actions/misc.d.ts.map +1 -1
- package/dist/cli/interactive/actions/misc.js +31 -7
- package/dist/cli/interactive/actions/misc.js.map +1 -1
- package/dist/cli/interactive/menu-defs.d.ts.map +1 -1
- package/dist/cli/interactive/menu-defs.js +4 -4
- package/dist/cli/interactive/menu-defs.js.map +1 -1
- package/dist/cli/interactive.d.ts.map +1 -1
- package/dist/cli/interactive.js +6 -1
- package/dist/cli/interactive.js.map +1 -1
- package/dist/cli/telemetry.d.ts +17 -0
- package/dist/cli/telemetry.d.ts.map +1 -1
- package/dist/cli/telemetry.js +33 -0
- package/dist/cli/telemetry.js.map +1 -1
- package/dist/cli/workspace-sync.d.ts +108 -0
- package/dist/cli/workspace-sync.d.ts.map +1 -0
- package/dist/cli/workspace-sync.js +199 -0
- package/dist/cli/workspace-sync.js.map +1 -0
- package/package.json +17 -12
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* workspace-sync.ts — push scan events to app.panguard.ai when authenticated
|
|
3
|
+
*
|
|
4
|
+
* Flow:
|
|
5
|
+
* 1. `pga audit` / `pga scan` finish a scan locally (offline-first)
|
|
6
|
+
* 2. If ~/.panguard/auth.json exists (user has run `pga login`), this module
|
|
7
|
+
* POSTs the findings to app.panguard.ai/api/v2/events so they appear in
|
|
8
|
+
* the customer dashboard timeline.
|
|
9
|
+
* 3. Anonymous / Community users are unaffected — they continue to use the
|
|
10
|
+
* existing TC telemetry path (tc.panguard.ai) via panguard-guard's
|
|
11
|
+
* ThreatCloudClient.
|
|
12
|
+
*
|
|
13
|
+
* Privacy:
|
|
14
|
+
* - Raw adversarial payloads are NEVER uploaded. Only: rule_id, severity,
|
|
15
|
+
* target (path/URL), target_hash (sha256 of content), and a 1-line summary
|
|
16
|
+
* produced by the CLI.
|
|
17
|
+
* - Endpoint identification: a stable hash of machine-id + logged-in user.
|
|
18
|
+
* Not the hostname itself, not the user's email.
|
|
19
|
+
*
|
|
20
|
+
* Failure mode:
|
|
21
|
+
* - Network / HTTP failure is logged via `log.debug` and swallowed.
|
|
22
|
+
* - 401 (token revoked/expired) prints ONE warning then deletes auth.json
|
|
23
|
+
* so subsequent commands don't keep hitting the broken path.
|
|
24
|
+
* - The main scan result printed to stdout is never altered by sync result.
|
|
25
|
+
*/
|
|
26
|
+
interface AuthInfo {
|
|
27
|
+
api_key: string;
|
|
28
|
+
workspace_id: string;
|
|
29
|
+
workspace_slug: string;
|
|
30
|
+
workspace_name: string;
|
|
31
|
+
tier: string;
|
|
32
|
+
user_email: string;
|
|
33
|
+
/**
|
|
34
|
+
* UUID of the matching TC org. Optional — only set if the workspace was
|
|
35
|
+
* provisioned with a linked TC org (see Supabase migration
|
|
36
|
+
* 20260422000006_tc_org_link.sql). Used by getTcCorrelationHeaders() so
|
|
37
|
+
* existing anonymous TC telemetry can be post-hoc correlated back to this
|
|
38
|
+
* workspace without breaking Community-tier anonymous behaviour.
|
|
39
|
+
*/
|
|
40
|
+
tc_org_id?: string;
|
|
41
|
+
}
|
|
42
|
+
export declare function authJsonPath(): string;
|
|
43
|
+
export declare function tryLoadAuth(): AuthInfo | null;
|
|
44
|
+
/**
|
|
45
|
+
* Headers to pass on any CLI → tc.panguard.ai request when the user is
|
|
46
|
+
* authenticated to a paid workspace. Harmless when TC doesn't know about
|
|
47
|
+
* workspaces yet (TC ignores unknown headers); enables retroactive
|
|
48
|
+
* correlation once TC gains workspace-aware endpoints.
|
|
49
|
+
*
|
|
50
|
+
* Returns an empty object if the user is anonymous (Community tier) so
|
|
51
|
+
* Community behaviour is byte-identical to pre-Phase-2 code.
|
|
52
|
+
*/
|
|
53
|
+
export declare function getTcCorrelationHeaders(): Record<string, string>;
|
|
54
|
+
export type EventType = 'scan.rule_match' | 'scan.completed' | 'guard.blocked' | 'guard.flagged' | 'trap.triggered' | 'respond.action';
|
|
55
|
+
export type Severity = 'critical' | 'high' | 'medium' | 'low' | 'info';
|
|
56
|
+
export interface WorkspaceEvent {
|
|
57
|
+
event_type: EventType;
|
|
58
|
+
severity: Severity;
|
|
59
|
+
rule_id?: string;
|
|
60
|
+
target: string;
|
|
61
|
+
target_hash?: string;
|
|
62
|
+
payload_summary: string;
|
|
63
|
+
occurred_at?: string;
|
|
64
|
+
metadata?: Record<string, unknown>;
|
|
65
|
+
}
|
|
66
|
+
export interface EndpointInfo {
|
|
67
|
+
machine_id: string;
|
|
68
|
+
hostname?: string;
|
|
69
|
+
os_type?: string;
|
|
70
|
+
panguard_version?: string;
|
|
71
|
+
}
|
|
72
|
+
export declare function getEndpointInfo(panguardVersion: string | undefined, userEmail: string): EndpointInfo;
|
|
73
|
+
interface SyncResult {
|
|
74
|
+
ingested: number;
|
|
75
|
+
skipped: string;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Push a batch of events to app.panguard.ai under the current workspace.
|
|
79
|
+
* Returns the number ingested. Non-throwing: any error is logged and the
|
|
80
|
+
* function returns `{ ingested: 0, skipped: <reason> }`.
|
|
81
|
+
*/
|
|
82
|
+
export declare function syncEvents(events: WorkspaceEvent[], opts?: {
|
|
83
|
+
appUrl?: string;
|
|
84
|
+
panguardVersion?: string;
|
|
85
|
+
/** Print a one-line success/failure summary to stdout. Default false. */
|
|
86
|
+
verbose?: boolean;
|
|
87
|
+
}): Promise<SyncResult>;
|
|
88
|
+
export interface AuditFindingLike {
|
|
89
|
+
ruleId?: string;
|
|
90
|
+
severity?: string;
|
|
91
|
+
title?: string;
|
|
92
|
+
description?: string;
|
|
93
|
+
[key: string]: unknown;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Build a WorkspaceEvent[] from an audit report's findings + a scan summary row.
|
|
97
|
+
* This is the shared shape emitted by both `pga audit` and `pga scan`.
|
|
98
|
+
*/
|
|
99
|
+
export declare function buildEventsFromAuditReport(args: {
|
|
100
|
+
target: string;
|
|
101
|
+
targetHash?: string;
|
|
102
|
+
riskLevel: string;
|
|
103
|
+
riskScore: number;
|
|
104
|
+
findings: AuditFindingLike[];
|
|
105
|
+
skillName?: string;
|
|
106
|
+
}): WorkspaceEvent[];
|
|
107
|
+
export {};
|
|
108
|
+
//# sourceMappingURL=workspace-sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-sync.d.ts","sourceRoot":"","sources":["../../src/cli/workspace-sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAcH,UAAU,QAAQ;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,WAAW,IAAI,QAAQ,GAAG,IAAI,CAS7C;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUhE;AAID,MAAM,MAAM,SAAS,GACjB,iBAAiB,GACjB,gBAAgB,GAChB,eAAe,GACf,eAAe,GACf,gBAAgB,GAChB,gBAAgB,CAAC;AAErB,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAEvE,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,SAAS,CAAC;IACtB,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAMD,wBAAgB,eAAe,CAC7B,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,SAAS,EAAE,MAAM,GAChB,YAAY,CAed;AAID,UAAU,UAAU;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,cAAc,EAAE,EACxB,IAAI,CAAC,EAAE;IACL,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GACA,OAAO,CAAC,UAAU,CAAC,CA2ErB;AAID,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAWD;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,cAAc,EAAE,CAoCnB"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* workspace-sync.ts — push scan events to app.panguard.ai when authenticated
|
|
3
|
+
*
|
|
4
|
+
* Flow:
|
|
5
|
+
* 1. `pga audit` / `pga scan` finish a scan locally (offline-first)
|
|
6
|
+
* 2. If ~/.panguard/auth.json exists (user has run `pga login`), this module
|
|
7
|
+
* POSTs the findings to app.panguard.ai/api/v2/events so they appear in
|
|
8
|
+
* the customer dashboard timeline.
|
|
9
|
+
* 3. Anonymous / Community users are unaffected — they continue to use the
|
|
10
|
+
* existing TC telemetry path (tc.panguard.ai) via panguard-guard's
|
|
11
|
+
* ThreatCloudClient.
|
|
12
|
+
*
|
|
13
|
+
* Privacy:
|
|
14
|
+
* - Raw adversarial payloads are NEVER uploaded. Only: rule_id, severity,
|
|
15
|
+
* target (path/URL), target_hash (sha256 of content), and a 1-line summary
|
|
16
|
+
* produced by the CLI.
|
|
17
|
+
* - Endpoint identification: a stable hash of machine-id + logged-in user.
|
|
18
|
+
* Not the hostname itself, not the user's email.
|
|
19
|
+
*
|
|
20
|
+
* Failure mode:
|
|
21
|
+
* - Network / HTTP failure is logged via `log.debug` and swallowed.
|
|
22
|
+
* - 401 (token revoked/expired) prints ONE warning then deletes auth.json
|
|
23
|
+
* so subsequent commands don't keep hitting the broken path.
|
|
24
|
+
* - The main scan result printed to stdout is never altered by sync result.
|
|
25
|
+
*/
|
|
26
|
+
import { createHash } from 'node:crypto';
|
|
27
|
+
import { readFileSync, unlinkSync } from 'node:fs';
|
|
28
|
+
import { homedir, hostname, platform } from 'node:os';
|
|
29
|
+
import { join } from 'node:path';
|
|
30
|
+
import { c, symbols } from '@panguard-ai/core';
|
|
31
|
+
const DEFAULT_APP_URL = 'https://app.panguard.ai';
|
|
32
|
+
const AUTH_JSON_RELATIVE = '.panguard/auth.json';
|
|
33
|
+
const TIMEOUT_MS = 5000;
|
|
34
|
+
export function authJsonPath() {
|
|
35
|
+
return join(homedir(), AUTH_JSON_RELATIVE);
|
|
36
|
+
}
|
|
37
|
+
export function tryLoadAuth() {
|
|
38
|
+
try {
|
|
39
|
+
const raw = readFileSync(authJsonPath(), 'utf-8');
|
|
40
|
+
const parsed = JSON.parse(raw);
|
|
41
|
+
if (!parsed.api_key || !parsed.workspace_id)
|
|
42
|
+
return null;
|
|
43
|
+
return parsed;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Headers to pass on any CLI → tc.panguard.ai request when the user is
|
|
51
|
+
* authenticated to a paid workspace. Harmless when TC doesn't know about
|
|
52
|
+
* workspaces yet (TC ignores unknown headers); enables retroactive
|
|
53
|
+
* correlation once TC gains workspace-aware endpoints.
|
|
54
|
+
*
|
|
55
|
+
* Returns an empty object if the user is anonymous (Community tier) so
|
|
56
|
+
* Community behaviour is byte-identical to pre-Phase-2 code.
|
|
57
|
+
*/
|
|
58
|
+
export function getTcCorrelationHeaders() {
|
|
59
|
+
const auth = tryLoadAuth();
|
|
60
|
+
if (!auth)
|
|
61
|
+
return {};
|
|
62
|
+
const headers = {
|
|
63
|
+
'X-Panguard-Workspace-Id': auth.workspace_id,
|
|
64
|
+
};
|
|
65
|
+
if (auth.tc_org_id) {
|
|
66
|
+
headers['X-Panguard-Tc-Org-Id'] = auth.tc_org_id;
|
|
67
|
+
}
|
|
68
|
+
return headers;
|
|
69
|
+
}
|
|
70
|
+
// ─── Stable endpoint id (not PII) ──────────────────────────────────────────
|
|
71
|
+
let cachedMachineId = null;
|
|
72
|
+
export function getEndpointInfo(panguardVersion, userEmail) {
|
|
73
|
+
if (!cachedMachineId) {
|
|
74
|
+
// Combine OS hostname + userEmail (from auth) + node arch → sha256.
|
|
75
|
+
// Server never sees the raw values, and the hash is stable across runs of
|
|
76
|
+
// the same user on the same machine, giving the dashboard a useful
|
|
77
|
+
// "endpoint" without leaking hostname or email to the database.
|
|
78
|
+
const seed = `${hostname()}::${userEmail}::${process.arch}`;
|
|
79
|
+
cachedMachineId = 'm_' + createHash('sha256').update(seed).digest('hex').slice(0, 48);
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
machine_id: cachedMachineId,
|
|
83
|
+
hostname: hostname(),
|
|
84
|
+
os_type: platform(),
|
|
85
|
+
...(panguardVersion ? { panguard_version: panguardVersion } : {}),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Push a batch of events to app.panguard.ai under the current workspace.
|
|
90
|
+
* Returns the number ingested. Non-throwing: any error is logged and the
|
|
91
|
+
* function returns `{ ingested: 0, skipped: <reason> }`.
|
|
92
|
+
*/
|
|
93
|
+
export async function syncEvents(events, opts) {
|
|
94
|
+
if (events.length === 0) {
|
|
95
|
+
return { ingested: 0, skipped: 'empty' };
|
|
96
|
+
}
|
|
97
|
+
const auth = tryLoadAuth();
|
|
98
|
+
if (!auth) {
|
|
99
|
+
// Not authenticated — not an error, just means Community mode.
|
|
100
|
+
return { ingested: 0, skipped: 'anonymous' };
|
|
101
|
+
}
|
|
102
|
+
const appUrl = (opts?.appUrl ?? process.env['PANGUARD_APP_URL'] ?? DEFAULT_APP_URL).replace(/\/$/, '');
|
|
103
|
+
const endpoint = getEndpointInfo(opts?.panguardVersion, auth.user_email);
|
|
104
|
+
const body = { events, endpoint };
|
|
105
|
+
try {
|
|
106
|
+
const res = await fetch(`${appUrl}/api/v2/events`, {
|
|
107
|
+
method: 'POST',
|
|
108
|
+
headers: {
|
|
109
|
+
'Content-Type': 'application/json',
|
|
110
|
+
Authorization: `Bearer ${auth.api_key}`,
|
|
111
|
+
'User-Agent': `panguard-cli/${opts?.panguardVersion ?? 'unknown'}`,
|
|
112
|
+
},
|
|
113
|
+
body: JSON.stringify(body),
|
|
114
|
+
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
115
|
+
});
|
|
116
|
+
if (res.status === 401) {
|
|
117
|
+
// Token revoked or expired — clear auth.json so future commands go
|
|
118
|
+
// anonymous instead of repeatedly failing.
|
|
119
|
+
try {
|
|
120
|
+
unlinkSync(authJsonPath());
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// fine
|
|
124
|
+
}
|
|
125
|
+
if (opts?.verbose) {
|
|
126
|
+
console.log(` ${c.caution(symbols.warn)} ${c.dim('Session expired. Run')} ${c.sage('pga login')} ${c.dim('to reconnect.')}`);
|
|
127
|
+
}
|
|
128
|
+
return { ingested: 0, skipped: 'auth_revoked' };
|
|
129
|
+
}
|
|
130
|
+
if (!res.ok) {
|
|
131
|
+
if (opts?.verbose) {
|
|
132
|
+
console.log(` ${c.caution(symbols.warn)} ${c.dim(`Dashboard sync failed (HTTP ${res.status}) — results are local only.`)}`);
|
|
133
|
+
}
|
|
134
|
+
return { ingested: 0, skipped: `http_${res.status}` };
|
|
135
|
+
}
|
|
136
|
+
const parsed = (await res.json().catch(() => ({})));
|
|
137
|
+
const ingested = typeof parsed.ingested === 'number' ? parsed.ingested : events.length;
|
|
138
|
+
if (opts?.verbose) {
|
|
139
|
+
console.log(` ${c.safe(symbols.pass)} ${c.dim(`${ingested} event${ingested === 1 ? '' : 's'} synced to`)} ${c.sage(auth.workspace_name)}`);
|
|
140
|
+
}
|
|
141
|
+
return { ingested, skipped: '' };
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
// Network / timeout / malformed response. Swallow — offline-first principle.
|
|
145
|
+
if (opts?.verbose) {
|
|
146
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
147
|
+
console.log(` ${c.dim(`Dashboard sync skipped (${msg.slice(0, 60)}) — results are local only.`)}`);
|
|
148
|
+
}
|
|
149
|
+
return { ingested: 0, skipped: 'network_error' };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/** Convert a normalized severity string (from audit/scan reports) to the allowed enum. */
|
|
153
|
+
function normalizeSeverity(s) {
|
|
154
|
+
const lower = (s ?? '').toLowerCase();
|
|
155
|
+
if (lower === 'critical' || lower === 'high' || lower === 'medium' || lower === 'low') {
|
|
156
|
+
return lower;
|
|
157
|
+
}
|
|
158
|
+
return 'info';
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Build a WorkspaceEvent[] from an audit report's findings + a scan summary row.
|
|
162
|
+
* This is the shared shape emitted by both `pga audit` and `pga scan`.
|
|
163
|
+
*/
|
|
164
|
+
export function buildEventsFromAuditReport(args) {
|
|
165
|
+
const out = [];
|
|
166
|
+
// One event per rule match — this is the unit of compliance evidence.
|
|
167
|
+
for (const f of args.findings) {
|
|
168
|
+
if (!f.ruleId)
|
|
169
|
+
continue;
|
|
170
|
+
out.push({
|
|
171
|
+
event_type: 'scan.rule_match',
|
|
172
|
+
severity: normalizeSeverity(typeof f.severity === 'string' ? f.severity : undefined),
|
|
173
|
+
rule_id: f.ruleId,
|
|
174
|
+
target: args.target,
|
|
175
|
+
...(args.targetHash ? { target_hash: args.targetHash } : {}),
|
|
176
|
+
payload_summary: (typeof f.title === 'string' ? f.title : `${f.ruleId} match`).slice(0, 200),
|
|
177
|
+
metadata: {
|
|
178
|
+
skill_name: args.skillName ?? undefined,
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
// One summary event per scan run (lets the dashboard show "scans/day" even
|
|
183
|
+
// when findings are zero).
|
|
184
|
+
out.push({
|
|
185
|
+
event_type: 'scan.completed',
|
|
186
|
+
severity: 'info',
|
|
187
|
+
target: args.target,
|
|
188
|
+
...(args.targetHash ? { target_hash: args.targetHash } : {}),
|
|
189
|
+
payload_summary: `Scan completed — risk=${args.riskLevel}, score=${args.riskScore}, findings=${args.findings.length}`,
|
|
190
|
+
metadata: {
|
|
191
|
+
risk_level: args.riskLevel,
|
|
192
|
+
risk_score: args.riskScore,
|
|
193
|
+
findings_count: args.findings.length,
|
|
194
|
+
skill_name: args.skillName ?? undefined,
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
return out;
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=workspace-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-sync.js","sourceRoot":"","sources":["../../src/cli/workspace-sync.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@panguard-ai/panguard",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.5",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -37,23 +37,28 @@
|
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"commander": "^12.0.0",
|
|
40
|
+
"js-yaml": "^4.1.0",
|
|
41
|
+
"pdfkit": "^0.15.0",
|
|
40
42
|
"zod": "^3.24.0",
|
|
41
|
-
"@panguard-ai/
|
|
42
|
-
"@panguard-ai/
|
|
43
|
-
"@panguard-ai/
|
|
44
|
-
"@panguard-ai/panguard-
|
|
45
|
-
"@panguard-ai/
|
|
46
|
-
"@panguard-ai/
|
|
47
|
-
"@panguard-ai/
|
|
48
|
-
"@panguard-ai/
|
|
49
|
-
"@panguard-ai/panguard-
|
|
43
|
+
"@panguard-ai/core": "1.5.5",
|
|
44
|
+
"@panguard-ai/panguard-scan": "1.5.5",
|
|
45
|
+
"@panguard-ai/atr": "1.5.5",
|
|
46
|
+
"@panguard-ai/panguard-guard": "1.5.5",
|
|
47
|
+
"@panguard-ai/security-hardening": "1.5.5",
|
|
48
|
+
"@panguard-ai/panguard-skill-auditor": "1.5.5",
|
|
49
|
+
"@panguard-ai/panguard-chat": "1.5.5",
|
|
50
|
+
"@panguard-ai/scan-core": "1.5.5",
|
|
51
|
+
"@panguard-ai/panguard-mcp": "1.5.5"
|
|
50
52
|
},
|
|
51
53
|
"optionalDependencies": {
|
|
52
|
-
"
|
|
53
|
-
"@panguard-ai/threat-cloud": "1.
|
|
54
|
+
"agent-threat-rules": "^2.1.1",
|
|
55
|
+
"@panguard-ai/threat-cloud": "1.5.5",
|
|
56
|
+
"@panguard-ai/panguard-trap": "1.5.5"
|
|
54
57
|
},
|
|
55
58
|
"devDependencies": {
|
|
59
|
+
"@types/js-yaml": "^4.0.9",
|
|
56
60
|
"@types/node": "^22.14.0",
|
|
61
|
+
"@types/pdfkit": "^0.13.0",
|
|
57
62
|
"typescript": "~5.7.3"
|
|
58
63
|
},
|
|
59
64
|
"scripts": {
|