Skip to content

Releases

v0.3.12 — distinct export failure codes

Choose a tag to compare

@chimneyQ chimneyQ released this 18 Oct 16:21

0.3.12

Fixed: every export failure returned 409.

exists, unsupported, empty, unwritable and unreadable all came back as 409, so the settings row could not tell "press confirm to overwrite" from "retrying will never help". A read-only path or a Node without getCACertificates kept the row offering a confirmation that could never succeed.

Now: exists → 409, unsupported/empty → 422, everything else → 500. The row only enters its confirm state on 409, and shows 422/500 as a plain failure.

Fixed: a malformed request body was silently read as force: false. A caller sending broken JSON got reason: exists and would conclude the export was impossible, when the real problem was its own request. It now answers 400 with bad-request.

The body reader also destroys the request past its 8 KB cap instead of leaving the stream open.

Gates: offline 104 (2 new), client 27, packaging 20, release 34.

Full Changelog: v0.3.11...v0.3.12

v0.3.11 — one definition of a usable CA bundle

Choose a tag to compare

@chimneyQ chimneyQ released this 18 Oct 16:01

0.3.11

Fixed: "exists" and "not found" could disagree about the same path.

Presence was judged two ways — describeCaBundle demanded a regular file, while the export refused to overwrite on a plain existsSync, which is also true for a directory. A path occupied by a directory therefore reported "file not found" in the settings page while the export refused with reason: exists. Both sides now go through one definition, and a failed write reports the real cause (EISDIR / ENOTDIR).

WAL is bounded. PRAGMA wal_autocheckpoint = 400 keeps knowledge.db-wal near 1.6 MB instead of letting the default 1000-page threshold leave a multi-megabyte side file behind.

Docs (added after release, commit f36bc4b). The README never described the 0.3.9 export row — it only mentioned caPemPath in the config table. Both language versions now cover what auto points at, that the package does not ship the file, the badge/button behaviour, the confirm-before-overwrite rule, and the caveat that exporting the system store does nothing if the proxy root was never installed there. Assertion 14 also stopped hardcoding 88 and now reads the count smoke.mjs reports, so it cannot rot again.

Gates: offline 102, client 27, packaging 20, release 34.

v0.3.10 — CA row reads /status itself

Choose a tag to compare

@chimneyQ chimneyQ released this 18 Oct 15:44

0.3.10

Fixed: the CA row said "file not found" while the file was there, and the button looked dead.

The row took its bundle from the settings-form snapshot (props.useToolkitCard). That model carries Config fields only — it never holds the status payload — so bundle was always {} and present was always false. The server was correct the whole time: /status returned present: true, bytes: 842639 while the badge said otherwise, and the click sent no request at all, because the row believed there was nothing to replace.

Fix: the row now fetches /status itself on mount and again after every export attempt, so the badge reflects the real file. A checking… state covers the first paint instead of flashing "missing".

