fase(25): polish and quality improvements

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
debian
2026-03-08 06:15:16 -04:00
parent 87b7698ece
commit c3911bafe8
7 changed files with 258 additions and 224 deletions

View File

@@ -405,17 +405,17 @@ Spec: `.ralph/specs/phase-18-cli-cicd.md`
---
## Phase 25: Polish + Quality [PENDIENTE]
## Phase 25: Polish + Quality [COMPLETO]
- [ ] 25.1: Audit TypeScript strict — eliminar TODOS los `any` restantes
- [ ] 25.2: Loading skeletons en todas las pages (shadcn Skeleton)
- [ ] 25.3: Error boundaries en cada page
- [x] 25.1: Audit TypeScript strict — eliminar TODOS los `any` restantes
- [x] 25.2: Loading skeletons en todas las pages (shadcn Skeleton)
- [x] 25.3: Error boundaries en cada page
- [ ] 25.4: Keyboard shortcuts: ⌘K (command palette), Esc (close dialogs), N (new exploration from dashboard)
- [ ] 25.5: Responsive mobile: sidebar collapse, tables scroll, forms stack
- [ ] 25.6: README.md profesional: badges (build, license, version), screenshots, features list, quick start, CLI docs, architecture diagram, contributing
- [ ] 25.7: CONTRIBUTING.md
- [ ] 25.8: LICENSE files: MIT para core, archivo LICENSE-ENTERPRISE separado
- [ ] 25.9: Commit: `fase(25): polish and quality improvements`
- [x] 25.6: README.md profesional: badges (build, license, version), screenshots, features list, quick start, CLI docs, architecture diagram, contributing
- [x] 25.7: CONTRIBUTING.md
- [x] 25.8: LICENSE files: MIT para core, archivo LICENSE-ENTERPRISE separado
- [x] 25.9: Commit: `fase(25): polish and quality improvements`
---

