Changelog

Tiyi release history.

Every entry maps back to a commit and a verification command. Items are Shipped only after implementation, verification, and required docs are complete — otherwise Planned or In progress. Archived entries preserve the terminology and commands that existed at that time; use the newest entry and current documentation for supported operations.

v3.5.3 2026-08-10 Shipped
Native IP-list enforcement + incremental alert remediation

v3.5.3 moves country and CIDR IP-list enforcement out of SecLang into a compressed native matcher, so large geo:CC blocks can no longer truncate CRS, and keeps auto-remediation appending while an alert stays firing.

  • Native tiyi_iplist. Minimized prefixes compile into a deterministic compressed artifact matched before rate limiting and Coraza. Country CIDRs never enter SecLang; oversized policies fail visibly and keep the last-good configuration.
  • SecLang completeness guard. Apply rejects physical Coraza lines over 48 KiB, broken Include graphs, or a missing terminal parse canary before local or Agent Caddy load.
  • Bundle v3. Local/Agent config bundles carry the native IP-list artifact. This binary rejects retained v2 bundles; generate and apply a fresh revision.
  • Incremental auto-remediation. While an occurrence remains firing, each evaluation may append the next five new qualifying attackers (≤50 unique IPs per occurrence) with per-IP reservation and fixed TTL batches; UI shows partial/progress receipts.
  • Rule-owned deny lists. Auto-create reuses the managed list by alert-rule ID with locale-aware display names; deleting the rule releases the list as ordinary operator content.
  • Rate-limit runtime bound. Per-policy token-bucket state is capped; unseen identities fail closed when the budget is full rather than granting an unbounded burst.
v3.5.2 2026-08-09 Shipped
Display timezone + clearer protection authoring

v3.5.2 hardens day-to-day operator UX on top of v3.5: one display-timezone chain, a clearer IP-list ownership model, safer RE2 custom-rule authoring, and a more readable audit ledger.

  • Display timezone. Header override → system-wide app.timezone → browser IANA. Tables, charts, relative presets, and custom ranges share the conversion path. API, SQLite, audit-chain, SIEM, and export timestamps remain UTC; process logs still follow the host timezone.
  • IP Lists ownership. Protection → IP Lists owns shared list content with Create only / Create and apply. Policy IP access edits bindings only. The flow is Define a list → Apply to a scope → Query IP.
  • RE2 workbench. Selecting the regex operator explains query-string inclusion, generates escaped exact/tree/prefix/suffix/case-insensitive patterns, warns on near-universal expressions, and rejects invalid RE2 (including PCRE lookaround/backreferences) before save.
  • Audit Trail. Labeled filters, operator/resource names in the ledger, readable change summaries, cursor-based Load more, and permission-gated chain verification.
  • CRS / limits polish. Shared PL1–PL4 discrete paranoia controls with blocking/log-only/inactive posture; Request limits separate parameter vs upload ceilings with explicit CRS-default vs override switches.
  • Remediation receipts. Auto-remediation completion/failure notifications render concise action receipts instead of repeating the firing investigation snapshot.
v3.5.1 2026-08-06 Shipped
Fail-closed client-IP topology + intent-based rule drafting

v3.5.1 hardens the v3.5 executable client-IP topology and turns Attack Log rule drafting into an intent-based workflow that can skip CRS without disabling the rest of the WAF.

  • Header-owned extraction. Each Header independently chooses automatic verified-proxy skipping or fixed extraction (single IP, leftmost, rightmost, Nth-from-right). CDN and proxy ranges compile into one physical lookup pool while node labels and legal topology transitions stay intact.
  • Fail-closed topology checks. Automatic extraction requires a terminal RemoteAddr on a proxy node connected to Tiyi, then scans right to left. Cross-branch hops, all-trusted chains, XFF paths through preserve/duplicate/unknown writers, and claimed upstream hops behind an overwrite writer reject that rule and continue to the next Header or RemoteAddr fallback.
  • Intent-based Attack Log drafting. Create rule from this event groups actions as Block request, Tune CRS false positives, and High-risk CRS exceptions. Every item states query/descendant/method scope; root / cannot create path-scoped drafts.
  • CRS-only skip outcome. Visual and seeded rules can compile ctl:ruleRemoveByTag=OWASP_CRS so OWASP CRS is skipped while Tiyi custom rules, IP controls, and other rule sets remain active. High-risk actions require an extra confirmation.
  • Operator docs. QUICKSTART, PRDs, trust/API docs, and website EN/zh changelog and build stamps track the patch.
v3.5.0 2026-08-03 Shipped
Executable client-IP topology + safer protection authoring

v3.5.0 makes client-IP resolution an executable topology operators can sample, verify, and apply, turns dashboard security rankings into immediate response actions, and gives rule and endpoint-limit changes one deterministic path from evidence to enforcement.

  • Executable client-IP topology. Sites is the sole global entry. Full and quick editors show a live node/edge/rule graph with CDN/proxy pills, path-conditioned header rules, unsaved-preview status, and verified drafts that can apply to the source site or promote to the global default.
  • Site analysis. Memory-only sampling (five minutes or 50 requests) distinguishes facts, range/path verification, advisory provider signatures, and conflicts before anything is saved. Provider-specific and generic headers may coexist on multi-CDN/stacked graphs because every rule is conditioned on its verified node path.
  • Dashboard security insights. Six simultaneous SecurityFact ranking cards—including Attacked sites—plus an attack-origin country/region strip. Hover actions exclude ranks from the current view or globally block attacker IPs and geo:CC entries for 24 hours.
  • Geo country compilation. The live DB-IP Country reader publishes an immutable Country→CIDR snapshot on boot/upload/refresh/delete; every policy compiler path consumes the same resolver so Dashboard/global country blocks compile cleanly.
  • Canonical endpoint rate limits. Endpoint rows now have one source of truth across API, CLI, policy, site override, and compiled data plane. Paths are unique within policy or site scope, create and update are explicit, and a matching site row deterministically overrides the inherited policy row before CRS runs.
  • Evidence-to-protection workflow. Attack Logs can draft exact-path, segment-bounded path-tree, method/path, IP/path, or retained User-Agent rules. Structured CRS evidence can instead seed a path-scoped target exclusion or rule disable; duplicate IP actions and whole-path WAF bypass seeds are removed.
  • Draft-safe policy editing. Policy and site custom-rule editors use focused subviews, while site rate limits edit inline with field-level validation. Modified drafts require an explicit discard before navigation or drawer close.
  • Operator surfaces. Product-tour screenshots refresh against a live multi-node instance and now include fleet topology and hash-chain audit; QUICKSTART, PRDs, and generated API docs track the clean-break client-IP contract.