New assertion: the row must call fetch(STATUS_PATH and must not read state.data…caBundle, so it cannot drift back onto the form snapshot.

Verified against the running routes: GET /status → present:true; POST export-ca with no force → 409 exists; with force:true → 200, 842140 bytes, 500 certificates.

Gates: offline 100 (1 new), client 27, packaging 20, release 34.

Full Changelog: v0.3.9...v0.3.10

v0.3.9 — export the CA bundle from the settings page

Choose a tag to compare

@chimneyQ chimneyQ released this 18 Oct 15:33

0.3.9

New: the CA bundle can be exported from the settings page.

caPemPath: auto has always pointed at <DSH_HOME>/context-mode/ca/windows-roots.pem — a file this package has never shipped. On a fresh machine it simply is not there, so a network behind a TLS-inspecting proxy stays unable to fetch, and the only clue was an ENOENT in a status line.

The row under caPemPath now reports whether that file exists and offers a button that writes it from the host's own root store (tls.getCACertificates('system')).

  • Loading only stats the file. Presence is a statSync; taking the snapshot (~500 certificates, ~820 KB, tens of ms) happens only when the button is pressed. An assertion pins that apply() never reads the bundle.
  • An existing bundle is never replaced on one click. The first press asks; only the explicit confirmation sends force.
  • What it does not do: it exports the system store. If the proxy root was never installed into that store, the exported bundle is still not enough — the row says so rather than promising a fix.
  • The route is POST /_dsh/context-toolkit/export-ca, registered through the same ctx.inject(['webServer']) seam as the status route, so a host without a web server still loads the plugin.

Note: 0.3.8 was consumed by an earlier placeholder publish and its tag points at an intermediate commit; 0.3.9 is the feature release.

Gates: offline 99 (5 new), client 27, packaging 20, release 34.

Full Changelog: v0.3.8...v0.3.9

v0.3.8 — export the CA bundle from the settings page

Choose a tag to compare

@chimneyQ chimneyQ released this 18 Oct 15:30

0.3.8

New: the CA bundle can be exported from the settings page.

caPemPath: auto has always pointed at <DSH_HOME>/context-mode/ca/windows-roots.pem — a file this package has never shipped. On a fresh machine it simply is not there, so a network behind a TLS-inspecting proxy stays unable to fetch, and the only clue was an ENOENT in a status line.

The row under caPemPath now reports whether that file exists and offers a button that writes it from the host's own root store (tls.getCACertificates('system')).

  • Loading only stats the file. Presence is a statSync; taking the snapshot (~500 certificates, ~820 KB, tens of ms) happens only when the button is pressed. An assertion pins that apply() never reads the bundle.
  • An existing bundle is never replaced on one click. The first press asks; only the explicit confirmation sends force.
  • What it does not do: it exports the system store. If the proxy root was never installed into that store, the exported bundle is still not enough — the row says so rather than promising a fix.
  • The route is POST /_dsh/context-toolkit/export-ca, registered through the same ctx.inject(['webServer']) seam as the status route, so a host without a web server still loads the plugin.

Gates: offline 99 (5 new), client 27, packaging 20, release 34.

Full Changelog: v0.3.7...v0.3.8

v0.3.7 — CA-path body cap no longer hangs

Choose a tag to compare

@chimneyQ chimneyQ released this 18 Oct 14:33

0.3.7

Fixed: a page larger than fetchMaxBytes hung ctk_fetch_and_index forever.

The CA path reads the body by hand, and on hitting the cap it called response.destroy() without settling the promise — no resolve, no reject. The tool then sat there until its own 180 s timeout. Only the CA branch could hit this: the no-CA branch still uses the built-in fetch, which caps nothing.

Every exit now settles through one finish(): cap reached, body ended, or read error. Reaching the cap stops the stream and hands back the bytes that fit.

httpsGetWithCa is exported and covered by two assertions against a real local HTTPS server — a 3 MB body through a 64 KB cap settles promptly, and a small body still comes back untouched. The bug survived because the four existing caPemPath assertions all covered resolveCaBundle, which never reads a body.

Gates: offline 94, client 27, packaging 20, release 34 — all pass.

Full Changelog: v0.3.6...v0.3.7

v0.3.6 — caPemPath becomes real, and fetching can reach the network

Choose a tag to compare

@chimneyQ chimneyQ released this 18 Oct 13:47

0.3.6 - caPemPath becomes real, and fetching can reach the network

caPemPath has been in this plugin's own cordis.patch.yml since the very first commit, annotated "Every value below is validated against the plugin's Config schema". It was not:

  • not in the Config schema,
  • not read anywhere in index.js,
  • not mentioned in either README.

zod's loose mode let the key through silently, so it looked configurable while having no effect. This release makes it real — declared, read, and honoured.

Why it mattered here

ctk_fetch_and_index could not fetch a single public page on this machine. Every https request failed with:

UNABLE_TO_VERIFY_LEAF_SIGNATURE

Node's built-in roots do not include the local TLS-inspection certificate. The plugin even had a branch that described this failure — "the TLS handshake failed. A local interception certificate is the usual cause." — while offering no way to fix it.

What it does now

caPemPath names the trust store:

Value Meaning
auto (default) <DSH_HOME>/context-mode/ca/windows-roots.pem — this machine's exported Windows roots
an absolute path that PEM file
empty Node's default roots

When a bundle is configured, fetching goes through node:https with ca set and follows redirects by hand. The built-in fetch cannot take a per-call CA — its dispatcher is undici's, and undici is not importable from a plugin here (ERR_MODULE_NOT_FOUND), which is exactly why the original attempt never landed. The output now states which trust store was used, and an unreadable path is reported rather than silently falling back — falling back would recreate the failure the setting exists to prevent.

Measured

Condition Result
default trust store UNABLE_TO_VERIFY_LEAF_SIGNATURE
bundle injected HTTPS 200, including a two-hop redirect

Tests. 92 offline (4 new: default / real file / unreadable path / file without a certificate), 27 client, 20 package, 34 release gate. Reverting the implementation fails "caPemPath resolves a real PEM file" immediately.

Also visible on the settings page: the field is staged with bilingual labels, so the fix is one edit away if the path ever moves.

v0.3.5

Choose a tag to compare

@chimneyQ chimneyQ released this 17 Oct 14:27
  • Fixed: four gate bypasses. The gate asks whether the command word of a segment is a flood tool, so anything that legally precedes that word has to be peeled first — otherwise it inspects a variable assignment and calls it safe. Previously missed: FOO=1 curl …, PATH=/x curl … (assignment prefixes were never peeled), nice -n 5 curl …, timeout 30 curl … (a wrapper's own options were read as the command word), and sudo FOO=1 curl … (the prefix loop capped at two tokens). Prefixes are now peeled as assignment → wrapper → wrapper options → assignment, with seven must-block and six must-allow assertions; two negative controls knock out the assignment peel and the option skip respectively. [a6129be]

v0.3.4

Choose a tag to compare

@chimneyQ chimneyQ released this 17 Oct 11:05
  • Fixed: output that a tool already truncated is no longer compressed a second time. An upstream tool (ops_bash) truncates its own output and spills the rest to a file, and the sandbox (ctk_execute) caps a run at 256 KB and closes with a ~~~ line; this layer used to compress those already-handled bodies again — saving nothing, storing a second copy of the same original, and counting the same traffic twice. Both markers ([output truncated; full output: …] and a standalone ~~~ line) are recognised and skipped, and the reason is reported in a new "skip reasons" ledger line. [038447b]

v0.3.3

Choose a tag to compare

@chimneyQ chimneyQ released this 17 Oct 09:04
  • Docs: adds this bilingual changelog, listed in the manifest and gated by release-check; the README and repository description were refreshed too. The npm package now carries the changelog with each release. [01d7107]