Skip to content

Release 1.19.0: log-injection guard, secret scanning, Vue console without Maps - #575

Merged
suculent merged 725 commits into
mainfrom
thinx-staging
Oct 21, 2026
Merged

suculent merged 725 commits into
mainfrom
thinx-staging

Conversation

@suculent

@suculent suculent commented Oct 21, 2026 •

Copy link
Copy Markdown
Owner

Release PR for 1.19.0. The v1.17/v1.18 content already reached main as the squash in #574 (v1.18.4749); this carries what came after it on thinx-staging.

Security

  • lib/thinx/logsafe.js: a log-injection guard (line breaks removed, control characters replaced, length capped), applied at the CodeQL js/log-injection sites. Util.redactToken and Util.redactEmail now return single-line text.
  • CodeQL highs fixed:
    • Bearer header and trailing-slash parsing no longer use slow regexes.
    • Notifier envelope paths are validated.
    • Env and source keys refuse __proto__, constructor and prototype (new invalid_key / invalid_tag responses).
    • Owner ids, API keys and OAuth codes are gone from log lines.
  • Open CodeQL alerts on thinx-staging: 58 → 2 (the two Util.responder stack-trace alerts are left open). Reviewed false positives are dismissed with reasons.
  • Pre-commit secret scan: .githooks/pre-commit (gitleaks on staged changes, redacted), .gitleaks.toml, scripts/install-git-hooks.sh (npm run setup:secret-hook; does not touch core.hooksPath). GitHub push protection is now enabled on the repo.

Vue console

  • Removed the unused vue2-google-maps plugin and the Maps API key wiring (VUE_APP_GOOGLE_MAPS_APIKEY in docker-swarm.yml and in the Vue image build). The legacy console keeps its own GOOGLE_MAPS_APIKEY.
  • services/console → 3a372a5 (Vue console 2.2.0).

Housekeeping

  • AGENTS.md: Vue console is console.thinx.cloud, legacy console and API are rtm.thinx.cloud.
  • The sample thinx-firmware-* checkouts are gitignored.
  • Version bump 1.18.4749 → 1.19.0.

Merge note

main currently requires signed commits, and thinx-staging still contains two unsigned commits from 2026-10-09 (58027c18, 3152af99). As with #574, this needs an admin squash.

https://claude.ai/code/session_01AkccHxz4x7iue88b1jw7Ma

…1 ledger

- 36-REVIEW-DISPOSITION: WR-01, IN-01, IN-02, IN-03 fixed with their console commits, open: 0
- ROADMAP Phase 48: Closed in Phase 47 block for Phase 35 IN-06 and IN-07

Claude-Session: https://claude.ai/code/session_014ZVXKS2uhAMrLdLzKmNufX
…-03, POL-02, FIX-02)

- services/console 31bce2b -> 591033e: build log search with highlight, wrap and
  scroll, id-only open, dashboard View, navbar static rows, one status mapping
- 36 WR-01, IN-01..IN-03 and 35 IN-06, IN-07 fixes ride this console range

Claude-Session: https://claude.ai/code/session_014ZVXKS2uhAMrLdLzKmNufX
- console 591033e and gitlink ab37879 on thinx-staging, pipeline 5673 legacy-off OK
- bundle ab37879 live with all Phase 47 markers, Legacy byte-identical, 7442 200, WS 2/2
- 11 human checks queued for end-of-phase UAT

Claude-Session: https://claude.ai/code/session_014ZVXKS2uhAMrLdLzKmNufX
- operator answer verbatim: shread-all (shred-all)
- KEYMIG-01..03 complete; Phase 41 ready for verification

Claude-Session: https://claude.ai/code/session_01AkccHxz4x7iue88b1jw7Ma
Archive the v1.17 Deploy-Key OpenBao Transit roadmap, requirements and
phase directories under the vault-transit workstream, collapse its
ROADMAP, add the workstream and project ledger entries, evolve
PROJECT.md and append the v1.17 retrospective.

Claude-Session: https://claude.ai/code/session_01AkccHxz4x7iue88b1jw7Ma
CodeQL #352/#353 on release PR #574: the owner id reached console.log's
format-string argument and was flagged as clear-text logging. Log the
error message through a constant %s format and leave the owner to the
audit log line that follows.

