Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

Technical requirements for OpenHunterAI's black-box pentest workflow and MVP architecture.

> Release status: this document mixes implemented features with proposed tools.
> The running stack is React/Vite, Express/TypeScript, Go, Postgres and NATS;
> the technology catalogue below is not a ready-to-use capability guarantee.
> See [public release gates](docs/PUBLIC_RELEASE_READINESS.md),
> [current architecture](docs/ARCHITECTURE.md) and
> [mandatory security guardrails](docs/SECURITY_GUARDRAILS.md).
> Raw credentials, HAR and sensitive request/response data are not report artifacts.

## 1. Technical Scope

- **Model**: AI Agentic Workflow — AI orchestrates, analyzes context, and chooses actions; open-source tools handle recon, crawling, request sending, OAST, and known-vulnerability checks.
Expand Down
38 changes: 36 additions & 2 deletions contracts/api/public-api.openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,45 @@ paths:
- name: format
in: query
schema:
enum: [html, pdf]
type: string
enum: [docx, csv, json, html, pdf]
default: html
- name: view
in: query
schema:
type: string
enum: [snapshot, latest]
default: latest
responses:
"200":
description: On-demand sanitized HTML/PDF export
description: On-demand sanitized final or superseded report download; Content-Disposition attachment. JSON contains snapshot and optional latestOverlay. CSV separates findings, hardening, coverage gaps, and limitations.
content:
application/json:
schema:
type: object
required: [snapshot]
properties:
snapshot:
type: object
latestOverlay:
type: object
text/csv:
schema:
type: string
application/vnd.openxmlformats-officedocument.wordprocessingml.document:
schema:
type: string
format: binary
text/html:
schema:
type: string
application/pdf:
schema:
type: string
format: binary
"400":
description: Unsupported format/view, or report is not finalized
"401":
description: Authentication required
"404":
description: Report does not exist in the current organization
5 changes: 4 additions & 1 deletion docs/ACCEPTANCE_CRITERIA.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,10 @@ raw credentials/cookies/tokens/HAR/request/response are not stored/logged/report
detected secrets store only masked fingerprint/hash/metadata
report_v1 structured JSON is the canonical report snapshot
draft sections stream over SSE
HTML/PDF exports are generated on demand and not persisted as artifacts
DOCX/CSV/JSON/HTML/PDF exports are generated on demand and not persisted as artifacts
downloads require an org-scoped final or superseded report; drafts cannot be downloaded as final
JSON preserves the report_v1 snapshot; latest status is an optional separate overlay
CSV neutralizes spreadsheet formulas and separates validated findings from hardening/coverage rows
LLM ranking recommendations cannot invent findings or override deterministic policy
```

Expand Down
2 changes: 1 addition & 1 deletion docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ web dashboard
→ manual retest / Monitor Workspace
```

Core v1 stores sanitized reports/findings in Postgres. External artifact storage is not a core v1 dependency. HTML/PDF exports are rendered on demand from sanitized report JSON and are not stored as files.
Core v1 stores sanitized reports/findings in Postgres. External artifact storage is not a core v1 dependency. DOCX/CSV/JSON/HTML/PDF exports are rendered on demand from sanitized report JSON and are not stored as files. Downloads require an org-scoped final or superseded snapshot. JSON includes the canonical snapshot and, when requested, a separate latest-status overlay. CSV is a flat findings/coverage summary, not a lossless replacement for JSON.

Reports use `report_v1` structured JSON snapshots in Postgres. Draft report sections stream to the UI through SSE while a scan runs.

Expand Down
201 changes: 201 additions & 0 deletions docs/PUBLIC_RELEASE_READINESS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
# Public Release Readiness

Baseline: LumosLab-Innovation/OpenHunterAI `main` at
`48bf9036debf797cef3d24308c3cfa1ec2a20c15` (2026-08-26).
Implementation branch: `feat/public-release-readiness`.

This is a release gate, not a claim that the product is ready. Do not change
repository visibility, deploy, or start a target scan as part of this checklist.
The earlier June checkout is not the release baseline.

## 1. License and ownership

Owner intent: community inspection, contribution and noncommercial use;
commercial use requires a separately negotiated license from the rights holder.

Recommended model: unmodified **PolyForm Noncommercial 1.0.0** for community
distribution, plus a separate commercial agreement. Describe this as
**source-available**, not OSI open source. An OSI license cannot prohibit
commercial use. PolyForm also permits specified nonprofit/institutional uses;
it is not a personal-use-only license.

The commercial agreement should cover the intended use (internal commercial
testing, paid services, hosting, redistribution), term, fees, support, liability
and transfer on acquisition. The community license does not automatically collect
fees or guarantee a sale. Existing grants and third-party rights survive according
to their terms.

Do not apply a new root license until these gates are met:

- [ ] Owner confirms the actual legal licensor name and commercial contact.
- [ ] Confirm rights to the existing contributions. Git author names are not
proof of employment, assignment or permission to relicense.
- [ ] Inventory third-party code and retain its licenses/notices. In particular,
`third_party_research/openhack/LICENSE` is MIT and
`third_party_research/strix/LICENSE` is Apache-2.0; neither becomes
noncommercial merely by adding a root license.
- [ ] Counsel reviews the commercial agreement and contributor agreement (CLA).
Prefer a nonexclusive grant that lets contributors retain their copyright,
while expressly allowing commercial sublicensing, relicensing and transfer
to a successor. A DCO or PR checkbox alone does not establish these rights.
- [ ] Establish a verifiable CLA acceptance record before merging new external
contributions. Resolve existing contributions separately; no retroactive
assumption of consent.
- [ ] Add the exact license text, copyright notice, licensing FAQ and contribution
instructions after approval. Do not publish a placeholder legal identity.

References: [PolyForm terms](https://polyformproject.org/licenses/noncommercial/1.0.0),
[OSI definition](https://opensource.org/osd),
[Harmony contributor agreement options](https://www.harmonyagreements.org/docs/ha-combined-v1).
These are implementation recommendations, not a legal opinion.

## 2. Keep the actual architecture

```text
Local web / terminal / user-invoked coding skill
-> authenticated Public API
-> verified scope + authorization + deterministic plan + approval gates
-> Postgres (state, sanitized activity, report_v1)
-> NATS -> orchestrator -> Browser / R / Z / N / O / S
-> LLM Gateway (configured aliases only)
-> finding gate -> reporting
-> browser-session (manual login; encrypted captured state with expiry)
<- persisted SSE events, final report downloads, explicit failure/coverage
```

Use the existing Express/TypeScript API, React/Vite frontend, Go workers,
Postgres and NATS. Do not introduce Python/FastAPI/Celery/Next.js/MinIO merely
because the current README names them in a technology wish list. Reconcile
the README with implementation and move unimplemented proposals into a roadmap.
The priority docs remain SECURITY_GUARDRAILS, ACCEPTANCE_CRITERIA and PRD.

R is already in current main's plan and local composition. Do not delete it to
match an older four-unit description. Its staging/CI deployment remains pending
per PRODUCTION_READINESS. Compact UI labels and upstream attribution serve
different purposes: preserve legal/tool attribution in documentation.

## 3. Delivery phases and exit checks

### A. Downloads (implemented on this branch, not deployed)

- DOCX, CSV and JSON join the existing HTML/PDF export endpoint.
- Generate on demand; no new artifact store or raw evidence retention.
- Require the existing org-scoped report lookup and final/superseded state.
- JSON: `snapshot.content` remains `report_v1`; `view=latest` adds
`latestOverlay` without rewriting the stored snapshot.
- DOCX: scope, summary, findings/proof references, developer fixes, coverage,
hardening, limitations and manual retest context.
- CSV: UTF-8 BOM, CRLF, quoted cells, formula neutralization;
`type,id,title,severity,confidence,asset,detail,fix` columns. Row types are
summary, validated_finding, hardening, coverage_gap, limitation, skipped and
optional latest_status. Use JSON for complete machine-readable data.
- The web uses an authenticated download, format/view selectors, pending/error
states and disables download while the report is a draft.

Checks: `npm test` and `npm run typecheck` in `gateway/public-api`;
`npm run build` in `frontend`; browser checks for desktop/mobile download,
failure and draft states. Tests use explicitly local fixtures, not real scans.

Verified 2026-09-07: 48 API tests passed, API typecheck passed, frontend production
build passed. `frontend/tests/report-downloads.mjs` passed desktop (1440px) and
mobile (390px) download/view checks, draft disabling, error display and no
horizontal overflow or page errors. This does not prove a deployed scan.
Run the browser check against a local Vite server on port 3017 with
`node tests/report-downloads.mjs` from `frontend`. It needs Playwright;
`PLAYWRIGHT_PACKAGE` may point to an existing installation and
`PLAYWRIGHT_CHROMIUM_EXECUTABLE` to an existing Chromium executable. It does not
connect to a real target or install a production mock path.

Existing limitation: the older PDF renderer truncates to 45 lines and does not
properly support Unicode. It is not proof of a complete report export. Fix or
retire that implementation before claiming every advertised format is complete.

### B. One reproducible local setup

- Pin the toolchain and dependency locks. Fresh clone must not depend on a
developer's generated Prisma client or machine-global ignore settings.
- Supply a Docker-first bootstrap, migration and health check using existing
compose files. Keep internal services off public interfaces.
- Generate local secrets, keep provider keys in ignored local configuration,
and report missing configuration truthfully. Never embed production keys.
- Document verification, authorization, manual login, start, stop and export
as a short working quickstart. Separate optional provider setup from startup.
- Exit: a clean machine can reach the UI, configure its own provider, authorize
an external test target, obtain a real final report and stop the local stack.
Restart preserves data; uninstall does not delete volumes without confirmation.

### C. Terminal streaming and live console

- Reuse persisted live events and the same public authentication/scope checks.
No extra event bus and no browser-accessible shell execution.
- A bounded full-width log view: timestamp, actor, phase, level and sanitized
text; filters, pause display, follow tail and connection state.
- A terminal client renders the same events. Strip control/ANSI/OSC sequences
from untrusted text; never accept shell commands from an event body.
- Cursor ordering must include a stable tie-breaker; resume after disconnect
without gaps or duplicate rows. Initial pagination cannot silently discard
events beyond a fixed window. Terminal completion follows backend completion.
- Exit: test more than 1,000 events, reconnect/reload, equal timestamps,
cancellation, slow consumer, failed backend and mobile overflow. No fake
delay, simulated evidence or raw chain-of-thought.

### D. Module settings and durable checkpoints

- Reuse the deterministic plan builder. User selection only narrows what
authorization, package, intensity, budgets and policy already permit.
- Allow optional execution units to be disabled; record effective settings
on the scan and skipped units with reasons in coverage. Fan-in waits only
for the effective plan, never a disabled unit.
- Scope validation, credential/evidence sanitizer, approval enforcement,
finding promotion and final reporting are mandatory and cannot be toggled off.
- Checkpoints pause before new module dispatch, not by pretending an in-flight
action was undone. Persist state; resume must not repeat completed work.
Cancellation prevents new actions and finalizes partial coverage honestly.
- Keep user checkpoint decisions distinct from sensitive-action approval.
A checkpoint resume never grants an approval or refreshes expired scope.
- Exit: restart at each checkpoint, duplicate callback/decision, scope expiry,
timeout, cancel during work, skipped dependencies and all-optional-units-off.
No quota or Free Hunter policy changes without explicit owner approval.

### E. Coding-tool package

- Start with one user-invoked skill and a thin client for existing public APIs,
not new GitHub/Jira integrations or a second privileged execution path.
- Document supported clients and installation/removal. A plugin only packages
that skill/client when a selected coding client actually requires one.
- Actions: inspect an authorized plan, start on explicit user request, follow
events, retrieve sanitized reports and request a narrow manual retest.
- Never give the model raw login storage, cookies, passwords, keys or an
automatic approval capability. Use existing human approval/login rooms.
- Exit: clean install, sign-in/out, expired auth, wrong-org denial, uninstall,
safe error rendering and no background/deployment-triggered retest.

### F. Release acceptance

- [ ] All legal gates in section 1 approved.
- [ ] README matches the actual stack and tested capabilities.
- [ ] Check tracked files and full git history for secrets without printing
values. Rotate any previously exposed credentials before public release;
deleting them from the latest file alone is insufficient.
- [ ] Publish a third-party notice inventory; verify compatibility of binaries,
templates and copied code, not just top-level npm dependencies.
- [ ] Full local E2E on an authorized controlled external test target with a
known vulnerable route and fixed negative control; no private target.
- [ ] User completes any required login/captcha/MFA manually.
- [ ] Validated finding has actual sanitized evidence; fixed route creates no
fabricated finding; coverage-only completion remains honest.
- [ ] Exports match the final report, including Free limits and skipped modules.
- [ ] Independent QA reviews evidence for each phase. A green build alone does
not certify deployment, scan effectiveness or secret absence.
- [ ] Any release/deployment records exact SHA and runtime/browser evidence.

## 4. Owner decisions still needed

1. Legal licensor identity, rights to existing contributions, commercial contact.
2. Local distribution retains existing Free/paid quotas, or has a separately
approved noncommercial entitlement? Until decided, preserve existing quotas.
3. Named coding clients for the first supported installation; do not promise
every editor or add unrequested integrations.

No changes to licensing, package entitlements, public visibility or production
infrastructure are implied by passing phase A.
1 change: 1 addition & 0 deletions frontend/.env.public-site
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
VITE_PUBLIC_SITE=true
17 changes: 17 additions & 0 deletions frontend/index.public-site.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!doctype html>
<html lang="en" class="dark">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#0d1014" />
<meta
name="description"
content="OpenHunterAI — a governed workspace for authorized external web and application security testing."
/>
<title>OpenHunterAI — Authorized security testing workspace</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/public-site.tsx"></script>
</body>
</html>
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"type": "module",
"scripts": {
"build": "tsc -p tsconfig.json && vite build",
"build:public-site": "tsc -p tsconfig.json && vite build --mode public-site && node -e \"require('fs').renameSync('dist/index.public-site.html', 'dist/index.html')\"",
"dev": "vite --host 0.0.0.0 --port 3001",
"preview": "vite preview --host 0.0.0.0 --port 3001",
"typecheck": "tsc -p tsconfig.json --noEmit",
Expand Down
20 changes: 18 additions & 2 deletions frontend/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,18 @@ function RequireAuth({ children }: { children: React.ReactNode }) {
return <>{children}</>;
}

ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
const isPublicSite = import.meta.env.VITE_PUBLIC_SITE === 'true';

function PublicSite() {
return (
<ThemeProvider>
<HomePage />
</ThemeProvider>
);
}

function Application() {
return (
<ThemeProvider>
<AuthProvider>
<BrowserRouter>
Expand All @@ -44,5 +54,11 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
</BrowserRouter>
</AuthProvider>
</ThemeProvider>
);
}

ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
{isPublicSite ? <PublicSite /> : <Application />}
</React.StrictMode>,
);
Loading
Loading