109 lines
7.2 KiB
Markdown
109 lines
7.2 KiB
Markdown
# CertScope-Public
|
||
|
||
CertScope is a compact, self-hosted domain posture inspector. Enter one public hostname and get an explainable report across DNS, TLS and HTTP(S), with deterministic findings, evidence pointers and portable exports.
|
||
|
||
## The problem it solves
|
||
|
||
Configuration risk is spread across DNS records, certificates and HTTP response policy. CertScope puts those signals in one small report and explains each score deduction with the observed evidence and a practical remediation.
|
||
|
||

|
||
|
||
## What it checks
|
||
|
||
- DNS A, AAAA, MX, NS, TXT/SPF and DMARC records, including partial family/query states.
|
||
- TLS protocol, endpoint address, certificate identity, SAN/hostname coverage, trust state, validity dates and fingerprint.
|
||
- HTTP-to-HTTPS behavior, validated redirect chains, terminal status semantics and security headers.
|
||
- Evidence-backed edge-case checks for malformed certificate windows, MX/SPF/DMARC posture and partial record-family failures.
|
||
- HSTS value quality, directive-aware CSP quality, `nosniff`, browser-style Referrer-Policy fallback evaluation and clickjacking protection.
|
||
- Stable diagnostics, evidence pointers, remediation and JSON/Markdown export.
|
||
|
||
The built-in `portfolio-demo.invalid` fixture is deterministic and does not use the network, so the product can be reviewed in under 30 seconds. Before a scan, the landing explains the product boundary. After a scan, it becomes an inspection workspace: provenance, completeness, timestamp, actions and evidence are kept together without fictional dashboard features. If a re-inspection fails, the previous validated report stays visible with its original demo/live label and an explicit error banner.
|
||
|
||
## Scoring
|
||
|
||
Each category starts at 100 and applies only the negative impacts of findings in that category, clamped to 0–100. The overall score is the rounded equal-weighted average:
|
||
|
||
```text
|
||
overall = round((DNS + TLS + HTTP) / 3)
|
||
```
|
||
|
||
`deductions` is `100 - overall`; it is not the sum of category losses. Missing evidence caused by a partial collector is not silently converted into a finding or score penalty. The report shows completeness separately.
|
||
|
||

|
||
|
||
## Security boundary
|
||
|
||
CertScope accepts one normalized DNS hostname, not a URL or IP literal. It resolves A and AAAA answers before connecting and rejects every non-public-unicast address, including private, loopback, link-local, multicast, CGNAT and ULA space. HTTP/TLS connect directly to a validated address while retaining the normalized hostname for Host/SNI. Every redirect is checked again, limited to three hops, restricted to HTTP(S) and default ports; blocked redirect targets and HTTPS-to-HTTP downgrades are retained as findings. DNS, TLS and HTTP have hard aggregate deadlines; candidate address attempts are bounded.
|
||
|
||
The unauthenticated API has a process-local four-slot concurrency guard and a 30-request/60-second fair-use window. Forwarded client headers are only used when `CERTSCOPE_TRUST_PROXY=true`; otherwise requests share a conservative direct-client bucket. Authentication, accounts, persistence, queues, workers, AI and multi-host scanning are deliberately out of scope. See [SECURITY.md](SECURITY.md) and [the threat model](docs/THREAT_MODEL.md).
|
||
|
||
## Run locally
|
||
|
||
```bash
|
||
npm ci
|
||
npm run dev
|
||
```
|
||
|
||
Open `http://localhost:3000`, inspect a public hostname, or choose **Load demo** for the offline fixture.
|
||
|
||
The release checks are:
|
||
|
||
```bash
|
||
npm ci
|
||
npm audit --omit=dev --audit-level=high
|
||
npm audit --audit-level=moderate
|
||
npm run lint
|
||
npm run typecheck
|
||
npm test
|
||
npm run build
|
||
npx playwright install chromium
|
||
npm run test:e2e
|
||
npm run sbom
|
||
```
|
||
|
||
`npm run sbom` writes an ignored production CycloneDX file named `certscope-sbom.cdx.json`.
|
||
|
||
## Your first inspection
|
||
|
||
1. Enter one public hostname, without a URL scheme, path or IP literal.
|
||
2. Read the collection status for DNS, TLS and HTTP before interpreting the score.
|
||
3. Open a finding to inspect the observed evidence and recommended change.
|
||
4. Export the report when you need a reproducible handoff; rerun the inspection after changing the target.
|
||
|
||
A blocked target is a safety decision, and an unavailable collector is incomplete evidence. Neither should be interpreted as a successful check. The screenshots above are offline fixtures; they do not imply that the demonstration hostname is reachable.
|
||
|
||
## Docker deployment
|
||
|
||
```bash
|
||
docker compose up -d --build
|
||
```
|
||
|
||
Open `http://localhost:1251`. The image uses Next.js standalone output, a pinned Node Alpine base and a non-root runtime. Compose drops capabilities, enables no-new-privileges, uses a read-only filesystem and bounds temporary storage and resources. `/api/health` reports the application version and build revision.
|
||
|
||
Compose publishes port 1251 on all host interfaces. Bind the mapping to loopback (`127.0.0.1:1251:3000`) or place the service behind an authenticated HTTPS reverse proxy before exposing it beyond a trusted network. Set `CERTSCOPE_TRUST_PROXY=true` only when trusted proxy headers cannot be supplied directly by clients.
|
||
|
||
## Portfolio walkthrough
|
||
|
||
1. Start on the landing to see the exact DNS, TLS and HTTP scope and public-target safeguards.
|
||
2. Click **Load demo** to open the offline, deterministic fixture.
|
||
3. Compare the dominant overall score with the DNS, TLS and HTTP category cards and report context.
|
||
4. Read the completeness indicator and severity-first findings list; open a finding for remediation, then use **View evidence** to jump to its structured DNS, TLS, HTTP or Raw evidence. Close the drawer with Escape.
|
||
5. Use the structured DNS, TLS and HTTP tabs; evidence is explicitly `Yes`, `No` or `Unavailable` when a collector is partial. Raw remains the complete normalized JSON with copy, download and line-wrap controls.
|
||
6. Re-inspect the current host or export JSON/Markdown. On mobile, these actions live behind **Actions**.
|
||
|
||
## Project shape
|
||
|
||
`app/` contains the Next.js presentation, health route and inspect API. The report workspace is composed from focused report action, utility and DNS/TLS/HTTP evidence components; `lib/inspect/` contains normalization/policy, deadlines, collectors, header posture parsing, diagnostics, scoring, demo data and exports. Collectors return evidence plus `_meta` status even when a probe fails; presentation code does not perform network probes.
|
||
|
||
## Demo screenshots
|
||
|
||
The images above show the bundled `portfolio-demo.invalid` fixture. They do not contain production targets or confidential inspection results; the captured UI version may precede the current package version.
|
||
|
||
## License
|
||
|
||
No project-wide license file is included in this repository. Publishing the source does not grant an open-source license. Normal copyright restrictions and the applicable terms for individual third-party components remain in effect.
|
||
|
||
## Public source distribution
|
||
|
||
The private canonical repository remains the development source. Reviewed snapshots are synchronized automatically to `CertScope-Public` after changes reach its default branch. The public export contains application source, dependency locks, generic deployment examples and selected demo visuals; private Git history, infrastructure workflows and operational records are excluded. `PUBLIC_SOURCE_MANIFEST.json` identifies the exact source revision and file hashes.
|