v3.4.0 2026-07-30 Shipped
One Controller, convergent configuration, operator trust

v3.4.0 makes the served state explicit from durable configuration through the operator UI, while removing the legacy HA contract.

  • Single Controller. tiyi run owns state, API, UI, and a factual built-in local data plane. Role, epoch, promotion, replication, standby, and alternate-Controller surfaces are removed; remote Agents continue serving their last accepted signed bundle during an outage.
  • Convergent configuration. Durable desired/active revisions, immutable artifacts, local rollback, per-target delivery, content-addressed Agent envelopes, and contextual retry replace handler-local mutate/apply compensation.
  • Health truth. Active upstreams pass a strict Controller-side submit probe before mutation. Continuous Caddy health is bound to the exact configuration generation and artifact hash, so stale reports cannot claim a candidate is active.
  • Security and reliability. Generated fail-closed authorization, rotating HttpOnly refresh sessions, password token revocation, structured logging, correlated internal errors, panic-isolated workers, bounded shutdown, and pre-write quotas harden the management plane.
  • Operator experience. Exact request/bandwidth dashboards, shared local/remote node trends, site request-path overviews, local configuration history, adaptive row actions, automatic Geo lifecycle, and security-only Request Evidence defaults make day-two state easier to read and safer to operate.
  • Clean-break boundary. Databases below schema 47 are rejected without mutation; start v3.4.0 with fresh state and re-enroll remote Agents.
v3.3.1 2026-07-24 Shipped
Request evidence + producer-direct SIEM

v3.3.1 adds two optional, bounded observation planes and hardens long-running telemetry storage without moving any storage or network work into the WAF request path.

  • Request Evidence. Global and per-site off, security_only, and retained_logs policies retain unredacted parsed headers and bounded body bytes beside authorized Attack/Access log drawers; fresh installs remain off.
  • Durable local and Agent storage. Append-only daily segments, quotas, retention, deterministic exemplar convergence, resumable 64 KiB CRC32C Agent uploads, and durable acknowledgements bound memory, disk, and reconnect behavior.
  • Producer-direct SIEM. Up to 32 independent UDP/TCP/TLS destinations select native Caddy access JSON, native Coraza audit JSON, or Tiyi-formatted sources with per-target queues, framing, timeouts, and diagnostics. Signed Agent last-known-good profiles continue while the Controller is offline.
  • Operational visibility. Log Pipeline exposes evidence, raw-source, and per-destination queue/drop/failure/panic lanes. Dashboard Top cards use exact normalized URL templates and fixed UA classes.
  • Runtime hardening. Idle previous-day SQLite WALs are safely truncated behind partition lease fences, and Tiyi defaults to GOGC=200 plus a soft memory limit at 90% of the detected host/container limit unless standard Go overrides are supplied.
v3.3.0 2026-07-22 Shipped
SecurityFacts consolidation + alert auto-remediation
The sessionized incident, attack-campaign, and MITRE-mapping layer is removed; immutable, partitioned SecurityFacts are now the sole security-event truth, with a fresh-install schema-43 cutover (no in-place upgrade from older state). Alert auto-remediation turns a firing alert into a reviewed IP-list or custom-rule draft; a durable fact journal and bounded Live Tail (≤200 rows, one event per 500 ms window) keep investigation fast. Operator docs, merge log, and website synchronized in EN + zh.
v3.2.1 2026-07-17 Shipped
v3.2.0 QA hardening + reliability
Closes the v3.2.0 QA pass: unmatched Host headers return 421 instead of bypassing the WAF, CRS rule 980099 outbound correlation runs cleanly, and drawer, auto-close, and i18n defects are fixed. Reliability additions include SQLite BUSY retry, an orphan-evidence lookup index with a durable join worker, and bounded per-response network GeoIP enrichment.
v3.2.0 2026-07-16 Shipped
Observation v2 + persistent attack campaigns

v3.2 turns request observation into an isolated, evidence-first pipeline and adds a durable campaign layer for correlating incidents without placing analytics in the data path.

  • Observation v2. Exact hot-path counters, compact SecurityFact/Finding evidence, retained request detail, and SIEM delivery are independent truth planes. Explicit global/per-site evidence policy and tiered retention replace legacy log settings.
  • Durable agent delivery. Agent spool, ACK/retry, protocol fencing, partition management, and panic-isolated observation callbacks keep proxy traffic independent from log consumers and analytical workers.
  • Persistent Attack Campaigns. Deterministic source/target, Geo/ASN, and MITRE projections feed an evidence graph and timeline with immutable revisions, conflict-safe triage, merge/split, membership, and edge review.
  • API Inventory. Telemetry Explorer discovers endpoints with live QPS, status, and latency, then supports confirm, quarantine, hide, and block workflows.
  • Actionable alerts. Localized alert titles and payloads include evidence URLs, target labels, campaign TTP context, and an explicit Geo/ASN caveat.
  • Operator experience and docs. Updated EN/zh screenshots, campaign and incident workflows, plus task-based operations, troubleshooting, and upgrade guidance across the website and public repos.
  • Clean-state boundary. Because there is no supported production upgrade population yet, pre-v3.2 development/test databases and agent identity/bundle state are rejected; reset and re-enrollment are explicit.
v3.1.0 2026-07-12 Shipped
Task-oriented navigation + accessible admin workspaces

