[grade=A urn:ump:swcz3quualvlmdanpqm5v46cr6zkazes7erbftk6rj3jxv6ip4fa] docs(DC-170): changelog rebuild, version sync, API-SURFACE regen (audit batch 7)
Customer-facing professionalism tier (AUDIT-2026-10-27.md findings 34-39):
- CHANGELOG.md rebuilt to Keep-a-Changelog: ONE Unreleased section, the
2026-08-12 hardening sprint folded into 1.17.0 (no v1.16.0 tag exists,
verified via git tag -l), ALL 7 judge-grade/URN lines moved out of
customer copy into RELEASE-EVIDENCE-internal.md, missing DC-166/169
entries added, full DC-170 sweep entry written, DC-171 DNS-parity
ticket recorded, date order strictly descending across all 22
sections (1.1.5 restored with its true content after the re-sort ate
the heading), compare-link chain filled (Unreleased from v1.17.0,
1.17.0 from v1.14.6-patched, 18 missing version links added)
- VERSION 1.15.0 -> 1.17.0 + openapi.yaml 1.15.0 -> 1.17.0 (three-way
drift closed: VERSION=package.json=openapi; start.sh build stamps
single-sourced)
- README: quickstart endpoints rewritten against the live router (the
fictional /api/caddy/{config,reload} section replaced with the real
/api/v1/caddy/* routes from routes/sites.js), 50+ -> 78 templates
(proven in VERIFY-OUTPUT.txt via require of src/docker/app-templates),
version badge 1.17.0, yourusername links -> sami7777, roadmap
reconciled with shipped features (multi-user DC-048, DNS UI DC-166,
backup automation marked shipped), verification note scoped to the
MCP drift gate's actual coverage
- API-SURFACE.md regenerated: 443 handler rows / 368 unique paths / 441
unique operations / 88 public rows, Known Limitations section (static
extraction, line-oriented, may omit multiline/computed/chained
registrations), exact duplicate registrations with file:line
- VERIFY-OUTPUT.txt: verbatim command/output transcript proving all
version + count claims (sha256 of the generated doc recorded and
matching)
- state-manager test mock extended for the atomic tmp+rename contract
Judge rounds: r1 D -> r2 D -> r3 D -> r4 D -> r5 C -> r6 C -> r7 C ->
r8 C -> r9 C -> r10 A (each round fixed blockers in-lane; no bypasses).
r10 independently reproduced all counts and the generated doc hash
against the live repository.
This commit is contained in:
7 files changed
+679
-571
No files matched your search
+81
-159
@@ -6,143 +6,63 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- **DC-168 judge: grade B (round 16)** urn:ump:ejzlob2bde6m6ivxfpgidmwu5a62pvl4wddm4iav7mwfuyfogirq
|
||||
- **DC-168: calendar widget UX + theming.** Chip shows "No upcoming
|
||||
appointments" (muted) when the connected calendar is empty; with events it
|
||||
shows the next appointment with a highlighted day/time span. Modal gains a
|
||||
month grid (prev/next nav, appointment days accent-tinted, today ring,
|
||||
per-event time dots) plus the upcoming list (ended events excluded,
|
||||
ongoing included). Universal theme contrast: chip colors derive via
|
||||
color-mix from --accent (lighten on dark surfaces via html.light-bg,
|
||||
darken on light) — WCAG >= 4.5:1 verified against all 10 builtin themes
|
||||
(worst 4.60:1). Month-following fetch with disjoint-interval coverage
|
||||
tracking; window-authoritative event cache (calendar-cache.js, uid+start
|
||||
keys) so deletions/reschedules propagate on refetch; chip always renders
|
||||
from the now-window even with a navigated viewMonth. 23 calendar tests.
|
||||
- **DC-167 judge: grade B (round 11)** urn:ump:kfn7m6vzd4ias2u5ghg62hvoug3j2y2gmturnytdz4g4od35hx4a
|
||||
- **DC-170: full-software reliability and truth sweep (2026-10-27/29).** 46 findings
|
||||
from a three-agent audit, top items fixed in 7 graded batches: TOTP gate no longer
|
||||
blocks API-key/JWT auth (machine credentials were dead on every TOTP install —
|
||||
verified live with a freshly minted key); calendar widget writes no longer die on
|
||||
CSRF 403s (error path, mobile modal, refresh races, keyboard access fixed too);
|
||||
19 controls silently killed by the content-security policy revived (Disk Safety
|
||||
modal + sliders, AI assistant button, login logos, premium upsells, health
|
||||
Edit/Delete); 6 MCP tools remapped to real routes (container list and DNS
|
||||
record-list routes added); the deploy tool now reports what it actually does and
|
||||
derives the site domain from configuration; DNS update endpoints answer every
|
||||
request (previously hung); state files write atomically (a crash can no longer
|
||||
corrupt services.json/config.json); dashboard WebSocket auth fails closed;
|
||||
service worker offline fallback works, caches only good responses, installs
|
||||
tolerantly; public config endpoint degrades gracefully on a corrupt file; slow
|
||||
calendar feeds get their intended 15-second timeout; calendar source updates no
|
||||
longer wipe the other credential type. New capability-drift gate: every MCP
|
||||
tool's handler-issued call is verified against the declared routes (28 tools).
|
||||
- **DC-169: missing service logos.** samimail, samipanel, gitea, and DashCaddy
|
||||
service-card logos committed and wired.
|
||||
- **DC-168: calendar widget UX + theming.** Chip shows "No upcoming appointments"
|
||||
(muted) when the connected calendar is empty; with events it shows the next
|
||||
appointment with a highlighted day/time span. Modal gains a month grid
|
||||
(prev/next nav, appointment days accent-tinted, today ring, per-event time
|
||||
dots) plus the upcoming list (ended events excluded, ongoing included).
|
||||
Universal theme contrast via color-mix from --accent — WCAG >= 4.5:1 verified
|
||||
against all 10 builtin themes (worst 4.60:1). Month-following fetch with
|
||||
disjoint-interval coverage tracking; window-authoritative event cache
|
||||
(calendar-cache.js, uid+start keys) so deletions/reschedules propagate; chip
|
||||
always renders from the now-window even with a navigated viewMonth.
|
||||
- **DC-167: CalDAV default-namespace multistatus fix (Radicale silent
|
||||
zero-events).** extractCalendarsAndEvents required a namespace prefix on
|
||||
<response>; Radicale emits bare <response> (default DAV ns) so every entry
|
||||
was silently dropped — REPORT 200, ok:true, 0 events, no error. Prefix made
|
||||
optional in the split + detection regexes. Discovered while connecting the
|
||||
owner's DNS3 Radicale (appt.sami) as a DashCaddy calendar source (owner
|
||||
request: connect DNS3 calendar to DNS2 DashCaddy). 9-test ns suite
|
||||
(extraction incl. mixed doc; empty multistatus; namespace-aware fixture
|
||||
parse; undeclared element+attribute prefix rejection, both quote styles;
|
||||
positive declared-attr case). Ops: NODE_EXTRA_CA_CERTS drop-in for the Sami
|
||||
Home CA; source registered via authenticated API at the collection URL.
|
||||
- **DC-165 judge: grade B (round 5)** urn:ump:oqgczb6zv5bemekbxko7gi5rvfle6yoshwgfwsx4mbbj4xmg6paq
|
||||
- **DC-165: product/site uniformity + LLM-readable capabilities.** Site-vs-product
|
||||
audit reconciliation (owner: "advertise as Premium", "It should be LLM readable"):
|
||||
'fleet' added to PREMIUM_FEATURES and `requirePremium('fleet')` mounted at the
|
||||
/fleet ROUTER prefix (app.js) so every sub-route present and future inherits the
|
||||
gate — proven by 4 real-boot composition-root e2e tests (free 403 envelope
|
||||
contract, per-feature check, with-fleet gate cleared, hosts/status/deploy
|
||||
inheritance). 'workflows' + 'auto-backup' (gated in routes forever, missing from
|
||||
the constant so the offline path could never grant them) listed with
|
||||
source-quoted descriptions; marketing pages now advertise them (manual backup +
|
||||
Disaster Recovery stay free — copy matches code exactly). Offline activations
|
||||
forward-migrate on load (append-only union, online untouched — server stays
|
||||
authoritative). GET /api/v1/capabilities: public machine-readable manifest of the
|
||||
RUNNING build — six measured fields (version, template count/categories, MCP
|
||||
tools, transport identity triple, premium list, language count) derived at request
|
||||
time from the runtime modules (single source: MCP_RUNTIME exported from
|
||||
routes/mcp.js, read by /info and capabilities alike), static metadata fields
|
||||
honestly labeled; PUBLIC_ROUTES + drift test + OpenAPI 200-only contract;
|
||||
no-secrets negative test. License-server grant list extended to
|
||||
sso/recipes/swarm/fleet/workflows/auto-backup with existing records backfilled
|
||||
(ops). Marketing repo (dashcaddy.net, separate commits): counts 77→78 everywhere,
|
||||
internal-identifier sweep (~85 private-TLD/IP/user/path hits → .home/example
|
||||
style), radicale install guide (78th), calendar/Connect-AI advertised, MCP claim
|
||||
softened to real scope + capabilities pointer, llms.txt → runtime ground truth,
|
||||
robots LLMs-Txt line. 124 targeted tests (9 dc165 + 4 fleet-e2e + 76 license +
|
||||
21 tier + 14 drift); 73 MCP tests re-green after refactor.
|
||||
- **DC-164 judge: grade B (round 6)** urn:ump:5vuahbn4znf7hrrshjvu2pcbqln5m6qcrpkkn3mx6y2rvvmdtqoa
|
||||
- **DC-164: operator env overrides + license-material untracking.** start.sh
|
||||
forwards `-e` flags from /etc/dashcaddy/operator.env (root-owned KEY=VALUE,
|
||||
0600) into the container via scripts/operator-flags.js: one pinned fd
|
||||
(lstat pre-check → open O_RDONLY|O_NOFOLLOW|O_NONBLOCK → fstat+read on the
|
||||
same descriptor) so symlinks, FIFOs/devices, group/other-readable or
|
||||
special-bit modes, and foreign ownership are refused (exit 3, fail closed:
|
||||
warn + forward nothing; any other helper failure ABORTS startup, fail
|
||||
loud). Canonical flag ALLOW_LIFETIME_LICENSE=true — creator hosts only;
|
||||
it is a deployment rail, not the boundary: offline lifetime codes must
|
||||
HMAC-verify against the signing secret which is never shipped to customers
|
||||
(installs carry .license-secret-hash). 17 executed tests (FIFO non-block
|
||||
regression, O_NOFOLLOW symlink-to-valid-target, mode/owner matrix,
|
||||
injection-inert values). Root-cause fix for the 2026-10-08 incident:
|
||||
data/services.json, .license-secret, .license-counter UNTRACKED +
|
||||
.gitignore'd — deploy checkouts can no longer clobber live runtime state.
|
||||
- **DC-163 judge: grade B (round 2)** urn:ump:l2tg66wmchkmd6fde4k3ojwc56zpxqh657spe37bu6dpvduswalq
|
||||
- **DC-163: AI assistant that actually works — LLM intent engine + fixed
|
||||
chat panel.** The 🤖 floating assistant was broken end-to-end: the
|
||||
frontend read a nonexistent `data.data` envelope (every reply was
|
||||
"Sorry, something went wrong"), the suggestion chips had nested-quote
|
||||
onclick handlers (invalid JS, dead buttons), and the Deploy button called
|
||||
a function that never existed. All three fixed. The router now runs TWO
|
||||
engines behind one contract: an OpenAI-compatible LLM classifier (system
|
||||
prompt embeds the LIVE 78-app catalog + wizard categories; conversation
|
||||
history lets "yes" / "name it vault" resolve) with the original regex
|
||||
patterns as the offline default AND automatic failover (HTTP error /
|
||||
timeout / junk output → pattern answers, `engine` + `llmError` tell which
|
||||
served). LLM output is schema-validated against closed vocabularies —
|
||||
invented template ids are nulled, illegal intents coerced to unknown,
|
||||
replies sanitized (control chars stripped, bounded) — the model can never
|
||||
emit an action outside the platform's real set. Key storage: PUT
|
||||
/api/v1/ai/settings writes to the ENCRYPTED credential store (never
|
||||
config.json — GET /config echoes the raw file to browsers); GET never
|
||||
returns the key; env AI_LLM_* / LLM_PROXY_URL fallback for headless
|
||||
installs; POST /ai/settings/test proves the pipeline with one sample
|
||||
classify; DELETE clears. Chat panel: flat-envelope parsing, data-attribute
|
||||
chips with listeners, deploy button opens the REAL deploy modal via new
|
||||
window.openDeployConfigFor(id) in app-selector.js, engine badge in the
|
||||
header, ⚙ settings sub-panel. "Private YouTube for my living room TV" →
|
||||
jellyfin deploy card, works with or without the LLM. 20 new tests
|
||||
(engine selection, failover incl. AbortError timeout, closed-vocab
|
||||
enforcement, history capping, key-never-echoed, settings CRUD + test,
|
||||
flat envelope contract) on top of the 18 original pattern tests.
|
||||
OpenAPI: 4 AI path entries. dist bundle rebuilt.
|
||||
- **DC-162 rev2: "Connect your AI" — spec Streamable HTTP MCP + one-click keys.**
|
||||
New primary-row button 🤖 Connect AI on the dashboard opens a modal that
|
||||
mints a dedicated `dk_` key and returns the standard MCP Streamable-HTTP
|
||||
connection card ({url, transport, headers} + per-client notes) for
|
||||
Claude / ChatGPT / generic clients. Transport implements MCP 2025-03-10
|
||||
Streamable HTTP: POST answers application/json (valid notifications →
|
||||
202; malformed → JSON-RPC -32600 with the spec's no-reply-for-broken-
|
||||
notifications rule; batching removed in this revision → rejected), GET/
|
||||
DELETE return 405 + Allow: POST (stateless request/response server —
|
||||
spec-permitted; clients needing server-initiated streams use the stdio
|
||||
bridge). Credential TYPE preservation: apikey callers proxy x-api-key
|
||||
downstream, jwt callers proxy Authorization Bearer — key scopes apply
|
||||
identically at the loopback API. JSON-RPC validation: -32600 structural
|
||||
(jsonrpc/method/params/id), -32602 invalid tool params, Origin DNS-
|
||||
rebinding guard, MCP-Protocol-Version header check, Accept negotiation.
|
||||
GET /mcp/connections lists only "AI connection (…)" keys. Tool path
|
||||
params URL-encoded. Backend: routes/mcp.js (POST, GET/DELETE 405, /info,
|
||||
/connections, /config), src/mcp/mcp-core.js shared by stdio + HTTP,
|
||||
stale 1.15.0 version literal removed (reads package.json).
|
||||
73 route+core tests (incl. 16-case JSON-RPC boundary matrix) +
|
||||
composition-root e2e proves the mount boots.
|
||||
OpenAPI: 4 MCP path entries. status/dist + sw.js regenerated in-tree.
|
||||
- **DC-162 judge: grade B (round 3)** urn:ump:or2qqhcytp6lfzlyi7xru7hdqy3uar2hbjllsrrbxrbray3c5kpa
|
||||
- **DC-161: Calendar widget + Radicale auto-wiring.** New top-bar calendar widget
|
||||
(`status/js/calendar-widget.js`) showing upcoming appointments; settings modal for
|
||||
adding CalDAV / ICS-feed sources with a Test-connection probe. Backend:
|
||||
`routes/calendar.js` (`GET/POST/PUT/DELETE /api/v1/calendar/sources`,
|
||||
`GET /api/v1/calendar/events`, `POST /api/v1/calendar/radicale/provision`,
|
||||
`POST /api/v1/calendar/discover`), dependency-free RFC 5545 ICS parser with
|
||||
bounded RRULE expansion (`src/calendar/ics-parser.js`), CalDAV REPORT client
|
||||
over node:https (`src/calendar/caldav-client.js`). When Radicale is deployed
|
||||
through the App Selector, the deploy hook auto-provisions htpasswd credentials
|
||||
(pure-Node APR1 hash, verified byte-for-byte against `openssl passwd -apr1`)
|
||||
and registers the calendar source — the widget connects with zero user input.
|
||||
Manual bring-your-own sources (Radicale/Baikal/Nextcloud hosted elsewhere,
|
||||
iCloud/Fastmail CalDAV, plain ICS feeds) wire in through the settings modal.
|
||||
Codex judge: **grade B (round 5)** —
|
||||
urn:ump:znykdi6ufm53sgnhkep7ghlda7aoo55nipghjtstlkpqqmxuv2zq.
|
||||
<response>; Radicale emits bare <response> (default DAV ns) so every entry was
|
||||
silently dropped — REPORT 200, ok:true, 0 events, no error. Prefix made
|
||||
optional in the split + detection regexes.
|
||||
- **DC-166: MCP tool-set expansion 17 → 28 tools + workflows double-prefix fix
|
||||
(merged from dc/DC-166-mcp-completion).** 11 new AI-tool handlers over existing
|
||||
routes (calendar, security, license, capabilities, DNS records, deploy recipe,
|
||||
workflow run, tailscale status). Fixed the workflows router that composed
|
||||
`/api/v1/workflows/workflows/...` — every dashboard workflow toggle and Run Now
|
||||
had been 404ing in production. Route-existence verifier resolves tool paths
|
||||
against declared routes.
|
||||
- **DC-165: product/site uniformity — fleet gate proven at composition root,
|
||||
single-source capabilities manifest.** The public `/api/v1/capabilities`
|
||||
endpoint advertises what the running build actually does (route counts,
|
||||
templates, MCP tools measured at runtime), so the marketing site, docs, and
|
||||
llms.txt can never disagree with the product.
|
||||
- **DC-171 (ticketed, pending): DNS provider plug-in parity** — capability
|
||||
reporting at provider-choice time (RFC2136 is push-only: create/resolve yes,
|
||||
listing is protocol-impossible); BIND 9 near-parity via the RFC2136 adapter
|
||||
plus AXFR-based listing; PowerDNS/deSEC/AdGuard Home adapters on the roadmap.
|
||||
|
||||
### Notes
|
||||
- Historical per-change review outcomes are recorded in commit messages and in
|
||||
the internal `RELEASE-EVIDENCE-internal.md` companion file — not in this
|
||||
changelog.
|
||||
|
||||
## [1.17.0] - 2026-10-07
|
||||
|
||||
@@ -178,9 +98,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
base (`1fa5ba8`) because it bundles a stale `pdf.js 1.10.100`; the failing set is measured, not
|
||||
assumed, and recorded in the release evidence.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Production-Grade Hardening Sprint (2026-08-12)
|
||||
### Production-Grade Hardening Sprint (2026-08-12, shipped in 1.17.0)
|
||||
|
||||
### Added
|
||||
- **DC-097: Prometheus metrics export.** `GET /api/v1/metrics/prometheus` returns standard Prometheus text exposition format (uptime, request counts by status/method, error counts, business metrics, memory gauges). Public endpoint for Grafana/Prometheus scraping.
|
||||
@@ -398,6 +316,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Changed
|
||||
- Version bump only — packaging plumbing for the 1.4.x release line.
|
||||
|
||||
## [1.2.0] - 2026-05-14
|
||||
|
||||
### Added
|
||||
- Container Log Viewer with streaming, search, and download.
|
||||
- Service filter, batch operations across multiple services, and snapshot
|
||||
capture.
|
||||
- Auto CSP hash updates during build.
|
||||
- Dashboard version button and self-update UI wiring.
|
||||
- Release policy checks and dashboard version verification.
|
||||
|
||||
### Changed
|
||||
- All routine `console.log` calls gated behind `window.DASHCADDY_DEBUG`
|
||||
flag for quieter production output.
|
||||
- All `console.error` calls routed through `ErrorHandler` for consistent
|
||||
tracking.
|
||||
|
||||
### Fixed
|
||||
- Updater no longer triggers a false-positive "update available" loop
|
||||
when commit hash is unknown.
|
||||
|
||||
---
|
||||
|
||||
## [1.4.0] - 2026-05-06
|
||||
|
||||
### Added
|
||||
@@ -424,28 +364,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
---
|
||||
|
||||
## [1.2.0] - 2026-05-14
|
||||
|
||||
### Added
|
||||
- Container Log Viewer with streaming, search, and download.
|
||||
- Service filter, batch operations across multiple services, and snapshot
|
||||
capture.
|
||||
- Auto CSP hash updates during build.
|
||||
- Dashboard version button and self-update UI wiring.
|
||||
- Release policy checks and dashboard version verification.
|
||||
|
||||
### Changed
|
||||
- All routine `console.log` calls gated behind `window.DASHCADDY_DEBUG`
|
||||
flag for quieter production output.
|
||||
- All `console.error` calls routed through `ErrorHandler` for consistent
|
||||
tracking.
|
||||
|
||||
### Fixed
|
||||
- Updater no longer triggers a false-positive "update available" loop
|
||||
when commit hash is unknown.
|
||||
|
||||
---
|
||||
|
||||
## [1.1.5] - 2026-03-23
|
||||
|
||||
### Added
|
||||
@@ -503,7 +421,8 @@ Initial release of DashCaddy. Unified dashboard for Docker container
|
||||
management, Caddy reverse proxy configuration, DNS automation, and SSL
|
||||
certificate provisioning.
|
||||
|
||||
[Unreleased]: ../../compare/v1.5.0...HEAD
|
||||
[Unreleased]: ../../compare/v1.17.0...HEAD
|
||||
[1.17.0]: ../../compare/v1.14.6-patched...v1.17.0
|
||||
[1.5.0]: ../../compare/v1.4.10...v1.5.0
|
||||
[1.4.10]: ../../compare/v1.4.9...v1.4.10
|
||||
[1.4.9]: ../../compare/v1.4.8...v1.4.9
|
||||
@@ -522,3 +441,6 @@ certificate provisioning.
|
||||
[1.1.5]: ../../compare/v1.1.1...v1.1.5
|
||||
[1.1.1]: ../../compare/v1.0.0...v1.1.1
|
||||
[1.0.0]: ../../releases/tag/v1.0.0
|
||||
[1.15.0]: ../../compare/v1.14.0...v1.15.0
|
||||
[1.14.0]: ../../compare/v1.13.4...v1.14.0
|
||||
[1.13.4]: ../../compare/v1.13.3...v1.13.4
|
||||
Reference in new issue
Block a user