Claude-Session: https://claude.ai/code/session_01AkccHxz4x7iue88b1jw7Ma
- notifier: refuse a worker job status whose owner, udid or build_id is
  not path-segment shaped before building the envelope paths (#144-#147)
- apienv: refuse __proto__/constructor/prototype as an env key (#175)
- origins: strip trailing slashes with a loop, not /\/+$/ (#142)
- owner: constant format string in the password-reset log (#164)
- util, apikey: stop logging the unserialisable message and the owner id
  (#162, #157)

Claude-Session: https://claude.ai/code/session_01AkccHxz4x7iue88b1jw7Ma
The c7e5a8a guards held at runtime, but CodeQL still flagged the
dynamic env-key write and the envelope paths. Build the env entry with
Object.fromEntries, and validate the owner/udid/build_id into locals
that are the only values joined into the envelope paths.

Claude-Session: https://claude.ai/code/session_01AkccHxz4x7iue88b1jw7Ma
- router: parse the Bearer header without a polynomial regex (#141)
- oauth_return: strip trailing slashes with a loop (#143)
- devices: strip every double quote from the owner view key (#149, #150)
- messenger: never log the apikey object (#159)
- device, deployment: no dynamic property writes from request data (#176, #177)

Claude-Session: https://claude.ai/code/session_01AkccHxz4x7iue88b1jw7Ma
New dependency-free lib/thinx/logsafe.js replaces line breaks and other
control characters and caps the length. Applied at the CodeQL
js/log-injection sites (device registration, source/repository/device
logs, CORS and CSRF warnings, notifier, owner, sanitka, transfer, ...).
Util.redactToken/redactEmail now return single-line text, which covers
every log line that prints a redacted token or e-mail.

router.slack no longer logs the OAuth redirect URL, code or state: it
logs the path and whether a code and state were present.

Claude-Session: https://claude.ai/code/session_01AkccHxz4x7iue88b1jw7Ma
CodeQL's log-injection query only accepts a replace() whose replacement
is the empty string as the line-break barrier, so logSafe now removes
\n and \r instead of replacing them with a space. Also bound the
version-segment loop in parseDeviceVersion to 8 segments (new
js/loop-bound-injection).

Claude-Session: https://claude.ai/code/session_01AkccHxz4x7iue88b1jw7Ma
- deployment: logSafe on the rewritten version string
- oauth_return: the return-origin cookie takes Secure from req.secure
- sources: refuse __proto__/constructor/prototype as source id or tag

Claude-Session: https://claude.ai/code/session_01AkccHxz4x7iue88b1jw7Ma
…ware checkouts

- .githooks/pre-commit runs gitleaks on the staged changes only, output redacted
- scripts/install-git-hooks.sh (npm run setup:secret-hook) symlinks it into the
  hooks directory without touching core.hooksPath, so the roborev hooks keep working
- .gitleaks.toml extends the default rules with three narrow, commented allowlists
- ignore the untracked thinx-firmware-* sample checkouts (CI webhook URLs inside)

Claude-Session: https://claude.ai/code/session_01AkccHxz4x7iue88b1jw7Ma
The [[allowlists]]/targetRules form needs gitleaks 8.25 and was silently
ignored, so the hook would have flagged generic-key noise in .planning.
Use per-rule allowlists instead: history findings drop from 111 to 27,
no token rule is relaxed for .planning, and a staged fake token there is
still blocked.

Claude-Session: https://claude.ai/code/session_01AkccHxz4x7iue88b1jw7Ma
… swarm env

The Vue console no longer loads Google Maps (console ec5b7f1), so the
VUE_APP_GOOGLE_MAPS_APIKEY build arg, its swarm environment line and the
GOOGLE_MAPS_APIKEY required-variable check for the Vue job are removed.
GOOGLE_MAPS_APIKEY stays in the legacy console's Dockerfile (static map).

Claude-Session: https://claude.ai/code/session_01AkccHxz4x7iue88b1jw7Ma
Vue console is console.thinx.cloud; the legacy AngularJS console (and the
API) is rtm.thinx.cloud. The old single "Production console URL" line hid it.

Claude-Session: https://claude.ai/code/session_01AkccHxz4x7iue88b1jw7Ma
Also points services/console at 3a372a5 (vue console 2.2.0).

Claude-Session: https://claude.ai/code/session_01AkccHxz4x7iue88b1jw7Ma
@codacy-production

codacy-production Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics -32 complexity · -5 duplication

Metric Results
Complexity -32
Duplication -5

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

main holds the #574 squash (1d94a95), whose tree equals thinx-staging at
e59b268. Conflicts were only the version fields (kept 1.19.0) and the
logSafe wrapping in lib/thinx/github.js (kept ours); the resulting tree is
identical to thinx-staging, so this commit only joins the histories.

Claude-Session: https://claude.ai/code/session_01AkccHxz4x7iue88b1jw7Ma
@coveralls

Copy link
Copy Markdown

Coverage Status

coverage: 72.706% (+0.05%) from 72.661% — thinx-staging into main

@suculent
suculent merged commit a1e64ed into main Oct 21, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants