feat(web): add category tabs, validation, and paste support#62
feat(web): add category tabs, validation, and paste support#62danielewood merged 8 commits intomainfrom
Conversation
AIA fetches within each depth round now run concurrently using a goroutine pool with semaphore. Reduces wall-clock time from ~30s to ~4s for stores with many leaf certificates. MemStore mutations remain sequential — no synchronization changes needed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allow users to paste PEM/certificate text directly into the page (Ctrl+V / Cmd+V) instead of requiring file drag-and-drop. Paste events on the document are intercepted, converted to bytes via TextEncoder, and fed through the same certkitAddFiles pipeline as file drops. Input fields (password box) are excluded so normal paste still works there. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix index-out-of-bounds panic in checkTrustChain when certificate has empty CommonName and empty Organization (validate.go:256) - Add context cancellation check on AIA semaphore acquire to prevent goroutines blocking after context timeout (aia.go) - Extract shared addFileObjects helper to eliminate DRY violation between processFiles and processPasted - Show user-visible error when all pasted/dropped inputs fail to parse - Add 1 MB paste size limit to prevent browser memory exhaustion - Add processing guard to prevent concurrent paste+drop operations - Show feedback when pasting while WASM is still loading - Escape cert.cert_type in key detail badge HTML for defense-in-depth - Remove dead "Serial" check in buildMetadataHTML - Remove dead visibleCertSKIs state variable - Add commit refs to all changelog entries (CL-3/CL-4) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Reset button clears `processing` flag as escape hatch for stuck state (e.g., WASM crash leaving a hung promise) - Wrap processFiles arrayBuffer calls in try/catch so file-read errors show a user-visible status instead of being silently swallowed Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
82e9a01 to
2fb7a63
Compare
There was a problem hiding this comment.
Pull request overview
This PR enhances the web UI with category-based certificate organization, browser-based validation using Mozilla root store, concurrent AIA resolution with progress tracking, and paste support for certificate data.
Changes:
- Replace tab-based navigation with category tabs (Leaf, Intermediate, Root, Keys) and click-to-expand validation details
- Add WASM validation function that performs expiration, key strength, signature, and trust chain checks
- Parallelize AIA fetches (default 20, WASM uses 50 concurrent requests) with progress reporting
- Enable Ctrl+V/Cmd+V paste support for certificate data (1 MB limit)
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| web/public/index.html | Adds category tab navigation, progress bar UI, removes old filter checkboxes, restructures table headers |
| web/public/app.js | Implements category tabs, paste handler, detail row expansion with validation, progress callbacks, processing guards |
| internal/certstore/aia.go | Adds concurrent AIA fetching with semaphore, progress callbacks, Mozilla root checks |
| cmd/wasm/validate.go | New validation function with expiration, key strength, signature, and trust chain checks |
| cmd/wasm/aia.go | Integrates progress callback to JavaScript via setTimeout |
| CHANGELOG.md | Documents new features with commit references |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Include previously uncommitted main.go (certkitValidateCert registration, serial/subject/EKU fields, formatDN/formatEKUs helpers) and style.css (category tabs, validation detail rows, metadata grid, clickable rows). Address CLAUDE.md violations in validate.go: - ERR-6: return MozillaRootPool error immediately instead of logging - CS-5: use checkTrustChainInput struct for checkTrustChain (>2 params) - CC-2: bind validation goroutine to context with 30s timeout Add ARIA accessibility: - role="tablist" on category nav, role="tab" + aria-selected on buttons - role="progressbar" with aria-valuemin/max/now on AIA progress bar - Dynamic aria-valuenow updates in JS progress callback and reset helpers Dismiss Copilot wg.Go() false positive — method exists in Go 1.25+. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
Update TestResolveAIA_CancelledContext to not assert fetchCalled: the context-cancellable semaphore select may short-circuit before reaching the fetcher, making the assertion non-deterministic. Warnings are produced either way. Fix prettier formatting on style.css. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace stale mirrors-prettier (v3.1.0, last stable release) with a local hook running npx prettier, matching CI's npx prettier@latest (3.8.1). The version mismatch caused formatting drift between local pre-commit and CI checks. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…etail rows - Thread single `now` into checkTrustChainInput to avoid dual time.Now() calls producing inconsistent results near expiry boundaries - Hoist extKeyUsageNames map to package-level var (avoid per-call alloc) - Guard certRowClick against out-of-order async resolution (check selectedDetailSKI and tr.isConnected after await) - Reset aria-selected alongside class toggle in reset handler - Use fmt.Errorf %w wrapping for JSON marshal error in validate Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
test comment |
|
Removing test comment posted earlier. |
Code reviewFound 4 issues: 1 bug and 3 CLAUDE.md violations. Inline comments follow in separate messages since the review API requires approval in this environment. Bug (internal/certstore/aia.go:109): progressTotal overflow in multi-depth AIA resolution progressTotal is computed once before the depth loop by counting only the certs currently in the store that satisfy needsResolution. But newly-fetched intermediates are added to the store during Phase 3 of each round and can themselves satisfy needsResolution in a subsequent round, causing them to be added to processed too. Concrete trace with a leaf -> intermediate -> root chain where only the leaf was uploaded:
The final tick at line 244 resets the bar to 100% at the end, but the mid-loop call with completed > total already causes progressFill.style.width = 200% in the browser. This is not a theoretical edge case -- it is the normal multi-depth resolution path. Fix: recompute progressTotal at the start of each round (e.g. progressTotal += len(queue) before Phase 1), or cap the reported value with min(len(processed), progressTotal) in the OnProgress call. |
|
CLAUDE.md CTX-2 violation (cmd/wasm/validate.go:79): context discarded runValidation accepts context.Context as its first parameter but immediately discards it. The caller at line 41 establishes a 30-second timeout that is never honored: ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
// ...
result, err := runValidation(ctx, globalStore, ski) // ctx silently dropped insideCTX-2 (MUST): Propagate non-nil ctx; honor Done/deadlines/timeouts. If the user navigates away or the browser tab is closed, runValidation continues running to completion regardless of the timeout. The context should be propagated to its callees, or -- if propagation is genuinely impossible in the WASM context -- the parameter should be removed and the timeout enforced at a different boundary. |
|
CLAUDE.md CL-3 / CL-4 violation (CHANGELOG.md:12): commit refs do not exist in this repository The refs d8b9759 and 837e5e8 used in lines 12-19 and the corresponding link definitions added at lines 576-577 do not match any commit in this PR or anywhere in the repository history. These appear to be stale SHAs from a previous branch iteration before a rebase or squash. The actual PR commits are: 4e8b1a0, f544847, 607edcb, 2fb7a63, 3feac67, 33c9588, b9430db, eb372e0. CL-3 (MUST): each entry must end with the commit ref that introduced the change. CL-4 (MUST): the link definition at the bottom must point to the actual commit. Update all five entries and both link definitions to the correct SHAs. |
|
CLAUDE.md T-9 violation (cmd/wasm/validate.go:131): certkit-specific policy logic has no tests checkExpiration, checkKeyStrength, checkSignature, and checkTrustChain implement certkit certificate validation policy -- thresholds like RSA < 2048 = fail, MD5/SHA1 = fail/warn, and the expired-cert time-travel heuristic -- that are certkit-specific decisions, not thin stdlib wrappers. T-9 (MUST): Test certkit logic, not upstream behavior. The |
Extract validation policy logic from cmd/wasm/validate.go into internal/certstore/validate.go — removes //go:build constraint so checks are reachable by go test. WASM file is now a thin JS wrapper. Add tests for CheckExpiration, CheckKeyStrength, CheckSignature, and CheckTrustChain covering policy thresholds (RSA <2048 = fail, MD5/SHA1 = fail/warn, expired/not-yet-valid, nil roots, self-signed). Fix progressTotal overflow in AIA resolution: recompute total each depth round to include newly-discovered intermediates, preventing completed from exceeding total mid-loop. Propagate context through RunValidation with ctx.Err() check between root pool load and validation checks, honoring the 30s WASM timeout. Fix stale changelog refs: d8b9759/837e5e8 (pre-rebase) → 392878a (squash merge SHA). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address post-merge review findings from PR #62 Extract validation policy logic from cmd/wasm/validate.go into internal/certstore/validate.go — removes //go:build constraint so checks are reachable by go test. WASM file is now a thin JS wrapper. Add tests for CheckExpiration, CheckKeyStrength, CheckSignature, and CheckTrustChain covering policy thresholds (RSA <2048 = fail, MD5/SHA1 = fail/warn, expired/not-yet-valid, nil roots, self-signed). Fix progressTotal overflow in AIA resolution: recompute total each depth round to include newly-discovered intermediates, preventing completed from exceeding total mid-loop. Propagate context through RunValidation with ctx.Err() check between root pool load and validation checks, honoring the 30s WASM timeout. Fix stale changelog refs: d8b9759/837e5e8 (pre-rebase) → 392878a (squash merge SHA). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: simplify substring matching in validation tests Replace custom containsSubstring/findSubstring helpers with strings.Contains from the standard library. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Summary
certkitValidateCertfunction that runs expiration, key strength, signature algorithm, and trust chain checks against the Mozilla root store — results displayed inline in expandable detail rowsTest plan
go test -race ./...passesGOOS=js GOARCH=wasm go vet ./cmd/wasm/ && go build -o /dev/null ./cmd/wasm/cd web && npm testpasses🤖 Generated with Claude Code