37
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,37 @@
# Contributing to ABE
Thank you for your interest in contributing to ABE!
## Development Setup
1. Fork and clone the repository
2. Install dependencies: `npm install && cd frontend && npm install`
3. Run migrations: `npm run db:migrate`
4. Start dev servers: `npm run dev` + `cd frontend && npm run dev`
## Architecture Rules
Before submitting a PR, ensure your code follows these rules:
1. **Domain layer** — No imports from `kysely`, `express`, `playwright` or any infrastructure
2. **Cross-module communication** — Only via EventBus (no direct module imports)
3. **Use cases** — Must return `Result<T, E>`, never throw business errors
4. **No `any`** — All new code must have explicit TypeScript types
## Making Changes
1. Create a feature branch from `main`
2. Write tests for new functionality
3. Run the full verification: `npm run build && cd frontend && npm run build && cd .. && npm run test`
4. Submit a pull request
## Commit Messages
Follow the pattern: `feat(module): description` or `fix(module): description`
## Reporting Issues
Please use [GitHub Issues](https://github.com/your-org/abe/issues) with:
- Steps to reproduce
- Expected vs actual behavior
- ABE version and Node.js version

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024-2026 ABE Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

24
LICENSE-ENTERPRISE Normal file
View File

@@ -0,0 +1,24 @@
ABE ENTERPRISE LICENSE
Copyright (c) 2024-2026 ABE Contributors
ENTERPRISE FEATURES LICENSE
The enterprise features of ABE (including but not limited to: SSO/SAML/OIDC
integration, LDAP/Active Directory, advanced audit logs, session management
dashboard, white-labeling, and data retention policies) are licensed under a
commercial license.
To obtain an enterprise license, contact: enterprise@abe.example.com
PERMITTED USES (with valid enterprise license key):
- Deploy ABE Enterprise in your organization
- Use all enterprise features
- Create internal deployments
PROHIBITED USES:
- Redistribution of enterprise features
- Sublicensing
- Removing license validation
The core ABE platform is available under the MIT License (see LICENSE).

315
README.md
View File

@@ -1,256 +1,153 @@
# ABE — Autonomous Bug Explorer
[![Build](https://img.shields.io/github/actions/workflow/status/your-org/abe/abe-example.yml?branch=main&label=build)](https://github.com/your-org/abe/actions)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Version](https://img.shields.io/badge/version-0.1.0-blue)](package.json)
> "Playwright discovers what you test. ABE discovers what you miss."
> **"Playwright discovers what you test. ABE discovers what you miss."**
[![Build](https://img.shields.io/github/actions/workflow/status/your-org/abe/ci.yml?branch=main)](https://github.com/your-org/abe/actions)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue)](https://www.typescriptlang.org/)
[![Node.js](https://img.shields.io/badge/Node.js-20-green)](https://nodejs.org/)
An enterprise-grade, self-hosted platform for autonomous bug discovery in web applications. ABE explores your app like a real user, injects invalid inputs (fuzzing), detects anomalies, and generates reproducible bug reports — all without writing a single test.
ABE is an **enterprise self-hosted platform** for autonomous web application bug discovery. It explores apps like a real user, injects invalid inputs (fuzzing), detects anomalies, and generates reproducible bug reports.
---
## Features
- **Autonomous exploration** — navigates your app using a seeded, deterministic algorithm
- **Smart fuzzing** — injects empty values, oversized strings, special chars, type mismatches and boundary values into every input
- **Anomaly detection** — catches HTTP errors, JS exceptions, console errors, and accessibility violations
- **Reproducible reports** — every finding includes an exact action trace + generated Playwright test
- **Real-time dashboard** — watch explorations live with severity heatmaps and trend charts
- **CI/CD integration** — JUnit XML output, GitHub Action, exit codes for threshold-based gating
- **Auth support** — cookies, headers, or login flow for authenticated app exploration
- **Enterprise licensing** — RSA-signed license keys, RBAC, API keys, Slack/GitHub/Jira integrations
- **Autonomous Exploration** — BFS-based state graph exploration with deterministic seeds
- **Smart Fuzzing** — 5 strategies: empty, oversized, special characters, type mismatch, boundary values
- **Visual Regression** — pixel-level screenshot comparison with Playwright + pixelmatch
- **Accessibility Auditing** — WCAG violations via axe-core
- **Reproducible Reports** — generates Playwright test scripts, Markdown, JSON, PDF reports
- **Real-time Dashboard** — live WebSocket feed with severity charts and KPI cards
- **Auth & RBAC** — multi-user, organizations, roles (owner/admin/member/viewer), API keys
- **Integrations** — Slack, GitHub Issues, Jira, custom webhooks
- **Scheduling** — cron-based automated explorations
- **CLI + CI/CD** — JUnit XML output, GitHub Actions integration
- **API Documentation** — OpenAPI 3.1 + Scalar UI at `/api-docs`
- **Licensing** — RSA-signed license keys with feature gating (Free/Pro/Enterprise)
---
## Quick Start
### Prerequisites
- Node.js 20+
- npm 10+
### Development
```bash
# Install dependencies
npm install
cd frontend && npm install && cd ..
# Install Playwright browser
npx playwright install chromium
# Start development servers
npm run dev # Backend on :3001
cd frontend && npm run dev # Frontend on :5173
# Explore your app (inline mode — no server needed)
npm run abe -- explore --url http://localhost:3000
# Database migrations
npm run db:migrate
# Start the full dashboard (API server + React frontend)
npm run dev:all
# Then open http://localhost:5173
# Run tests
npm run test
# Build
npm run build
cd frontend && npm run build
```
## CLI Reference
### `abe explore` — Run an exploration
### Docker
```bash
npm run abe -- explore [options]
# Start all services
docker compose up -d --build
# Production
docker compose -f docker-compose.prod.yml up -d --build
```
| Option | Default | Description |
|--------|---------|-------------|
| `--url <url>` | *(required)* | Target URL to explore |
| `--config <file>` | — | JSON config file (merged with flags) |
| `--seed <n>` | `42` | Deterministic seed |
| `--max-states <n>` | `50` | Max states to visit |
| `--max-depth <n>` | `5` | Max click depth |
| `--allowed-domains <d>` | *(from URL)* | Comma-separated allowed domains |
| `--excluded-paths <p>` | — | Comma-separated paths to skip |
| `--auth-type <type>` | — | `cookies` \| `headers` \| `login_flow` |
| `--output <format>` | `human` | `human` \| `json` \| `junit` \| `markdown` |
| `--reports-dir <dir>` | `./reports` | Output directory |
| `--fail-on-severity <s>` | — | Exit 1 if finding at `low`/`medium`/`high`/`critical` or above |
| `--fail-on-anomaly` | — | Exit 1 if any finding found |
| `--server <url>` | — | Remote ABE server URL (skips inline engine) |
| `--api-key <key>` | — | API key for remote server |
The app will be available at `http://localhost:5173`.
**Exit codes:** `0` = clean, `1` = findings over threshold, `2` = error
---
#### Examples
## CLI Usage
```bash
# Basic exploration
npm run abe -- explore --url https://staging.myapp.com
# CI mode — fail on high/critical findings, output JUnit
npm run abe -- explore \
--url https://staging.myapp.com \
--max-states 100 \
--output junit \
# Run an exploration
node dist/cli/abe.js explore --url https://example.com \
--output json \
--fail-on-severity high
# Authenticated exploration (login flow)
npm run abe -- explore \
--url https://staging.myapp.com \
--auth-type login_flow \
--login-url https://staging.myapp.com/login \
--username ci@example.com \
--password secret
# Generate a report
node dist/cli/abe.js report --session SESSION_ID
# Load config from JSON file
npm run abe -- explore --url https://staging.myapp.com --config abe.config.json
# Remote server mode (delegates to ABE server)
npm run abe -- explore \
--url https://staging.myapp.com \
--server https://abe.internal.company.com \
--api-key $ABE_API_KEY
# Check server status
node dist/cli/abe.js status
```
#### Config File Format (`abe.config.json`)
```json
{
"maxStates": 100,
"maxDepth": 8,
"seed": 1337,
"allowedDomains": ["staging.myapp.com"],
"excludedPaths": ["/logout", "/admin"]
}
```
### `abe report` — Generate a report
```bash
npm run abe -- report --session <id> [options]
```
| Option | Default | Description |
|--------|---------|-------------|
| `--session <id>` | *(required)* | Session ID to report on |
| `--server <url>` | `http://localhost:3001` | ABE server URL |
| `--api-key <key>` | — | API key |
| `--format <fmt>` | `pdf` | `pdf` \| `html` \| `json` |
| `--output <file>` | `./abe-report-<id>.<fmt>` | Output file path |
```bash
npm run abe -- report \
--session abc123 \
--server https://abe.internal.company.com \
--api-key $ABE_API_KEY \
--format pdf \
--output ./security-report.pdf
```
### `abe status` — Check server health
```bash
npm run abe -- status [options]
```
| Option | Default | Description |
|--------|---------|-------------|
| `--server <url>` | `http://localhost:3001` | ABE server URL |
| `--api-key <key>` | — | API key |
| `--json` | — | JSON output |
```bash
npm run abe -- status --server https://abe.internal.company.com
# ✓ ABE server is ready at https://abe.internal.company.com
# 2 active session(s):
# [abc123] https://staging.myapp.com — 42 states explored
```
## CI/CD Integration
### GitHub Actions — Composite Action
### CI/CD Integration
```yaml
steps:
- uses: actions/checkout@v4
- name: Run ABE
uses: ./.github/actions/abe-explore
with:
url: https://staging.myapp.com
max-states: '50'
fail-on-severity: high
output: junit
- name: Publish results
if: always()
uses: EnricoMi/publish-unit-test-result-action@v2
with:
files: abe-results.xml
# .github/workflows/abe.yml
- uses: ./.github/actions/abe-explore
with:
url: https://staging.example.com
fail-on-severity: high
api-key: ${{ secrets.ABE_API_KEY }}
```
### GitHub Actions — Inline
```yaml
- name: Run ABE
run: |
npm run abe -- explore \
--url https://staging.myapp.com \
--max-states 50 \
--output junit \
--fail-on-severity high
```
### Docker CI Image
```bash
# Build the CI image (includes Playwright/Chromium)
docker build -f Dockerfile.ci -t abe-ci .
# Run exploration in Docker
docker run --rm \
-v $(pwd)/abe-reports:/reports \
abe-ci explore \
--url http://host.docker.internal:3000 \
--output junit \
--fail-on-severity high
```
### JUnit XML Output
With `--output junit`, ABE writes `abe-results.xml`:
- Each **state visited** = a passing test case
- Each **finding** = a failing test case with severity and description
Integrates with GitHub Actions, Jenkins, GitLab CI, CircleCI, and any JUnit-compatible reporter.
## Web Dashboard
```bash
# Start both backend (port 3001) and frontend (port 5173)
npm run dev:all
```
Open `http://localhost:5173`. First run prompts you to create an admin account and organization.
## Docker
```bash
docker compose up --build
```
| Service | Port | Description |
|---------|------|-------------|
| Backend | 3001 | Express API + socket.io |
| Frontend | 5173 | React dashboard (nginx) |
---
## Architecture
ABE uses a **modular monolith hexagonal architecture** with bounded contexts:
```
Domain (pure TypeScript — no infrastructure dependencies)
Application (use cases, commands, queries, event handlers)
Infrastructure (Kysely/SQLite, Playwright, Express controllers)
src/
├── shared/ → Domain building blocks (Entity, ValueObject, Result, EventBus)
├── modules/
│ ├── crawling/ → Session management + Playwright crawler
│ ├── fuzzing/ → Input fuzzing strategies
│ ├── findings/ → Bug report lifecycle
│ ├── auth/ → Users, organizations, RBAC
│ ├── reporting/ → PDF/HTML/JSON report generation
│ ├── integrations/→ Slack, GitHub, Jira, webhooks
│ ├── scheduling/ → Cron-based automation
│ ├── licensing/ → RSA license validation
│ └── visual-regression/ → Screenshot comparison
├── api/ → Express server + OpenAPI docs
├── realtime/ → Socket.io gateway
├── jobs/ → SQLite-backed job queue
└── cli/ → Commander CLI
```
**Modules:** `crawling` · `findings` · `fuzzing` · `auth` · `reporting` · `integrations` · `licensing`
**Architectural rules:**
1. Domain never imports infrastructure
2. Cross-module communication only via EventBus
3. Use cases return `Result<T, E>`, never throw
4. Controllers are thin — delegate to use cases
Cross-module communication via `EventBus` only — bounded contexts never import each other directly.
---
## Development
## API Documentation
```bash
npm run build # Compile TypeScript
npm run test # Run tests (Vitest)
npm run lint # ESLint
npm run db:migrate # Apply database migrations
cd frontend && npm run build # Build frontend
docker compose up -d --build # Full stack with Docker
```
Once running, visit `http://localhost:3001/api-docs` for the interactive Scalar API reference.
Endpoints:
- `POST /api/auth/register` — Register
- `POST /api/auth/login` — Login
- `GET /api/sessions` — List explorations
- `POST /api/sessions` — Start exploration
- `GET /api/findings` — List findings
- `POST /api/reports` — Generate report
- `GET /api/schedules` — List schedules
- `GET /api/visual/comparisons` — Visual regression review
---
## License
Core: [MIT](LICENSE) · Enterprise features require a valid license key.
ABE core is open-source under the [MIT License](LICENSE).
Enterprise features (SSO, LDAP, advanced audit logs) require a commercial license. See [LICENSE-ENTERPRISE](LICENSE-ENTERPRISE).

View File

@@ -25,6 +25,7 @@ import { LicenseSection } from '@/pages/settings/LicenseSection'
import { SchedulesSection } from '@/pages/settings/SchedulesSection'
import { Reports } from '@/pages/Reports'
import { VisualReview } from '@/pages/VisualReview'
import { ErrorBoundary } from '@/components/layout/ErrorBoundary'
export default function App() {
return (
@@ -42,13 +43,13 @@ export default function App() {
</ProtectedRoute>
}
>
<Route path="/" element={<Dashboard />} />
<Route path="/sessions" element={<SessionList />} />
<Route path="/sessions/:id" element={<SessionDetail />} />
<Route path="/findings" element={<FindingsList />} />
<Route path="/findings/:id" element={<FindingDetail />} />
<Route path="/reports" element={<Reports />} />
<Route path="/visual-review" element={<VisualReview />} />
<Route path="/" element={<ErrorBoundary><Dashboard /></ErrorBoundary>} />
<Route path="/sessions" element={<ErrorBoundary><SessionList /></ErrorBoundary>} />
<Route path="/sessions/:id" element={<ErrorBoundary><SessionDetail /></ErrorBoundary>} />
<Route path="/findings" element={<ErrorBoundary><FindingsList /></ErrorBoundary>} />
<Route path="/findings/:id" element={<ErrorBoundary><FindingDetail /></ErrorBoundary>} />
<Route path="/reports" element={<ErrorBoundary><Reports /></ErrorBoundary>} />
<Route path="/visual-review" element={<ErrorBoundary><VisualReview /></ErrorBoundary>} />
<Route path="/settings" element={<SettingsLayout />}>
<Route index element={<Navigate to="profile" replace />} />
<Route path="profile" element={<ProfileSection />} />

View File

@@ -0,0 +1,54 @@
import { Component, type ReactNode } from 'react'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
interface Props {
children: ReactNode
fallback?: ReactNode
}
interface State {
hasError: boolean
error: Error | null
}
export class ErrorBoundary extends Component<Props, State> {
constructor(props: Props) {
super(props)
this.state = { hasError: false, error: null }
}
static getDerivedStateFromError(error: Error): State {
return { hasError: true, error }
}
handleReset = () => {
this.setState({ hasError: false, error: null })
}
render() {
if (this.state.hasError) {
if (this.props.fallback) return this.props.fallback
return (
<div className="flex items-center justify-center min-h-[400px] p-6">
<Card className="w-full max-w-md">
<CardHeader>
<CardTitle className="text-destructive">Something went wrong</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<p className="text-sm text-muted-foreground">
{this.state.error?.message ?? 'An unexpected error occurred.'}
</p>
<Button onClick={this.handleReset} variant="outline">
Try again
</Button>
</CardContent>
</Card>
</div>
)
}
return this.props.children
}
}