Commit Graph
22 Commits
Author SHA1 Message Date
Hermes b0fcfddc2c chore(DC-163): record grade B (round 2) in changelog
urn:ump:l2tg66wmchkmd6fde4k3ojwc56zpxqh657spe37bu6dpvduswalq
2026-10-08 15:05:15 -07:00
Hermes e80e3273b7 [pending-judge] feat(DC-163): AI assistant that works — LLM intent engine + fixed chat panel
The floating assistant was broken end-to-end; Sami said "Do it that works".
Three user-visible bugs fixed + the promised LLM delegation implemented:

FRONTEND (status/js/ai-chat.js — rewritten):
- Response parsing: old code read data.data; the API returns the FLAT ok()
  envelope — EVERY reply rendered "Sorry, something went wrong". Now reads
  the real shape (contract asserted by route test).
- Suggestion chips: onclick="...send('"Deploy Plex"')" — nested quotes,
  invalid JS, dead buttons (shipped like this). Now data-driven buttons with
  addEventListener.
- Deploy button: called window.openAppSelector which NEVER existed anywhere
  in the tree (grep-verified). Now opens the REAL deploy modal via new
  window.openDeployConfigFor(templateId) exported by app-selector.js —
  resolves against the live API template cache, reuses showDeployConfig
  (same path a manual catalog click takes). Widgets route to the grid.
- Conversation history (last 6 turns) now rides along per request, engine
  badge in header, ⚙ settings sub-panel (baseUrl/model/API key + Test +
  Remove), all server text via textContent (no HTML injection), CSP-safe
  (no inline handlers).

BACKEND (routes/ai-intent.js):
- TWO engines, one contract. LLM classifier (OpenAI-compatible chat
  completions) with system prompt embedding the LIVE 78-app catalog + the
  six wizard categories; regex patterns kept as the zero-config default and
  the automatic failover (HTTP error, timeout via AbortController,
  unparseable output -> pattern answers; response carries engine +
  llmError so the UI can say which served — no silent degradation).
- Closed-vocabulary schema validation: intent MUST be in the known set else
  'unknown'; appId MUST exist in APP_TEMPLATES else nulled (hallucinated
  ids cannot leak into deploy plans); categories filtered to the wizard's
  real keys; reply stripped of control chars + bounded to 600; history
  role-filtered (only user/assistant pass — client-injected system turns
  dropped) + capped; input capped to 1000 chars.
- enrich() rebuilds the response contract per intent; pattern-canned
  response is dropped when the LLM rerouted the intent (no stale shape);
  deployPlan body.port now fills from the template's defaultPort (was
  hardcoded null); deployPlan shape asserted against wizard usage.