v3.1.0 reorganizes the management plane around the jobs operators perform, then applies one responsive and accessible interaction system across the highest-traffic security workflows.

  • Seven task-oriented groups. Operations, Application Delivery, Protection, Fleet, Events & Logs, Detection & Response, and Administration replace resource-shaped menu silos without changing route URLs or RBAC permissions.
  • Focused application shell. The desktop rail has one collapse model, concise labels, distinct hover/current states, and a compact header; mobile prioritizes navigation, search, theme, language, and identity while moving Copilot to a thumb-sized floating action.
  • Keyboard-accessible navigation. Submenus expose expanded/current state, Enter and Space operation, focus-visible treatment, and reduced-motion support. Permission filtering still removes empty groups server-side.
  • Consistent operator workspaces. Policy and site-security workspaces gain clearer overview/module navigation, unsaved-change protection, and reusable empty, diff, live-state, and YAML-apply patterns; alerting, incident response, certificates, agents, logs, settings, and list pages share the same visual and interaction language.
  • Documentation contract. PRD-UI v3.9, the operator quickstart, and the admin-navigation design record the stable information architecture, responsive behavior, and accessibility acceptance criteria.
  • Verified: go test ./..., buf lint, pnpm typecheck, locale-key validation, production web build, and desktop/mobile Playwright QA.
v3.0.9 2026-07-10 Shipped
Visual-rule bypass action + responsive admin UI

v3.0.9 extends the visual rule builder with an explicit bypass action for trusted false-positive exceptions, and rolls out a responsive-width and copy-affordance pass across the admin UI.

  • Bypass WAF action. The visual builder's action set (block / log / pass) gains bypass, which compiles to pass,nolog,ctl:ruleEngine=Off so matching traffic skips the rest of WAF inspection. Plain pass is now pass,nolog (silent, passes only that rule; later CRS rules still run); block and log still audit-log.
  • False-positive handoff. The security-event Create rule from this event menu adds Allow this path / false positive, which drafts a tightly scoped bypass rule scoped to the event's site.
  • Responsive drawers and modals. Every Tiyi drawer and modal width now clamps to the viewport via a shared useResponsiveWidth helper, so wide drawers no longer overflow smaller screens.
  • Markdown copy buttons. Fenced code blocks in AI and markdown output get a native, localized copy button (replacing click-to-copy on the whole block); TiyiCopyButton is localized.
  • Recipe catalog launcher. The custom-rule builder's server template catalog moves behind a compact Browse recipes control so recipe browsing no longer splits the edit form; the static eight-preset selector remains as a fallback.
  • Field-mask fix. Visual-spec custom-rule updates now send the correct protojson field-mask path (visualSpec), so edits to visual rules persist correctly.
  • Verified: go test ./..., buf lint, pnpm --filter @vben/web-antd typecheck, python3 scripts/i18n_check.py, and signed linux/amd64 + linux/arm64 release packaging.
v3.0.8 2026-07-09 Shipped
Policy enforcement hardening + doctor state-ownership repair

A focused hardening pass on v3.0.7: closes a rate-limit enforcement gap for sites running the inherited policy, tightens IP-list and CRS-scalar mutation semantics, and gives tiyi doctor a way to repair service-owned state directories.

  • Policy-wide rate limits enforced everywhere. Rate-limit endpoints were only merged into a site's compiled policy when a site overlay existed, so sites running the inherited policy silently skipped policy-wide limits. The merge now runs for every site, overlay or not.
  • IP-list update_mask preserves kind. Updating an IP list with a field mask that omits kind no longer resets it; the stored kind is retained unless explicitly changed.
  • CRS enable_default_collections tri-state. The scalar is now a proto3 optional so an explicit "off" survives protojson round-trips instead of collapsing back to the inherited default.
  • Doctor state-ownership repair. tiyi doctor now inspects whether the state directory tree is writable by the configured service user, and --fix-state-ownership (root) chowns it back; custom supervisors are supported via --service-user/--service-group.
  • Security-event handoff + UI refinements. "Create alert rule from this event" again resolves its target dropdown; the site policy-override modal is replaced by an inline panel; a shared datetime formatter is adopted across list views.
  • Verified: go test ./..., buf lint, pnpm --filter @vben/web-antd typecheck, python3 scripts/i18n_check.py, and signed linux/amd64 + linux/arm64 release packaging.
v3.0.7 2026-07-08 Shipped
Scoped IP control + site security overlays

IP-list controls now match how operators actually apply allow/deny decisions: lists are reusable data objects, and the effective action lives on the binding at global, policy, or site scope.

  • Global / policy / site scope. IP-list bindings now carry the action, bypass mode, and scope. The compiler enforces the visible priority order global allow > global deny > site allow > site deny > site policy effective config, including allow-list bypass modes for all-WAF or IP-list-only skip.
  • IP Control UI. The IP Lists page is now an IP Control workspace with Global lists, an IP list library, reference counts, apply-now targets, and a scoped Lookup IP table that explains why a source address was allowed, denied, monitored, or left alone.
  • Site Security protection. Site rows now open an effective-config drawer with inherited policy rows plus editable site deltas for CRS scalar overrides, rule overrides, custom rules, IP lists, rate limits, and diff/restore-inheritance controls.
  • Security-event actions. Event drawers can quick allow/block a source IP at global or current-site scope with optional expiry, without navigating away from the investigation.
  • Install ownership hardening. tiyi install --now now recurses through the state directory so root-owned embedded CRS files left by a prior sudo tiyi standalone run cannot break systemd applies.
  • Verified: go test ./..., buf lint, pnpm --filter @vben/web-antd typecheck, python3 scripts/i18n_check.py, and signed linux/amd64 + linux/arm64 release packaging.
v3.0.6 2026-07-06 Shipped
Alert-rule authoring redesign + dashboard/telemetry rework

