Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

### Changed

- Hardened the v2.1.0 release candidate with real English, Korean, and combined local OCR smoke coverage plus reproducible browser, privacy, CSP, asset, locale, responsive, accessibility, and regression evidence.
- Hardened v2 promotion gates for all ten production tools, vendored-resource integrity, local-only network invariants, save failure paths, and resource boundaries.
- Upgraded secure-metadata to v0.1.1 so JPEG Privacy Clean preserves one valid rendering Orientation while removing other targeted EXIF/GPS data without decoding or re-encoding pixels.
- Aligned Image and PDF Metadata action panels and bounded their primary decoded summaries while retaining complete details.
Expand Down
2 changes: 2 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ The root [README](../README.md) introduces Secure Tools. This directory owns det
| [Dependencies](./dependencies.md) | Production runtime inventory, versions, vendoring, licenses, and integrity ownership |
| [Local OCR foundation](./ocr-foundation.md) | Self-hosted Tesseract assets, languages, lifecycle, cancellation, caching, and privacy guarantees |
| [Sprint 16B Image → Text QA](./sprint-16b-qa.md) | Automated and Chromium browser evidence for the v2.1.0 Image → Text workflow |
| [Sprint 16C v2.1.0 release hardening](./sprint-16c-v2.1-release-hardening.md) | Release-candidate regression, OCR, privacy, browser, performance, and readiness evidence |
| [v2.1.0 release notes draft](./v2.1.0-release-notes-draft.md) | Unpublished release-note copy for the later promotion and release task |
| [Tool status](./tool-status.md) | Production and planned surfaces, supported formats, behavior, and resource boundaries |
| [Search discovery and metadata](./seo.md) | Canonical routes, crawler files, metadata policy, maintenance, and submission steps |
| [Cloudflare Pages migration bridge](./cloudflare-pages-bridge.md) | H3.2/H3.3 provenance plus the prepared H3.5 hostname-specific indexing, activation, validation, and rollback contracts |
Expand Down
6 changes: 3 additions & 3 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Production routes load application code and pinned libraries from the same origi
The homepage points to stable category hubs instead of maintaining a flat list of every utility:

- PDF: six production tools;
- Image: four production tools;
- Image: five production tools, including Image → Text OCR;
- Privacy: a cross-category hub for the two metadata tools;
- Scan/OCR and Media: planned, non-interactive surfaces.

