sertivibed 0.1.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.
@@ -0,0 +1,278 @@
1
+ "use strict";
2
+ /**
3
+ * Markdown Reporter
4
+ *
5
+ * Genererer profesjonell rapport UTEN LLM.
6
+ * Alt er deterministisk og basert på claims + evidence.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.generateMarkdownReport = generateMarkdownReport;
10
+ const types_1 = require("../types");
11
+ // ============================================
12
+ // MAIN EXPORT
13
+ // ============================================
14
+ function generateMarkdownReport(result) {
15
+ const sections = [];
16
+ sections.push(generateHeader(result));
17
+ sections.push(generateScopeSection(result));
18
+ sections.push(generateCoverageSection(result));
19
+ sections.push(generateSummarySection(result));
20
+ if (result.claims.length > 0) {
21
+ sections.push(generateFindingsSection(result));
22
+ }
23
+ sections.push(generatePassedSection(result));
24
+ sections.push(generateActionPlanSection(result));
25
+ sections.push(generateFooter(result));
26
+ return sections.join("\n\n");
27
+ }
28
+ // ============================================
29
+ // HEADER
30
+ // ============================================
31
+ function generateHeader(result) {
32
+ const verdict = getVerdict(result);
33
+ const verdictEmoji = verdict === "BESTÅTT" ? "✅" : verdict === "BESTÅTT MED MERKNADER" ? "⚠️" : "❌";
34
+ return `
35
+ ═══════════════════════════════════════════════════════════════════════════════
36
+ SERTIVIBED SIKKERHETSRAPPORT
37
+ ${result.meta.projectName}
38
+ ${new Date(result.meta.scannedAt).toLocaleDateString("no-NO")}
39
+ ═══════════════════════════════════════════════════════════════════════════════
40
+
41
+ ${verdictEmoji} **Totalvurdering: ${verdict}**
42
+ `.trim();
43
+ }
44
+ // ============================================
45
+ // SCOPE
46
+ // ============================================
47
+ function generateScopeSection(result) {
48
+ const confidence = result.meta.totalFilesScanned > 10 ? "HØY" :
49
+ result.meta.totalFilesScanned > 3 ? "MEDIUM" : "LAV";
50
+ const skippedCount = result.rulesSkipped?.length || 0;
51
+ const totalRules = result.rulesChecked.length + skippedCount;
52
+ return `
53
+ ## Scope & Dekning
54
+
55
+ | Område | Detaljer |
56
+ |---------------------|----------------------------------------|
57
+ | Prosjekt | ${result.meta.projectName} |
58
+ | Stack | ${result.meta.stack.join(", ") || "Ukjent"} |
59
+ | Filer analysert | ${result.meta.totalFilesScanned} |
60
+ | Regler kjørt | ${result.rulesChecked.length}/${totalRules} |
61
+ | Varighet | ${result.meta.scanDurationMs}ms |
62
+ | Confidence | ${confidence} |
63
+ `.trim();
64
+ }
65
+ // ============================================
66
+ // COVERAGE
67
+ // ============================================
68
+ function generateCoverageSection(result) {
69
+ const rulesExecuted = result.rulesChecked.join(", ");
70
+ let skippedSection = "";
71
+ if (result.rulesSkipped && result.rulesSkipped.length > 0) {
72
+ const skippedList = result.rulesSkipped
73
+ .map(s => `- ⏭️ ${s.ruleId}: ${s.reason}`)
74
+ .join("\n");
75
+ skippedSection = `
76
+ **Regler hoppet over:**
77
+ ${skippedList}
78
+ `;
79
+ }
80
+ return `
81
+ ## Coverage
82
+
83
+ **Regler kjørt:**
84
+ ✅ ${rulesExecuted}
85
+ ${skippedSection}
86
+ **Filer analysert:**
87
+ - ${result.meta.totalFilesScanned} totalt
88
+ `.trim();
89
+ }
90
+ // ============================================
91
+ // SUMMARY
92
+ // ============================================
93
+ function generateSummarySection(result) {
94
+ const { summary } = result;
95
+ return `
96
+ ## Sammendrag
97
+
98
+ | Severity | Antall | Betydning |
99
+ |-----------|--------|------------------------------------------|
100
+ | 🔴 CRITICAL | ${summary.bySeverity.CRITICAL.toString().padStart(2)} | Må fikses umiddelbart |
101
+ | 🟠 HIGH | ${summary.bySeverity.HIGH.toString().padStart(2)} | Må fikses før produksjon |
102
+ | 🟡 MEDIUM | ${summary.bySeverity.MEDIUM.toString().padStart(2)} | Bør fikses snart |
103
+ | 🟢 LOW | ${summary.bySeverity.LOW.toString().padStart(2)} | Vurder å fikse |
104
+ | ⚪ INFO | ${summary.bySeverity.INFO.toString().padStart(2)} | Informasjon |
105
+
106
+ **Totalt:** ${summary.total} funn | **Bestått:** ${summary.passed} regler | **Feilet:** ${summary.failed} regler
107
+ `.trim();
108
+ }
109
+ // ============================================
110
+ // FINDINGS
111
+ // ============================================
112
+ function generateFindingsSection(result) {
113
+ const findings = result.claims
114
+ .sort((a, b) => types_1.SEVERITY_ORDER[b.severity] - types_1.SEVERITY_ORDER[a.severity])
115
+ .map((claim, index) => generateFinding(claim, index + 1))
116
+ .join("\n\n---\n\n");
117
+ return `
118
+ ## Funn
119
+
120
+ ${findings}
121
+ `.trim();
122
+ }
123
+ function generateFinding(claim, index) {
124
+ const severityEmoji = getSeverityEmoji(claim.severity);
125
+ const impactLabel = getImpactLabel(claim.impactType);
126
+ let evidenceSection = "";
127
+ if (claim.evidence.length > 0) {
128
+ evidenceSection = `
129
+ **Bevis fra koden:**
130
+
131
+ ${claim.evidence.slice(0, 3).map(e => `
132
+ 📄 \`${e.path}\` (linje ${e.lineStart}-${e.lineEnd})
133
+ \`\`\`
134
+ ${e.snippet}
135
+ \`\`\`
136
+ `).join("\n")}`;
137
+ }
138
+ let correlationSection = "";
139
+ if (claim.correlationDetails) {
140
+ correlationSection = `
141
+ **Kryss-korrelasjon:**
142
+ - Koden bruker funksjonaliteten ✓
143
+ - SQL-pattern som mangler: \`${claim.correlationDetails.sqlMissing}\`
144
+ `;
145
+ }
146
+ return `
147
+ ### ${severityEmoji} Funn #${index}: ${claim.title}
148
+
149
+ **Regel:** ${claim.ruleId}
150
+ **Kategori:** ${claim.category}
151
+ **Severity:** ${claim.severity}
152
+ **Impact:** ${impactLabel}
153
+
154
+ **Beskrivelse:**
155
+ ${claim.statement}
156
+ ${evidenceSection}
157
+ ${correlationSection}
158
+ **Verifisering:**
159
+ ${claim.verificationSteps.map((s, i) => `${i + 1}. ${s}`).join("\n")}
160
+
161
+ **Anbefalt fiks:**
162
+ \`\`\`
163
+ ${claim.fixHint}
164
+ \`\`\`
165
+ `.trim();
166
+ }
167
+ // ============================================
168
+ // PASSED
169
+ // ============================================
170
+ function generatePassedSection(result) {
171
+ const failedRules = new Set(result.claims.map(c => c.ruleId));
172
+ const passedRules = result.rulesChecked.filter(id => !failedRules.has(id));
173
+ if (passedRules.length === 0) {
174
+ return `## Bestått\n\nIngen regler bestått uten funn.`;
175
+ }
176
+ return `
177
+ ## Bestått (ingen funn)
178
+
179
+ ${passedRules.map(id => `✅ ${id}`).join("\n")}
180
+ `.trim();
181
+ }
182
+ // ============================================
183
+ // ACTION PLAN
184
+ // ============================================
185
+ function generateActionPlanSection(result) {
186
+ if (result.claims.length === 0) {
187
+ return `
188
+ ## Handlingsplan
189
+
190
+ 🎉 Ingen sikkerhetsfunn! Prosjektet bestod alle ${result.rulesChecked.length} sjekker.
191
+ `.trim();
192
+ }
193
+ const prioritized = result.claims
194
+ .sort((a, b) => types_1.SEVERITY_ORDER[b.severity] - types_1.SEVERITY_ORDER[a.severity])
195
+ .slice(0, 5);
196
+ const rows = prioritized.map((claim, i) => {
197
+ const time = estimateFixTime(claim);
198
+ return `| ${i + 1} | ${claim.title} | ${claim.severity} | ${time} |`;
199
+ });
200
+ return `
201
+ ## Prioritert Handlingsplan
202
+
203
+ | # | Funn | Severity | Estimert tid |
204
+ |---|------|----------|--------------|
205
+ ${rows.join("\n")}
206
+
207
+ **Anbefaling:** Start med CRITICAL og HIGH severity funn. Disse bør fikses før produksjon.
208
+ `.trim();
209
+ }
210
+ // ============================================
211
+ // FOOTER
212
+ // ============================================
213
+ function generateFooter(result) {
214
+ return `
215
+ ---
216
+
217
+ ## Metadata
218
+
219
+ | | |
220
+ |---|---|
221
+ | Rapport generert | ${result.meta.scannedAt} |
222
+ | Sertivibed versjon | ${result.meta.certivibeVersion} |
223
+ | Regler versjon | ${result.meta.rulesVersion} |
224
+
225
+ **Ansvarsfraskrivelse:**
226
+ Denne rapporten er en automatisert screening av vanlige sikkerhetsfeil.
227
+ Den erstatter ikke en full sikkerhetsrevisjon utført av sertifiserte eksperter.
228
+ Sertivibed garanterer ikke at alle sårbarheter er identifisert.
229
+
230
+ ---
231
+ *Generert av Sertivibed — Evidence-first security screening*
232
+ `.trim();
233
+ }
234
+ // ============================================
235
+ // HELPERS
236
+ // ============================================
237
+ function getVerdict(result) {
238
+ const { summary } = result;
239
+ if (summary.bySeverity.CRITICAL > 0)
240
+ return "IKKE BESTÅTT";
241
+ if (summary.bySeverity.HIGH >= 2)
242
+ return "IKKE BESTÅTT";
243
+ if (summary.bySeverity.HIGH === 1)
244
+ return "BESTÅTT MED MERKNADER";
245
+ if (summary.bySeverity.MEDIUM > 2)
246
+ return "BESTÅTT MED MERKNADER";
247
+ return "BESTÅTT";
248
+ }
249
+ function getSeverityEmoji(severity) {
250
+ switch (severity) {
251
+ case "CRITICAL": return "🔴";
252
+ case "HIGH": return "🟠";
253
+ case "MEDIUM": return "🟡";
254
+ case "LOW": return "🟢";
255
+ case "INFO": return "⚪";
256
+ }
257
+ }
258
+ function getImpactLabel(impact) {
259
+ switch (impact) {
260
+ case "data_exposure": return "Dataeksponering";
261
+ case "privilege_escalation": return "Privilegie-eskalering";
262
+ case "functional_break": return "Funksjonell feil";
263
+ case "info_leak": return "Informasjonslekkasje";
264
+ default: return impact;
265
+ }
266
+ }
267
+ function estimateFixTime(claim) {
268
+ switch (claim.category) {
269
+ case "RLS": return "15-30 min";
270
+ case "AUTH": return "30-60 min";
271
+ case "XSS": return "10-20 min";
272
+ case "SECRETS": return "5-10 min";
273
+ case "PRIVACY": return "10-15 min";
274
+ case "STORAGE": return "20-30 min";
275
+ case "CONFIG": return "10-15 min";
276
+ default: return "15-30 min";
277
+ }
278
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Sertivibed Rules v0.1
3
+ *
4
+ * 12 regler som gir høy verdi med lav falsk positiv rate.
5
+ *
6
+ * Kategorier:
7
+ * - RLS (3 regler): Database row-level security
8
+ * - AUTH (1 regel): Service role leakage
9
+ * - PRIVACY (2 regler): Token storage, PII logging
10
+ * - SECRETS (1 regel): Hardcoded API keys
11
+ * - XSS (2 regler): Frontend injection risks
12
+ * - STORAGE (2 regler): File upload security
13
+ * - CONFIG (1 regel): Security headers
14
+ */
15
+ import { Rule } from "../types";
16
+ export declare const RULES: Rule[];
17
+ export declare function getRuleById(id: string): Rule | undefined;
18
+ export declare function getRulesByCategory(category: Rule["category"]): Rule[];
19
+ export declare function getRulesBySeverity(severity: Rule["severity"]): Rule[];
@@ -0,0 +1,263 @@
1
+ "use strict";
2
+ /**
3
+ * Sertivibed Rules v0.1
4
+ *
5
+ * 12 regler som gir høy verdi med lav falsk positiv rate.
6
+ *
7
+ * Kategorier:
8
+ * - RLS (3 regler): Database row-level security
9
+ * - AUTH (1 regel): Service role leakage
10
+ * - PRIVACY (2 regler): Token storage, PII logging
11
+ * - SECRETS (1 regel): Hardcoded API keys
12
+ * - XSS (2 regler): Frontend injection risks
13
+ * - STORAGE (2 regler): File upload security
14
+ * - CONFIG (1 regel): Security headers
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.RULES = void 0;
18
+ exports.getRuleById = getRuleById;
19
+ exports.getRulesByCategory = getRulesByCategory;
20
+ exports.getRulesBySeverity = getRulesBySeverity;
21
+ exports.RULES = [
22
+ // ============================================
23
+ // RLS RULES (3)
24
+ // ============================================
25
+ {
26
+ id: "RLS001",
27
+ title: "RLS ikke aktivert på tabell",
28
+ category: "RLS",
29
+ severity: "CRITICAL",
30
+ kind: "absence",
31
+ pattern: "ENABLE ROW LEVEL SECURITY",
32
+ paths: [
33
+ "**/supabase-setup.sql",
34
+ "**/supabase/migrations/**/*.sql",
35
+ "**/*.sql"
36
+ ],
37
+ rationale: "Uten RLS kan enhver autentisert bruker lese alle rader i tabellen. Dette er den vanligste og mest alvorlige feilen i Supabase-apper.",
38
+ fixHint: "ALTER TABLE <tabellnavn> ENABLE ROW LEVEL SECURITY;",
39
+ impactType: "data_exposure"
40
+ },
41
+ {
42
+ id: "RLS002",
43
+ title: "Manglende DELETE policy når .delete() brukes",
44
+ category: "RLS",
45
+ severity: "MEDIUM",
46
+ kind: "correlation",
47
+ paths: [], // Ikke brukt for correlation
48
+ correlate: {
49
+ codePattern: "\\.delete\\s*\\(",
50
+ codePaths: ["**/src/**/*.ts", "**/src/**/*.tsx", "**/src/**/*.js", "**/src/**/*.jsx"],
51
+ sqlPattern: "FOR DELETE",
52
+ sqlPaths: ["**/*.sql"],
53
+ condition: "code_without_sql"
54
+ },
55
+ rationale: "Koden prøver å slette data, men ingen DELETE-policy finnes. Dette vil enten feile eller (verre) tillate sletting uten autorisasjonssjekk.",
56
+ fixHint: "CREATE POLICY \"users_delete_own\" ON <tabell> FOR DELETE USING (auth.uid() = user_id);",
57
+ impactType: "functional_break"
58
+ },
59
+ {
60
+ id: "RLS003",
61
+ title: "Policy mangler eierskapssjekk",
62
+ category: "RLS",
63
+ severity: "HIGH",
64
+ kind: "presence",
65
+ pattern: "USING\\s*\\(\\s*true\\s*\\)|USING\\s*\\(\\s*auth\\.uid\\(\\)\\s+IS\\s+NOT\\s+NULL\\s*\\)",
66
+ paths: ["**/*.sql"],
67
+ rationale: "En policy som bare sjekker 'true' eller 'auth.uid() IS NOT NULL' bekrefter innlogging, men ikke eierskap. Bruker A kan lese bruker B sine data.",
68
+ fixHint: "Endre USING (true) til USING (user_id = auth.uid())",
69
+ impactType: "data_exposure"
70
+ },
71
+ // ============================================
72
+ // AUTH RULES (1)
73
+ // ============================================
74
+ {
75
+ id: "AUTH001",
76
+ title: "Service role key i klientkode",
77
+ category: "AUTH",
78
+ severity: "CRITICAL",
79
+ kind: "presence",
80
+ pattern: "service_role|SUPABASE_SERVICE_ROLE|SERVICE_ROLE_KEY",
81
+ paths: [
82
+ "**/src/**/*.ts",
83
+ "**/src/**/*.tsx",
84
+ "**/src/**/*.js",
85
+ "**/src/**/*.jsx",
86
+ "**/app/**/*.ts",
87
+ "**/app/**/*.tsx",
88
+ "**/pages/**/*.ts",
89
+ "**/pages/**/*.tsx",
90
+ "**/components/**/*.ts",
91
+ "**/components/**/*.tsx"
92
+ ],
93
+ rationale: "Service role key omgår ALL Row Level Security. Hvis den er i klientkode, kan en angriper hente den fra browser DevTools og få full databasetilgang.",
94
+ fixHint: "Bruk kun anon key i frontend. Service role kun på server med proper auth.",
95
+ impactType: "privilege_escalation"
96
+ },
97
+ // ============================================
98
+ // PRIVACY RULES (2)
99
+ // ============================================
100
+ {
101
+ id: "PRIV001",
102
+ title: "Auth token i localStorage",
103
+ category: "PRIVACY",
104
+ severity: "MEDIUM",
105
+ kind: "presence",
106
+ pattern: "localStorage\\.(setItem|getItem)\\s*\\([^)]*(?:token|auth|session|jwt|access_token|refresh_token)",
107
+ paths: [
108
+ "**/src/**/*.ts",
109
+ "**/src/**/*.tsx",
110
+ "**/src/**/*.js",
111
+ "**/src/**/*.jsx"
112
+ ],
113
+ rationale: "Tokens i localStorage er sårbare for XSS-angrep. Supabase håndterer dette automatisk — manuell lagring tyder på feil implementasjon.",
114
+ fixHint: "La Supabase håndtere token-lagring automatisk, eller bruk httpOnly cookies.",
115
+ impactType: "data_exposure"
116
+ },
117
+ {
118
+ id: "PRIV002",
119
+ title: "PII i console.log",
120
+ category: "PRIVACY",
121
+ severity: "MEDIUM",
122
+ kind: "presence",
123
+ pattern: "console\\.(log|info|debug|warn|error)\\s*\\([^)]*(?:email|password|token|user|session|phone|ssn|personnummer|fødselsnummer)",
124
+ paths: [
125
+ "**/src/**/*.ts",
126
+ "**/src/**/*.tsx",
127
+ "**/src/**/*.js",
128
+ "**/src/**/*.jsx"
129
+ ],
130
+ rationale: "Logger i produksjon kan inneholde sensitiv info som ender i browser console, Sentry, eller log-filer. GDPR-brudd waiting to happen.",
131
+ fixHint: "Fjern console.log eller redakt sensitive felter før logging.",
132
+ impactType: "info_leak"
133
+ },
134
+ // ============================================
135
+ // SECRETS RULES (1)
136
+ // ============================================
137
+ {
138
+ id: "SEC001",
139
+ title: "Hardkodet API-nøkkel",
140
+ category: "SECRETS",
141
+ severity: "HIGH",
142
+ kind: "presence",
143
+ // Matcher vanlige API-nøkkel-mønstre, men ikke env-variabler
144
+ pattern: "(?:apiKey|api_key|apikey)\\s*[:=]\\s*['\"][A-Za-z0-9_-]{20,}['\"]|sk-[A-Za-z0-9]{32,}|AIza[A-Za-z0-9_-]{35}",
145
+ paths: [
146
+ "**/src/**/*.ts",
147
+ "**/src/**/*.tsx",
148
+ "**/src/**/*.js",
149
+ "**/src/**/*.jsx",
150
+ "**/*.json"
151
+ ],
152
+ rationale: "API-nøkler hardkodet i koden havner i git-historikk og er vanskelig å rotere. Bruk miljøvariabler.",
153
+ fixHint: "Flytt til .env fil og bruk process.env.API_KEY",
154
+ impactType: "privilege_escalation"
155
+ },
156
+ // ============================================
157
+ // XSS RULES (2)
158
+ // ============================================
159
+ {
160
+ id: "XSS001",
161
+ title: "dangerouslySetInnerHTML brukt",
162
+ category: "XSS",
163
+ severity: "HIGH",
164
+ kind: "presence",
165
+ pattern: "dangerouslySetInnerHTML",
166
+ paths: [
167
+ "**/src/**/*.tsx",
168
+ "**/src/**/*.jsx",
169
+ "**/components/**/*.tsx",
170
+ "**/components/**/*.jsx"
171
+ ],
172
+ rationale: "dangerouslySetInnerHTML injiserer rå HTML i DOM. Hvis innholdet kommer fra bruker-input eller database, er dette en XSS-vektor.",
173
+ fixHint: "Bruk en sanitizer som DOMPurify, eller unngå rå HTML helt.",
174
+ impactType: "data_exposure"
175
+ },
176
+ {
177
+ id: "XSS002",
178
+ title: "innerHTML assignment",
179
+ category: "XSS",
180
+ severity: "HIGH",
181
+ kind: "presence",
182
+ pattern: "\\.innerHTML\\s*=",
183
+ paths: [
184
+ "**/src/**/*.ts",
185
+ "**/src/**/*.tsx",
186
+ "**/src/**/*.js",
187
+ "**/src/**/*.jsx"
188
+ ],
189
+ rationale: "Direkte innerHTML-tilordning er en klassisk XSS-vektor. React bruker dette internt med dangerouslySetInnerHTML, men manuell bruk er risikabelt.",
190
+ fixHint: "Bruk textContent for tekst, eller sanitize HTML med DOMPurify.",
191
+ impactType: "data_exposure"
192
+ },
193
+ // ============================================
194
+ // STORAGE RULES (2)
195
+ // ============================================
196
+ {
197
+ id: "STOR001",
198
+ title: "Fil-opplasting uten validering",
199
+ category: "STORAGE",
200
+ severity: "MEDIUM",
201
+ kind: "presence",
202
+ pattern: "\\.upload\\s*\\(|storage\\.from\\s*\\(",
203
+ paths: [
204
+ "**/src/**/*.ts",
205
+ "**/src/**/*.tsx",
206
+ "**/src/**/*.js",
207
+ "**/src/**/*.jsx"
208
+ ],
209
+ rationale: "Filopplasting uten type/størrelse-validering kan føre til storage-misbruk eller ondsinnet innhold. Sjekk at det er validering FØR upload-kallet.",
210
+ fixHint: "Valider filtype (MIME + extension) og størrelse før upload.",
211
+ impactType: "info_leak"
212
+ },
213
+ {
214
+ id: "STOR002",
215
+ title: "Offentlig storage URL uten signering",
216
+ category: "STORAGE",
217
+ severity: "MEDIUM",
218
+ kind: "presence",
219
+ pattern: "getPublicUrl\\s*\\(",
220
+ paths: [
221
+ "**/src/**/*.ts",
222
+ "**/src/**/*.tsx",
223
+ "**/src/**/*.js",
224
+ "**/src/**/*.jsx"
225
+ ],
226
+ rationale: "getPublicUrl gir en URL som er tilgjengelig for alle. Hvis filen inneholder sensitiv data, bruk createSignedUrl med kort TTL i stedet.",
227
+ fixHint: "Bruk createSignedUrl for sensitive filer, eller sett opp storage policies.",
228
+ impactType: "data_exposure"
229
+ },
230
+ // ============================================
231
+ // CONFIG RULES (1)
232
+ // ============================================
233
+ {
234
+ id: "CONF001",
235
+ title: "Manglende Content Security Policy",
236
+ category: "CONFIG",
237
+ severity: "LOW",
238
+ kind: "absence",
239
+ pattern: "Content-Security-Policy|contentSecurityPolicy",
240
+ paths: [
241
+ "**/next.config.js",
242
+ "**/next.config.ts",
243
+ "**/next.config.mjs",
244
+ "**/vercel.json",
245
+ "**/middleware.ts"
246
+ ],
247
+ rationale: "Content Security Policy (CSP) begrenser hvilke scripts som kan kjøre. Uten CSP er XSS-angrep lettere å utføre.",
248
+ fixHint: "Legg til CSP headers i next.config.js eller middleware.",
249
+ impactType: "info_leak"
250
+ }
251
+ ];
252
+ // ============================================
253
+ // HELPERS
254
+ // ============================================
255
+ function getRuleById(id) {
256
+ return exports.RULES.find(r => r.id === id);
257
+ }
258
+ function getRulesByCategory(category) {
259
+ return exports.RULES.filter(r => r.category === category);
260
+ }
261
+ function getRulesBySeverity(severity) {
262
+ return exports.RULES.filter(r => r.severity === severity);
263
+ }
package/dist/scan.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Sertivibed Scanner
3
+ *
4
+ * Hovedlogikk for å kjøre regler og samle claims.
5
+ */
6
+ import { ScanResult, ScanConfig } from "./types";
7
+ export declare function scan(config: ScanConfig): Promise<ScanResult>;
8
+ export { RULES } from "./rules/index";