The alert-rule builder becomes template-first, the dashboard and telemetry explorer get a ground-up rework, and a one-click bridge closes the "incident fired but I can't set an alert" gap.

  • Template-first alert rules. The builder now opens with a gallery of 8 vetted starters (critical incident, sustained 5xx surge, attack storm, agent offline, cert expiring, ACME failed, origin bypass, 4xx scan spike). The kind dropdown is grouped into Symptoms / Attack signatures / Infrastructure and exposes all 9 backend kinds — block-rate spike is no longer hidden. Each kind gets a structured form with anti-flap hold-before-firing / hold-after-resolve defaults.
  • Incident → alert bridge. A firing incident now has "Create alert rule" and "Alert on this source IP" actions right in its drawer; they carry the incident into a reviewed draft (sessionStorage handoff) that dedups against existing rules and shows an origin banner.
  • New default alert seeds. Every deployment now ships with a "Sustained 5xx surge" alert and an "Agent offline >10m" alert enabled on boot, so availability and data-plane liveness are covered out of the box.
  • Dead-field fixes. AttackClass and source-IP CIDRs now actually filter security-threshold counts; the MinSeverity=0 incident bug (which silently matched every severity) is fixed with an optional severity pointer; the dead PolicyID field is removed.
  • Dashboard overview rework. A site filter and time-range control now scope the overview, reorganized into traffic, security-response, attack-distribution, top-K drill-down, and certificate rows.
  • Telemetry explorer. A new QPS/blocked line chart with crosshair and tooltip; realtime queries now anchor to the newest flushed 10s bucket instead of wall clock, so the freshest durable point is always shown.
  • Site TLS, agent groups, silences. Site TLS gains an explicit HTTP-only / redirect / serve-both / ACME-only mode control; agent-group selection adds explicit-agent + group pickers with a live match preview; alert silences gain value-picker matchers including attack class.
  • Verified: go test ./..., cross-build for linux/amd64 + linux/arm64, and license/release-key tests.
v3.0.5 2026-07-04 Shipped
Agent metrics trend + apply/update hardening

Operator-facing reliability for agent monitoring, site apply, and self-update.

  • 7-day agent metric history. The agent detail drawer now retains seven days of per-agent samples and renders a trend view (requests/sec, blocked/sec, connections, CPU, memory), so operators see history instead of only the latest push.
  • Dashboard drill-down time range. Clicking a top attacker on the dashboard now opens Security Events scoped to the dashboard's selected time range, instead of being locked to the last 15 minutes.
  • IP-host site apply. Sites with an IP-literal primary host no longer fail their local HTTPS health check: Tiyi emits a single-uploaded-certificate fallback policy so Caddy can validate the certificate through the loopback path before applying.
  • Startup preflight. standalone and agent now run a preflight before opening SQLite, generating the JWT warning, or starting Caddy; if the state directory, admin sockets, API listener, or proxy ports cannot be created or bound, the command exits with one actionable error (sudo, tiyi install --now, or writable --state-db / socket / high-port flags).
  • tiyi update precheck + progress. Self-update now shows download progress and pre-checks write privileges to the install directory, failing fast with a sudo/root hint instead of after a long download.
  • Verified: go test ./..., buf lint, make build-all, and license/release-key tests.
v3.0.4 2026-07-02 Shipped
Install diagnostics + tiyi doctor

Diagnostics polish for real Linux hosts: the copy-paste install path stays simple, while failures now point operators at the exact sudo PATH or port conflict to fix.

  • Default command stays simple. The public install command remains curl -fsSL https://www.tiyisec.com/install.sh | bash && sudo tiyi install --now; full-path guidance is shown only when sudo cannot resolve the installed binary.
  • Installer environment checks. After installing or updating the binary, install.sh highlights sudo secure_path gaps and listeners on 80/443/8080, including stop/change-port guidance when another service owns a port.
  • tiyi doctor. A new non-mutating diagnostic command checks config loading, systemd availability, sudo PATH visibility, and role-specific port listeners for standalone, server, secondary, agent, and dashboard installs.
  • CentOS/RHEL compatibility. Legacy OpenSSL builds that lack pkeyutl -rawin still get required SHA-256 verification in the installer; signed tiyi update remains the fully verified update path.
  • Verified: go test ./..., focused doctor unit tests, installer syntax + lockstep checks, temp-prefix installer smoke, and website/public-doc consistency checks.
v3.0.3 2026-07-02 Shipped
China mirror install + signed update fallback

Operational polish for regions where GitHub is slow or unreliable, plus a tighter public documentation surface for runtime configuration.

  • GitHub primary, Gitee fallback. install.sh keeps GitHub as the default source and falls back to the Gitee release mirror when needed; operators can force the mirror with TIYI_MIRROR=gitee.
  • Signed update mirror selection. tiyi update supports auto, github, and gitee mirror modes while preserving SHA-256 and Ed25519 verification before replacing the binary.
  • User-oriented env docs. Runtime env documentation now follows server.yaml config keys only, recommends YAML for persistent service config, and documents config-derived names such as TIYI_AUTH_BOOTSTRAP_ADMIN_PASSWORD and TIYI_LICENSE_KEY_PATH.
  • Public docs cleanup. Operator-facing docs and command help use tiyi update, remove private design references, and keep the website, GitHub public repo, and Gitee public repo aligned.
  • Verified: go test ./..., buf lint, installer syntax checks, and website/public installer lockstep.
v3.0.2 2026-06-28 Shipped
Frictionless install + deterministic first-run admin

A smoother five-minute path from install to a working dashboard login, with no journal-scraping for the admin password.

  • Deterministic first-run admin. sudo tiyi install --now (standalone) pre-creates the admin account before starting the service and prints the login — URL, username, and password — directly from the installer. The one-time secret never reaches journald, and the service skips its own random-password banner.
  • Re-run = in-place update. When tiyi is already installed, install.sh uses the signed tiyi update path (downloading only when a newer release exists) and then re-installs + restarts the service, instead of pulling the full tarball again.
  • Reachable by default. The API and dashboard now bind 0.0.0.0:8080 by default (still login-protected).
  • Verified: go test ./... and frontend unit tests green, plus a live install QA (credential banner, 0.0.0.0:8080 listener, working login) on a clean host.
