<feed xmlns='http://www.w3.org/2005/Atom'>
<title>vyos-documentation.git/.github/workflows, branch claude/datatables-2x-upgrade</title>
<subtitle>VyOS readthedocs (mirror of https://github.com/vyos/vyos-documentation.git)
</subtitle>
<id>https://git.amelek.net/vyos/vyos-documentation.git/atom?h=claude%2Fdatatables-2x-upgrade</id>
<link rel='self' href='https://git.amelek.net/vyos/vyos-documentation.git/atom?h=claude%2Fdatatables-2x-upgrade'/>
<link rel='alternate' type='text/html' href='https://git.amelek.net/vyos/vyos-documentation.git/'/>
<updated>2026-07-28T15:38:48+00:00</updated>
<entry>
<title>docs: upgrade vendored DataTables 1.11.5 -&gt; 2.3.8</title>
<updated>2026-07-28T15:38:48+00:00</updated>
<author>
<name>Yuriy Andamasov</name>
<email>yuriy@vyos.io</email>
</author>
<published>2026-07-28T15:25:46+00:00</published>
<link rel='alternate' type='text/html' href='https://git.amelek.net/vyos/vyos-documentation.git/commit/?id=b3aeaf3e80e05b692d132de6bd316dceab41be0b'/>
<id>urn:sha1:b3aeaf3e80e05b692d132de6bd316dceab41be0b</id>
<content type='text'>
Swap the vendored single-component DataTables downloader build from 1.11.5
to 2.3.8 (docs/_static/js/datatables.js, docs/_static/css/datatables.css).
The only init site, docs/_static/js/tables.js, uses the option-less
jQuery-style $('#id').DataTable() form, which is unchanged in 2.x, so
neither it nor docs/_templates/layout.html needed edits. jQuery 3.6.0 is
still injected ahead of the bundle by sphinxcontrib-jquery and satisfies
2.x.

Remove docs/_static/css/DataTables-1.11.5/ (10 sort-icon images). 2.x draws
sort indicators in pure CSS: the new datatables.css contains no url()
references at all, and the replaced 1.11.5 stylesheet was the only thing in
the repo that referenced those files.

Migrate custom selectors for the 2.x generated-class renames, each verified
against the downloaded bundle rather than assumed:

  - .dataTables_info -&gt; .dt-info                 (tables.css, text.css)
  - .paginate_button -&gt; .dt-paging-button        (tables.css, text.css)
  - #coverage a.paginate_button{,.current,.next,.previous}
      -&gt; #coverage button.dt-paging-button{...}
    2.x renders paging controls as &lt;button&gt; (was &lt;a&gt; in 1.x), so the old
    rules failed on both element type and class. The .current/.next/
    .previous modifiers are still emitted and are retained.

The #table-cfgcmd_wrapper / #table-opcmd_wrapper rules are deliberately
untouched: only the wrapper *class* changed (dataTables_wrapper -&gt;
dt-container); the element id is still &lt;tableId&gt;_wrapper.

Drop the CodeQL exclusion (.github/codeql/codeql-config.yml, plus the
optional codeql-cfg-path input in .github/workflows/codeql.yml). That
config existed solely to paths-ignore the 1.11.5 bundle, which tripped 7
alerts (5x js/incomplete-multi-character-sanitization, 2x
js/incomplete-sanitization). Upstream 2.x hardened the implicated helpers -
_stripHtml now runs a do/while fixpoint over the &lt;script&gt; strip, and
_escapeHtml uses all-global regexes - so those patterns are not expected to
recur. Removing the exclusion restores default CodeQL coverage of the file;
this PR's own CodeQL run is the empirical test.

Provenance (DataTables downloader builder, styling "DataTables default",
component set dt only - the 2.x equivalent of the previous #dt/dt-1.11.5):

  https://cdn.datatables.net/v/dt/dt-2.3.8/datatables.js
    sha256 184fb4bd0b9a81a955acd608ba94d0643c74271e78c0fae30f1f40b824f88b1d
  https://cdn.datatables.net/v/dt/dt-2.3.8/datatables.css
    sha256 e37677437e0fbe4a463aafc83bc4ea8d60986b72050ba9f47f740b41148184ae

Verified with a local make html: build succeeded, and coverage.html renders
both tables (table-cfgcmd 9095 rows, table-opcmd 3036 rows) with the 2.3.8
assets injected in the correct order after jQuery.

🤖 Generated by [robots](https://vyos.io)
</content>
</entry>
<entry>
<title>security: remediate CodeQL code-scanning alerts (#2171)</title>
<updated>2026-07-28T09:16:46+00:00</updated>
<author>
<name>Yuriy Andamasov</name>
<email>yuriy@vyos.io</email>
</author>
<published>2026-07-28T09:16:46+00:00</published>
<link rel='alternate' type='text/html' href='https://git.amelek.net/vyos/vyos-documentation.git/commit/?id=95e9ad86def9b1f33d65a422e1235011e0fb1225'/>
<id>urn:sha1:95e9ad86def9b1f33d65a422e1235011e0fb1225</id>
<content type='text'>
* security: remediate CodeQL code-scanning alerts (picker XSS sinks, test sanitization, vendored DataTables exclusion)

Remediates all 11 open CodeQL alerts on the default branch:

- version-picker.js (js/xss-through-dom, alerts 1-3): percent-encode every
  DOM-derived path component (select.value, parsed location segments) at URL
  construction time via encodePath()/langUrlFor(), and tighten the
  parseLocation slug charset to [A-Za-z0-9._-]. No-op on legitimate sphinx
  slugs — URLs stay byte-identical (asserted by tests).

- workers/apex/test/manifest.test.ts (js/incomplete-multi-character-
  sanitization, alert 6): strip HTML comments from the root.html fixture
  repeatedly to a fixpoint instead of a single pass.

- docs/_static/js/datatables.js (alerts 4,5,7-11): excluded from CodeQL
  analysis via .github/codeql/codeql-config.yml (new codeql-cfg-path input
  to the fleet reusable workflow). The file is vendored stock DataTables
  1.11.5; the flagged helpers are display/sort normalization, not
  sanitization boundaries. Excluding keeps the vendored copy byte-identical
  to upstream instead of hand-patching it.

Adds 9 picker tests (hostile-input encoding + slug-charset accept/reject);
workers suite 103/103 green.

🤖 Generated by [robots](https://vyos.io)

* security: normalize pre-existing percent escapes in encodePath

Adversarial-review finding (Codex, medium): location.pathname returns
well-formed escapes verbatim, so blind encodeURIComponent double-encoded
them (%2E -&gt; %252E), broke the HEAD probe on escaped deep links, and
dumped the user at the version root. Each segment is now decoded first
(malformed escapes keep the raw segment — no throw), then re-encoded to
canonical single encoding. Decoding cannot resurrect dot-segments:
the URL parser resolves '.'/'..' and their percent-encoded forms during
navigation, so pathname never presents them (verified against the WHATWG
parser in Node).

workers suite 106/106 (+2 regression tests, mutation-verified).

🤖 Generated by [robots](https://vyos.io)

* security: normalize percent escapes per run, not per segment

Round-2 adversarial finding (Codex, medium): whole-segment decode meant
one malformed escape (a%20b%zz) threw for the segment and double-encoded
the valid escapes beside it. encodeSegment now decodes+re-encodes each
well-formed %HH run independently; literal spans (including a bare '%')
always pass through encodeURIComponent, so taint neutralization holds
unconditionally; a run decoding to invalid UTF-8 stays verbatim (already
pure %HH text).

workers suite 108/108 (+2 discriminating regression tests).

🤖 Generated by [robots](https://vyos.io)</content>
</entry>
<entry>
<title>ci: T9082: onboard CodeQL scanning via central reusable workflow (#2151)</title>
<updated>2026-07-14T17:24:14+00:00</updated>
<author>
<name>Yuriy Andamasov</name>
<email>yuriy@vyos.io</email>
</author>
<published>2026-07-14T17:24:14+00:00</published>
<link rel='alternate' type='text/html' href='https://git.amelek.net/vyos/vyos-documentation.git/commit/?id=fc86a64665824b4efb7b4b4d7fba6e9ffa2b406d'/>
<id>urn:sha1:fc86a64665824b4efb7b4b4d7fba6e9ffa2b406d</id>
<content type='text'>
🤖 Generated by [robots](https://vyos.io)</content>
</entry>
<entry>
<title>docs-infra: use PR number (not head ref) in apex-deploy concurrency group</title>
<updated>2026-07-12T13:45:54+00:00</updated>
<author>
<name>Yuriy Andamasov</name>
<email>yuriy@vyos.io</email>
</author>
<published>2026-07-12T13:45:54+00:00</published>
<link rel='alternate' type='text/html' href='https://git.amelek.net/vyos/vyos-documentation.git/commit/?id=d5028041cb783f5c9f3279f38828dbacbb38081f'/>
<id>urn:sha1:d5028041cb783f5c9f3279f38828dbacbb38081f</id>
<content type='text'>
Phase-0 CodeRabbit finding on the PR-trigger commit: github.head_ref is
not unique across forks, so two PRs from different forks with the same
branch name would share a concurrency group. Key on
github.event.pull_request.number instead.

🤖 Generated by [robots](https://vyos.io)
</content>
</entry>
<entry>
<title>docs-infra: run workers tests on PRs (gap let broken deps land)</title>
<updated>2026-07-12T13:42:21+00:00</updated>
<author>
<name>Yuriy Andamasov</name>
<email>yuriy@vyos.io</email>
</author>
<published>2026-07-12T13:42:21+00:00</published>
<link rel='alternate' type='text/html' href='https://git.amelek.net/vyos/vyos-documentation.git/commit/?id=01a7a7b939af3eba31e776dc07e0e7bee3c47874'/>
<id>urn:sha1:01a7a7b939af3eba31e776dc07e0e7bee3c47874</id>
<content type='text'>
apex-deploy.yml's test job only triggered on push to rolling, so no
PR-level check ran the workers/ vitest suite — that's how the vitest
3.2/pool-workers 0.18.4 peer conflict landed on rolling undetected
(two dependabot PRs merged clean since nothing exercised `npm ci` in
workers/ pre-merge).

Add a `pull_request` trigger scoped to `workers/**` so the test job
runs pre-merge. Gate deploy-canary and deploy-production with
`if: github.event_name != 'pull_request'` so PR runs test only —
no canary/production deploys fire on a PR (deploy-production would
also auto-skip via `needs: deploy-canary` once canary skips, but the
explicit `if:` keeps intent visible). Concurrency group now branches
per-event so PR runs queue/cancel independently of the rolling deploy
group instead of colliding with it.

Validated with actionlint + a YAML parse check.

🤖 Generated by [robots](https://vyos.io)
</content>
</entry>
<entry>
<title>docs-infra: retry LaTeX only when PDF absent; constrained poppler install</title>
<updated>2026-07-10T16:57:21+00:00</updated>
<author>
<name>Yuriy Andamasov</name>
<email>yuriy@vyos.io</email>
</author>
<published>2026-07-10T16:57:21+00:00</published>
<link rel='alternate' type='text/html' href='https://git.amelek.net/vyos/vyos-documentation.git/commit/?id=ac31ab70216716bcaebb4168074b9a790f4fda8a'/>
<id>urn:sha1:ac31ab70216716bcaebb4168074b9a790f4fda8a</id>
<content type='text'>
🤖 Generated by [robots](https://vyos.io)
</content>
</entry>
<entry>
<title>docs-infra: PDF artifact check — exact file, page-count floor, restored retry</title>
<updated>2026-07-10T16:45:50+00:00</updated>
<author>
<name>Yuriy Andamasov</name>
<email>yuriy@vyos.io</email>
</author>
<published>2026-07-10T16:45:50+00:00</published>
<link rel='alternate' type='text/html' href='https://git.amelek.net/vyos/vyos-documentation.git/commit/?id=bd19892033a56782065b40a11adf7162a9dacb4a'/>
<id>urn:sha1:bd19892033a56782065b40a11adf7162a9dacb4a</id>
<content type='text'>
🤖 Generated by [robots](https://vyos.io)
</content>
</entry>
<entry>
<title>docs-infra: force latexmk through per-glyph/per-image LaTeX errors in PDF build</title>
<updated>2026-07-10T15:21:14+00:00</updated>
<author>
<name>Yuriy Andamasov</name>
<email>yuriy@vyos.io</email>
</author>
<published>2026-07-10T15:21:01+00:00</published>
<link rel='alternate' type='text/html' href='https://git.amelek.net/vyos/vyos-documentation.git/commit/?id=361c586a7bd16d1697b6038d4188716f801b9fd5'/>
<id>urn:sha1:361c586a7bd16d1697b6038d4188716f801b9fd5</id>
<content type='text'>
pdflatex hard-errors on the Devanagari etymology text in
docs/introducing/history.md ("! LaTeX Error: Unicode character व
(U+0935) not set up for use with LaTeX") and separately cannot embed
several pre-existing .webp images (no BoundingBox) — both previously
undiscovered because the Devanagari error always halted the build
first. latexmk -f (force mode) + pdflatex -interaction=nonstopmode
makes the build tolerate both classes of per-glyph/per-image failure
and finish, matching how ReadTheDocs has always built this project's
PDF (verified against the live docs.vyos.io PDF: same Devanagari
glyphs blanked, same ~4 images embedded out of 2000+ pages).

latexmk exits non-zero in force mode even on a fully-produced PDF, so
the workflow step now verifies the artifact itself (exists, &gt;2MB)
instead of relying on the command's exit code.

🤖 Generated by [robots](https://vyos.io)
</content>
</entry>
<entry>
<title>docs: Cloudflare Workers hosting pipeline (apex, content workers, CI, previews) (#2140)</title>
<updated>2026-07-10T14:14:13+00:00</updated>
<author>
<name>Yuriy Andamasov</name>
<email>yuriy@vyos.io</email>
</author>
<published>2026-07-10T14:14:13+00:00</published>
<link rel='alternate' type='text/html' href='https://git.amelek.net/vyos/vyos-documentation.git/commit/?id=21689ef59b0eb34b1a29eda739dc10d33d25b44a'/>
<id>urn:sha1:21689ef59b0eb34b1a29eda739dc10d33d25b44a</id>
<content type='text'>
* docs-infra: scaffold Cloudflare workers workspace (versions.json v2, matrix, toolchain)

🤖 Generated by [robots](https://vyos.io)

* docs-infra: record full Phase-0 plan decision in workers/PLAN.md

🤖 Generated by [robots](https://vyos.io)

* docs-infra: shared content worker — asset serving, cache classes, X-Docs-Build, canary no-store

🤖 Generated by [robots](https://vyos.io)

* docs-infra: run worker script before assets; test fetch entrypoint

🤖 Generated by [robots](https://vyos.io)

* docs-infra: apex manifest loader + dispatch map + runtime binding guard (TDD)

🤖 Generated by [robots](https://vyos.io)

* docs-infra: apex redirects (aliases, PDF, trailing-slash) + special paths (TDD)

🤖 Generated by [robots](https://vyos.io)

* docs-infra: PDF redirect honors pdf:null and preserves query

🤖 Generated by [robots](https://vyos.io)

* docs-infra: apex UA gate — allowlist-wins, log-only AI crawlers, empty block list at launch

🤖 Generated by [robots](https://vyos.io)

* docs-infra: apex router (pipeline §3.2), themed 404/503, /kb seam, env configs + congruence test

🤖 Generated by [robots](https://vyos.io)

* docs-infra: add missing-User-Agent regression test for apex UA gate

🤖 Generated by [robots](https://vyos.io)

* docs-infra: R2-streaming preview worker — MIME map, noindex, no-store (TDD)

🤖 Generated by [robots](https://vyos.io)

* docs-infra: preview 404 no-store + fetch handler tests

🤖 Generated by [robots](https://vyos.io)

* docs-infra: bootstrap script — binding-target workers must exist before apex deploys

🤖 Generated by [robots](https://vyos.io)

* docs-infra: apex run_worker_first, lockfile for npm ci, PDF Location from manifest

🤖 Generated by [robots](https://vyos.io)

* docs-infra: derive html_baseurl from DOCS_VERSION_SLUG with RTD fallback (canonical gate prereq)

🤖 Generated by [robots](https://vyos.io)

* docs-infra: version picker + status banner + language scaffold (vanilla JS, TDD pure core)

🤖 Generated by [robots](https://vyos.io)

* docs-infra: picker preserves query+hash across switch; valid breadcrumb markup

🤖 Generated by [robots](https://vyos.io)

* docs-infra: Pagefind search wrapper with runtime base-path + preview prefix handling (TDD)

🤖 Generated by [robots](https://vyos.io)

* docs-infra: pagefind wrapper — asset-failure notice + UI stylesheet load

🤖 Generated by [robots](https://vyos.io)

* docs-infra: gate Pagefind searchbox to CF builds (RTD keeps stock search until cutover)

🤖 Generated by [robots](https://vyos.io)

* docs-infra: deploy sanity gates — limits, critical pages, count-delta, canonical (TDD)

🤖 Generated by [robots](https://vyos.io)

* docs-infra: hermetic gate tests via fixture versions.json

🤖 Generated by [robots](https://vyos.io)

* docs-infra: docs-build workflow — candidate/smoke/promote two-stage deploy + registry + rollback

Two-stage CF Workers pipeline: build in pinned container, assemble artifact,
sanity gates, deploy candidate, scoped pre-traffic smoke via canary apex,
promote (rollback-id capture, hostname purge, registry upload), post-promote
probe + auto-rollback. DOCS_CF_LIVE repo variable gates every docs.vyos.io
production interaction pre-cutover.

scripts/docs_gates/smoke.py adds one authorized check beyond the spec: the
version's index.html probe asserts the #vyos-search mount div is present in
the response body, guarding CI silently forgetting DOCS_VERSION_SLUG (which
would otherwise ship stock RTD search without the Pagefind gate noticing).

🤖 Generated by [robots](https://vyos.io)

* docs-infra: build docs image in-workflow with buildx cache (v4.1 — digest pin dropped)

Plan v4.1 amendment: the ghcr.io digest-pinned image does not exist (workflow
would hard-fail at the first docker step on every push). Replace the BUILD_IMAGE
env placeholder with an in-workflow docker build from docker/Dockerfile via
docker/setup-buildx-action@v3 + docker/build-push-action@v6 (context: docker/,
load: true, tags: docs-build:local, GHA cache from/to). The checked-out commit
is the pin; buildx GHA cache keeps repeat builds cheap. Sphinx-build step swaps
to docs-build:local; inner script unchanged.

🤖 Generated by [robots](https://vyos.io)

* docs-infra: apex/preview deploy workflow — canary auto, production behind environment approval

* docs-infra: apex-deploy concurrency guard (per-ref, cancel-in-progress)

🤖 Generated by [robots](https://vyos.io)

* docs-infra: fork-safe PR preview pipeline — approval record, R2 prefixes, label consumption, cleanup

* docs-infra: nightly preview sweep — pipefail + per-prefix failure isolation

🤖 Generated by [robots](https://vyos.io)

* docs-infra: nightly canary QA — per-entry sweep + URL-parity corpus vs RTD

🤖 Generated by [robots](https://vyos.io)

* docs-infra: parity sweep scoped to CF-built versions; transport-error resilience

🤖 Generated by [robots](https://vyos.io)

* docs-infra: one-off bootstrap workflow (binding targets — runs once on this push)

🤖 Generated by [robots](https://vyos.io)

* docs-infra: remove one-off bootstrap workflow (bootstrap complete)

🤖 Generated by [robots](https://vyos.io)

* docs-infra: one-off canary apex + preview deploy (route targets for Task 3.6 step 2c)

🤖 Generated by [robots](https://vyos.io)

* docs-infra: remove one-off canary deploy workflow (targets live)

🤖 Generated by [robots](https://vyos.io)

* docs-infra: address Phase-0 CodeRabbit findings (canonical gate, error caching, registry pointer, validation)

🤖 Generated by [robots](https://vyos.io)

* docs-infra: strengthen manifest tests (full dispatch iteration, mutation-free validate)

🤖 Generated by [robots](https://vyos.io)

* docs-infra: address GitHub CodeRabbit review (pointer-after-probe, fail-closed sweeps, block-precedence UA gate, preview hardening)

🤖 Generated by [robots](https://vyos.io)

* docs-infra: adversarial review fixes — error no-store, probe retry, PR-list membership, preview dotted-segment

🤖 Generated by [robots](https://vyos.io)

* docs-infra: serve oversized legacy PDF from R2 via apex (spec §5 fallback)

The 1.3 PDF (29.2 MiB) exceeds the 25 MiB static-asset cap and is absent
from the legacy content Worker's build, so /_/downloads/en/1.3/pdf/ (and
the picker's PDF link) 301'd into a dead-end 404 post-cutover. Add the R2
object fallback spec §5 already documented but never implemented: a
DOCS_PDFS R2 bucket binding on the apex Worker, a manifest pdf_r2_key
field (1.3 only), and a router step ahead of version dispatch that streams
the object with its own cache class (canary/error still force no-store).

🤖 Generated by [robots](https://vyos.io)

* docs-infra: PDF R2 fallback honors Range + If-None-Match, preserves ETag

🤖 Generated by [robots](https://vyos.io)</content>
</entry>
<entry>
<title>ci: track Context7 LTS variants by branch instead of moved git tags (#2127)</title>
<updated>2026-07-02T16:58:16+00:00</updated>
<author>
<name>Yuriy Andamasov</name>
<email>yuriy@vyos.io</email>
</author>
<published>2026-07-02T16:58:16+00:00</published>
<link rel='alternate' type='text/html' href='https://git.amelek.net/vyos/vyos-documentation.git/commit/?id=d22ad24b1cded33c62714b10d48f2abd0e35dce5'/>
<id>urn:sha1:d22ad24b1cded33c62714b10d48f2abd0e35dce5</id>
<content type='text'>
* ci: track Context7 LTS variants by branch instead of moved git tags

Switch the Context7 1.5/1.4 variants from tag-backed to branch-backed:

- context7.json: previousVersions entries `{tag:"1.5"}`/`{tag:"1.4"}` →
  `{branch:"circinus"}`/`{branch:"sagitta"}`. Context7 now indexes the
  LTS branch HEADs directly.
- Delete update-version-tags.yml. Its sole purpose was force-moving the
  git tags 1.5/1.4 to circinus/sagitta HEAD so the tag-backed Context7
  variants tracked the branches. With branch-backed variants Context7
  tracks the HEAD natively, so the tag indirection — and its re-run
  "moves the tag backward" footgun — is gone.
- context7-refresh.yml: trigger directly on push to rolling/circinus/
  sagitta (docs/** + context7.json paths) instead of chaining off the
  deleted tag-mover via workflow_run; refresh payload uses
  `branch:"circinus"`/`branch:"sagitta"` for the non-default variants.

Operator follow-up (post-merge): the circinus/sagitta branch variants
must be registered in the Context7 dashboard (a refresh by branch 404s
until Context7 crawls the new config), and the now-unused git tags
1.5/1.4 can be deleted.

🤖 Generated by [robots](https://vyos.io)

* ci: harden jq repo interpolation in context7-refresh

Adversarial review (agy): use the $GITHUB_REPOSITORY runner env var
(mapped as REPO) instead of inlining ${{ github.repository }} into the
jq command string, matching the safe env-mapping pattern already used
for EVENT_NAME/REF_NAME. github.repository is validated and low-risk,
but this structurally removes the interpolation-into-shell surface.

🤖 Generated by [robots](https://vyos.io)</content>
</entry>
</feed>
