diff --git a/.gitattributes b/.gitattributes index 70f4e6e..f1b36f2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,4 @@ # Worker resources must remain Linux-compatible even inside Windows/macOS installers. runner/** text eol=lf +*.docx binary +*.xlsx binary diff --git a/README.md b/README.md index da2cbfb..2a8ab30 100644 --- a/README.md +++ b/README.md @@ -38,10 +38,10 @@ The [source inspection workflow](docs/source-navigation.md) explains stale/legac ## Run and install -The 0.4.1 source prepares a security hotfix. Its [release notes](docs/releases/v0.4.1.md) +Version 0.4.1 includes bounded worker-report reads and verified source review. Its [release notes](docs/releases/v0.4.1.md) and [full-main finding/validation report](docs/reports/codeql-main-fixes-2026-11-09.md) describe the bounded worker reader and the fresh native/download checks required -before publication. A source version change alone does not replace a published download. +before release promotion. Check Releases for the currently published downloads; a source version alone does not replace one. For end users, use the checksummed OS-specific packages in Releases. The UI runtime is bundled. Open the app's **Code Flow → Open local website** menu for browser use; no login token appears in the URL. Compiler jobs require an isolated local Unix/named-pipe Docker engine and the trusted worker image. Missing isolation is blocked, never passed; there is no host-execution fallback. Save/edit/static review/history/help remain usable without Docker. @@ -115,3 +115,9 @@ GitHub Actions `security-extended` analysis, review steps and unsupported scope. The [dated scan report](docs/reports/codeql-2026-11-09.md) distinguishes actual results from pending/missing evidence. Static scanning supplements the existing runtime, dependency, privacy and isolation checks; it does not certify every input or platform. + +## Documentation editions + +Start with the [organized handbook](docs/handbook.md) for current usage, design, security and test guidance. Reviewed downloadable editions: [project-guide.docx](docs/reports/project-guide.docx) · [validation-review.docx](docs/reports/validation-review.docx) · [validation-evidence.xlsx](docs/reports/validation-evidence.xlsx). + +[Publication identities and source scope](docs/reports/publications.json) · [Documentation validation record](docs/reports/documentation-refresh-2026-11-09.md). Historical results retain their own tested revision and date. diff --git a/docs/code-index.md b/docs/code-index.md index d34fb26..16c2bd9 100644 --- a/docs/code-index.md +++ b/docs/code-index.md @@ -3216,6 +3216,151 @@ Generated declaration locations. Python uses AST; JS/TS uses declaration-line ma | variable | `real` | 148 | | parameter | `kwargs` | 150 | +## tests/test_publications.py + +| Kind | Declaration | Line | +|---|---|---| +| variable | `FILES` | 29 | +| variable | `NS` | 30 | +| variable | `XML_BYTES` | 31 | +| function | `validate_publications(root)` | 34 | +| parameter | `root` | 34 | +| variable | `reports` | 36 | +| variable | `manifest` | 37 | +| variable | `source` | 38 | +| variable | `records` | 45 | +| variable | `r` | 46 | +| variable | `workflows` | 48 | +| variable | `r` | 49 | +| variable | `r` | 60 | +| variable | `record` | 63 | +| variable | `stream` | 66 | +| variable | `payload` | 67 | +| variable | `package` | 74 | +| variable | `members` | 75 | +| variable | `m` | 76 | +| variable | `names` | 76 | +| variable | `required` | 77 | +| variable | `m` | 85 | +| variable | `xml` | 87 | +| variable | `member` | 88 | +| variable | `lower` | 89 | +| variable | `marker` | 91 | +| variable | `xml_stream` | 101 | +| variable | `xml_bytes` | 102 | +| variable | `text` | 105 | +| variable | `marker` | 106 | +| variable | `relation` | 110 | +| variable | `approval` | 118 | +| variable | `count` | 119 | +| variable | `n` | 123 | +| variable | `name` | 127 | +| variable | `node` | 127 | +| variable | `tables` | 127 | +| variable | `t` | 131 | +| variable | `cells` | 134 | +| variable | `node` | 136 | +| variable | `c` | 137 | +| variable | `n` | 140 | +| variable | `row` | 141 | +| variable | `expected` | 142 | +| variable | `actual` | 148 | +| variable | `c` | 148 | +| function | `copy_publications(tmp_path)` | 153 | +| parameter | `tmp_path` | 153 | +| variable | `source` | 155 | +| variable | `target` | 156 | +| variable | `name` | 158 | +| function | `rewrite_package(root, filename, change)` | 163 | +| parameter | `change` | 163 | +| parameter | `filename` | 163 | +| parameter | `root` | 163 | +| variable | `path` | 165 | +| variable | `original` | 166 | +| variable | `entries` | 167 | +| variable | `m` | 167 | +| variable | `package` | 169 | +| variable | `content` | 170 | +| variable | `name` | 170 | +| variable | `manifest_path` | 172 | +| variable | `manifest` | 173 | +| variable | `r` | 174 | +| variable | `record` | 174 | +| variable | `payload` | 175 | +| function | `test_actual_reviewed_publications_are_bound_to_source_and_workflows()` | 181 | +| function | `test_actual_binary_tamper_fails_digest(tmp_path)` | 186 | +| parameter | `tmp_path` | 186 | +| variable | `root` | 188 | +| variable | `path` | 189 | +| function | `test_renamed_publication_cannot_select_an_external_path(tmp_path)` | 195 | +| parameter | `tmp_path` | 195 | +| variable | `root` | 197 | +| variable | `path` | 198 | +| variable | `record` | 199 | +| function | `test_rehashed_active_office_members_still_fail(tmp_path, member)` | 210 | +| parameter | `member` | 210 | +| parameter | `tmp_path` | 210 | +| variable | `root` | 212 | +| parameter | `entries` | 216 | +| function | `test_rehashed_zip_without_document_root_fails(tmp_path)` | 222 | +| parameter | `tmp_path` | 222 | +| variable | `root` | 224 | +| parameter | `entries` | 225 | +| function | `test_rehashed_workbook_missing_actual_filter_fails(tmp_path)` | 230 | +| parameter | `tmp_path` | 230 | +| variable | `root` | 232 | +| function | `remove_filter(entries)` | 234 | +| parameter | `entries` | 234 | +| variable | `n` | 236 | +| variable | `name` | 236 | +| variable | `table` | 237 | +| function | `test_rehashed_workbook_changed_formula_fails(tmp_path)` | 246 | +| parameter | `tmp_path` | 246 | +| variable | `root` | 248 | +| function | `change_formula(entries)` | 250 | +| parameter | `entries` | 250 | +| variable | `name` | 252 | +| variable | `sheet` | 253 | +| variable | `formula` | 254 | +| function | `test_dishonest_compressed_xml_uses_bounded_actual_decompression(tmp_path, monkeypatch)` | 263 | +| parameter | `monkeypatch` | 263 | +| parameter | `tmp_path` | 263 | +| variable | `root` | 265 | +| variable | `name` | 266 | +| parameter | `entries` | 268 | +| variable | `path` | 270 | +| variable | `payload` | 271 | +| variable | `end` | 272 | +| variable | `cursor` | 273 | +| variable | `changed` | 274 | +| variable | `comment_size` | 276 | +| variable | `extra_size` | 276 | +| variable | `filename_size` | 276 | +| variable | `filename` | 277 | +| variable | `local` | 279 | +| variable | `changed` | 283 | +| variable | `cursor` | 284 | +| variable | `manifest_path` | 287 | +| variable | `manifest` | 288 | +| variable | `r` | 289 | +| variable | `record` | 289 | +| variable | `limits` | 292 | +| variable | `factory` | 293 | +| class | `BoundedInflater` | 295 | +| function | `__init__(self, actual)` | 298 | +| parameter | `actual` | 298 | +| parameter | `self` | 298 | +| function | `decompress(self, data, max_length)` | 302 | +| parameter | `data` | 302 | +| parameter | `max_length` | 302 | +| parameter | `self` | 302 | +| function | `__getattr__(self, attribute)` | 309 | +| parameter | `attribute` | 309 | +| parameter | `self` | 309 | +| function | `observed_factory(compression)` | 313 | +| parameter | `compression` | 313 | +| variable | `actual` | 315 | + ## tests/test_release.py | Kind | Declaration | Line | diff --git a/docs/handbook.md b/docs/handbook.md new file mode 100644 index 0000000..82be5e6 --- /dev/null +++ b/docs/handbook.md @@ -0,0 +1,67 @@ +# Code Flow Studio handbook + +By Jason Stys. + +Filter diagnostics, unused-code candidates and missed coverage; inspect hash-verified source and navigate safely to unchanged drafts. Fixed rapid typing, worker compatibility and native launch preparation. + +Turns report findings into a reproducible developer triage workflow while preserving source identity and isolated execution. + +## Read the documentation + +| Edition | Audience and contents | +| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------ | +| [project-guide.docx](reports/project-guide.docx) | User and developer guide: purpose, current usage, design, boundaries and source references. | +| [validation-review.docx](reports/validation-review.docx) | Reviewer edition: exact tested baseline, observed workflows, dated local results and remaining limits. | +| [validation-evidence.xlsx](reports/validation-evidence.xlsx) | Two filterable Excel Tables for observed workflows and test-source inventory, with recalculating outcome formulas. | + +The editable Markdown remains the maintenance source. The Word files are readable editions, and the workbook is an evidence index rather than a test runner. See [publication identities and review](reports/publications.json) and the [documentation refresh record](reports/documentation-refresh-2026-11-09.md). + +## Current usage and help + +[README quick start](../README.md) is the entry point. Use the project-specific guides below before changing inputs, operating modes or deployment assumptions. + +### Usage and operations + +- [release checklist v0.2](release-checklist-v0.2.md) +- [releases/v0.2.0](releases/v0.2.0.md) +- [releases/v0.2.1](releases/v0.2.1.md) +- [releases/v0.3.0](releases/v0.3.0.md) +- [releases/v0.4.0](releases/v0.4.0.md) +- [releases/v0.4.1](releases/v0.4.1.md) + +### Design and contracts + +- [adr polyglot evidence](adr-polyglot-evidence.md) +- [adr private local](adr-private-local.md) +- [architecture](architecture.md) +- [private api](private-api.md) +- [research](research.md) + +### Security and validation + +- [security](security.md) +- [test plan v0.2](test-plan-v0.2.md) +- [testing](testing.md) +- [validation locations](validation-locations.md) +- [validation polyglot](validation-polyglot.md) +- [validation v0.2](validation-v0.2.md) +- [validation](validation.md) + +## Historical results and reproduction + +The reviewed source is [`7d2158a57bb49e8f837fffbfe23b301902465412`](https://github.com/JasonStys/code-flow-studio/tree/7d2158a57bb49e8f837fffbfe23b301902465412). The observed functional workflow baseline is `7d2158a57bb49e8f837fffbfe23b301902465412`; those observations are recorded at `2026-11-10T13:28:55.865054+00:00`. They do not certify an unrun later revision. + +- [Detailed recorded validation](reports/native-http-drain-2026-11-10.md) +- [Current Actions](https://github.com/JasonStys/code-flow-studio/actions) records later integration checks separately. +- Preserve dated measurements and follow the existing testing guide to reproduce them; a test-source inventory alone does not establish execution. + +## Practical boundaries + +- Local account/vault plaintext is accessible to the trusted local service and device OS while unlocked; this is not browser-only end-to-end encryption or public SaaS authentication. +- Compiler tests require the fixed isolated local worker image. No host-code fallback, automatic Docker repair, universal coverage/bug detection or hostile-code security certification is provided. +- The five-second HTTP drain is not a universal exit-time guarantee: critical disk/container cleanup and vault sealing must finish safely; preserve recovery data on failure. +- Supported CodeQL categories, actual statement coverage, fixture browser journeys and tiny CPU training have distinct scopes. Passing checks do not establish model quality, vulnerability freedom or clean-machine installer acceptance. + +## Maintaining these editions + +Update the editable usage/design/test documents first. Rebuild and visually review every Word page and workbook tab before replacing an edition; verify the exact binary digests and evidence source in publications.json. Keep account data, logs with secrets, installed-app state and private test stores out of documentation. Source and release assets retain their existing security and licensing boundaries. diff --git a/docs/releases/v0.4.1.md b/docs/releases/v0.4.1.md index 26a7511..0ee3352 100644 --- a/docs/releases/v0.4.1.md +++ b/docs/releases/v0.4.1.md @@ -1,9 +1,26 @@ -# Code Flow Studio 0.4.1 — bounded worker reports +# Code Flow Studio 0.4.1 — bounded reports and safe shutdown By Jason Stys. This source prepares a hotfix; a new downloadable release requires successful exact-source validation, full-main CodeQL review and three-OS native package acceptance. Published 0.4.0 assets and tags remain unchanged. +The native account service gives HTTP work five seconds to drain, then cancels +and joins its own remaining request tasks before normal vault sealing. Real +offloaded disk operations and authorized local account/provider transitions finish +under the existing request mutex before cancellation is reported, including +repeated cancellation. Unlock/lock, provider destination/key/consent publication, +deletion, logout and recovery reset retain coherent local state. Request bodies, +AI calls and arbitrary network waits remain cancellable. + +Actual native acceptance now requires numeric HTTP-drain observations, completed +workspace/lifespan/server/main milestones and absence of both owned service and +bootloader PIDs, as well as the existing account/editor/privacy/lock checks. +The [native-drain report](../reports/native-http-drain-2026-11-10.md) records the +real held-request, snapshot/restore and cancellation controls. The five-second +HTTP budget is not a universal process-exit guarantee: critical disk/container +cleanup must finish safely, and failed cleanup preserves recovery data. No force +exit, skipped sealing, test retry or increased native deadline is introduced. + The fixed JavaScript/TypeScript worker bridge opens each native JSON report once, checks that descriptor's regular-file/size metadata, caps the bytes actually read at eight MiB plus one sentinel byte, and closes it even on malformed JSON or I/O diff --git a/docs/reports/documentation-refresh-2026-11-09.md b/docs/reports/documentation-refresh-2026-11-09.md new file mode 100644 index 0000000..2ad10cc --- /dev/null +++ b/docs/reports/documentation-refresh-2026-11-09.md @@ -0,0 +1,56 @@ +# Documentation refresh — 2026-11-09 + +By Jason Stys. + +This documentation-only edition describes source `7d2158a57bb49e8f837fffbfe23b301902465412`. It does not change application behavior, accounts, private data, installers or published releases. + +## Published editions and completed review + +| File | Bytes | SHA-256 | Reviewed scope | +| ---------------------------------------------------- | ----: | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- | +| [project-guide.docx](project-guide.docx) | 46007 | `4d0a998f70fb0d798a6a76e3739af62f54c73c4d147bc9ddbdf1f5f3bac0d039` | 6 pages, each individually viewed at original resolution | +| [validation-review.docx](validation-review.docx) | 47230 | `3e472c90824be2501e0acdc7aff2ea6750ca9f4f0109804d0ff97e74020ee973` | 6 pages, each individually viewed at original resolution | +| [validation-evidence.xlsx](validation-evidence.xlsx) | 7760 | `0a9b5f1e6239dcb400bf195887461fcc967eec545633d1ebf3280d3353356c71` | Both previews; two actual Tables/autoFilters, four formulas, 3/3/0/0 values and failure-toggle/restore verified | + +Word review checked plain black titles, readable pagination, whole table rows, source references, practical limits and absence of clipping or overflow. Render receipts were matched to the current DOCX digest before approval. Workbook review inspected both tab previews and actual exported Table/autoFilter elements; recalculated success/failure summaries were compared independently with workflow metadata. Static previews do not draw Excel dropdown arrows; the exported workbook contains the actual filters. + +## Evidence and change boundary + +- Functional baseline: `7d2158a57bb49e8f837fffbfe23b301902465412`. +- Workflow observation: `2026-11-10T13:28:55.865054+00:00`; exact run URLs and source identities remain in [publications.json](publications.json). +- Local document-package validation verifies exact copied bytes, Office ZIP integrity, approved page/tab identities and internal documentation links. Repository-specific documentation and source-policy commands are run separately and recorded in the integration handoff. +- Source/index metadata is regenerated using the repository’s existing tools. Existing privacy, security, coverage and workflow gates are retained. +- PR and later main workflows must pass independently. This record does not claim future or unrun integration CI success. + +## Interpretation + +The Word files document the cited source; dated source reports retain their original execution scope. A passing workflow is distinct from completed analysis with zero findings, and neither establishes production suitability. The Excel source inventory is not a per-test execution report. Checksums identify exact bytes, not a signature or publisher attestation. + +Use the [handbook](../handbook.md) to choose usage, design, security and test documentation. Keep editable Markdown and reviewed editions together; do not replace historical measurements with undated claims. + +## Local integration checks and future CI + +The runtime baseline above passed its full main workflows, actual full supported-language +CodeQL analysis and three-OS native acceptance. Final local documentation integration +passed 275 tests and 28 subtests in 48.49 seconds, measuring 1,539/1,808 controller/data +statements (85.12%, unchanged 80% floor). The ten publication cases include real +package tamper, closed filenames, macro/ActiveX/embedding rejection, missing Word +root, changed Excel filters/formulas and understated compressed XML sizes. + +Actual XML inflation is bounded to an eight-MiB read plus one sentinel byte before +checking actual/declared length. The genuine zlib oracle rejects the former +unbounded reader before a large output request; later CRC rejection alone is not +a memory-bound proof. Development-only defusedxml 0.7.1 forbids DTDs, with no new +application runtime dependency, account schema or migration. + +Ruff, 87 exact source maps, strict TypeScript/Vite production build, approved-byte/ +ZIP/source/workflow/link validation and diff hygiene passed. The existing pytest +cache and large UI-chunk warnings remain visible. All twelve current Word pages +and both workbook previews were independently viewed at original resolution; +saved OOXML contains the two actual Tables/autoFilters, all 27 source-bound test +paths and four formulas with 3/3/0/0 cached results. The matching failure-change/ +restore receipt was checked; native Excel recalculation is not claimed. + +These are local integration observations. Fresh PR and final main workflows and +later draft/download/installer acceptance remain separate required gates. Existing +0.4.0 public assets, installed user apps and account stores are unchanged. diff --git a/docs/reports/native-http-drain-2026-11-10.md b/docs/reports/native-http-drain-2026-11-10.md index 2627be2..fa468d1 100644 --- a/docs/reports/native-http-drain-2026-11-10.md +++ b/docs/reports/native-http-drain-2026-11-10.md @@ -2,6 +2,36 @@ By Jason Stys. +## Verified runtime-main acceptance — 2026-11-10 + +Source `7d2158a57bb49e8f837fffbfe23b301902465412` passed all three exact-main push workflows: [CodeQL](https://github.com/JasonStys/code-flow-studio/actions/runs/42823802503), [Desktop packages](https://github.com/JasonStys/code-flow-studio/actions/runs/42823802633), [Validate](https://github.com/JasonStys/code-flow-studio/actions/runs/42823802584). +Actual complete CodeQL logs and processed SARIF confirm all three supported +categories were processed without errors/warnings and report zero raw results; +the main open-alert inventory is empty. The separate CodeQL section preserves +rule/file counts, original fixed main findings and PR-only fixed instances. + +All three operating-system jobs passed both SDK and actual compiled-application +journeys. The [actual Windows job](https://github.com/JasonStys/code-flow-studio/actions/runs/42823802633/job/129855717692) recorded complete HTTP drain, +workspace sealing, lifespan/server/main completion and absence of both owned +service and bootloader PIDs. This is genuine packaged executable acceptance, +not downloaded-installer or clean-machine proof. Existing journey/launcher +deadlines and zero retries are unchanged. + +Local controller/training validation passed 265 tests and 28 subtests, measuring +1,539/1,808 statements (85.12%, unchanged 80% floor). All 48 controller/source +browser checks and 18 private-account checks passed across Chromium, Firefox and +WebKit. Five readiness/receipt/diagnostic cases, seven actual worker JSON-reader +cases, strict TypeScript/Vite build, Ruff and 86 checked source maps passed. +Hosted actual isolated workers and synthetic CPU training remain separate +acceptance lanes; no local Docker repair or live provider/model-quality claim is made. + +The earlier eeac acceptance and native failures retain historical scope. The new +finite-drain and completed-local-operation controls address a reproduced actual +mechanism; the exact historical held request remains unidentified. Current source +acceptance does not publish or replace a downloadable release. Fresh draft, +downloaded installer acceptance and owner promotion remain required; existing +0.4.0 assets and installed user accounts/apps are unchanged. + ## Observed defect and scope The [Windows native job](https://github.com/JasonStys/code-flow-studio/actions/runs/42796136482/job/129761676463) @@ -67,13 +97,9 @@ full-main CodeQL and later fresh draft/download acceptance remain separate gates ## References and retained boundaries -- [Pinned Uvicorn shutdown implementation](https://github.com/encode/uvicorn/blob/0.38.0/uvicorn/server.py) - drains connections/tasks before lifespan shutdown. -- [Python cancellation and shielding](https://docs.python.org/3.14/library/asyncio-task.html#shielding-from-cancellation) - distinguishes a protected child from its still-cancelled caller and requires - retaining a strong task reference. -- [Private account operation](../private-accounts.md) describes local trust, - recovery and the required container-only compiler boundary. +- [Pinned Uvicorn shutdown implementation](https://github.com/encode/uvicorn/blob/0.38.0/uvicorn/server.py) drains connections/tasks before lifespan shutdown. +- [Python cancellation and shielding](https://docs.python.org/3.14/library/asyncio-task.html#shielding-from-cancellation) distinguishes a protected child from its still-cancelled caller and requires retaining a strong task reference. +- [Private account operation](../private-accounts.md) describes local trust, recovery and the required container-only compiler boundary. No user account, installed application, existing public release, Docker engine, source-consent rule or worker-isolation permission was changed by these tests. diff --git a/docs/reports/native-registration-completion-2026-11-10.md b/docs/reports/native-registration-completion-2026-11-10.md index 808ac3e..8143a92 100644 --- a/docs/reports/native-registration-completion-2026-11-10.md +++ b/docs/reports/native-registration-completion-2026-11-10.md @@ -3,6 +3,49 @@ By Jason Stys. This follow-up changes validation and diagnostics; application behavior, account schemas and the prepared 0.4.1 product version are unchanged. +## Verified current-main source — 2026-11-10 + +Source `eeac1df6275437f401a8c060b7770c138dbaf132` passed all three exact-main +push workflows: [Validate 42791315575](https://github.com/JasonStys/code-flow-studio/actions/runs/42791315575), +[Desktop packages 42791315489](https://github.com/JasonStys/code-flow-studio/actions/runs/42791315489) +and [CodeQL 42791315566](https://github.com/JasonStys/code-flow-studio/actions/runs/42791315566). +The following older failures and local measurements retain their original scopes. + +Actual full-main job logs identify this source and contain no PR diff range or +incremental exclusion filter. They report 52/52 Python, 19/19 TypeScript, 10/10 +JavaScript, 1/1 HTML and 4/4 Actions files scanned. Processed SARIF has zero results +in each category, with 50 Python, 103 JavaScript/TypeScript and 23 Actions queries, +without processing errors/warnings. The main alert inventory is empty. Original +alerts 1–2 automatically closed as fixed; four later PR-only findings have fixed +instances at their own PR refs. No alert was dismissed or query suppressed. +Query counts and scanned-file inventory are not code coverage or vulnerability freedom. + +All three native operating-system jobs passed their SDK and actual compiled +application journeys. The actual Windows job +[129745181301](https://github.com/JasonStys/code-flow-studio/actions/runs/42791315489/job/129745181301) +completed SDK acceptance in 10.3 seconds and compiled acceptance in 7.7 seconds. +Both recorded shutdown HTTP 200/stopping true, actual workspace/lifespan/thread/main +completion and owned frozen-child/bootloader exit; the test also verifies those PIDs +are absent without terminating them. Packaged source identity and the corrected +worker resource SHA are checked against this checkout. This is native package +acceptance, not downloaded-installer or clean-machine proof. + +The complete source Validate gate includes actual isolated workers, privacy/browser +checks and synthetic training smoke; these are separate from static analysis and +local report fixtures. Local controller/training validation measured 1,462/1,734 +statements (84.31%, unchanged 80% floor), with 252 tests and 28 subtests. Five Node +readiness/receipt/descriptor cases and 81 source maps passed. These denominators do +not include worker runtime, trained-model quality or all renderer statements. + +The strengthened completion/diagnostic contracts now provide explicit evidence; +the original intermittent hosted registration/shutdown causes were not reproduced +or conclusively identified. Existing deadlines and zero retries remain unchanged. +A 0.4.1 downloadable release still needs independent draft/download/installer +acceptance and the release owner's promotion; this source observation does not +claim publication or change any installed application, account, store or 0.4.0 asset. + +## Earlier observations and independent regressions + ## Observed hosted failure The full-main source `4f1d0aafd151db3c183e342012900dc75beda96d` passed @@ -31,20 +74,9 @@ values, response bodies, aliases, passwords and recovery/vault material. ## Independent local checks -- Eighteen actual private-browser journeys passed across Chromium, Firefox and - WebKit, including genuine held registration and genuine duplicate-account cases. - The held response comes from the real service: while delivery is held the form - remains busy, with neither recovery nor workspace visible; releasing it completes - a real account/unlock/lock journey. No canned success payload or timed sleep is used. -- The duplicate-account case receives the real conflict response and requires the - helper to reject it before claiming recovery or workspace success. Replacing only - the helper with its previous committed implementation makes this regression fail; - the corrected file was restored byte-for-byte afterwards. -- The owned Windows Electron SDK journey passed in 5.7 seconds. A freshly rebuilt, - unsigned unpacked Windows development application passed in 5.5 seconds, with - embedded reviewed worker bytes and honestly dirty development provenance checked. - Both use disposable profiles and close only their owned process. They do not prove - installation, a clean machine, other operating systems or future hosted results. +- Eighteen actual private-browser journeys passed across Chromium, Firefox and WebKit, including genuine held registration and genuine duplicate-account cases. The held response comes from the real service: while delivery is held the form remains busy, with neither recovery nor workspace visible; releasing it completes a real account/unlock/lock journey. No canned success payload or timed sleep is used. +- The duplicate-account case receives the real conflict response and requires the helper to reject it before claiming recovery or workspace success. Replacing only the helper with its previous committed implementation makes this regression fail; the corrected file was restored byte-for-byte afterwards. +- The owned Windows Electron SDK journey passed in 5.7 seconds. A freshly rebuilt, unsigned unpacked Windows development application passed in 5.5 seconds, with embedded reviewed worker bytes and honestly dirty development provenance checked. Both use disposable profiles and close only their owned process. They do not prove installation, a clean machine, other operating systems or future hosted results. - Strict TypeScript/Vite build, Ruff and generated source-index checks passed. Existing large-chunk and pytest-cache warnings are not hidden. diff --git a/docs/reports/project-guide.docx b/docs/reports/project-guide.docx new file mode 100644 index 0000000..9e2d4f2 Binary files /dev/null and b/docs/reports/project-guide.docx differ diff --git a/docs/reports/publications.json b/docs/reports/publications.json new file mode 100644 index 0000000..331e7b9 --- /dev/null +++ b/docs/reports/publications.json @@ -0,0 +1,123 @@ +{ + "schemaVersion": 1, + "project": "code-flow-studio", + "author": "Jason Stys", + "editionDate": "2026-11-09", + "sourceBaseline": "7d2158a57bb49e8f837fffbfe23b301902465412", + "sourceUrl": "https://github.com/JasonStys/code-flow-studio/tree/7d2158a57bb49e8f837fffbfe23b301902465412", + "functionalEvidenceBaseline": "7d2158a57bb49e8f837fffbfe23b301902465412", + "evidenceObservedAt": "2026-11-10T13:28:55.865054+00:00", + "workflowEvidence": [ + { + "name": "CodeQL", + "headSha": "7d2158a57bb49e8f837fffbfe23b301902465412", + "event": "push", + "status": "completed", + "conclusion": "success", + "url": "https://github.com/JasonStys/code-flow-studio/actions/runs/42823802503" + }, + { + "name": "Desktop packages", + "headSha": "7d2158a57bb49e8f837fffbfe23b301902465412", + "event": "push", + "status": "completed", + "conclusion": "success", + "url": "https://github.com/JasonStys/code-flow-studio/actions/runs/42823802633" + }, + { + "name": "Validate", + "headSha": "7d2158a57bb49e8f837fffbfe23b301902465412", + "event": "push", + "status": "completed", + "conclusion": "success", + "url": "https://github.com/JasonStys/code-flow-studio/actions/runs/42823802584" + } + ], + "summary": "Filter diagnostics, unused-code candidates and missed coverage; inspect hash-verified source and navigate safely to unchanged drafts. Fixed rapid typing, worker compatibility and native launch preparation.", + "rationale": "Turns report findings into a reproducible developer triage workflow while preserving source identity and isolated execution.", + "limitations": [ + "Local account/vault plaintext is accessible to the trusted local service and device OS while unlocked; this is not browser-only end-to-end encryption or public SaaS authentication.", + "Compiler tests require the fixed isolated local worker image. No host-code fallback, automatic Docker repair, universal coverage/bug detection or hostile-code security certification is provided.", + "The five-second HTTP drain is not a universal exit-time guarantee: critical disk/container cleanup and vault sealing must finish safely; preserve recovery data on failure.", + "Supported CodeQL categories, actual statement coverage, fixture browser journeys and tiny CPU training have distinct scopes. Passing checks do not establish model quality, vulnerability freedom or clean-machine installer acceptance." + ], + "documents": [ + { + "filename": "project-guide.docx", + "mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "bytes": 46007, + "sha256": "4d0a998f70fb0d798a6a76e3739af62f54c73c4d147bc9ddbdf1f5f3bac0d039", + "sourceBaseline": "7d2158a57bb49e8f837fffbfe23b301902465412", + "visualReview": { + "approved": true, + "method": "Every current rendered page individually viewed at readable original resolution", + "pageCount": 6, + "renderedPageSha256": { + "page-1.png": "f6389eb6a6a07929fe59b777a6b106dfaf368c35c478846ea078d8407c5c16ea", + "page-2.png": "8d1029a2356088276ff475806232582176dee2edaec0343d5d98201c553b9304", + "page-3.png": "bfb2f61c30beb44e6cc916244eaf73efd515ef2944c50b3ba733e740d0ca11b6", + "page-4.png": "7dbcbac153ceec3e3eee6d5770adf2ba003db344ae175f474191c16fc0d099d8", + "page-5.png": "7e1532fc9e02a7df0af324e02c04c0d0ef7f7f2843c80860eba5ae889d76878e", + "page-6.png": "41f6baed81243199244f32799a0c14ab4b22759c88395ffef4a8131d616338cd" + } + } + }, + { + "filename": "validation-evidence.xlsx", + "mimeType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "bytes": 7760, + "sha256": "0a9b5f1e6239dcb400bf195887461fcc967eec545633d1ebf3280d3353356c71", + "sourceBaseline": "7d2158a57bb49e8f837fffbfe23b301902465412", + "visualReview": { + "approved": true, + "tabsReviewed": ["Workflow evidence", "Test sources"], + "previewSha256": { + "workflow-evidence.png": "b56139ba891c6c15b2f5cd2ae3b85cd173215943e01a0fb6e389cb9b8535eff5", + "test-sources.png": "c02062a33b3df1357abda90ea452b9f373b52f8b4b038af944a9b68a3ca4d786" + }, + "tables": [ + { + "path": "xl/tables/table1.xml", + "name": "WorkflowEvidence", + "range": "A7:D10", + "columns": 4, + "autoFilter": true, + "filterButtonsEnabled": true + }, + { + "path": "xl/tables/table2.xml", + "name": "TestSources", + "range": "A7:C34", + "columns": 3, + "autoFilter": true, + "filterButtonsEnabled": true + } + ], + "formulaCount": 4, + "failureSensitivityReceiptPassed": true, + "formulaErrors": 0 + } + }, + { + "filename": "validation-review.docx", + "mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "bytes": 47230, + "sha256": "3e472c90824be2501e0acdc7aff2ea6750ca9f4f0109804d0ff97e74020ee973", + "sourceBaseline": "7d2158a57bb49e8f837fffbfe23b301902465412", + "visualReview": { + "approved": true, + "method": "Every current rendered page individually viewed at readable original resolution", + "pageCount": 6, + "renderedPageSha256": { + "page-1.png": "d42862d4f851acb65c1a1ad6f5ee98fa15cbf51da50ac720a1dbb3360854d6ac", + "page-2.png": "86c87bf349b6e65419873670a7d2c27e5b1beb591796303696995bfe5f8445e6", + "page-3.png": "31c5dcb15bf5420267d77444e7c9db6812ab0a2a0b232d7044a7d7f0d75a1716", + "page-4.png": "56b49bfaa999a5dccb0bd5e47ca3f383551a22d7e1cd357847e2b51a72593e35", + "page-5.png": "d2b5d3195958a411937b1d74d4a6025d109f616b3145af4679f94fe8116081dc", + "page-6.png": "e6d9877b71bbac8d90a1d39b1d784db59c4a74902511e5a89c1281cff723987d" + } + } + } + ], + "scope": "Reviewed documentation editions of the cited source. Checksums identify bytes, not authorship. Historical measurements retain their own dates; integration CI must be checked separately." +} diff --git a/docs/reports/validation-evidence.xlsx b/docs/reports/validation-evidence.xlsx new file mode 100644 index 0000000..8b9a317 Binary files /dev/null and b/docs/reports/validation-evidence.xlsx differ diff --git a/docs/reports/validation-review.docx b/docs/reports/validation-review.docx new file mode 100644 index 0000000..9dac908 Binary files /dev/null and b/docs/reports/validation-review.docx differ diff --git a/pyproject.toml b/pyproject.toml index c6b9ba7..ffc53cb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ requires-python = ">=3.12" dependencies = ["fastapi==0.142.1", "uvicorn==0.38.0", "httpx==0.28.1", "pydantic==2.13.2", "cryptography==50.0.2", "psutil==7.2.2", "certifi==2026.10.19"] [project.optional-dependencies] -dev = ["pytest==9.0.3", "pytest-cov==7.0.0", "ruff==0.14.0", "pyinstaller==6.22.3", "hypothesis==6.142.4", "httpx2==2.13.1", "pip-audit==2.10.1"] +dev = ["pytest==9.0.3", "pytest-cov==7.0.0", "ruff==0.14.0", "pyinstaller==6.22.3", "hypothesis==6.142.4", "httpx2==2.13.1", "pip-audit==2.10.1", "defusedxml==0.7.1"] training = ["torch>=2.6,<3", "transformers>=4.56,<6", "datasets>=4,<5", "accelerate>=1.10,<2"] [project.scripts] diff --git a/tests/test_publications.py b/tests/test_publications.py new file mode 100644 index 0000000..470680c --- /dev/null +++ b/tests/test_publications.py @@ -0,0 +1,322 @@ +# +# Generated definition map; @L is the exact declaration line. +# Function/class docs explain behavior; variables/parameters are scoped inputs, outputs or state. +# classes: BoundedInflater@L295 +# functions: validate_publications(root)@L34; copy_publications(tmp_path)@L153; rewrite_package(root, filename, change)@L163; test_actual_reviewed_publications_are_bound_to_source_and_workflows()@L181; test_actual_binary_tamper_fails_digest(tmp_path)@L186; test_renamed_publication_cannot_select_an_external_path(tmp_path)@L195; test_rehashed_active_office_members_still_fail(tmp_path, member)@L210; test_rehashed_zip_without_document_root_fails(tmp_path)@L222; test_rehashed_workbook_missing_actual_filter_fails(tmp_path)@L230; remove_filter(entries)@L234; test_rehashed_workbook_changed_formula_fails(tmp_path)@L246; change_formula(entries)@L250; test_dishonest_compressed_xml_uses_bounded_actual_decompression(tmp_path, monkeypatch)@L263; __init__(self, actual)@L298; decompress(self, data, max_length)@L302; __getattr__(self, attribute)@L309; observed_factory(compression)@L313 +# variables: FILES@L29; NS@L30; XML_BYTES@L31; reports@L36; manifest@L37; source@L38; records@L45; r@L46; workflows@L48; r@L49; r@L60; record@L63; stream@L66; payload@L67; package@L74; members@L75; m@L76; names@L76; required@L77; m@L85; xml@L87; member@L88; lower@L89; marker@L91; xml_stream@L101; xml_bytes@L102; text@L105; marker@L106; relation@L110; approval@L118; count@L119; n@L123; name@L127; node@L127; tables@L127; t@L131; cells@L134; node@L136; c@L137; n@L140; row@L141; expected@L142; actual@L148; c@L148; source@L155; target@L156; name@L158; path@L165; original@L166; entries@L167; m@L167; package@L169; content@L170; name@L170; manifest_path@L172; manifest@L173; r@L174; record@L174; payload@L175; root@L188; path@L189; root@L197; path@L198; record@L199; root@L212; root@L224; root@L232; n@L236; name@L236; table@L237; root@L248; name@L252; sheet@L253; formula@L254; root@L265; name@L266; path@L270; payload@L271; end@L272; cursor@L273; changed@L274; comment_size@L276; extra_size@L276; filename_size@L276; filename@L277; local@L279; changed@L283; cursor@L284; manifest_path@L287; manifest@L288; r@L289; record@L289; limits@L292; factory@L293; actual@L315 +# parameters: root@L34; tmp_path@L153; change@L163; filename@L163; root@L163; tmp_path@L186; tmp_path@L195; member@L210; tmp_path@L210; entries@L216; tmp_path@L222; entries@L225; tmp_path@L230; entries@L234; tmp_path@L246; entries@L250; monkeypatch@L263; tmp_path@L263; entries@L268; actual@L298; self@L298; data@L302; max_length@L302; self@L302; attribute@L309; self@L309; compression@L313 +# + +"""Jason Stys: source-bound publication integrity with real Office tamper regressions. + +Symbol locations: docs/code-index.md. These checks validate tracked documentation; +they do not run Office, reproduce visual review, authenticate authorship or read accounts. +""" + +import hashlib +import io +import json +import re +import shutil +import struct +import zipfile +from pathlib import Path +from zipfile import ZIP_DEFLATED, ZIP_STORED, ZipFile + +import pytest +from defusedxml import ElementTree as ET + +FILES = {"project-guide.docx", "validation-review.docx", "validation-evidence.xlsx"} +NS = {"x": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"} +XML_BYTES = 8 * 1024 * 1024 + + +def validate_publications(root: Path) -> None: + """Require exact reviewed bytes, immutable provenance and bounded inactive Office structures.""" + reports = root / "docs" / "reports" + manifest = json.loads((reports / "publications.json").read_text(encoding="utf-8")) + source = manifest["sourceBaseline"] + if manifest["functionalEvidenceBaseline"] != source: + raise ValueError("Publication functional source identity") + if not re.fullmatch(r"[0-9a-f]{40}", source) or manifest["project"] != "code-flow-studio": + raise ValueError("Publication source identity") + if manifest["sourceUrl"] != "https://github.com/JasonStys/code-flow-studio/tree/" + source: + raise ValueError("Publication source URL") + records = manifest["documents"] + if len(records) != 3 or {r["filename"] for r in records} != FILES: + raise ValueError("Exact named publication set") + workflows = manifest["workflowEvidence"] + if {r["name"] for r in workflows} != { + "Validate", + "CodeQL", + "Desktop packages", + } or len(workflows) != 3: + raise ValueError("Publication workflow set") + if any( + r["headSha"] != source + or r["status"] != "completed" + or r["conclusion"] != "success" + or r["event"] != "push" + for r in workflows + ): + raise ValueError("Publication workflow identity/outcome") + for record in records: + if record["sourceBaseline"] != source or record["visualReview"]["approved"] is not True: + raise ValueError("Publication approval/source") + with (reports / record["filename"]).open("rb") as stream: + payload = stream.read(20 * 1024 * 1024 + 1) + if ( + len(payload) > 20 * 1024 * 1024 + or len(payload) != record["bytes"] + or hashlib.sha256(payload).hexdigest() != record["sha256"] + ): + raise ValueError("Publication digest/size") + with ZipFile(io.BytesIO(payload)) as package: + members = package.infolist() + names = [m.filename for m in members] + required = "xl/workbook.xml" if record["filename"].endswith(".xlsx") else "word/document.xml" + if ( + len(members) > 256 + or len(names) != len(set(names)) + or required not in names + or "[Content_Types].xml" not in names + ): + raise ValueError("Publication ZIP roots/identities") + if sum(m.file_size for m in members) > 32 * 1024 * 1024: + raise ValueError("Publication expanded budget") + xml = {} + for member in members: + lower = "/" + member.filename.replace("\\", "/").lower() + if any( + marker in lower for marker in ["/embeddings/", "/activex/", "vbaproject"] + ) or ".." in member.filename.replace("\\", "/").split("/"): + raise ValueError("Active/embedded publication member") + if ( + member.file_size > 8 * 1024 * 1024 + or member.flag_bits & 1 + or member.compress_type not in {ZIP_STORED, ZIP_DEFLATED} + ): + raise ValueError("Publication member budget/type") + if member.filename.endswith((".xml", ".rels")): + with package.open(member) as xml_stream: + xml_bytes = xml_stream.read(XML_BYTES + 1) + if len(xml_bytes) > XML_BYTES or len(xml_bytes) != member.file_size: + raise ValueError("Publication actual XML budget/length") + text = xml_bytes.decode("utf-8", errors="strict") + if any(marker in text.lower() for marker in [" Path: + """Copy only the four tracked documentation files into a disposable regression fixture.""" + source = Path(__file__).resolve().parents[1] / "docs" / "reports" + target = tmp_path / "docs" / "reports" + target.mkdir(parents=True) + for name in FILES | {"publications.json"}: + shutil.copyfile(source / name, target / name) + return tmp_path + + +def rewrite_package(root: Path, filename: str, change) -> None: + """Make a real changed ZIP and rebind its hash so structural checks, not the digest check, are exercised.""" + path = root / "docs" / "reports" / filename + with ZipFile(path) as original: + entries = {m.filename: original.read(m) for m in original.infolist()} + change(entries) + with ZipFile(path, "w", compression=ZIP_DEFLATED) as package: + for name, content in entries.items(): + package.writestr(name, content) + manifest_path = path.parent / "publications.json" + manifest = json.loads(manifest_path.read_text(encoding="utf-8")) + record = next(r for r in manifest["documents"] if r["filename"] == filename) + payload = path.read_bytes() + record["bytes"] = len(payload) + record["sha256"] = hashlib.sha256(payload).hexdigest() + manifest_path.write_text(json.dumps(manifest), encoding="utf-8") + + +def test_actual_reviewed_publications_are_bound_to_source_and_workflows(): + """Exercise actual tracked editions, not generated replicas or approval flags alone.""" + validate_publications(Path(__file__).resolve().parents[1]) + + +def test_actual_binary_tamper_fails_digest(tmp_path): + """A changed document cannot keep the original reviewed byte identity.""" + root = copy_publications(tmp_path) + path = root / "docs" / "reports" / "project-guide.docx" + path.write_bytes(path.read_bytes() + b"changed") + with pytest.raises(ValueError, match="digest/size"): + validate_publications(root) + + +def test_renamed_publication_cannot_select_an_external_path(tmp_path): + """Manifest names are closed before any document is opened.""" + root = copy_publications(tmp_path) + path = root / "docs" / "reports" / "publications.json" + record = json.loads(path.read_text(encoding="utf-8")) + record["documents"][0]["filename"] = "../external.docx" + path.write_text(json.dumps(record), encoding="utf-8") + with pytest.raises(ValueError, match="named publication set"): + validate_publications(root) + + +@pytest.mark.parametrize( + "member", + ["word/embeddings/example.bin", "word/activeX/example.xml", "word/vbaProject.bin"], +) +def test_rehashed_active_office_members_still_fail(tmp_path, member): + """A new digest never authorizes opaque embedded objects, ActiveX or macro members.""" + root = copy_publications(tmp_path) + rewrite_package( + root, + "project-guide.docx", + lambda entries: entries.update({member: b"synthetic fixture"}), + ) + with pytest.raises(ValueError, match="Active/embedded"): + validate_publications(root) + + +def test_rehashed_zip_without_document_root_fails(tmp_path): + """A valid ZIP and matching hash do not make a Word document.""" + root = copy_publications(tmp_path) + rewrite_package(root, "project-guide.docx", lambda entries: entries.pop("word/document.xml")) + with pytest.raises(ValueError, match="ZIP roots"): + validate_publications(root) + + +def test_rehashed_workbook_missing_actual_filter_fails(tmp_path): + """Inspect actual exported Table XML; an approval field cannot replace an autoFilter.""" + root = copy_publications(tmp_path) + + def remove_filter(entries): + """Remove the real first Table filter while leaving the rest of the actual workbook intact.""" + name = next(n for n in entries if n.startswith("xl/tables/")) + table = ET.fromstring(entries[name]) + table.remove(table.find("x:autoFilter", NS)) + entries[name] = ET.tostring(table) + + rewrite_package(root, "validation-evidence.xlsx", remove_filter) + with pytest.raises(ValueError, match="Tables/filters"): + validate_publications(root) + + +def test_rehashed_workbook_changed_formula_fails(tmp_path): + """A real changed formula is rejected even when its old cached value and new archive digest agree.""" + root = copy_publications(tmp_path) + + def change_formula(entries): + """Change actual exported XML rather than mocking a formula parser.""" + name = "xl/worksheets/sheet1.xml" + sheet = ET.fromstring(entries[name]) + formula = sheet.find(".//x:f", NS) + formula.text = "SUM(A8:A10)" + entries[name] = ET.tostring(sheet) + + rewrite_package(root, "validation-evidence.xlsx", change_formula) + with pytest.raises(ValueError, match="formula/cached"): + validate_publications(root) + + +def test_dishonest_compressed_xml_uses_bounded_actual_decompression(tmp_path, monkeypatch): + """A small real ZIP with understated sizes exercises actual zlib under an independent allocation-request budget.""" + root = copy_publications(tmp_path) + name = "word/dishonest.xml" + rewrite_package( + root, "project-guide.docx", lambda entries: entries.update({name: b"" + b"x" * 65536 + b""}) + ) + path = root / "docs" / "reports" / "project-guide.docx" + payload = bytearray(path.read_bytes()) + end = payload.rfind(b"PK\x05\x06") + cursor = struct.unpack_from("