v3.0.1 2026-06-27 Shipped
Multi-node cluster install + agent operations

Operational hardening for running Tiyi as a multi-node HA cluster, with every node managed by systemd on the default ports.

  • Cluster as systemd services. tiyi install --mode server|secondary|agent writes a hardened unit per node (80/443 via CAP_NET_BIND_SERVICE); the agent/secondary read their control-plane URL and one-use enrollment token from the unit's optional EnvironmentFile at /etc/tiyi/tiyi.env — the nginx-style drop-in. The agent-mode unit no longer carries control-plane-only flags it would reject.
  • WAF on remote agents. Agents materialize the embedded CRS locally and rewrite a delivered bundle's CRS include paths to their own copy, so WAF-enabled sites deploy and block (SQLi / XSS / LFI → 403) on remote agents, not just the control plane.
  • Accurate agent metrics. Per-agent requests/sec, blocked/sec, and active connections now come from the data-plane counters and stream to the control plane (previously always zero); CPU, memory, bandwidth, and goroutines stay exact.
  • Stable agent status. A connected, healthy agent stays online and no longer flaps online↔error — a metrics push refreshes liveness without masking a real apply error.
  • Console fixes. Agent commands from the node list/detail no longer fail with "command kind is required"; the Install Agent code blocks are readable in dark mode and now offer a systemd-service variant; the dashboard shell is served no-cache so UI upgrades load without a manual hard refresh.
  • Verified: go test ./... green, plus a live three-node cluster QA (primary + secondary + agent) covering enrollment, the license scale gate, WAF blocking, metric sync, and agent commands.
v3.0.0 2026-06-26 Shipped
First public release

Tiyi v3.0.0 is the first published GitHub Release: one signed binary distribution channel for Linux amd64 and arm64, with the installer served from both www.tiyisec.com/install.sh and the public GitHub raw URL.

  • Release assets include per-platform tarballs, SHA256SUMS, SHA256SUMS.sig, and release-manifest.json.
  • Downloads verify against release-key.pub using SHA-256 plus Ed25519 signatures.
  • Operators can update an installed binary with tiyi update --yes.
  • GitHub release: Tiyi v3.0.0.
2026-06-24 Shipped
One-binary scale licensing + first-run admin

One binary whose single enforced distinction is scale, not features. Every WAF capability stays in every edition; a vendor-signed license changes only the remote-node budget and displayed plan.

  • Community = local standalone WAF, free forever. With no valid license the full product runs on the local node and permits zero remote agents. Importing a license activates its Pro or Enterprise node budget without replacing the binary.
  • One always-on gate, inside the enrollment transaction. Legacy license.mode rows are ignored and writes are rejected. Count and insert share one transaction, so concurrent enrollments cannot slip past the signed budget. Existing sites, known agents, and local administration are never affected by license state.
  • One trust anchor. Licenses are Ed25519-signed against the vendor public key embedded in the binary; public-key overrides are removed. The release target pins its SHA-256 fingerprint, and schema-versioned claims reject unknown plans, invalid budgets, and bad timestamp ordering.
  • Safe degradation. Missing, invalid, tampered, or expired licenses resolve to Community. The data plane never stops, and known fingerprints always reconnect.
  • Authenticated live status. System → About shows edition, licensee/expiry, and the live "N of M remote nodes" count. License metadata is no longer exposed by the public Version RPC.
  • First-run admin. A standalone first boot with no users and no supplied credentials now auto-creates an admin with a random one-time password (printed once, stored only as a hash); tiyi server prints an actionable warning instead of leaving a silent dead-end login.
  • The vendor tool now creates private keys as 0600 with exclusive no-overwrite semantics; date-only expiries are inclusive through 23:59:59Z.
2026-06-18 Shipped
Site path routing (M9)

A site used to match on host only. It can now fan out by path prefix to multiple upstream pools behind one host and one certificate — API-gateway-style routing — with the data plane and every cross-layer path scope kept consistent.

  • Translator fan-out. One host route expands into per-prefix subroutes, each to its own upstream pool; the existing zero-route output stays byte-identical to before — a golden test pins it.
  • Per-route health. Each route gets a post-apply health probe (200–399 only); a down route backend fails the apply gate even when the site default is healthy.
  • Unmatched policy. Unmatched paths fall through to the site default upstream, or to a strict 404 allowlist that needs no default.
  • Full attribution. Every access-log row records the route_id and upstream_id that served it — through the parser, daily partitions, API/CLI filters, export, and the web log views.
  • One canonical path scope. /admin vs /Admin resolve identically across the WAF, IP lists, and the rate limiter; a case-insensitive hint, live canonical echo, and named case-duplicate error guard every path input on web + CLI.
  • Drive it from tiyi site routing get/set or the new web routes editor. Post-implementation review hardened zero-route/404 validation, atomic compensation capture, stable route IDs across replace, strict per-pool endpoint/scheme/health-URI checks, and canonical scoped CRS overrides.
  • Verified: go test ./... green, buf lint clean, vue-tsc clean. Interactive browser QA was skipped at operator request.
2026-06-18 Shipped
Policy rate-limit editor

