reposec 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.
package/README.md ADDED
@@ -0,0 +1,733 @@
1
+ # RepoSec
2
+
3
+ > **Find the security gaps in your public GitHub repo β€” before attackers do.**
4
+
5
+ RepoSec is a defensive, read-only scanner that audits a public GitHub repository and returns a clear, prioritized security report. It checks for exposed `.env` files, missing `.gitignore` rules, hardcoded secret patterns in source and deployed JavaScript bundles, missing `SECURITY.md` and `CODEOWNERS`, weak CI, Dockerfile misconfigurations, dependency hygiene, and more.
6
+
7
+ The scanner **never modifies** the target repository and **never exfiltrates** its data. It is a hygiene tool, not an offensive one.
8
+
9
+ <p align="left">
10
+ <a href="https://reposec.zanesense.dev"><img alt="Live Demo" src="https://img.shields.io/badge/Live%20Demo-reposec.zanesense.dev-22c55e?style=for-the-badge&logo=vercel&logoColor=white" /></a>
11
+ <a href="https://github.com/zanesense/reposec/blob/main/LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-22c55e?style=for-the-badge" /></a>
12
+ <a href="https://github.com/zanesense/reposec"><img alt="Version" src="https://img.shields.io/badge/version-0.1.0-6366f1?style=for-the-badge" /></a>
13
+ <a href="https://github.com/zanesense/reposec/stargazers"><img alt="Stars" src="https://img.shields.io/github/stars/zanesense/reposec?style=for-the-badge&color=facc15" /></a>
14
+ <a href="https://github.com/zanesense/reposec/issues"><img alt="Issues" src="https://img.shields.io/github/issues/zanesense/reposec?style=for-the-badge&color=f97316" /></a>
15
+ <a href="https://github.com/zanesense/reposec/pulls"><img alt="PRs" src="https://img.shields.io/github/issues-pr/zanesense/reposec?style=for-the-badge&color=38bdf8" /></a>
16
+ <img alt="Language" src="https://img.shields.io/badge/TypeScript-strict-3178c6?style=for-the-badge&logo=typescript&logoColor=white" />
17
+ <img alt="Framework" src="https://img.shields.io/badge/Next.js-16-000000?style=for-the-badge&logo=next.js&logoColor=white" />
18
+ <img alt="React" src="https://img.shields.io/badge/React-19-149eca?style=for-the-badge&logo=react&logoColor=white" />
19
+ <img alt="Last commit" src="https://img.shields.io/github/last-commit/zanesense/reposec?style=for-the-badge" />
20
+ </p>
21
+
22
+ > πŸš€ **[Try the live demo β†’](https://reposec.zanesense.dev)** β€” paste any public GitHub URL and get a security report in seconds. No signup, no token required.
23
+
24
+ ---
25
+
26
+ ## 🧭 Quick Links
27
+
28
+ | Link | Description |
29
+ | --- | --- |
30
+ | 🌐 [Live demo](https://reposec.zanesense.dev) | Hosted scanner at `reposec.zanesense.dev` |
31
+ | πŸ“¦ [Repository](https://github.com/zanesense/reposec) | Source code, issues, and releases |
32
+ | πŸ› [Issue tracker](https://github.com/zanesense/reposec/issues) | Report bugs and request features |
33
+ | πŸ”€ [Pull requests](https://github.com/zanesense/reposec/pulls) | Open a PR to contribute |
34
+ | ⭐ [Stargazers](https://github.com/zanesense/reposec/stargazers) | See who starred the project |
35
+ | πŸ“„ [License](https://github.com/zanesense/reposec/blob/main/LICENSE) | MIT terms |
36
+
37
+ ---
38
+
39
+ ## πŸ—‚οΈ Table of Contents
40
+
41
+ - [πŸ“– Overview](#-overview)
42
+ - [✨ Features](#-features)
43
+ - [🧠 How It Works](#-how-it-works)
44
+ - [πŸ“‚ Repository Structure](#-repository-structure)
45
+ - [🧰 Technologies](#-technologies)
46
+ - [πŸ“‹ Requirements](#-requirements)
47
+ - [πŸ› οΈ Installation](#️-installation)
48
+ - [Production build](#production-build)
49
+ - [βš™οΈ Configuration](#️-configuration)
50
+ - [πŸ› οΈ Usage](#️-usage)
51
+ - [Web UI](#web-ui)
52
+ - [Local CLI](#local-cli)
53
+ - [Programmatic API](#programmatic-api)
54
+ - [Screenshots](#screenshots)
55
+ - [πŸ§ͺ Testing](#-testing)
56
+ - [πŸ”„ Project Flow](#-project-flow)
57
+ - [πŸ”Œ API Reference](#-api-reference)
58
+ - [`POST /api/scan`](#post-apiscan)
59
+ - [πŸ’‘ Examples](#-examples)
60
+ - [Try these public repositories](#try-these-public-repositories)
61
+ - [What a finding looks like](#what-a-finding-looks-like)
62
+ - [πŸš€ Deployment](#-deployment)
63
+ - [Vercel (recommended)](#vercel-recommended)
64
+ - [Docker](#docker)
65
+ - [Self-hosted Node](#self-hosted-node)
66
+ - [πŸ—ΊοΈ Roadmap](#️-roadmap)
67
+ - [🀝 Contributing](#-contributing)
68
+ - [πŸ“ Changelog](#-changelog)
69
+ - [πŸ›Ÿ Troubleshooting](#-troubleshooting)
70
+ - [πŸ” Security](#-security)
71
+ - [πŸ“„ License](#-license)
72
+ - [❀️ Acknowledgements](#️-acknowledgements)
73
+
74
+ ---
75
+
76
+ ## πŸ“– Overview
77
+
78
+ Most repository leaks do not start with a sophisticated exploit. They start with **a committed `.env`, a missing `SECURITY.md`, or a CI workflow with `write-all` permissions**. RepoSec is a fast, opinionated linter for your repository's public surface: paste a GitHub URL, get a security score, a category-by-category pass/fail breakdown, severity-grouped findings, and copy-pasteable fixes.
79
+
80
+ It is built for:
81
+
82
+ - πŸ§‘β€πŸ’» **Maintainers** who want a quick hygiene check before tagging a release.
83
+ - πŸ›‘οΈ **Security engineers** who need a free, no-signup pre-audit for open-source projects.
84
+ - πŸ“š **Educators and students** who want to teach the basics of repo hardening with a live report.
85
+ - πŸ€– **LLM-assisted workflows** β€” every finding ships with a fix prompt you can paste into your editor agent.
86
+
87
+ Why a defensive tool? Because catching mistakes early is cheaper, friendlier, and more effective than chasing them after a leak. RepoSec is intentionally framed as a **scanner**, not an exploit kit.
88
+
89
+ ---
90
+
91
+ ## ✨ Features
92
+
93
+ - πŸ” **12 static check modules** covering env hygiene, secrets, docs, scripts, GitHub features, container hygiene, community health, CI quality, repo metadata, source patterns, and dependencies.
94
+ - 🧠 **55+ secret patterns** out of the box, ported from the [gitleaks](https://github.com/gitleaks/gitleaks) ruleset: OpenAI, Anthropic (incl. admin), Groq, HuggingFace (user + org), Perplexity, Notion, GitHub (classic + fine-grained), GitLab, npm, PyPI, Slack (tokens + webhook URLs), Discord, Telegram, Twilio, SendGrid, Mailgun, Stripe (live + test), Google API, AWS (AKIA/ASIA + Bedrock ABSK + secret keys), Azure AD, Alibaba, Heroku, Pulumi, Fly.io, New Relic, Dynatrace, Grafana Cloud, Databricks, HashiCorp Vault (service + batch), Terraform Cloud, EasyPost, ReadMe, Prefect, Sourcegraph, Microsoft Teams webhooks, private key blocks, SSH public keys, generic JWTs, database URLs, curl auth in shell commands, and generic credential assignments.
95
+ - πŸ“Š **Security score (0–100)** with bands: _Excellent_, _Good_, _Fair_, _Weak_, _Critical_.
96
+ - πŸ—‚οΈ **Per-category breakdown** showing exactly which checks passed, failed, warned, or were missing.
97
+ - 🧾 **Severity-grouped findings** with masked evidence and a "Fix it like this" panel.
98
+ - πŸ“₯ **One-click exports** for:
99
+ - Markdown report
100
+ - JSON report
101
+ - SARIF report for GitHub Code Scanning
102
+ - `SECURITY.md` template
103
+ - `.env.example` template
104
+ - GitHub issue checklist
105
+ - LLM fix prompt
106
+ - πŸŒ— **Polished UI** with a RepoSec design system, light/dark theming, and accessible shadcn-style primitives.
107
+ - πŸ§ͺ **Read-only by design** β€” no writes, no auth, no database, no telemetry beyond the GitHub API.
108
+ - 🐒 **No GitHub auth required** for public repos. Optional token raises the rate limit to 5000 req/h.
109
+
110
+ ### New scanner capabilities
111
+
112
+ - **Full-repo secret file selection:** RepoSec fetches likely secret-bearing files across the tree, including JS/TS, Python, env files, shell scripts, Terraform, config files, keys, SQL, and source maps while skipping dependencies, build output, binary-heavy files, and oversized blobs.
113
+ - **Deployed bundle scanning:** paste an optional deployed app URL and RepoSec fetches the public page, discovers JavaScript bundles and source maps, and scans the same assets users can inspect in Chrome DevTools Sources. If the repo metadata has a homepage URL, the API attempts that scan automatically.
114
+ - **SARIF export:** reports can be exported as SARIF for GitHub Code Scanning and compatible security dashboards.
115
+ - **Baseline suppression:** reviewed findings can be ignored with `.reposecignore`, `reposec-baseline.json`, or `.reposec-baseline.json` by matching finding id, fingerprint, file, file:line, or title.
116
+ - **Local CLI:** scan private/local repos without uploading contents using `npm run scan:local -- .`; add `--history` to scan recent git history and `--format sarif` for CI output.
117
+ - **Confidence and fingerprints:** secret findings include `confidence`, `fingerprint`, and optional `verified` metadata. Raw secret values stay server-side and evidence remains masked.
118
+ - **Opt-in verification:** supported GitHub, Stripe, and HuggingFace tokens can be verified live with the web checkbox, API `verify: true`, or CLI `--verify`.
119
+
120
+ ---
121
+
122
+ ## 🧠 How It Works
123
+
124
+ RepoSec is a server-rendered Next.js application. The browser is a thin client; the real work happens in `app/api/scan/route.ts`.
125
+
126
+ ```mermaid
127
+ flowchart TD
128
+ A[User pastes a public GitHub URL] --> B[Client posts to /api/scan]
129
+ A2[Optional deployed app URL] --> B
130
+ B --> C[Server parses owner/repo]
131
+ C --> D[GitHub REST API: repo metadata]
132
+ D --> E[GitHub tree API: file tree]
133
+ E --> F[Fetch important files and likely secret-bearing source files]
134
+ B --> X[Fetch deployed HTML, JS bundles, and source maps]
135
+ F --> G[Rule-based scanner: 12 modules]
136
+ X --> G
137
+ G --> H[Score calculation: 100 minus weighted findings]
138
+ H --> I[ScanReport JSON]
139
+ I --> J[Client renders score, tabs, findings]
140
+ J --> K[Exports: Markdown, JSON, SECURITY.md, .env.example, issue checklist, fix prompt]
141
+ ```
142
+
143
+ Key design choices:
144
+
145
+ - **Server-side fetching** keeps the GitHub token (if any) out of the browser and avoids CORS surprises.
146
+ - **Static rule engine** in `lib/scanner.ts` β€” easy to extend, deterministic, easy to test.
147
+ - **Bounded client-bundle scanning** only fetches public HTTPS pages/assets, caps file sizes, and blocks private/internal hosts.
148
+ - **No persistence**: a scan is a single request/response cycle. There is no database to leak.
149
+
150
+ ---
151
+
152
+ ## πŸ—‚οΈ Repository Structure
153
+
154
+ ```text
155
+ reposec/
156
+ β”œβ”€β”€ app/
157
+ β”‚ β”œβ”€β”€ layout.tsx # Root layout: fonts, theme, nav, footer, toaster
158
+ β”‚ β”œβ”€β”€ page.tsx # Landing page with sample repos
159
+ β”‚ β”œβ”€β”€ globals.css # Tailwind v4 + RepoSec design tokens
160
+ β”‚ β”œβ”€β”€ loading.tsx # Global loading skeleton
161
+ β”‚ β”œβ”€β”€ not-found.tsx # Custom 404
162
+ β”‚ β”œβ”€β”€ scan/page.tsx # Scan-in-progress + result view
163
+ β”‚ β”œβ”€β”€ report/page.tsx # Alias of /scan, re-runs from query params
164
+ β”‚ └── api/scan/route.ts # Server-side scanner endpoint
165
+ β”‚
166
+ β”œβ”€β”€ components/
167
+ β”‚ β”œβ”€β”€ navbar.tsx # Top navigation
168
+ β”‚ β”œβ”€β”€ footer.tsx # Site footer
169
+ β”‚ β”œβ”€β”€ repo-input.tsx # GitHub URL input + sample repos
170
+ β”‚ β”œβ”€β”€ security-score.tsx # SVG score gauge with band
171
+ β”‚ β”œβ”€β”€ finding-card.tsx # Severity-grouped finding card
172
+ β”‚ β”œβ”€β”€ risk-badge.tsx # Severity badge
173
+ β”‚ β”œβ”€β”€ report-tabs.tsx # Overview / Findings / Fixes / Checks / Files / Export
174
+ β”‚ β”œβ”€β”€ export-button.tsx # Copy + download for one export item
175
+ β”‚ β”œβ”€β”€ scan-view.tsx # Scan state machine + UI
176
+ β”‚ β”œβ”€β”€ star-prompt.tsx # Friendly star CTA
177
+ β”‚ β”œβ”€β”€ doodles.tsx # Decorative SVG illustrations
178
+ β”‚ └── ui/ # shadcn-style primitives (button, card, input, badge, tabs, skeleton, dialog)
179
+ β”‚
180
+ β”œβ”€β”€ lib/
181
+ β”‚ β”œβ”€β”€ baseline.ts # .reposecignore / baseline suppression
182
+ β”‚ β”œβ”€β”€ client-bundle.ts # Public deployed JS bundle and source-map fetcher
183
+ β”‚ β”œβ”€β”€ fingerprint.ts # Stable secret fingerprints for dedupe/baselines
184
+ β”‚ β”œβ”€β”€ github.ts # GitHub API client, URL parsing, error model
185
+ β”‚ β”œβ”€β”€ local-repo.ts # Local filesystem and git-history scan loader
186
+ β”‚ β”œβ”€β”€ rules.ts # Secret pattern catalog + severity helpers
187
+ β”‚ β”œβ”€β”€ scan-targets.ts # Shared scannable file/path selection
188
+ β”‚ β”œβ”€β”€ scanner.ts # Rule-based scanner (12 modules, per-check pass/fail)
189
+ β”‚ β”œβ”€β”€ scoring.ts # Score calculation and band assignment
190
+ β”‚ β”œβ”€β”€ exporters.ts # Markdown / JSON / SARIF / templates / fix prompt
191
+ β”‚ β”œβ”€β”€ types.ts # Shared TypeScript types
192
+ β”‚ β”œβ”€β”€ verification.ts # Opt-in supported-token verification
193
+ β”‚ └── utils.ts # cn(), formatters, secret masking
194
+ β”‚
195
+ β”œβ”€β”€ public/
196
+ β”‚ β”œβ”€β”€ favicon.svg # RepoSec shield favicon
197
+ β”‚ └── screenshots/ # Captured Playwright screenshots of the live UI
198
+ β”‚
199
+ β”œβ”€β”€ scripts/
200
+ β”‚ β”œβ”€β”€ capture-screenshots.mjs # Playwright screenshot pipeline (npm run screenshots)
201
+ β”‚ β”œβ”€β”€ reposec-cli.mts # Local CLI scanner (npm run scan:local)
202
+ β”‚ β”œβ”€β”€ test-client-bundle.mts # Deployed JS bundle regression test
203
+ β”‚ └── test-scanner.mts # Rule-engine regression tests
204
+ β”‚
205
+ β”œβ”€β”€ .env.example # Template for optional GITHUB_TOKEN
206
+ β”œβ”€β”€ eslint.config.mjs # ESLint 9 + Next + TypeScript configs
207
+ β”œβ”€β”€ next.config.ts # Next.js config
208
+ β”œβ”€β”€ postcss.config.mjs # Tailwind v4 PostCSS plugin
209
+ β”œβ”€β”€ tsconfig.json # Strict TypeScript config
210
+ β”œβ”€β”€ package.json # Scripts and dependencies
211
+ └── README.md # You are here
212
+ ```
213
+
214
+ RepoSec is distributed under the MIT License. See [`LICENSE`](LICENSE) for the full terms.
215
+
216
+ ---
217
+
218
+ ## πŸ“¦ Technologies
219
+
220
+ | Layer | Choice |
221
+ | ---------------- | ----------------------------------------------------------------------------------- |
222
+ | Framework | [Next.js 16](https://nextjs.org/) (App Router) |
223
+ | Language | [TypeScript 5](https://www.typescriptlang.org/) (strict mode) |
224
+ | UI runtime | [React 19](https://react.dev/) |
225
+ | Styling | [Tailwind CSS v4](https://tailwindcss.com/) + RepoSec design tokens |
226
+ | UI primitives | shadcn-style components, locally authored (no CLI dependency) |
227
+ | Icons | [Lucide](https://lucide.dev/) |
228
+ | Toasts | [Sonner](https://sonner.emilkowal.ski/) |
229
+ | Class utilities | `clsx`, `tailwind-merge`, `class-variance-authority` |
230
+ | Animations | `tw-animate-css` |
231
+ | Data source | GitHub REST API + raw file downloads (no auth required) |
232
+ | Visual regression| [Playwright](https://playwright.dev/) (screenshot capture script) |
233
+ | Linting | ESLint 9 + `eslint-config-next` (core-web-vitals + typescript) |
234
+ | Type checking | `tsc --noEmit` |
235
+
236
+ ---
237
+
238
+ ## βœ… Requirements
239
+
240
+ - **Node.js** β‰₯ 18.18 (Node 20 LTS recommended)
241
+ - **npm** β‰₯ 9 (or any compatible package manager: pnpm, yarn, bun)
242
+ - A modern browser (the UI uses CSS `:has()`, color-mix, and modern flex/grid)
243
+ - **Optional:** a GitHub personal access token for higher rate limits
244
+
245
+ > No database, no Docker, no cloud account required for the MVP.
246
+
247
+ ---
248
+
249
+ ## πŸš€ Installation
250
+
251
+ ```bash
252
+ # 1. Clone the repository
253
+ git clone https://github.com/zanesense/reposec.git
254
+ cd reposec
255
+
256
+ # 2. Install dependencies
257
+ npm install
258
+
259
+ # 3. (Optional) Set up environment variables
260
+ cp .env.example .env.local
261
+ # then edit .env.local and add your GITHUB_TOKEN
262
+
263
+ # 4. Start the dev server
264
+ npm run dev
265
+ ```
266
+
267
+ Open <http://localhost:3000> and paste a public GitHub URL, e.g. `https://github.com/vercel/next.js`.
268
+
269
+ ### Production build
270
+
271
+ ```bash
272
+ npm run build
273
+ npm run start
274
+ ```
275
+
276
+ ---
277
+
278
+ ## πŸ”§ Configuration
279
+
280
+ RepoSec is configured entirely through environment variables. There are no config files to edit and no database to provision.
281
+
282
+ | Variable | Description | Required | Example |
283
+ | -------------- | ----------------------------------------------------------------------------------------------- | -------- | ------------- |
284
+ | `GITHUB_TOKEN` | Personal access token (classic or fine-grained, public repos only). Raises rate limit to 5000/h. | No | `ghp_xxx...` |
285
+
286
+ Create a local `.env.local` (or `.env`) from the template:
287
+
288
+ ```bash
289
+ cp .env.example .env.local
290
+ ```
291
+
292
+ If you skip this step, the scanner still works β€” you just share the 60 req/h anonymous rate limit. Rate-limit hits surface as a friendly error in the UI, courtesy of the `GitHubError` model in `lib/github.ts:54`.
293
+
294
+ ---
295
+
296
+ ## πŸ› οΈ Usage
297
+
298
+ ### Web UI
299
+
300
+ 1. Run `npm run dev` and open <http://localhost:3000>.
301
+ 2. Paste a public GitHub URL (or pick a sample repo).
302
+ 3. Optionally paste a deployed app URL to scan production JavaScript bundles and source maps.
303
+ 4. Optionally enable supported-token verification for GitHub, Stripe, and HuggingFace tokens.
304
+ 5. Watch the per-stage loader (metadata β†’ tree β†’ files β†’ deployed bundles β†’ rules β†’ score).
305
+ 6. Explore the report tabs:
306
+ - **Overview** β€” score gauge, severity counts, repo metadata, category breakdown.
307
+ - **Findings** β€” every finding as a card with masked evidence and a "Fix it like this" panel.
308
+ - **Fixes** β€” consolidated checklist.
309
+ - **Checks** β€” full per-check pass/fail/warn table.
310
+ - **Files** β€” file-grouped view of findings.
311
+ - **Export** β€” copy or download the artifacts.
312
+
313
+ ### Local CLI
314
+
315
+ Scan a local checkout without using the web UI:
316
+
317
+ ```bash
318
+ # Markdown report to stdout
319
+ npm run scan:local -- .
320
+
321
+ # Include recent git history blobs
322
+ npm run scan:local -- . --history
323
+
324
+ # Write SARIF for GitHub Code Scanning or CI dashboards
325
+ npm run scan:local -- . --format sarif --out reposec.sarif
326
+
327
+ # Opt in to supported live token verification
328
+ npm run scan:local -- . --verify
329
+ ```
330
+
331
+ Baseline files are honored in both web/API and local CLI scans:
332
+
333
+ ```text
334
+ # .reposecignore
335
+ src/config.ts:12
336
+ secret-generic-api-key-assignment-src/config.ts-12
337
+ 0123456789abcdef
338
+ ```
339
+
340
+ ```json
341
+ {
342
+ "ignore": [
343
+ { "file": "src/config.ts", "line": 12 },
344
+ { "fingerprint": "0123456789abcdef" }
345
+ ]
346
+ }
347
+ ```
348
+
349
+ ### Programmatic API
350
+
351
+ The scanner is exposed as a single POST endpoint:
352
+
353
+ ```http
354
+ POST /api/scan
355
+ Content-Type: application/json
356
+
357
+ {
358
+ "url": "https://github.com/vercel/next.js",
359
+ "siteUrl": "https://nextjs.org",
360
+ "verify": false
361
+ }
362
+ ```
363
+
364
+ Successful response:
365
+
366
+ ```json
367
+ {
368
+ "ok": true,
369
+ "report": {
370
+ "repo": { "owner": "vercel", "repo": "next.js", "defaultBranch": "canary", "isPrivate": false },
371
+ "score": 86,
372
+ "scoreBand": "good",
373
+ "summary": { "totalChecks": 42, "passed": 36, "failed": 4, "totalFindings": 6, "...": "..." },
374
+ "findings": [ { "id": "...", "title": "...", "severity": "high", "category": "secret", "...": "..." } ],
375
+ "scannedAt": "2026-06-05T08:00:00.000Z",
376
+ "durationMs": 1480
377
+ }
378
+ }
379
+ ```
380
+
381
+ Error responses use stable `code` values: `not_found`, `private`, `rate_limited`, `invalid`, `unknown`.
382
+
383
+ ### Screenshots
384
+
385
+ **Landing page**
386
+
387
+ ![RepoSec landing page](public/screenshots/01-home-light.png)
388
+
389
+ **Scanning state**
390
+
391
+ ![RepoSec scan-in-progress loader](public/screenshots/02-scan-loading.png)
392
+
393
+ **Report overview**
394
+
395
+ ![RepoSec report overview](public/screenshots/03-report-overview.png)
396
+
397
+ **Findings tab**
398
+
399
+ ![RepoSec findings tab](public/screenshots/04-report-findings.png)
400
+
401
+ **Export tab**
402
+
403
+ ![RepoSec export tab](public/screenshots/05-report-export.png)
404
+
405
+ To regenerate them: `npm run screenshots` (builds the app, serves it on port 4001, and captures each route with Playwright).
406
+
407
+ ---
408
+
409
+ ## πŸ§ͺ Testing
410
+
411
+ RepoSec ships with scanner regression tests, a deployed-bundle fixture test, screenshot-driven visual baselines, and a strict type/lint pipeline.
412
+
413
+ ```bash
414
+ # Type check (strict TypeScript)
415
+ npm run typecheck
416
+
417
+ # Lint (ESLint 9 + Next + TypeScript)
418
+ npm run lint
419
+
420
+ # Build the production bundle (catches many runtime issues at build time)
421
+ npm run build
422
+
423
+ # Run rule-engine and deployed-bundle scanner regressions
424
+ npm run test:scanner
425
+
426
+ # Regenerate the public/screenshots/ baseline
427
+ npm run screenshots
428
+
429
+ # Wipe build artifacts and the TS incremental cache
430
+ npm run clean
431
+ ```
432
+
433
+ ---
434
+
435
+ ## πŸ“Š Project Flow
436
+
437
+ End-to-end scan lifecycle:
438
+
439
+ ```mermaid
440
+ sequenceDiagram
441
+ participant U as User
442
+ participant W as Web UI (Next.js client)
443
+ participant A as /api/scan (Next.js server)
444
+ participant G as GitHub REST API
445
+ participant B as Public deployed JS bundles
446
+ participant R as Rule engine (lib/scanner.ts)
447
+ participant S as Scoring (lib/scoring.ts)
448
+
449
+ U->>W: Paste a public GitHub URL
450
+ W->>A: POST { url }
451
+ A->>G: GET /repos/{owner}/{repo}
452
+ G-->>A: Repo metadata
453
+ A->>G: GET /repos/{owner}/{repo}/git/trees/{branch}?recursive=1
454
+ G-->>A: File tree
455
+ A->>G: GET raw files (README, source, config, workflows, ...)
456
+ G-->>A: File contents
457
+ A->>B: GET HTML, JS bundles, source maps (optional)
458
+ B-->>A: Public client assets
459
+ A->>R: runScan(repoData)
460
+ R-->>A: findings + summary + checks
461
+ A->>S: calculateScore(findings)
462
+ S-->>A: score + band
463
+ A-->>W: { ok: true, report }
464
+ W-->>U: Render score, tabs, exports
465
+ ```
466
+
467
+ ---
468
+
469
+ ## πŸ“š API Reference
470
+
471
+ ### `POST /api/scan`
472
+
473
+ Validates a public GitHub URL, fetches repo data, runs the static scanner, and returns a `ScanReport`.
474
+
475
+ **Request body**
476
+
477
+ | Field | Type | Required | Description |
478
+ | ----- | ---- | -------- | ----------- |
479
+ | `url` | string | yes | Full public GitHub URL, e.g. `https://github.com/owner/repo`. Trailing slashes and `.git` suffixes are tolerated. |
480
+ | `siteUrl` | string | no | Optional public deployed app URL. RepoSec fetches public JS bundles and source maps from this site and scans them for secrets. HTTPS is enforced outside tests. |
481
+ | `verify` | boolean | no | Opt in to supported live token verification. Currently GitHub, Stripe, and HuggingFace are checked with bounded requests. Defaults to `false`. |
482
+
483
+ **Response (200)**
484
+
485
+ ```ts
486
+ interface ScanResponse {
487
+ ok: true;
488
+ report: ScanReport;
489
+ }
490
+ ```
491
+
492
+ Where `ScanReport` is defined in `lib/types.ts` and includes `repo`, `score`, `scoreBand`, `summary`, `findings`, `filesChecked`, `fileGroups`, `scannedAt`, and `durationMs`. Secret findings may also include `confidence`, `fingerprint`, and `verified` metadata.
493
+
494
+ **Error responses**
495
+
496
+ | Status | `code` | Meaning |
497
+ | ------ | -------------- | ------------------------------------------------------------- |
498
+ | 400 | β€” | Invalid JSON body or unparseable URL. |
499
+ | 404 | `not_found` | The repository does not exist or is not public. |
500
+ | 502 | `rate_limited` | GitHub rate limit reached (anonymous or token). |
501
+ | 502 | `private` | The repository is private or access is restricted. |
502
+ | 500 | `unknown` | Unexpected server error. |
503
+
504
+ Example error body:
505
+
506
+ ```json
507
+ {
508
+ "error": "API rate limit exceeded for your IP.",
509
+ "code": "rate_limited",
510
+ "status": 403
511
+ }
512
+ ```
513
+
514
+ ---
515
+
516
+ ## 🧩 Examples
517
+
518
+ ### Try these public repositories
519
+
520
+ | Repository | Why scan it |
521
+ | ---------- | -------------------------------------------- |
522
+ | `vercel/next.js` | Large, well-run project β€” should score in the _Good_ band. |
523
+ | `facebook/react` | Tests CI and metadata heuristics at scale. |
524
+ | `expressjs/express` | Classic Node.js project β€” interesting `.gitignore` and CI behavior. |
525
+
526
+ ### What a finding looks like
527
+
528
+ ```json
529
+ {
530
+ "id": "secret-stripe-live",
531
+ "title": "Stripe live secret key",
532
+ "description": "Looks like a live Stripe secret key. Roll the key if real.",
533
+ "severity": "critical",
534
+ "category": "secret",
535
+ "confidence": "high",
536
+ "fingerprint": "0123456789abcdef",
537
+ "verified": false,
538
+ "file": "src/config.ts",
539
+ "line": 12,
540
+ "evidence": "sk_l_********************def0",
541
+ "fix": "Move the key to an environment variable and reference it via process.env.",
542
+ "fixPrompt": "In src/config.ts:12, replace the hardcoded Stripe key with an env var..."
543
+ }
544
+ ```
545
+
546
+ The scanner masks secrets to `prefix****suffix` before they ever leave the server, so the UI never displays the raw value.
547
+
548
+ ---
549
+
550
+ ## 🚒 Deployment
551
+
552
+ RepoSec is a standard Next.js 16 app. It works on any platform that supports the Node.js runtime.
553
+
554
+ ### Vercel (recommended)
555
+
556
+ ```bash
557
+ # Install the Vercel CLI if you don't have it
558
+ npm i -g vercel
559
+
560
+ # Deploy from the project root
561
+ vercel
562
+ ```
563
+
564
+ Add `GITHUB_TOKEN` as an environment variable in the Vercel project settings if you want a higher rate limit.
565
+
566
+ ### Docker
567
+
568
+ > **TODO:** A Dockerfile is not yet committed. The recommended shape is:
569
+ >
570
+ > ```Dockerfile
571
+ > # syntax=docker/dockerfile:1
572
+ > FROM node:20-alpine AS deps
573
+ > WORKDIR /app
574
+ > COPY package.json package-lock.json ./
575
+ > RUN npm ci
576
+ >
577
+ > FROM node:20-alpine AS builder
578
+ > WORKDIR /app
579
+ > COPY --from=deps /app/node_modules ./node_modules
580
+ > COPY . .
581
+ > RUN npm run build
582
+ >
583
+ > FROM node:20-alpine AS runner
584
+ > WORKDIR /app
585
+ > ENV NODE_ENV=production
586
+ > COPY --from=builder /app/.next ./.next
587
+ > COPY --from=builder /app/public ./public
588
+ > COPY --from=builder /app/package.json ./package.json
589
+ > COPY --from=builder /app/node_modules ./node_modules
590
+ > EXPOSE 3000
591
+ > CMD ["npm", "run", "start"]
592
+ > ```
593
+
594
+ ### Self-hosted Node
595
+
596
+ ```bash
597
+ npm run build
598
+ GITHUB_TOKEN=ghp_xxx npm run start
599
+ ```
600
+
601
+ The server listens on port `3000` by default. Override with `PORT=4000 npm run start`.
602
+
603
+ ---
604
+
605
+ ## 🧭 Roadmap
606
+
607
+ Planned and aspirational improvements:
608
+
609
+ - 🧠 **Optional LLM layer** β€” "Bring Your Own Key" provider to add narrative remediation to the report.
610
+ - πŸ§ͺ **Unit tests** β€” expand the current scanner regression suite into Vitest coverage for `lib/scanner.ts`, `lib/rules.ts`, and `lib/scoring.ts`.
611
+ - 🐳 **Container hardening** β€” committed `Dockerfile` and `docker-compose.yml`.
612
+ - 🌐 **i18n** β€” multi-language report exports.
613
+ - πŸ”Œ **GitHub App mode** β€” comment the report on PRs via a public GitHub App.
614
+ - πŸ“¦ **More ecosystems** β€” Python (`requirements.txt`, `pyproject.toml`), Go (`go.mod`), Rust (`Cargo.toml`) lockfile and audit checks.
615
+ - πŸͺ **Webhooks** β€” scheduled scans for the repos you watch.
616
+ - πŸͺͺ **License detection** β€” extend SPDX detection beyond the GitHub API metadata.
617
+
618
+ - πŸ” **More verifiers** β€” add safe opt-in verification support for more providers without exposing raw secrets in reports.
619
+
620
+ > **TODO:** A separate `ROADMAP.md` is not currently checked in. The list above is the source of truth until it is.
621
+
622
+ ---
623
+
624
+ ## 🀝 Contributing
625
+
626
+ Contributions are very welcome β€” especially new secret patterns and new check modules.
627
+
628
+ 1. **Fork** the repository on GitHub.
629
+ 2. **Clone** your fork and create a feature branch:
630
+ ```bash
631
+ git checkout -b feat/add-discord-token-pattern
632
+ ```
633
+ 3. **Install** dependencies and start the dev server:
634
+ ```bash
635
+ npm install
636
+ npm run dev
637
+ ```
638
+ 4. **Make your changes.** When adding a new secret pattern, edit `lib/rules.ts:10` and follow the existing `SecretPattern` shape.
639
+ 5. **Run the quality checks** before committing:
640
+ ```bash
641
+ npm run lint
642
+ npm run typecheck
643
+ npm run build
644
+ ```
645
+ 6. **Commit** with a descriptive message:
646
+ ```bash
647
+ git commit -m "feat(scanner): add Discord bot token pattern"
648
+ ```
649
+ 7. **Push** your branch and open a **pull request** against `main`:
650
+ ```bash
651
+ git push origin feat/add-discord-token-pattern
652
+ ```
653
+
654
+ Please open an issue first if your change is large or design-related.
655
+
656
+ ---
657
+
658
+ ## πŸ“ Changelog
659
+
660
+ > **TODO:** A `CHANGELOG.md` is not yet committed. Notable milestones to seed it with:
661
+
662
+ - **0.1.0** β€” Initial MVP. Landing page, 12 check modules, 55+ secret patterns (ported from the gitleaks ruleset), score + band, exports (Markdown, JSON, `SECURITY.md`, `.env.example`, issue checklist, fix prompt), Playwright screenshot baseline.
663
+ - **0.2.0** β€” Full-tree secret target selection, deployed JavaScript bundle scanning, SARIF export, local CLI, git-history scanning, baseline suppression, confidence/fingerprint metadata, opt-in supported-token verification, and bundle scanner regression tests.
664
+
665
+ ---
666
+
667
+ ## πŸ› Troubleshooting
668
+
669
+ | Symptom | Cause | Fix |
670
+ | ------- | ----- | --- |
671
+ | `API rate limit exceeded` on the first scan | Anonymous GitHub limit (60 req/h) was hit. | Add `GITHUB_TOKEN` to `.env.local` and restart the dev server. |
672
+ | `Repository not found` for a repo you can see in the browser | The URL is wrong, the repo is private, or it was renamed. | Double-check the URL. RepoSec only scans public repos. |
673
+ | Scan returns 0 findings and a perfect score | The repo is small or has no scannable files (yet). | Try a larger public repo, e.g. `vercel/next.js`. |
674
+ | `.env.local` is missing after `cp .env.example .env.local` on Windows PowerShell | `cp` is not a native cmdlet. | Use `Copy-Item .env.example .env.local` instead. |
675
+ | `npm run screenshots` fails | Playwright browsers are not installed. | Run `npx playwright install` once before the first capture. |
676
+ | Deployed bundle scan finds no assets | The site URL is missing, not HTTPS, blocks server-side requests, or does not expose JS bundles through normal script/modulepreload tags. | Enter the public production URL manually and confirm the bundles are reachable without authentication. |
677
+ | CLI SARIF output is empty | No findings matched after baseline suppression. | Run `npm run scan:local -- . --format json` and inspect `summary.checks` and `filesChecked`. |
678
+ | A reviewed finding keeps returning | No baseline entry matches its id, fingerprint, file, or file:line. | Add the exact finding location or fingerprint to `.reposecignore` or `reposec-baseline.json`. |
679
+ | Build complains about a missing `next-env.d.ts` | The file is generated by Next.js on first run. | Run `npm run dev` once, or delete `.next` and rebuild. |
680
+ | Type errors after pulling new code | The incremental cache is stale. | Run `npm run clean` followed by `npm run typecheck`. |
681
+
682
+ ---
683
+
684
+ ## πŸ”’ Security
685
+
686
+ RepoSec is a **defensive** security tool. It is designed to help maintainers find their own mistakes, not to weaponize findings.
687
+
688
+ - βœ… The scanner is **read-only**. It never writes to the target repository.
689
+ - βœ… The scanner is **stateless**. No scan data is stored on the server.
690
+ - βœ… The scanner **masks secrets** before they appear in the UI or exports.
691
+ - βœ… Live verification is **opt-in** and raw candidates are discarded before reports are returned.
692
+ - βœ… Deployed bundle scanning is bounded to public HTTPS assets and blocks private/internal hosts.
693
+ - βœ… The scanner is **branded defensively** β€” the copy and code avoid language like "hack", "exploit", "bypass", or "steal".
694
+
695
+ To report a vulnerability in RepoSec itself, please open a private security advisory on GitHub:
696
+
697
+ https://github.com/zanesense/reposec/security/advisories/new
698
+
699
+ For supported versions and response timelines, see [`SECURITY.md`](SECURITY.md).
700
+
701
+ **Never** commit real secrets to this repository. The included `.gitignore` already excludes `.env*` (with `.env.example` whitelisted as a template).
702
+
703
+ ---
704
+
705
+ ## πŸ“„ License
706
+
707
+ RepoSec is licensed under the MIT License. See [`LICENSE`](LICENSE) for the full license text.
708
+
709
+ ---
710
+
711
+ ## ❀️ Acknowledgements
712
+
713
+ - πŸ›‘οΈ Inspired by the public hardening checklists from **GitHub**, **OWASP**, and **Snyk**.
714
+ - 🎨 UI primitives adapted from the [shadcn/ui](https://ui.shadcn.com/) patterns, locally authored and customised.
715
+ - πŸ–ΌοΈ Icons by [Lucide](https://lucide.dev/).
716
+ - πŸ”” Toasts by [Sonner](https://sonner.emilkowal.ski/).
717
+ - πŸ€– Build tooling by [Next.js](https://nextjs.org/), [React](https://react.dev/), [Tailwind CSS](https://tailwindcss.com/), and [TypeScript](https://www.typescriptlang.org/).
718
+ - πŸ§ͺ Visual baseline by [Playwright](https://playwright.dev/).
719
+ - πŸ’› Thanks to every maintainer who takes repo hygiene seriously.
720
+
721
+ ---
722
+
723
+ <p align="center">
724
+ <a href="#reposec">⬆️ Back to top</a>
725
+ &nbsp;Β·&nbsp;
726
+ <a href="https://reposec.zanesense.dev">🌐 Live demo</a>
727
+ &nbsp;Β·&nbsp;
728
+ <a href="https://github.com/zanesense/reposec">πŸ“¦ Repository</a>
729
+ &nbsp;Β·&nbsp;
730
+ <a href="https://github.com/zanesense/reposec/issues">πŸ› Report a bug</a>
731
+ &nbsp;Β·&nbsp;
732
+ <a href="https://github.com/zanesense/reposec/blob/main/LICENSE">πŸ“„ MIT License</a>
733
+ </p>