* ci: harden CI and supply-chain pipeline
* Add frontend Vitest step to ci.yml so the 241 existing frontend tests run on
every PR (mirrors the backend build/test/lint/audit order).
* Pin Node 26 as a single source of truth: new .node-version, node-version-file
on all setup-node calls, engines.node ">=26.0.0" in all three package.json
files. Matches the Dockerfile's node:26-alpine.
* SHA-pin remaining mutable actions in the start-app composite
(actions/setup-node v6, actions/cache v4.3.0).
* Pin Dockerfile supply-chain inputs: golang:1.26.3-alpine by sha256 digest in
both builder stages; replace mutable-tag git clone with commit-SHA fetch for
docker/cli (v29.4.1) and docker/compose (v5.1.3). LDFLAGS version strings
and otel patch preserved unchanged.
* Ref-scope docker-publish concurrency so two different release tags cannot
cancel each other; same-ref reruns still cancel as before.
* Harden CLA workflow: drop actions:write from permissions; tighten the
issue_comment trigger to PRs only (github.event.issue.pull_request != null)
matching the two documented CLA phrases. No PR code is checked out.
* Drop trivy-version: latest from both Trivy scans so the SHA-pinned
aquasecurity/trivy-action governs the bundled binary version. The
HIGH/CRITICAL gate, severity filter, and trivy.yaml (OpenVEX) are unchanged.
* Restructure Dependabot: add applies-to: security-updates groups for npm
(root/backend/frontend), docker, and github-actions; switch github-actions
to directories so the local composite action is monitored alongside the
top-level workflows.
* Add a daily scheduled SARIF security scan (security-scan.yml): two parallel
jobs scanning saelix/sencho:latest and a fresh main HEAD build, uploading to
GitHub code scanning. Least-privilege (contents: read, security-events:
write). Visibility only; existing PR-blocking and release-blocking Trivy
gates are not weakened.
Validation: backend tsc clean; frontend tsc clean; frontend npm test 27 files
/ 241 tests pass; npm audit --audit-level=high passes at root, backend, and
frontend; docker buildx build --check passes with no warnings (all pinned
digests resolve from the registry).
* ci(frontend): set explicit jsdom URL so localStorage initializes in CI
jsdom does not instantiate window.localStorage / sessionStorage when the
document has the opaque about:blank origin. Five frontend test files that
call localStorage.clear() in beforeEach started failing once the new
frontend Vitest step in this PR began running them on Linux CI runners.
Configuring environmentOptions.jsdom.url with a real same-origin URL is
the documented Vitest 4.x workaround and is a config-only change. All 27
test files (241 tests) pass locally with the fix applied.
The contributor-assistant action defaults to locking merged PRs to
"safeguard CLA signatures", but signatures are stored in
signatures/version1/cla.json and need no extra protection. The auto-lock
fires within seconds of merge and blocks release-please from posting its
"included in vX.Y.Z" comment on the merged release PR, failing the
release-please workflow on every release (0.67.1, 0.68.0).