The policy Rate Limits tab graduated from a sketch into an operator-usable editor, with validation that refuses any rule the agent could not actually enforce.

  • Endpoint rows. Path-pattern limits (e.g. /login, /api/auth/**) keyed by the resolved client IP, returning HTTP 429 when blocking — or a log-only canary mode to observe a new limit before enforcing.
  • Client scopes. Global ceilings across all paths keyed by ip, the session cookie, or a named header (header:<name>). Burst 0 means the burst equals the per-minute limit.
  • Inline validation. Save is blocked for missing paths/headers, non-positive limits, negative bursts, duplicate patterns/scopes, and unknown actions.
  • Canonicalization. The API folds legacy client_ipip and detectionlog; the compiler and runtime stay backward-compatible with historical rows. Enforced before Coraza, with no persistent collections.
  • Verified: go test ./... green, buf lint clean, vue-tsc clean.
2026-06-09 Shipped
AI advisory layer + interactive Copilot

An optional, default-off LLM advisory layer that sits beside the deterministic WAF — in the control plane, never in the request path, and never mutating state on its own. It enriches incidents, drafts human-approved tuning, and answers plain-English questions about your logs.

  • Streamed analysis. A global AI Copilot slide-over explains any incident or single log event, or analyzes a filtered log result set — streamed token-by-token. Subjects are reduced to redacted whitelist projections, never raw audit JSON.
  • Conversational agent. A StreamChat assistant answers open questions ("top 10 attackers in the last hour", "was example.com attacked today, from which IPs?") by tool-calling over five read-only, tenant-scoped log queries — it adds no new log surface.
  • Advisory, never autonomous. Incident enrichment, policy-tuning patches, NL→log-query translation, draft custom rules (forced log-only canary), and campaign correlation are all proposals; the only state-changing path is an explicit operator Apply routed through the existing audited mutation, gated by ai:apply.
  • Provider-agnostic + safe. OpenAI-compatible (OpenAI / Ollama / vLLM / LM Studio / llama.cpp) and Azure OpenAI; the key is KEK-encrypted, never a setting. Every prompt is redacted, dual-RBAC gated (ai:read plus the subject's own incident:read/log:read), rate-limited, and panic-isolated.
  • Verified: go test ./... green, buf lint clean, vue-tsc clean, i18n_check.py 0 missing, plus a Playwright QA pass against a mock provider.
2026-06-09 Shipped
Air-gap icons, telemetry explorer, static binary
  • Offline icon bundle. The admin console used to fetch icon SVGs from the public Iconify API at runtime — broken in air-gapped deployments. Icons are now collected from the frontend source + backend menu seeds and bundled at build time, registered before first paint.
  • Telemetry explorer. A new Top-N / time-series view over the built-in telemetry pipeline (QPS, top-K, series) — no external time-series database required.
  • Static binary. Release builds are now statically linked (CGO_ENABLED=0, pure-Go SQLite), dropping the build-host glibc dependency so the same artifact runs on older distributions (CentOS 7+).
  • Operator fixes. Stable per-event access-log IDs for exact lookup, boot-time config apply, and a fix that lands permission-restricted operators on the first page they can actually open instead of a hard-coded dashboard.
2026-05-31 Shipped
Security incident aggregation — Phase 1–4

A security_incident layer on top of the per-request security_event stream. It composes with — does not replace — the source-of-truth event rows, the audit chain, the alert evaluator, and SIEM egress.

  • Phase 1 — aggregation. Same (tenant, site, client_ip, attack_class) over a sliding idle window collapses into one incident. A security_incident_event link table (with event_id uniqueness) holds the relationship; security_event.incident_id is a query-accelerator cache. Detection follows OWASP AppSensor; the wire shape follows the OCSF class taxonomy. Migrations 00200021.
  • Phase 2 — operator polish. Reopen, merge, live-tail, and per-site incident overrides. The UI keeps incidents in view after merge/reopen and closes the drawer on re-activate.
  • Phase 3 — deterministic enrichment. Every incident is tagged at creation with its MITRE ATT&CK technique + sub-techniques and kill-chain stage (derived from attack_class + rule-id families) and a most-frequent country/ASN geo rollup. An operator-extensible mitre_mapping overlay (migration 0023) overrides the built-in mapping. Example: an RCE + 933 event yields T1190 [T1059, T1505.003] / execution and geo CN / AS4134.
  • Phase 4 — automated response. An incident_response_rule resource + IncidentResponseRuleService CRUD, and a responder that mutates live controls (deny IP list / rate-limit endpoint / alert webhook) on incident state transitions through the existing audited mutation paths. Default-off at three layers — no rule until created, every rule ships enabled=0, and the tenant kill switch incident.response_enabled defaults false. Every mutation is attributed to system:incident-response in the audit chain. A 60-second TTL sweeper auto-reverts expired deny entries through the audited RemoveIPListEntries path and recompiles the affected policies.
  • Surfaced via the tiyi incident / tiyi incident-response CLI verbs and a web UI under WAF → Automated Response. The Sigma-style operator-defined correlation DSL is explicitly deferred — the fixed 12-class + 4-axis-key correlation is the shipped v1.
  • Verified: go test ./... green, buf lint clean, vue-tsc clean, i18n_check.py 0 missing, plus a per-phase CLI/API runtime smoke test.
2026-05-31 Shipped
Alerting redesign — Phases 1–4 (D1–D14)

The evaluator's deterministic, poll-based shape and SQLite storage are kept; the missing half of every mature alerting system is added — the evaluation/notification split the industry converged on (Prometheus + Alertmanager), with no new external dependencies.

  • Correctness fixes. Closed a UI-exposed rule kind the backend never implemented, threshold counts that were silently capped at the query page size, and channel kinds whose UI/API contracts did not match their delivery implementation.
  • Lifecycle, not fire-once. A notification dispatcher drives pending → firing → recovered/resolved with for-duration debouncing, re-notification while an alert stays open, and auto-resolve — replacing the old "page exactly once, then go quiet" behavior.
  • Durability. A durable notification outbox (migration 0026) plus retry-with-backoff closes the crash-window that could permanently drop the only notification for a new alert. Evaluator state persists in alert_eval_state (migration 0025).
  • Security. Channel secrets (webhook URLs, PagerDuty keys, Slack tokens) moved from plaintext JSON to KEK-encrypted storage and are no longer returned verbatim on read or into the audit chain (migration 0024).
  • Quiet by default. Grouping, inhibition, and silences, plus a per-alert note timeline, rule lifecycle, and channel routing.
  • Implemented the previously-missing RPCs, audited silence mutations, and pruned dead cert UI along the way.
2026-05-31 Shipped
Pre-merge security + QA hardening
  • Fail-open RBAC gap closed — several system and certificate admin RPCs did not enforce a permission check and defaulted to allowing the call. Now gated, with a rbac_coverage_test.go regression test that asserts coverage across the surface.
  • Standalone dashboards read zero traffictelemetry.enabled defaults true, which gates off the legacy rollup writer, but the embedded StoreAccess path never called telemetry.Ingest, so access traffic was recorded nowhere the dashboard reads. Fixed by ingesting in StoreAccess, with a regression test.
  • Race-aware test budgetTestFlushReturnsTrueWhenDrained had a hard 2s drain budget the race detector's overhead blew past; made it race-aware. Also fixed a pre-existing gofmt drift so make lint is green.
v3.0.0-rc.1 2026-05-27 Shipped
Direct page-jump pagination for log views

CursorRequest.offset with a 100k cap, mutually exclusive with the cursor path. Offset accounting runs over post-filter rows so CIDR/rule filters skip the right number of matched rows. The frontend drops cursorStack + walkForwardTo in favor of computing offset directly from the target page.

  • 4 store tests + 2 wire tests pin offset semantics and rejection of cursor+offset misuse
  • Files: proto/tiyi/v1/common.proto, internal/store/log_repo.go, internal/api/log_handler.go, three log list .vue files
  • Verified: go test ./... green, buf lint clean, vue-tsc clean
2026-05-26 Shipped
Six post-deploy QA fixes
  • DEF-002 — IP-list geo:CC entries accepted at the API boundary (alpha-2/alpha-3 + curated PRIVATE/LOOPBACK buckets); the seclang compiler already expanded them at compile time, so the entry now flows through end-to-end without forking the dataset.
  • DEF-003 — bookmarkable parametric routes (/agents/:id, /waf/policies/:id) re-registered after the backend menu generation drops them; router.hasRoute guards against double-registration.
  • DEF-004ResolveAgentGroup now resolves selectors against ListAgents for either a saved-group id or an ad-hoc spec preview (matching by match_agent_ids ∪ tag_selectors).
  • DEF-005 — standalone agent commands now drained through a 2-second consumer; reload calls ApplyActiveSites; restart succeeds as a no-op (tearing down the local management plane is the wrong default).
  • DEF-006 — trust-profile mutations now write trust.update_profile, trust.reset_profile, trust.update_site_override, trust.reset_site_override, trust.refresh_cdn rows into the audit chain.
  • DEF-007 — access log default RecordingMode flipped from "off" to "on" at three layers, matching the System Settings copy "默认访问日志模式 = 完整(自动)".
2026-05-24 Shipped
Security hardening + frontend cleanup

Code-review pass on the full backend tree closed every actionable finding without dropping a feature.

  • KEK persistence — server only calls db.SetKEK(envelope.LoadKEK) when crypto.kek_file is explicitly configured. Previous unconditional override generated an ephemeral KEK on every restart, silently breaking encrypted cert keys, ACME accounts, and DNS provider credentials.
  • Persistent ed25519 bundle signing key — singleton row in bundle_signing_key, KEK-encrypted at rest. Pre-warmed in store.Open after migrations and Bootstrap. Replaces the per-restart in-memory generator that was defeating the agent's TOFU pin.
  • Agent revision replay protectionapplyConfigUpdate rejects any incoming bundle whose revision is not strictly greater than LastAppliedRevision.
  • Migration drift detectioninternal/store/migrate.go records SHA-256 of every applied migration; boot aborts on drift.
  • Frontend cleanup — dropped 16 Vben demo pages and 5 supporting .ts files, rewrote the layout shell, fixed broken role checks comparing against 'standby'/'active' (real values are standalone|primary|secondary).
2026-05-24 Shipped
WAF tune review — PRs 1–8

Deep review of the policy tune drawer surfaced and closed every actionable defect across eight coordinated PRs. Highlights:

  • Audit chain coverage — every Upsert/Update/Delete on rule_override, custom_rule, ip_list, ip_list_binding, rate_limit_endpoint now appends a hash-chained mutation row; previous code silently bypassed it.
  • Score-override emit — switched from additive setvar:tx.inbound_anomaly_score=+N to per-bucket tx.<sev>_anomaly_score_pl<pl> reset+set, eliminating double-count.
  • Bulk upserts atomicBulkUpsertRuleOverrides runs N upserts in a single transaction, all-or-nothing, with one bundle-hash refresh and one apply at the end.
  • Rule override action enumDEFAULT|DISABLE|LOG_ONLY|SCORE_OVERRIDE; legacy disabled bool and action string deprecated; score_override migrated to optional int32.
  • Field-mask discipline — UpdatePolicy enforces that empty ip_list_bindings only wipes when update_mask.paths includes the field.
  • Path-prefix validation — rejects non-printable ASCII and SecLang quoting metacharacters at the API boundary.
  • i18n locale parity — 1786/1786 keys balanced across en-US and zh-CN with vue-i18n linked-message escapes for every @-prefixed literal.
2026-05-16 Shipped
Client-IP trust pipeline

One trust pipeline ends per-component XFF parsing fragmentation. Replaces the blind XFF-first parse in the rate-limiter — the security-class fix.

  • tenant_settings.trust_profile_json + site.trust_profile_override_json
  • Auto-fetched CIDR snapshots for Cloudflare, Fastly, Akamai, CloudFront, Front Door, GCLB; refresher with per-job goroutine, jittered interval, and panic isolation
  • Translator emits trusted_proxies + trusted_proxies_strict per http.servers block
  • Strict right-to-left walk with verbatim Caddy v2 byte-for-byte semantics
  • TrustService.Explain traces every header to the resolved client IP for any (peer, headers) tuple
  • Default-on alert: Origin Bypass Attempt (5-minute window, severity high)
2026-05-10 Shipped
Telemetry pipeline (Phase 1–6)

Full counters → samples → API tree → read API → Prometheus exporter pipeline end-to-end.

  • Phase 1 — sharded ingress ring, 10s open-bucket aggregator, per-day SQLite partitions at logs/rollup_10s/YYYY-MM-DD.db
  • Phase 2 — Misra-Gries Top-K with __other__ bucket so SUM(*) equals true traffic; per-day dictionary log; hour/day/month downsamplers
  • Phase 3 — per-IP LRU + global sample rings; append-only circular-file WAL with CRC; replay-on-boot
  • Phase 4 — per-site URL prefix tree with MaxNodesPerSite + MaxDepth; janitor evicts idle low-traffic leaves into api_tree_archive
  • Phase 5 — REST API at /api/v1/telemetry/* + frontend explorer
  • Phase 6 — Prometheus exporter at /metrics on the local admin socket
  • Legacy cutoverlogsink.recordAccessRollup short-circuits when telemetry is active, ending the per-event traffic_rollup_minute write that amplified I/O at high event rates
2026-05-09 Shipped
Frontend shell complete

Every server-seeded menu route resolves to a real page, the core admin pages are wired end-to-end, and the reusable Tiyi UI components ship.

  • Dashboard with GetDashboardStats, GetTrafficTimeseries, GetAttackDistribution, GetTopAttackers, StreamAlerts
  • Policy editor with 12 tabs, deep-linkable: CRS Core · HTTP Policy · Limits · Rule Tuning · IP Lists · Custom Rules · Plugins · Rate Limits · Exclusions · Preview · Versions · Test Lab
  • System branch: Health, Log Pipeline, Users, Roles, Settings (10 tabs), Replication, Updates (4 tabs), About
  • Alert Rules, Alert Channels, IP Lists, Agents detail, Telemetry Explorer, Audit + diff drawer
  • Resilience primitives: useResilientStream, formatRpcError, useResponsiveWidth
  • Full zh-CN + en-US, all $t() call sites resolve
2026-05-07 Shipped
WAF policies — full lifecycle

Store/API/Web/CLI CRUD; built-in templates (Strict/Standard/Permissive); version snapshots and rollback; engine-state switch; CRS binding; rule-override / custom-rule / IP-list / plugin / rate-limit tuning paths; SecLang preview; CRS impact preview; policy test lab.

  • Deterministic SecLang compilation with CRS best-practice advisory warnings
  • Per-site policy overlays cover scalars plus site-scoped rule/custom/IP-list/rate-limit tuning without forking the policy
  • CRS rule-exclusion packages (WordPress, Drupal, Nextcloud, phpBB, phpMyAdmin, XenForo, cPanel, DokuWiki) with offline archive upload
2026-05-07 Shipped
Remote agents

One-use enrollment tokens, mounted AgentStream, tiyi agent runtime, live remote bundle delivery / cache / apply-result reporting, best-effort remote access/security/error log upload.

  • Pinned bundle-signing public-key verification, TOFU on first contact
  • Periodic metrics push (memory/CPU)
  • Agent role tracking (primary / secondary / agent)
  • tiyi agents issue-token | install-script | send-command | commands CLI
2026-05-06 Shipped
ACME — Phases A through D
  • Phase A — real RFC 8555 client (wrapping golang.org/x/crypto/acme) replaces the self-signed stub; per-(tenant, directory) account lifecycle
  • Phase B — multi-agent HTTP-01 with a loopback responder on every agent and (token, key_authorization) broadcast through the agent stream
  • Phase C — DNS-01 with pluggable driver registry: full Cloudflare driver, Route53 + Aliyun credential-validating stubs; authoritative-NS-aware propagation checker
  • Phase D — observability: dashboard exposes certs_expiring_14d, acme_renewals_failed_24h, etc.; default alerts seeded
  • UI: "Issue (ACME)" modal, per-row Renew action, "DNS Providers" page
2026-05-05 Shipped
CRS catalog + sites + log forwarding
  • OWASP CRS 4.25.0 ruleset embedded in the binary, auto-imported on first boot
  • GitHub-release fetch via SystemService.ListUpstreamCrsReleases; offline archive upload also supported
  • Sites lifecycle: store/API/Web/CLI CRUD/status; real Caddy JSON preview; uploaded cert and WAF policy selection
  • Standalone runtime: Caddy access logs through tiyi.log_forwarder; Coraza SecAuditLogType tiyi; live security tail
2026-05-03 Shipped
WAF interception fix + boundary defer recover

Closed the "empty reply from server" bug on blocked requests. Root cause: a typed-nil-in-interface panic in audit_writer.auditMessages (message.Data() returned a non-nil interface wrapping a nil *MessageData) unwound coraza-caddy's deferred tx.ProcessLogging before the WAF middleware returned its caddyhttp.HandlerError.

Three boundaries now have defer recover() at function level: audit_writer.Writer.Write, log_forwarder.writeAccessLine/writeWAFLine, and logsink workers. Cross-layer canary at /debug/logsink/stats exposes a panicked counter.

2026-05-01 Shipped
Alerts, audit SIEM, full standalone observability
  • Alert evaluator with security_threshold, error_threshold, audit_failure kinds and webhook / Slack / PagerDuty / Feishu / WeCom delivery
  • Audit-chain rows forwarded through SIEM with explicit siem.filter.include_audit flag
  • RFC 5424 / CEF / LEEF formats over TCP / UDP / unixgram
  • Vben pages for security, access, error, live-tail, audit, alerts (active / rules / channels)
2026-04-28 Shipped
Foundation
  • Go 1.25.0; ConnectRPC 1.19.2; 14 services under proto/tiyi/v1/*.proto
  • SQLite schema (full Phase-1) — audit, CRS, policy_version, config_bundle
  • Server modes: standalone, server/primary, secondary/standby, dashboard, agent
  • Local admin socket with OS-file-permission auth
  • Argon2id login, JWT issue/verify, refresh-token chain
  • Koanf config loader; SQLite open/migrate/bootstrap; permission and menu seeds
  • Audit spine — repo, hash chain, verifier, AuditService, mutation audit rows, tiyi audit CLI
← Back to home