- Key storage: PUT /ai/settings stores {baseUrl,model,apiKey} in the
  ENCRYPTED credential store (key 'ai:llm') via ctx.credentialManager —
  NOT config.json (GET /config echoes the raw file to the browser; that
  route's shape was verified before this decision). Blank apiKey on PUT
  keeps the stored one. GET /ai/settings reports configured/source/model/
  hasApiKey — the key value NEVER crosses the wire (asserted). Env
  fallback AI_LLM_BASE_URL/AI_LLM_API_KEY/AI_LLM_MODEL + legacy
  LLM_PROXY_URL for headless installs. POST /ai/settings/test = one-shot
  real classify probe returning ok/sample or ok:false/reason (never
  throws). DELETE clears.
- GET /ai/capabilities now reports engine + llm status (pattern was honest
  marketing before; now it can be true).

MOUNT (src/app.js): aiIntentRoutes receives siteConfig, log, fetchImpl
(ctx.fetchT — test-injectable) and credentialManager.

Docs: OpenAPI +4 AI path entries (intent, capabilities, settings, settings/test); CHANGELOG entry; dist bundle rebuilt
(openDeployConfigFor present in features.js; SW cache c62511c40d).

Tests: 20 NEW in __tests__/routes/ai-intent-engine.test.js (engine
selection w/ and w/o store, off-catalog phrasing via mock LLM,
hallucinated-id nulling, illegal intent coercion, HTTP-500 failover,
AbortError timeout failover, markdown-fence repair, reply sanitization,
history cap+role filter, env config path, intent-disagreement rebuild w/
real jellyfin port 8096, flat envelope contract, 400s, 1000-char cap,
settings GET/PUT/DELETE/test incl. key-never-echoed assertions,
capabilities engine reporting) + the 18 original pattern tests unchanged +
composition-root e2e 8 pass. Full suite: 3643 passed; only the pre-existing
pdf-parse billing family red (6 failed in documented band [5,7], patch
touches no billing file).
2026-10-08 14:42:31 -07:00
Hermes 2aa1247a94 chore(DC-162): record grade B (round 3) + sync changelog test count
urn:ump:or2qqhcytp6lfzlyi7xru7hdqy3uar2hbjllsrrbxrbray3c5kpa
2026-10-08 04:03:21 -07:00
Hermes c9015b59ad [pending-judge] feat(DC-162 rev2): "Connect your AI" — spec Streamable HTTP MCP + one-click keys
Judge r1 (grade D) blockers, each fixed and tested:

1. TRANSPORT: custom POST-only JSON-RPC → MCP 2025-03-10 Streamable HTTP
   (spec-canonical; replaced HTTP+SSE). POST answers application/json for
   requests; valid notifications -> 202 empty; malformed notifications ->
   no reply (204); batching removed in this revision -> arrays rejected
   -32600. GET (server->client stream) and DELETE (session termination)
   answer 405 + Allow: POST — the spec's explicit allowance for stateless
   request/response servers; documented in /info + modal + OpenAPI.
   Origin header validated when present (DNS-rebinding MUST); Accept
   negotiation (json required, else 406); MCP-Protocol-Version header
   checked when sent. Clients needing server-initiated streams use the
   stdio bridge (unchanged, shares mcp-core).

2. CREDENTIAL TYPE PRESERVATION: routes/mcp.js now forwards the SAME
   scheme the caller authenticated with (req.auth.type from
   middleware.js:549-586): apikey -> x-api-key, jwt -> Authorization
   Bearer (NOT dk_-coerced-x-api-key as r1 did). mcp-core createToolHandler
   accepts explicit headers. Tests assert BOTH shapes downstream
   (apikey carries x-api-key & no Authorization; jwt carries Bearer & no
   x-api-key; zero downstream calls for session denial).

3. JSON-RPC VALIDATION: validateJsonRpc — jsonrpc:'2.0', non-empty string
   method, params object-or-omitted, id string|number|null. Invalid
   Request -32600 (empty body, empty array, batch); tools/call without
   string params.name -> -32602; unknown method -> -32601; error envelopes
   carry id null when unpairable. Transport primitives rejected by the
   app-wide strict JSON parser (400; asserted).

4. REPRODUCIBILITY: status/dist/features.js + sw.js regenerated and
   committed IN THE PATCH (repo convention: DC-130/131 committed bundle
   rebuilds). Verifier greps the built bundle for aiconn- (23),
   mcp/connections (1), httpConfig (2) so a clean `git am` checkout serves
   the real frontend.

Judge r1 polish, all applied:
- verifier accepts 0_PATCH.diff / PATCH.diff naming (indexed artifact);
- connections list filtered server-side to "AI connection (...)" keys
  (new GET /mcp/connections, session-only; modal switched to it);
- URL-encoded tool path params (serviceId, containerId, action,
  templateId, category, zone) in mcp-core.

Config shape: POST /mcp/config (session-only; apikey 403) returns the
standard Streamable-HTTP card {url, transport: streamable-http, headers:
{x-api-key}, mcpProtocolVersion} + per-client note (ChatGPT note states
the public-https requirement honestly; no fabricated connector claims).

Tests: 57 green (34 route incl. auth matrix/type-preservation/transport
rules/JSON-RPC errors + 23 core). Composition-root e2e (8) boots the real
createApp with the mount. eslint 0 errors. Full suite: only the
pre-existing pdf-parse billing family red (unchanged since base 470dfaa).
2026-10-08 03:46:56 -07:00
Hermes 470dfaac2a chore(DC-161): record grade B (round 5) in changelog
urn:ump:znykdi6ufm53sgnhkep7ghlda7aoo55nipghjtstlkpqqmxuv2zq
2026-10-07 21:20:04 -07:00
Hermes 74e21c1edc [pending-judge] feat(DC-161): calendar widget + Radicale auto-wiring
- Top-bar calendar widget (status/js/calendar-widget.js): next-appointment
  display, settings modal with CalDAV/ICS source management and a
  Test-connection probe. Follows the weather-widget pattern.
- Backend routes/calendar.js: sources CRUD (secrets in credential manager,
  never in responses), aggregated events across sources with per-source
  error isolation, Radicale provision endpoint, CalDAV discover probe.
- src/calendar/ics-parser.js: dependency-free RFC 5545 parser with bounded
  RRULE expansion (DAILY/WEEKLY-BYDAY/MONTHLY/YEARLY, COUNT/UNTIL/INTERVAL,
  EXDATE consumes COUNT, RECURRENCE-ID overrides), 500-event cap.
- src/calendar/caldav-client.js: CalDAV REPORT time-range queries over
  node:https (no new deps), HTTPS-enforced off localhost, 5MiB response cap.
- src/calendar/radicale-provisioner.js: zero-config auto-wiring - generates
  a 24-char password, writes Radicale htpasswd config (pure-Node APR1 hash
  verified byte-for-byte against openssl passwd -apr1 vectors), stores
  credentials, registers the source. Deploy hook in routes/apps/deploy.js
  wires any Radicale deployed via the App Selector automatically.
- Radicale app template (tomsquest/docker-radicale) in the catalog.
- Tests: 32 new (parser unit, provisioner unit incl. openssl vectors,
  route tests). Full suite 3552 passed; only pre-existing pdf-parse
  billing/invoice failures remain (proven red at base 448f535).
- OpenAPI: 5 calendar paths documented. CHANGELOG entry added.
2026-10-07 19:57:22 -07:00
Hermes 448f5358bf [pending-judge] release: v1.17.0 - version bump 1.16.0 -> 1.17.0 + changelog for the integrated catalog pipeline (DC-160, DC-CATALOG-3) 2026-10-07 08:48:45 -07:00
Krystie 503de258b8 [grade=pending] QA sprint: commit 103 at-risk files from multi-agent sprint work
Committed by Hermes autonomous QA sprint 2026-08-13.
These files were modified during the Aug 12 sprint but never committed.
2026-08-12 17:34:10 -07:00
Krystie d9e61ce1b7 DC-053: Public share links + Tailscale-mediated share (Pro-gated)
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled
- Share-store: HMAC-signed tokens bound to serviceId+kind, persistent
  signing secret in dataDir/.share-secret, atomic writes, auto-prune
- Routes: admin endpoints gated on licenseManager.isPro() (402 Free);
  public endpoints CSRF-exempt (token IS proof)
- Tailscale path: mints single-use ephemeral pre-auth key, emails
  join link, rolls back share record if createAuthKey throws
- Email-failure path: exposes urlPath for manual delivery fallback
- 53 new tests (24 store + 29 routes), full suite 1372/1372
- Drift-test parser hardened against quoted-word comments
- share-store dataDir resolver handles Proxy/function values

CHANGELOG + BACKLOG updated.
2026-07-21 00:45:46 -07:00
hermes 321334cd33 DC-048: multi-user bootstrap + admin invites (opt-in)
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled
Implements the user-store + invite-store + admin routes. The whole
system is opt-in via siteConfig.authProviders.email.enabled = true;
single-user TOTP-only installs see zero behavior change.

Backend:
- src/security/user-store.js: users + allowlist + bootstrap sentinel,
  atomic writes, last-admin protection, defensive dataDir resolver.
- src/security/invite-store.js: single-use tokens (SHA-256 hashed on
  disk), TTL, auto-prune, defensive dataDir resolver.
- routes/auth/admin.js: /me, /admin/users (CRUD), /admin/allowlist,
  /admin/invites (CRUD), public /invites/:token (peek + accept).
- routes/auth/index.js: wires userStore, gates admin router on
  email auth being enabled.
- src/auth/providers/email.js: verify() enforces allowlist, creates
  user record, tags req.user; default-enabled flipped to opt-in.
- src/auth/providers/totp.js: bootstraps system@totp.local admin on
  first verify so current DNS2 operator shows in /admin/users.
- src/security/audit-logger.js: middleware adds userId/userEmail/
  userRole/viaProvider to log details when req.user is tagged.
- PUBLIC_ROUTES + CSRF allowlists updated for invite redemption.

Frontend:
- status/js/admin.js: modal overlay with users list (role-edit,
  delete), invite form (email/role/TTL), copy-link button,
  outstanding-invites list with revoke. Exports window.AdminPanel.
- status/js/core/init.js: calls AdminPanel.attachTrigger so the
  Admin button only appears when /me returns isAdmin=true.

Tests: 35 new tests across 3 files (user-store, invite-store, auth
multistore integration). Full suite: 1298/1298 passing.

Docs: BACKLOG.md marks DC-048 done. CHANGELOG.md [Unreleased]
section gets the DC-048 entry.
2026-07-20 17:44:11 -07:00
Hermes Agent bd480a69a7 BACKLOG + CHANGELOG: mark DC-049 done
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled
Track record of the auth-gate UI work plus the historical delta from
DC-046/047/050/049 commit chain. No code changes.
2026-07-20 02:23:26 -07:00
Hermes Agent c619d3a36b DC-046 DC-047 pluggable auth providers + email magic link
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled
Pluggable AuthProvider framework for any future auth method (OIDC, SAML,
passkeys) to plug in without touching the auth path again. Two
implementations ship:

  * TOTP — refactored from routes/auth/totp.js into src/auth/providers/totp.js
    as one AuthProvider impl. Legacy /api/v1/totp/* routes stay mounted for
    back-compat; new /api/v1/auth/login/totp/* routes use the new shape.

  * EmailMagicLink — src/auth/providers/email.js. Initiate issues a 32-byte
    base64url token, stores its SHA-256 hash in data/email-tokens.json
    (atomic lockfile-based mutation, automatic TTL cleanup), and delivers via
    nodemailer if providers.email.{host,port,username,password} is set OR
    falls back to log.info('auth', 'email magic link issued', ...) for dev.
    Verify accepts the token, marks it used, creates the same DashCaddy
    session cookie that TOTP uses (single global cookie model).

createAuthProviderRegistry() composes both implementations and exposes
them via /api/v1/auth/login/{methods, :provider/initiate, :provider/verify,
recovery-info} and /api/v1/auth/disable/:provider. PUBLIC_ROUTES + CSRF
exemptions updated to use :provider placeholder (parameterized for future
providers).

Test fix: src/utilities/middleware.js PUBLIC_ROUTES and csrf-protection.js
both switched to the :provider form because the prior literal 'totp'
wouldn't match the parameterized mount path Express 4.22 produces.

Test fix: __tests__/public-routes-drift.test.js extractMountPath() was
broken for Express 4.22's new ^/path/?(?=/|$) source format (no \?\?
terminator in the literal-mount case). Rewrote the parser to normalize
escaped slashes + trailing lookaheads instead of relying on regex
matching against the raw source.

New: __tests__/auth-provider-registry.test.js — 9 tests covering registry
composition, getProvider round-trip, listEnabled no-secrets-leak guarantee,
enabled-flag respect, listAll vs listEnabled distinction, email provider
dev-console fallback (token written to JSON store + log.info with
deliveredVia: 'dev-console' + response masked), verify rejects unknown
tokens via AuthenticationError.

Tests: 1241/1241 passing across 46 suites (was 1232; +9 new).

DNS2 deploy: this commit + bump VERSION to 1.16.0 + publish tarball to
get.dashcaddy.net + docker build + bash start.sh. The image-layer migration
from DC-050 also runs on first container recreate post-merge.
2026-07-20 01:40:33 -07:00
Hermes Agent 894e091335 DC-050 harden dataDir + add image-layer migration
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled
Three-part fix for the silent data-loss failure mode that survives DC-039:
If SERVICES_FILE env was unset, platformPaths.dataDir resolved to /etc/dashcaddy
(image-layer path), and audit/license/error logs would silently land there and
vanish on every container recreate.

1. platform-paths.assertSafe({mode:'production'}) — throws FATAL on forbidden
   zones (/app/src,routes,scripts,utils,managers,security + /etc/* + /usr + /var).
   Bypassed with SKIP_DATA_DIR_GUARD=1.
2. server.js calls assertSafe() before any runtime work.
3. start.sh one-time migration: scans 6 known image-layer zombie paths,
   copies non-empty content to bind mount with 'migrated-' prefix,
   gated by sentinel file. Survives set -e per-file failures.

19/19 platform-paths tests + 5/5 shell migration tests.
Suite: 1066/1067 (1 pre-existing public-routes-drift failure from in-flight
auth refactor, untouched by this commit).

Verified live on DNS2: live audit log at /app/data/audit-log.json (315KB,
active) is unaffected; vestigial 2-byte /app/src/security/audit-log.json +
140KB /app/src/utils/error.log (pre-DC-039 era) will be recovered on next
container recreate.
2026-07-20 00:53:05 -07:00
Krystie fb8942a3fa chore(release): bump to 1.15.0 — DC-042/043 Tailscale admin + DC-044 health-check marker
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled
2026-07-14 02:13:29 -07:00
Sami a79dc5a738 docs(changelog): document 1.14.0 release + desloppify changes
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled
2026-06-28 03:51:15 -07:00
Hermes 5f6c25d2e3 DC-018/DC-019: mark done, bump v1.13.5, CHANGELOG
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled
2026-06-27 07:03:41 -07:00
Hermes 8973392c61 BACKLOG: audit DC-013/014/015/016 — all four already implemented, mark done
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled
Picked up the four 'Still Open' standardization items from the audit doc
as Option B work. Audited each before starting implementation:

  DC-013 (config schema migration) — src/config/migrations.js exists with
    a versioned migration system (CURRENT_VERSION=2, v1 dns normalization,
    v2 dns.provider field), loadAndMigrate() writes back to disk only when
    version changes, called from src/config/site.js on every startup.
    Guarded by 21 tests in __tests__/config-migrations.test.js.

  DC-014 (monitoring endpoint opt-in) — MONITORING_PUBLIC env var +
    config.monitoring.public both work via an IIFE in
    src/utilities/middleware.js line 297. Routes are conditionally public
    based on the flag. Default is 'true' for back-compat with existing
    dashboards that pre-load widget data. Flipping the default to 'false'
    is a fresh change with a real UX cost.

  DC-015 (CSRF token path duplication) — grep confirms only
    /api/v1/csrf-token exists. /api/v1/auth/csrf-token was never
    implemented or was already cleaned up.

  DC-016 (per-call fetchT timeouts) — src/utils/http.js defines
    fetchT(url, opts, timeoutMs) with AbortSignal.timeout() in the
    native branch and explicit timeout handlers in the http/https
    raw-request branches. 5s default covers most calls; 8 of 77 sites
    pass explicit overrides. 5min global request timeout is the backstop.

All four tasks reassigned from krystie → hermes because the work shifted
from 'implement' to 'verify and document'. No code changes in this commit
— only BACKLOG.md and CHANGELOG.md updated to reflect actual state.

This commit is the meta-example for Pitfall 20 (just added to the
standardization pitfalls reference): audit docs decay as fast as fixes
land. Always audit before implementing.
2026-06-25 17:27:56 -07:00
Hermes 8ec6c0ca6a DC-012: Add Kubernetes-style /healthz + /readyz probe aliases
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled
Fresh users copy-pasting healthcheck blocks from k8s/Docker docs need
the standard short aliases. Without /healthz and /readyz they get
connection refused. This commit:

1. Adds /healthz + /readyz as root-level aliases for /health/live +
   /health/ready in src/app.js. Handler bodies DRYed into named
   functions (livenessHandler, readinessHandler) so a probe semantics
   change updates all five paths at once.

2. Removes the dead /api/v1/health*, /api/v1/health/live, /api/v1/health/ready
   registrations from PUBLIC_ROUTES and CSRF exclusion list — those
   routes were never actually mounted on the apiRouter (only root
   paths existed). Anyone probing /api/v1/health now gets a clean 404
   instead of being routed through to a duplicate root handler.

3. Adds bypass for the 5 probe paths in three places where it matters:
   - PUBLIC_ROUTES (no auth)
   - csrf-protection.js excludedPaths (no CSRF check)
   - middleware.js request-logging exclusion (k8s polling every 10s
     doesn't flood the audit log)
   - middleware.js Tailscale auth bypass (probes don't carry Tailscale
     identity headers)

4. Adds __tests__/health-probe-aliases.test.js (19 tests):
   - Alias equivalence (/healthz == /health/live, /readyz == /health/ready)
   - Back-compat (/health == /health/live)
   - Path consolidation (all 3 /api/v1/health* return 404)
   - Source-of-truth PUBLIC_ROUTES allowlist sync check
   - Source-of-truth src/app.js mount list sync check (catches drift
     between handler mount and middleware allowlist)

5. Documents probes in README (copy-paste docker-compose.yml +
   Kubernetes blocks) and user-guide (Health Probes section + System
   API table updated).

Post-fix: 941/941 tests pass (+19 new). Zero new ESLint warnings
introduced. The pre-existing warnings/errors in src/app.js line 906
('os' is not defined) and the empty blocks in logging.test.js are
not regressions from this commit.
2026-06-25 17:16:16 -07:00
Hermes 283121edba Merge krystie-improvements into main
Resolves 24 conflicts between Hermes (DC-008/009/010 + response-helper
envelope standardization) and Krystie (DC-005 src/ refactor path fixes,
DC-006 TOTP integration, DC-007 new test suites, cloud backup
destinations).

Conflict resolutions:
- src/utils/logging.js:    took ours (consumers depend on logError/
                            safeErrorMessage/createLogger exports)
- src/config/site.js:      merged (her factored validateAndLogConfig +
                            applyConfigFields helpers)
- src/context/dns.js:      took hers (admin/readonly role iteration for
                            write operations)
- src/utilities/backup-
  manager.js:              took hers (Dropbox/WebDAV/SFTP cloud feature)
- status/dist/*, status/
  sw.js:                   took hers (minified bundles + newer SW cache)

Additional fix (post-merge regression):
- src/monitoring/health-checker.js: fixed DC-005 path miss —
  'require(./platform-paths)' → 'require(../../platform-paths)'

Test status: 921/922 passing. One known failure in logging.test.js
(async file-handle timing) tracked as follow-up.
2026-06-25 16:43:10 -07:00
Hermes 7f6be1c2b3 DC-009: populate [Unreleased] section in CHANGELOG.md
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled
Documents all unreleased work since v1.5.0:
- Security: TOTP 4-part recovery system
- Added: OpenClaw routes, auto-backup + storage limits, monitoring widget, Sami Files template, unified logger, notification manager, update UX, 7 new test files (120 tests)
- Changed: Route response standardization (DC-010, ~62 calls), /api/v1/ versioning, release.sh hardening
- Fixed: DC-011 credential route regression, 19 ESLint warnings (DC-004), workflow engine init, container-logs wireModal misuse, CSP hash mismatch, SW cache tag, updater false-positive loop
- Removed: legacy test scripts (moved to scripts/legacy/, preserved), stale root files, dead routes/ directory
2026-06-25 15:47:12 -07:00
Hermes 53680c4c74 v1.13.4: Standardize all route responses to use response helpers
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled
Convert ~160 raw res.json()/res.status().json() calls across 32+ files
to use centralized helpers from src/utils/responses.js (ok, errorResponse,
successMessage, notFound, validationError, forbidden, unauthorized, conflict).

No behavior changes — response shapes are identical. Future schema changes
(e.g., requestId envelope) only need to update one module.

Fix error vs errorResponse signature mismatch in routes/health.js CA cert
endpoint where error(res, message, statusCode) was being called with
errorResponse(res, statusCode, message, extras) argument order.

Files changed: middleware.js, csrf-protection.js, error-handler.js,
license-manager.js, src/app.js, and 27 route files.

Test suite: 755 pass / 4 pre-existing failures (services credential tests).
2026-06-11 00:48:13 -07:00
SamiandClaude Opus 4.7 d36705bd90 feat: 1.5.0 prep — API v1 cutover, LICENSE, CHANGELOG, CI
- Remove legacy /api/ mount; all routes now under /api/v1/ only
- Update path matchers (CSRF excludes, public routes, audit log, rate limits)
- Move standalone routes (/api/network/ips, /api/docs, /api/docs/spec) to v1
- Update openapi.yaml (110 paths), CA pages, and 4 lingering frontend files
- Add LICENSE (proprietary EULA), CHANGELOG.md (Keep a Changelog format)
- Add .gitea/workflows/ci.yml (test+lint and security audit jobs)
- Fix 9 pre-existing no-empty lint errors so CI starts green
- Drop ad-hoc scratch reports and *.bak files from repo root

All 739 jest tests pass. Lint is clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 11:38:45 -07:00