@spool-lab/core 0.4.12 → 0.5.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/README.md +2 -2
- package/dist/db/db.d.ts +10 -2
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/db.js +119 -10
- package/dist/db/db.js.map +1 -1
- package/dist/db/queries.d.ts +5 -5
- package/dist/db/queries.d.ts.map +1 -1
- package/dist/db/queries.js +32 -14
- package/dist/db/queries.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/observability/exporter-file.d.ts +30 -0
- package/dist/observability/exporter-file.d.ts.map +1 -0
- package/dist/observability/exporter-file.js +125 -0
- package/dist/observability/exporter-file.js.map +1 -0
- package/dist/observability/exporter-pretty.d.ts +27 -0
- package/dist/observability/exporter-pretty.d.ts.map +1 -0
- package/dist/observability/exporter-pretty.js +84 -0
- package/dist/observability/exporter-pretty.js.map +1 -0
- package/dist/observability/index.d.ts +2 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +2 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/layer.d.ts +29 -0
- package/dist/observability/layer.d.ts.map +1 -0
- package/dist/observability/layer.js +45 -0
- package/dist/observability/layer.js.map +1 -0
- package/dist/parsers/opencode.d.ts +23 -0
- package/dist/parsers/opencode.d.ts.map +1 -0
- package/dist/parsers/opencode.js +358 -0
- package/dist/parsers/opencode.js.map +1 -0
- package/dist/projects/sessions.d.ts +29 -1
- package/dist/projects/sessions.d.ts.map +1 -1
- package/dist/projects/sessions.js +115 -11
- package/dist/projects/sessions.js.map +1 -1
- package/dist/security/index.d.ts +14 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +7 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/maintenance.d.ts +15 -0
- package/dist/security/maintenance.d.ts.map +1 -0
- package/dist/security/maintenance.js +68 -0
- package/dist/security/maintenance.js.map +1 -0
- package/dist/security/profile.d.ts +47 -0
- package/dist/security/profile.d.ts.map +1 -0
- package/dist/security/profile.js +131 -0
- package/dist/security/profile.js.map +1 -0
- package/dist/security/purge.d.ts +68 -0
- package/dist/security/purge.d.ts.map +1 -0
- package/dist/security/purge.js +193 -0
- package/dist/security/purge.js.map +1 -0
- package/dist/security/repo.d.ts +190 -0
- package/dist/security/repo.d.ts.map +1 -0
- package/dist/security/repo.js +594 -0
- package/dist/security/repo.js.map +1 -0
- package/dist/security/scan.d.ts +50 -0
- package/dist/security/scan.d.ts.map +1 -0
- package/dist/security/scan.js +122 -0
- package/dist/security/scan.js.map +1 -0
- package/dist/security/types.d.ts +146 -0
- package/dist/security/types.d.ts.map +1 -0
- package/dist/security/types.js +10 -0
- package/dist/security/types.js.map +1 -0
- package/dist/security/worker.d.ts +69 -0
- package/dist/security/worker.d.ts.map +1 -0
- package/dist/security/worker.js +228 -0
- package/dist/security/worker.js.map +1 -0
- package/dist/sync/source-paths.d.ts +1 -0
- package/dist/sync/source-paths.d.ts.map +1 -1
- package/dist/sync/source-paths.js +48 -6
- package/dist/sync/source-paths.js.map +1 -1
- package/dist/sync/syncer.d.ts +9 -1
- package/dist/sync/syncer.d.ts.map +1 -1
- package/dist/sync/syncer.js +128 -16
- package/dist/sync/syncer.js.map +1 -1
- package/dist/sync/watcher.d.ts.map +1 -1
- package/dist/sync/watcher.js +8 -2
- package/dist/sync/watcher.js.map +1 -1
- package/dist/types.d.ts +15 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/util/resolve-bin.d.ts +34 -0
- package/dist/util/resolve-bin.d.ts.map +1 -1
- package/dist/util/resolve-bin.js +175 -20
- package/dist/util/resolve-bin.js.map +1 -1
- package/package.json +11 -2
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
import type { SensitiveKind } from '@spool-lab/redact';
|
|
3
|
+
import type { FindingRow, FindingState, OccurrenceBySession, RiskByCategoryRow, SessionWithFindingCounts } from './types.js';
|
|
4
|
+
export interface FindingFilter {
|
|
5
|
+
sessionId?: number;
|
|
6
|
+
kind?: SensitiveKind;
|
|
7
|
+
/** Multi-select kinds. When non-empty takes precedence over `kind`.
|
|
8
|
+
* Used by the Security page filter pills which support clicking
|
|
9
|
+
* multiple chips to OR them together. */
|
|
10
|
+
kinds?: readonly SensitiveKind[];
|
|
11
|
+
state?: FindingState | 'any';
|
|
12
|
+
severity?: 'high' | 'low';
|
|
13
|
+
/** When true, info-tier kinds (absolute-path / ip / internal-host)
|
|
14
|
+
* are excluded at the SQL layer. Needed by SessionCard fetches —
|
|
15
|
+
* a session with 800+ absolute-path + a handful of api-keys would
|
|
16
|
+
* otherwise have its non-info findings shoved off the first page
|
|
17
|
+
* by `detected_at DESC` ordering, and the client-side info filter
|
|
18
|
+
* has nothing left to render. Ignored when `kind` or `kinds`
|
|
19
|
+
* explicitly includes an info kind. */
|
|
20
|
+
excludeInfo?: boolean;
|
|
21
|
+
limit?: number;
|
|
22
|
+
offset?: number;
|
|
23
|
+
}
|
|
24
|
+
export interface SessionFindingFilter {
|
|
25
|
+
kind?: SensitiveKind;
|
|
26
|
+
kinds?: readonly SensitiveKind[];
|
|
27
|
+
state?: FindingState | 'any';
|
|
28
|
+
severity?: 'high' | 'low';
|
|
29
|
+
/** Free-text on session title. */
|
|
30
|
+
text?: string;
|
|
31
|
+
limit?: number;
|
|
32
|
+
offset?: number;
|
|
33
|
+
}
|
|
34
|
+
export interface Page<T> {
|
|
35
|
+
rows: T[];
|
|
36
|
+
hasMore: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface FindingInput {
|
|
39
|
+
sessionId: number;
|
|
40
|
+
messageId: number | null;
|
|
41
|
+
kind: SensitiveKind;
|
|
42
|
+
valueHash: string;
|
|
43
|
+
confidence: number;
|
|
44
|
+
provider: string;
|
|
45
|
+
startOffset: number;
|
|
46
|
+
endOffset: number;
|
|
47
|
+
/** Allowlist hit at insert time → 'dismissed'; else 'active'. */
|
|
48
|
+
state: FindingState;
|
|
49
|
+
}
|
|
50
|
+
/** Insert a batch of findings. Caller wraps in a transaction. */
|
|
51
|
+
export declare function insertFindings(db: Database.Database, rows: readonly FindingInput[]): void;
|
|
52
|
+
/** Delete all non-purged rows for the providers being rescanned —
|
|
53
|
+
* i.e. wipe the producer's previous output so the upcoming
|
|
54
|
+
* `insertFindings` is the canonical truth.
|
|
55
|
+
*
|
|
56
|
+
* Includes `state='dismissed'` deliberately: those rows are derived
|
|
57
|
+
* state. The user's "ignore" decisions live in `allowlist_session`
|
|
58
|
+
* and `allowlist_global` (preserved here), and the scan path
|
|
59
|
+
* re-emits findings as `state='dismissed'` whenever it encounters a
|
|
60
|
+
* hit that matches an allowlist row. Re-inserting also keeps
|
|
61
|
+
* `findings.value_hash` aligned with the per-kind allowlist
|
|
62
|
+
* preference (security.json `kindAllowlist`) — without this delete,
|
|
63
|
+
* a mute → unmute cycle would accumulate phantom dismissed rows
|
|
64
|
+
* (one set per cycle), inflating audit counts and breaking
|
|
65
|
+
* `riskByCategory` totals over time.
|
|
66
|
+
*
|
|
67
|
+
* Purged rows are the only state that's NOT producer-derived —
|
|
68
|
+
* they correspond to destructive `messages.content_text` rewrites
|
|
69
|
+
* the user explicitly approved. Preserving them is the audit
|
|
70
|
+
* contract documented in the design doc. */
|
|
71
|
+
export declare function deleteRefreshableFindings(db: Database.Database, sessionId: number, providers: readonly string[]): void;
|
|
72
|
+
/** @deprecated Renamed to {@link deleteRefreshableFindings} after the
|
|
73
|
+
* active-only filter was found to leak phantom dismissed rows
|
|
74
|
+
* across mute→unmute cycles. Kept as a thin alias so callers
|
|
75
|
+
* outside the repo don't break mid-stack. */
|
|
76
|
+
export declare const deleteActiveFindings: typeof deleteRefreshableFindings;
|
|
77
|
+
/** Recompute sessions.scan_finding_count + scan_high_count from the
|
|
78
|
+
* findings table.
|
|
79
|
+
*
|
|
80
|
+
* Counts EXCLUDE info-tier kinds (absolute-path, ip, internal-host).
|
|
81
|
+
* Those are stored — useful for an opt-in "Show informational
|
|
82
|
+
* signals" toggle — but they don't drive the Library row badge
|
|
83
|
+
* because their pattern-only signal has too high a false-positive
|
|
84
|
+
* rate to be meaningful at first glance. */
|
|
85
|
+
export declare function updateSessionCounts(db: Database.Database, sessionId: number): void;
|
|
86
|
+
export declare function setSessionScanProfile(db: Database.Database, sessionId: number, profile: string, completedAt: string): void;
|
|
87
|
+
/** Set every session's scan_profile to NULL — used by "Rescan all" so
|
|
88
|
+
* every session re-enqueues. */
|
|
89
|
+
export declare function invalidateAllScanProfiles(db: Database.Database): number;
|
|
90
|
+
/** Drop the scan profile for one session — used by the sync cascade
|
|
91
|
+
* when a session's messages change after first scan. */
|
|
92
|
+
export declare function invalidateSessionScanProfile(db: Database.Database, sessionId: number): void;
|
|
93
|
+
/** Sessions whose stored profile doesn't structurally match
|
|
94
|
+
* `currentProfile`. Used at boot for backfill enqueue. */
|
|
95
|
+
export declare function listSessionsNeedingScan(db: Database.Database, currentProfile: string): number[];
|
|
96
|
+
export declare function listFindings(db: Database.Database, filter: FindingFilter): FindingRow[];
|
|
97
|
+
export declare function listFindingsPage(db: Database.Database, filter: FindingFilter): Page<FindingRow>;
|
|
98
|
+
export declare function listSessionsWithFindings(db: Database.Database, filter: SessionFindingFilter): SessionWithFindingCounts[];
|
|
99
|
+
export declare function listSessionsWithFindingsPage(db: Database.Database, filter: SessionFindingFilter): Page<SessionWithFindingCounts>;
|
|
100
|
+
/** Total distinct sessions matching the same filter as
|
|
101
|
+
* `listSessionsWithFindings` — used by the renderer to show
|
|
102
|
+
* "涉及 N 个会话" without loading every page. Cheaper than the list
|
|
103
|
+
* query: no SELECT projection, no GROUP BY, no ORDER BY. */
|
|
104
|
+
export declare function countSessionsWithFindings(db: Database.Database, filter: SessionFindingFilter): number;
|
|
105
|
+
/** Risk by category — one row per kind that has ≥ 1 active finding.
|
|
106
|
+
* Drives the Watchtower-style panel on the Security page. */
|
|
107
|
+
export declare function riskByCategory(db: Database.Database): RiskByCategoryRow[];
|
|
108
|
+
/** Cross-session blast radius for one leaked value. Returns every
|
|
109
|
+
* session that has ≥ 1 ACTIVE finding sharing the given
|
|
110
|
+
* `(kind, valueHash)`, with the per-session occurrence count, project,
|
|
111
|
+
* and most-recent detection time. Ordered most-recent-first.
|
|
112
|
+
*
|
|
113
|
+
* Spool already collapses repeated occurrences of a value WITHIN a
|
|
114
|
+
* session into one row (×N); this extends that view across the whole
|
|
115
|
+
* archive so the user can see "this same key also leaked in 4 other
|
|
116
|
+
* sessions". Dismissed/purged occurrences are excluded — they no
|
|
117
|
+
* longer expose the value through search / AI / browse. */
|
|
118
|
+
export declare function occurrencesByValueHash(db: Database.Database, kind: SensitiveKind, valueHash: string): OccurrenceBySession[];
|
|
119
|
+
/** The most recent `scan_completed_at` across ALL sessions, regardless
|
|
120
|
+
* of whether they currently have active findings. Drives the Security
|
|
121
|
+
* page's "scanned X ago" label. Deriving it from the filtered,
|
|
122
|
+
* paginated findings list undercounts: a session scanned + cleaned
|
|
123
|
+
* (no active findings) drops off that list and stops contributing, so
|
|
124
|
+
* the label could read older than the true last scan. Returns null
|
|
125
|
+
* when nothing has been scanned yet. */
|
|
126
|
+
export declare function lastScanCompletedAt(db: Database.Database): string | null;
|
|
127
|
+
/** Read the live raw value for one finding. Used by the UI's review
|
|
128
|
+
* panel and the Purge confirm dialog. Returns null when the finding
|
|
129
|
+
* no longer points at a valid message (race against session
|
|
130
|
+
* deletion) or has been purged (offsets now point at the mask). */
|
|
131
|
+
export declare function getFindingValue(db: Database.Database, findingId: number): string | null;
|
|
132
|
+
/** Bulk version of `getFindingValue` — one SQL query for N finding
|
|
133
|
+
* ids instead of N round-trips. Caller fans the result map back out
|
|
134
|
+
* by id; missing keys are treated as `null` (purged / vanished). */
|
|
135
|
+
export declare function getFindingValues(db: Database.Database, findingIds: readonly number[]): Record<number, string | null>;
|
|
136
|
+
export interface AllowlistSnapshot {
|
|
137
|
+
/** (kind|value_hash) keys for this session. */
|
|
138
|
+
session: Set<string>;
|
|
139
|
+
/** (kind|value_hash) keys, global scope. */
|
|
140
|
+
global: Set<string>;
|
|
141
|
+
}
|
|
142
|
+
export declare function getAllowlists(db: Database.Database, sessionId: number): AllowlistSnapshot;
|
|
143
|
+
export declare function isAllowlisted(allow: AllowlistSnapshot, kind: SensitiveKind, valueHash: string): boolean;
|
|
144
|
+
export declare function addAllowlistSession(db: Database.Database, sessionId: number, kind: SensitiveKind, valueHash: string): void;
|
|
145
|
+
export declare function addAllowlistGlobal(db: Database.Database, kind: SensitiveKind, valueHash: string): void;
|
|
146
|
+
export declare function removeAllowlistSession(db: Database.Database, sessionId: number, kind: SensitiveKind, valueHash: string): void;
|
|
147
|
+
export declare function removeAllowlistGlobal(db: Database.Database, kind: SensitiveKind, valueHash: string): void;
|
|
148
|
+
export interface AllowlistEntryRow {
|
|
149
|
+
scope: 'session' | 'global';
|
|
150
|
+
kind: SensitiveKind;
|
|
151
|
+
valueHash: string;
|
|
152
|
+
createdAt: string;
|
|
153
|
+
/** Session row context — null for global entries. */
|
|
154
|
+
sessionUuid: string | null;
|
|
155
|
+
sessionTitle: string | null;
|
|
156
|
+
/** The live plaintext value, reconstructed at read time from a
|
|
157
|
+
* matching non-purged finding's message text (NOT stored on the
|
|
158
|
+
* allowlist row). Null when no such finding survives — the source
|
|
159
|
+
* message was purged, the finding was deleted, or the session is
|
|
160
|
+
* gone — in which case the UI falls back to the kind label alone. */
|
|
161
|
+
value: string | null;
|
|
162
|
+
}
|
|
163
|
+
/** All allowlist rows from both tables, joined with the originating
|
|
164
|
+
* session metadata. Drives the Settings → Security pane's "Manage…"
|
|
165
|
+
* modal so the user can review and revoke past decisions.
|
|
166
|
+
*
|
|
167
|
+
* Each entry's display value is reconstructed live from a matching
|
|
168
|
+
* finding's message text — the same plaintext the findings view
|
|
169
|
+
* shows (blurred). Nothing is persisted on the allowlist row. */
|
|
170
|
+
export declare function listAllowlistEntries(db: Database.Database): AllowlistEntryRow[];
|
|
171
|
+
/** Total allowlist rows across both scopes. A cheap header badge —
|
|
172
|
+
* two `SELECT COUNT(*)` summed, no per-row value reconstruction.
|
|
173
|
+
* Use this instead of `listAllowlistEntries().length` for counts. */
|
|
174
|
+
export declare function countAllowlistEntries(db: Database.Database): number;
|
|
175
|
+
/** Flip a finding to 'dismissed' and, depending on scope, write the
|
|
176
|
+
* allowlist entry so future rescans honor the decision. Caller
|
|
177
|
+
* wraps in a transaction. */
|
|
178
|
+
export declare function dismissFinding(db: Database.Database, findingId: number, scope: 'session' | 'global', recomputeCounts?: boolean): number | null;
|
|
179
|
+
/** Batch variant of {@link dismissFinding}. Dismisses many findings in a
|
|
180
|
+
* single transaction — one allowlist write + one `updateSessionCounts`
|
|
181
|
+
* per affected session instead of N parallel IPC round-trips, each of
|
|
182
|
+
* which recomputes counts. Mirrors the bulk-purge pattern
|
|
183
|
+
* (`purgeFindings`). Returns the distinct session ids touched, in
|
|
184
|
+
* first-seen order, so the IPC layer can emit one change event per
|
|
185
|
+
* session. Unknown ids are skipped. */
|
|
186
|
+
export declare function dismissFindings(db: Database.Database, findingIds: readonly number[], scope: 'session' | 'global'): number[];
|
|
187
|
+
/** Re-activate a dismissed finding and remove the allowlist entry
|
|
188
|
+
* that pinned it (both scopes, since UI doesn't always know which). */
|
|
189
|
+
export declare function undismissFinding(db: Database.Database, findingId: number): number | null;
|
|
190
|
+
//# sourceMappingURL=repo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repo.d.ts","sourceRoot":"","sources":["../../src/security/repo.ts"],"names":[],"mappings":"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"}
|