Expand Down Expand Up @@ -44,7 +44,7 @@ The current production inventory and tool-specific behavior live in [tool status
- `js/i18n.js` resolves six supported languages, applies translations without reload, updates document metadata and `<html lang>`, and preserves tool state when language changes.
- `js/config.js` centralizes repository links.
- `tools/shared/` owns common file admission, signature validation, image/PDF helpers, queue conventions, local save behavior, and shared tool presentation.
- `tools/shared/ocr.js` owns language selection, same-origin OCR paths, normalized progress, orientation-aware image preparation, worker reuse, cancellation, and disposal. It is infrastructure only and is not linked from the public tool surface.
- `tools/shared/ocr.js` owns language selection, same-origin OCR paths, normalized progress, orientation-aware image preparation, worker reuse, cancellation, and disposal for the public Image → Text workflow.
- The File System Access API is used when available; a revoking Blob-download fallback serves other browsers.

Tool implementations retain specialized models when their workflows differ. Organizer uses a page grid and PDF rendering lifecycle; Metadata tools use bounded inspection models and fail-closed output verification. Shared UI does not erase these tool-specific guarantees.
Expand All @@ -57,7 +57,7 @@ Image conversion, resizing, and compression use browser decode, Canvas, and enco

## Development and delivery

Serving the committed production tree requires only an HTTP server. Reproducing OCR assets and running the full CI checks requires Node.js 24 and the exact lockfile. `npm run build` verifies prepared OCR assets, `npm test` runs the static and unit suite, and `node tests/ocr-smoke.test.mjs` performs real English recognition.
Serving the committed production tree requires only an HTTP server. Reproducing OCR assets and running the full CI checks requires Node.js 24 and the exact lockfile. `npm run build` verifies prepared OCR assets, `npm test` runs the static and unit suite, and `node tests/ocr-smoke.test.mjs` performs real English, Korean, and combined recognition.

`.github/workflows/ci.yml` validates pull requests and pushes to `main` using Node.js 24. It installs the lockfile only to reproduce and verify OCR assets, then checks commit-range whitespace, JavaScript syntax, unit coverage, and real local OCR without adding deployment behavior.

Expand Down
4 changes: 3 additions & 1 deletion docs/ocr-foundation.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ Production URLs are:

The service always passes explicit `workerPath`, `corePath`, and `langPath` values. `corePath` is the directory, so Tesseract.js can choose the scalar, SIMD, or relaxed-SIMD LSTM runtime. `workerBlobURL: false` creates a direct same-origin worker. Missing local assets produce a controlled initialization failure; the application has no CDN or external-service retry.

Browser HTTP cache and Tesseract.js model caching may allow a previously loaded workflow to run while disconnected. Secure Tools does not install a service worker and does not guarantee that application, worker, core, or model assets are available offline. A fresh or partially cached browser can therefore fail with the localized initialization error. There is no cloud fallback.

## Service behavior

`tools/shared/ocr.js` supports `eng`, `kor`, and `eng+kor` internally. UI code should present localized language names rather than these engine identifiers.
Expand All @@ -45,7 +47,7 @@ The public controller adds a monotonically increasing request identity around th

The browser smoke page at `tests/browser/ocr-smoke.html` runs the real browser bundle, direct worker, WASM core, and English model under the same strict meta CSP used by production pages. The public route uses the same runtime paths and unchanged production CSP. Browser QA also exercises the actual Image → Text selection, recognition, edit, copy/download, replace, remove, and cancellation paths.

Run the repeatable browser check with `npm run smoke:ocr:browser`, then open the printed localhost URL and require a visible `PASS` result. The page rejects any third-party resource entry it observes. The automated Node smoke test performs real English recognition using local core and trained data; unit tests cover path configuration, language mapping, progress, orientation cleanup, reuse, language replacement, initialization/recognition failures, cancellation, disposal, and stale callbacks.
Run the repeatable browser check with `npm run smoke:ocr:browser`, then open the printed localhost URL and require a visible `PASS` result. The page rejects any third-party resource entry it observes. The automated Node smoke test performs real English, Korean, and combined recognition using local core and trained data; unit tests cover path configuration, language mapping, progress, orientation cleanup, reuse, language replacement, initialization/recognition failures, cancellation, disposal, and stale callbacks.

## Adding a language

Expand Down
2 changes: 1 addition & 1 deletion docs/sprint-16b-qa.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Route: `/tools/image/to-text/`

- `npm run build`: pinned OCR assets match the installed packages and lockfile.
- `npm test`: syntax, state-machine, stale-callback, localization, route, CSP, privacy, responsive-contract, and regression suites pass.
- `node tests/ocr-smoke.test.mjs`: real local English OCR passes with the pinned core and language data.
- `node tests/ocr-smoke.test.mjs`: real local English, Korean, and combined OCR pass with the pinned core and language data.
- The browser smoke page completes real English OCR through the same direct worker, WASM core, and language-model paths and reports `PASS: HELLO`.

## Chromium browser QA
Expand Down
63 changes: 63 additions & 0 deletions docs/sprint-16c-v2.1-release-hardening.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Sprint 16C v2.1.0 release hardening

Date: 2026-09-23

Candidate: `v2.1` at `74d152a5b79a82abb38ca86d60b3b1b313041dce`

Production baseline: `main` at `4bc9fb5835d72b1512662d7ca80f2505ba08be00`

## Baseline and automated checks

- The baseline working tree was clean, `v2.1` matched `origin/v2.1`, and no open issue or pull request affected the candidate.
- Sprint 16A, Sprint 16B, the development-safety workflow, and branch-policy CI guard were present.
- A clean `npm ci --ignore-scripts` installed the exact lockfile with zero reported vulnerabilities.
- `npm run build`, `npm test`, `node tests/ocr-smoke.test.mjs`, and `git diff --check` passed before hardening.
- The real runtime smoke now recognizes English, Korean, and combined Korean/English fixtures through the pinned local runtime.
- The full suite covers every PDF and Image workflow, both metadata tools, direct routes, localization parity, CSP, SEO/canonical metadata, sitemap, deployment resources, object-URL cleanup, save behavior, and branch policy.

## OCR runtime, assets, and privacy

- Pinned packages remain `tesseract.js@7.0.0`, `tesseract.js-core@7.0.0`, and English/Korean data packages at `1.0.0`.
- Explicit worker, core, and language paths resolve under `/assets/vendor/tesseract/`; `workerBlobURL: false` keeps the worker same-origin. No CDN or OCR API fallback is present.
- The prepared inventory contains the engine, worker, both trained-data files, and all 18 scalar/SIMD/relaxed-SIMD core files. Manifest byte lengths and SHA-256 values match every deployed asset, with no duplicate or extra runtime copy.
- The complete committed OCR vendor tree is 49,961,571 bytes. Core variants total 45,244,609 bytes; English data is 2,952,873 bytes; Korean data is 1,572,336 bytes; worker files total 111,773 bytes; engine files total 63,110 bytes.
- Image → Text loads its OCR engine and modules only on its own route. Representative non-OCR pages do not reference the Tesseract runtime.
- Source images, filenames, decoded pixels, recognized text, and history are held only for the active in-memory workflow. Secure Tools does not persist them. Tesseract.js may cache static language-model bytes in IndexedDB; those dependency bytes contain no user content.

## Chromium browser QA

QA used the repository static server and the production Image → Text page under its unchanged production CSP.

- A clean-origin first run selected a real PNG, began combined recognition, cancelled during initialization, reported the localized cancelled state, and retried successfully.
- Combined OCR returned `한글 HELLO`. The result remained editable; clipboard copy preserved mixed Korean/English text; TXT download reported the expected source-derived filename.
- Replacing the source with a 3000 × 2000 PNG and recognizing eight text lines completed correctly. The page did not permanently freeze or lose its source/result state. This constrained browser run took about 14 minutes, so large-image latency remains device-dependent and cancellation is the practical escape path.
- The browser smoke page returned `PASS: HELLO` and would fail on any third-party resource entry. The production workflow produced no console or CSP warning.
- With the local server stopped after prior loading, Chromium reloaded the cached page and completed combined OCR from cached static runtime/model assets. This is observed cache behavior, not a full offline guarantee; a fresh browser without required cached assets cannot rely on offline OCR and receives the existing localized initialization failure.
- No hidden cloud fallback, user upload, analytics, telemetry, or third-party OCR request exists.

## Locale, theme, responsive, and accessibility QA

- English, Korean, Japanese, Spanish, German, and French each rendered the localized Image → Text heading with zero raw translation keys. Automated parity covers all 817 keys, placeholders, metadata, controls, errors, status text, and accessibility labels.
- System, Light, and Dark selected distinct resolved theme values without changing workflow state.
- At 375 × 812 the document width stayed within the viewport and the picker, recognition action, and result textarea remained visible and usable. The tablet check at 768 pixels also had no horizontal overflow.
- The browser accessibility tree exposed the file picker, language selector, result editor, cancel/retry, copy, and download controls with names in the active locale. Unit/static checks cover live status, busy/disabled state, logical native controls, visible focus rules, and reduced-motion rules.

## Existing-tool and discovery regression

- Direct Chromium navigation loaded Images → PDF, PDF Merge, PDF Split, PDF Organizer, PDF → Images, PDF Metadata, Image Converter, Resize, Compress, and Image Metadata with their file controls and localized headings.
- Automated workflow tests exercise actual processing, cancellation/error paths, signature validation, output generation, and metadata verification for those tools.
- Image → Text has one canonical route, localized title/description metadata, Open Graph metadata, sitemap membership, and Image-category discovery. No duplicate canonical route was found.

## Findings

| Severity | Finding | Status |
| --- | --- | --- |
| MEDIUM | Architecture documentation still described four Image tools and called OCR non-public after Sprint 16B. | Fixed: inventory and public OCR ownership now match the implementation. |
| LOW | The real runtime smoke covered English only, leaving Korean and combined model execution to unit/browser evidence. | Fixed: deterministic Korean/English fixture now exercises `kor` and `eng+kor`. |
| LOW | A 3000 × 2000 OCR run took about 14 minutes in the constrained Chromium QA profile. | Open limitation: operation completed correctly; progress/cancel remain available and latency depends on image and device. No arbitrary file limit was introduced. |

No BLOCKER or HIGH issue was found. No CSP or dependency change was required.

## Release readiness

**GO.** The v2.1 candidate has no remaining release blocker and is ready for a separate release-promotion pull request into `main`. This hardening Sprint does not create that PR, a tag, or a GitHub Release.
11 changes: 11 additions & 0 deletions docs/v2.1.0-release-notes-draft.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Secure Tools v2.1.0 release notes — draft

Status: unpublished. Use this draft during the separate v2.1.0 promotion and release task.

Secure Tools v2.1.0 adds Image → Text, a local OCR workflow for one PNG, JPEG, or WebP image. Recognition supports English, Korean, and combined English + Korean, with editable results, clipboard copy, and UTF-8 text download.

The OCR engine, worker, WebAssembly core, and trained language data are pinned and served from the Secure Tools origin. Images and recognized text stay in the browser, no OCR server or analytics endpoint is used, and Secure Tools stores no OCR history. The browser may cache static language-model data for performance; that cache contains no user image or recognized text.

The six interface locales remain English, Korean, Japanese, Spanish, German, and French. This release also hardens cancellation and retry, stale-result protection, worker and preview cleanup, production asset integrity, Content Security Policy compatibility, responsive behavior, accessibility, and existing PDF and image-tool regression coverage.

PDF OCR, searchable PDF output, batch OCR, camera capture, and additional recognition languages are outside v2.1.0.
Loading
Loading