Changelog¶
All notable changes to the SerOps project will be documented in this file.
The format follows Keep a Changelog. SerOps uses Semantic Versioning starting at v1.0.0. Entries under [Unreleased] ship in the next tagged release.
[Unreleased]¶
[1.2.5] - 2026-10-21¶
Personal notifications work again. No migrations: set
SEROPS_VERSION=1.2.5 or --version 1.2.5.
Fixed¶
- Personal notifications for subscribed projects (email, in-app and digests) were not being sent since the September 2026 notifications rework. They work again, now also respect your own severity choices, and daily or weekly digests arrive at 09:00 in your time zone. Deactivated users and users who left the organisation no longer receive them. The notifications guide now describes the real behaviour (opt-in subscriptions; quiet hours suppress rather than postpone).
Changed¶
- The frontend
.env.examplerecommends the relativeVITE_BASE_URL=/apiin production when the app and the API share a host (no CORS setup, one build for any domain).
[1.2.4] - 2026-10-21¶
Integrations screens: dark mode, keyboard access and consistency. No
migrations, frontend only: set SEROPS_VERSION=1.2.4 or --version 1.2.4.
Fixed¶
- Log and metric provider rows, badges, health status and the provider dialogs ignored dark mode (white rows with light text).
- Provider pickers were not reachable by keyboard; they are now radio cards.
- Source Control showed Add integration twice and offered Jenkins, a CI/CD-only provider.
- Every Integrations tab has the same header, with the add action in the
same place; tabs are in the URL (
?tab=cicd|logs|metrics). - Integration, provider and cluster dialogs: every field is linked to its label, for screen readers. All 69 provider screens pass an automated accessibility check in light, dark and phone layouts.
- A few panels (postmortem preview, metric tooltips, error panel, project environments) no longer force light colours.
[1.2.3] - 2026-10-20¶
Fixes a 1.2.2 regression. No migrations: set SEROPS_VERSION=1.2.3 or
--version 1.2.3.
Fixed¶
- After saving their profile, a user's browser stored the organisation as
a number, and the new organisation badge in 1.2.2 then broke the
sidebar on every page until site data was cleared. Login, profile and
demo sign-in now all return the organisation's name (plus
organisation_id), and the sidebar ignores anything else. - Demo sign-in returns the user's permissions, so the demo shows the right controls straight away.
[1.2.2] - 2026-10-20¶
A security release from an internal review and penetration test of roles, permissions and multi-tenancy, plus confirming an issue's root cause when resolving it, one issue per shared cause, and logos and photos stored in the database. Read the upgrade notes: re-run Setup Webhook on each repository binding. Migrations Data 0051–0053, Projects 0015, Organisations 0013, Users 0012.
Added¶
- Resolving an issue from its panel asks you to confirm or correct the
root cause and the fix (prefilled with the AI's). Later analyses use the
team's version first and see what the AI had said when it was
corrected; similar-incident search uses it too. The panel shows who
confirmed it. Migration
Data 0052. - Evidence on the analysis page links to where it lives: a commit to the batch's code changes (highlighted), a metric anomaly to its metrics, a pipeline to the timeline, and the failing trace to the trace.
- The organisation logo is shown next to the organisation name in the sidebar. Settings → General and Profile have Remove logo and Remove photo.
Security¶
- Dependencies with known vulnerabilities upgraded: Django 5.1 → 5.2
LTS (5.2.17; 5.1 is past end of support), Django REST framework
3.17.2, PyJWT 2.15, Pillow 12.3 (uploaded logos and photos go through
it), requests 2.33, urllib3 2.8, and others. React Router 7.18 in the
frontend. Two unused packages removed (
djangorestframework-simplejwt,react-stepper-horizontal, which pulled in React 15).pip-auditandnpm auditreport no known vulnerabilities. - The Django admin (
/api/admin/) is off by default (setDJANGO_ADMIN_ENABLED=Trueto use it). It had no limit on failed logins, while every install has a superuser from the quick start. When enabled, its login now allows 10 failures per 10 minutes per client. Login rate limits also stop trusting client-writtenX-Forwarded-Forentries (TRUSTED_PROXY_COUNT, default1). - The app's pages were served without security headers (an nginx
inheritance pitfall dropped them), so on Helm installs another site
could embed SerOps in a frame (clickjacking). Every response now
carries
X-Frame-Options: DENY,frame-ancestors 'none',nosniff, a Referrer-Policy and a Permissions-Policy. Docker Compose installs were covered by Caddy. - An admin could change another member's email (then reset their password and sign in as them). The team API no longer changes emails; members change their own in their profile. The last admin of an organisation can no longer be demoted or removed, and an invalid role returns an error instead of a server error.
- A user of one organisation could create or delete webhooks on another organisation's GitLab project, using that organisation's stored token. Webhook actions now only act on the caller's own projects.
- Only admins add, edit, delete or test SCM/CI integrations (they hold credentials), as already for log/metric sources; only admins delete projects and services; viewers no longer read the security and SSO settings. The Integrations and Projects pages hide those controls from users who can't use them.
- Viewers are read-only again everywhere: they could trigger AI analyses and post-mortem drafts, change legacy GitLab projects, run provider checks, acknowledge issues and change the setup flow.
- The AI provider list is shared by every organisation; on installs with several organisations, only platform staff can change it now (an organisation admin could change or delete a provider for everyone).
- The SCM webhook receiver (
/api/webhooks/scm/<id>/) accepted any payload when a binding had no secret, so a guessed binding id let an unauthenticated caller inject code-change data into a project. Every SCM binding now gets a secret on creation and the receiver rejects a binding without one. Existing bindings are backfilled (migrationProjects 0015); re-point the provider-side webhook via Setup Webhook to send the new secret. - The legacy GitLab project list (
GET /api/providers/) returned the stored access token (encrypted, but still) to any member of the org, including viewers. The token is write-only now and never returned. - Permissions are checked one way everywhere, modelled on Airflow and
Grafana: a catalogue of named permissions (
project.write,integration.manage, …) granted to the three roles, plus two platform permissions no organisation role holds. Every API endpoint declares the permission each method needs, and anything undeclared is refused. A test fails the build when an endpoint declares nothing, so a new endpoint can't ship open to every signed-in user. Nine overlapping role checks were replaced. See Team Management and Permissions. - Viewers no longer read retention, data usage or the AI budget (now
settings.read, like the security settings). - Superusers could read and change any organisation's data through the API (batches, post-mortems, issues, projects, including deleting them), and this wasn't audited. The quick start creates a superuser, so on an install with several organisations its operator could reach every tenant. Superusers and staff are now held to their own organisation like everyone else; install-wide operations use platform permissions.
- A test now calls every API route as another organisation's admin and superuser, and fails on any leak, so a new endpoint can't ship without the organisation filter.
- Ids sent in request bodies were not always checked against your
organisation. A member could create a service in another
organisation's project (
POST /api/services/…with its id), subscribe to another organisation's project and receive its incident notifications, see another organisation's project names through an escalation rule, and attach another organisation's environment or cluster to a deployment. Every writable relation is now limited to your organisation, and a test fails the build when a new one isn't. - A CI/CD binding could take over another organisation's GitLab project (the legacy record is shared per GitLab project id): binding the same pipeline id moved it, with a new token, to the binding's organisation, whose legacy webhook paths then received the other organisation's CI events. The record now stays with its organisation.
- Refused requests are recorded in the audit log (Access Denied,
with the missing permission), once per user and path every 10 minutes.
Audit entries now record the client address seen by your proxy, not an
address the client wrote into
X-Forwarded-For. MigrationData 0053. - The Helm chart no longer publishes
/metrics/on the ingress. It has no authentication by default, so on Helm installs anyone could read the install's request, analysis and AI-token counters (no organisation data). Prometheus scrapes it inside the cluster; see Self-metrics to publish it with basic auth. - The backend no longer has a
/images/route. Nothing used it, and withDEBUG=Trueit served the backend directory,.envincluded. Production settings (DEBUGoff) never served it.
Fixed¶
- Uploaded organisation logos and profile photos never displayed on a
production install (they were served only with
DEBUGon, and on Helm only one backend pod had the file). Both are now stored in the database, resized to a small PNG. MigrationsOrganisations 0013andUsers 0012: existing profile photos are imported from the media volume; existing organisation logos were never kept there and must be uploaded again. - Uploading a profile photo now updates the page and the top bar straight away.
- On the analysis page, each issue shows its status, and its button reads View issue (it said "Open", which read like a status).
- Memory and CPU metrics answered with a server error when no metrics
source was configured; they return an empty result now.
GET /api/settings/api-keys/<provider_id>/returned a server error; it returns that provider's key (masked).
Changed¶
- One shared cause is one issue. When DNS, a cache, a database, a
certificate or one deploy breaks several services, SerOps raises one
issue on the component where the cause lives and lists the others as
"also affects", instead of one CRITICAL issue per service. Filtering
issues by a service includes causes elsewhere that affect it.
Migration
Data 0051(newaffected_servicesfield). - The SerOps mark in the sidebar is smaller.
- The login and profile responses list the user's
permissions. The app shows buttons and settings pages from that list instead of its own copy of the role table: the Settings menu now only lists the pages a role can open, and role changes apply when the app next loads. - Users (not only admins) can run a health check on an existing log or metric source, like verifying any other integration.
[1.2.1] - 2026-10-19¶
Fixes found by testing SerOps' root cause analysis on twelve simulated
incidents: the AI now sees every data source a batch carries, and diff
line numbers survive redaction. Also the SerOps "SO" logo and corrected
Helm install docs. No migrations: set SEROPS_VERSION=1.2.1 or
--version 1.2.1.
Fixed¶
- The AI now sees all the incident data in a batch. Logs, metrics, code changes, CI results and traces were left out of the prompt whenever the organisation had no integration configured for that source, even though the batch carried them (OpenTelemetry traces, webhook commits and CI results, and alerts arrive without one). A source now counts as available when it is configured or the batch has data from it.
- Code diffs sent to the AI kept their hunk headers: the phone-number
redaction turned
@@ -88,9 +88,9 @@into@@ -88,9 [PHONE],9 @@, dropping the line numbers that tie a change to a stack frame. - A rejected Gemini key ("API key not valid") is reported as an authentication error instead of an unknown one.
- Helm docs: the from-source install command failed (setting one field of
ingress.hostsdropped its paths), and neither install explained how to use your own hostname; both now use a small values file.
Changed¶
- The app uses the SerOps "SO" logo again (sidebar, sign-in pages, browser icons).
[1.2.0] - 2026-10-18¶
A redesigned app, root cause analysis that reads the part of a diff the
incident points at, code diffs for every SCM provider, and redaction of
code before it reaches the AI. No database migrations and no new
environment variables: upgrade by setting SEROPS_VERSION=1.2.0
(Docker Compose) or --version 1.2.0 (Helm).
Added¶
- The AI reads the part of a diff the incident points at. Diff excerpts are chosen from the stack traces and error text in the batch's logs (Python, JavaScript/TypeScript, Java/Kotlin, Go, Ruby, PHP, C#): whole hunks around the named lines and functions, within a fixed budget of about 3,000 tokens. Previously each file got its first 500 characters.
- Diff text for GitHub, Bitbucket and Azure DevOps. Only GitLab stored diff content before; the others stored file names and line counts only.
- Azure DevOps repositories. The repository picker lists Git
repositories across the organisation, and bindings accept
organisation/project/repository, so repositories named differently from their project work. The organisation saved on the integration now reaches every request. - Redesigned app: grouped navigation (Integrations and Alerts & routing now have their own entries; Dashboard is Overview, Data is Analyses), an environment picker on every page, full-width pages, a single page header, compact settings controls, the SerOps logo, and dark mode across every page. The list of received traces is reachable from Settings → Distributed Traces and the ⌘K palette.
Security¶
- Code diffs and commit messages are redacted (credentials, tokens, emails) before they reach the AI, like logs. If redaction fails, the diff text is left out. See What SerOps reads from your repositories.
Fixed¶
- Correlations were dropped for a whole batch when an error log named a file and the batch had code changes.
- Settings → AI showed $0.00 spent this month when no budget cap was set.
- An open tab no longer shows an error after an upgrade; it reloads into the new version.
- Turning off deduplication, recent resolutions or auto-cleanup could not be saved.
[1.1.1] - 2026-10-17¶
Fixes found by end-to-end testing of v1.1.0 on Kubernetes: Sentinel now
skips recurring errors, trace error spans are recognised, chat uses the
selected model, and deploy and notification webhooks are hardened.
Upgrade by setting SEROPS_VERSION=1.1.1 (Docker Compose) or
--version 1.1.1 (Helm).
Fixed¶
- Sentinel skipped almost nothing. It compared log patterns with issue fingerprints (a different hash), so every window containing a warning or error counted as a "new error pattern" and went to the AI. Sentinel now remembers the warning/error patterns it has seen per project and environment (numbers, IDs and timestamps ignored) and forgets one after 6 hours unseen, so recurring errors no longer trigger analysis while new or returning ones still do. The "issue regression" rule, which could never fire for the same reason, is removed.
- Spans from OpenTelemetry JSON exporters lost their status and kind. OTLP/HTTP JSON sends these as integers, which were ignored, so failing spans never counted as errors in the analysis.
- AI chat always used Gemini, whatever model was selected, and failed on installs without a Gemini key.
- Argo CD and Flux deploy events could not authenticate. Argo CD cannot
compute the documented HMAC and Flux sends its signature in another
header. Argo CD now sends the binding secret as a bearer token, and
Flux's
generic-hmacsignature (X-Signature) is accepted. See GitOps deploy events.
Security¶
- Slack and Teams channel URLs must be public https URLs, checked when saved and again when sending, so an organisation admin cannot make the server call internal services or the cloud metadata endpoint.
- Deploy webhooks refuse unsigned events. A binding without a secret no longer accepts anything, and unknown bindings and bad signatures get the same answer, so binding IDs cannot be probed.
Upgrade notes: migrations Data.0049 and Data.0050 run
automatically. If you send deploy events from Argo CD or Flux, update their
configuration as described in GitOps deploy events.
[1.1.0] - 2026-10-17¶
A UI release: SerOps opens on what is broken and why, with an incident
page, ⌘K search, dark mode, phone layouts and WCAG 2 AA accessibility.
Upgrade by setting SEROPS_VERSION=1.1.0 (Docker Compose) or
--version 1.1.0 (Helm).
Upgrade notes
- No database migrations and no configuration changes.
- The issue list API gains optional filters (
project,environment,component,since_hours); existing calls are unchanged.
Added¶
- The Overview opens on what's broken now: the most severe open issue with why it is happening and what to do, plus the next ones, before the numbers. "All clear" when nothing is open.
- Incident page: a batch is titled by the AI's hypothesis, with Acknowledge (stops escalation for its open issues), Copy link, Draft post-mortem and Re-run analysis.
- ⌘K / Ctrl+K search: jump to any page, open issue or project, start an investigation or switch theme from the keyboard (also in the top bar).
- Dark mode that works everywhere, and a compact density option in the profile menu.
- Issues: filter by time ("seen in the last 24 h / 7 / 30 days", API
since_hours), a Last seen column, and when the list last refreshed. - UI quality checks in CI: every main page is checked for accessibility (WCAG 2 AA, light and dark), phone layout and table alignment against the quick-start stack built from the commit, with screenshots in the report.
- Issues side panel: click any issue (or press Enter) to read its root
cause, recommendation and correlations without leaving the list, then
resolve, mute, acknowledge, open the analysis, investigate that time window,
ask the AI or copy a link (
/dash/issues?id=…). - Issues filters: filter by project, environment and service; the severity
and status tiles are now clickable filters; a result count shows what
matches. The API's issue list accepts
project,environmentandcomponent(the service).
Fixed¶
- Read-only demo: every refused change now shows one friendly notice
instead of a different error per page ("Error", "Rotation failed", a raw
demo_read_onlycode), and Settings says up front that it is read-only. /notificationscrashed; it is now a full page at/dash/notifications(the digest email links there).- 89 English and 101 French interface texts were missing, so some labels
showed raw keys (
common.active) and French users saw English. A test now fails if a key is missing from either language. - The timeline's lane toggles were unreadable (coloured text on grey).
- Browser tabs are titled per page ("Issues · SerOps") instead of all reading "SerOps".
- Profile and registration labels fell back to a serif font; the demo user's role reads "Read-only demo".
- Settings → General showed the same heading twice; Investigate now defaults to the production environment.
- Issues: rows show readable status labels, the root cause under the title and full service names; bulk actions only offer what applies to the selection; phones get one card per issue instead of a cut-off table.
- Tables on the batch page and in Settings → Audit log were narrower than the search bar above them (a Data-page style leaked onto every table).
- Phones: tables turn into one card per row (Data, Projects, Delivery, Traces, Investigate, Team, Audit log and more); the batch page, Dashboard charts, timeline and metrics no longer overflow or overlap.
- The Create Project dialog kept Save below the screen; the 7-day trend drew smoothed hills between whole counts (now bars); Recent AI analyses hid most items in a small scroll box; the investigation / alert badge sat in the Environment column (now a Trigger column); an empty batch showed an empty table.
- Typing
(or[in the Data or batch log search crashed the page. - In the live demo, Settings disables every change with an explanation instead of letting Save, Test or Rotate fail.
- The last rows' action menus on Issues were cut off.
Accessibility¶
- The main pages pass an automated WCAG 2 AA check (axe) with no violations, down from 214: secondary text, badges, links and health tiles meet 4.5:1 contrast; icon buttons, links and form fields have accessible names; the user menu's list structure and decorative charts are fixed.
[1.0.3] - 2026-10-15¶
A security and feature release: SSO tenant isolation, Investigate
(on-demand analysis), and fixes that make scheduled and alert-triggered
analysis work on Kubernetes. Upgrade by setting SEROPS_VERSION=1.0.3
(Docker Compose) or --version 1.0.3 (Helm).
Upgrade notes
- Migrations run automatically:
Users.0011(drops the unused SAML and realm fields),Data.0048(investigations, batchtrigger; existing alert batches are tagged),notifications.0007. - Helm installs: scheduling and AI analysis never ran before this
release (see Fixed). After upgrading, drop the stale scheduler backlog
once:
kubectl exec deploy/<release>-celery-worker -- celery -A api purge -Q normal -f. - A Helm install with
django.publicUrlunset now derivesAPI_URLfrom the first ingress host (https when TLS is configured).
Security¶
- SSO could sign in as a member of another organisation. The SSO callback matched the email the identity provider returned against every user, so an admin who pointed their organisation's SSO at a provider they control could sign in as anyone. It now signs in only members of the organisation that started the flow, refuses inactive users and emails the provider marks unverified, and checks SSO is still switched on.
- The login and SSO endpoints revealed which emails have an account. Login answers an unknown email and a wrong password the same way, and SSO sign-in gives one answer whenever SSO is not available.
- SSO sign-in showed internal errors. An organisation without security
settings got
500 "SecuritySettings matching query does not exist.".
Added¶
- Investigate. Analyse a time window now, from the sidebar, a
deployment on the dashboard ("Investigate") or a batch ("Re-run
analysis"). Same pipeline as scheduled analysis; Sentinel never skips
it, it reads the whole window, and it notifies only the requester unless
routing is opted in. Limited to two running and ten an hour per
organisation. See Investigate and the
/api/data/investigations/API. MigrationData.0048. - Batches carry
trigger(scheduled,alert,manual), shown as a badge on alert and investigation batches. DEMO_ONLY_LOGIN=true, for a public demo host: the login page shows only "Try the live demo", and password login, SSO and password reset are refused server-side.- Settings → Security shows the redirect URI to register at the identity provider.
Changed¶
- "Try the live demo" appears only where a demo user is seeded.
- A failed SSO sign-in returns to the login page with a message instead of a JSON error.
- SAML settings are removed (migration
Users.0011). SAML sign-in never worked; use OpenID Connect, which Okta, Entra ID, Google and Keycloak all support. Organisations set to SAML have SSO switched off. - The unused SSO "Realm" field is removed; the discovery URL already names the realm.
- Helm: the chart now sets
API_URLandREACT_URLfrom the ingress host (ordjango.publicUrl). They were unset, so the SSO redirect URI readNone/auth/sso/callbackand account activation emails failed.
Fixed¶
- Helm: no batch was ever scheduled or analysed. The worker consumed
only the
high_priorityandceleryqueues, while the scheduler runs onnormaland AI analysis onbackground, so those tasks waited forever. The worker now always consumes all four queues, including on releases upgraded with--reuse-values. Periodic tasks now expire after one interval, so a backlog is not replayed. After upgrading an existing Helm install, drop the stale scheduler backlog once:kubectl exec deploy/<release>-celery-worker -- celery -A api purge -Q normal -f. - Batches could be linked to another organisation's project. The pipeline looked the project up again by name, and names are only unique within an organisation. It now uses the project it was given.
- Alert-triggered analysis never ran. The alert's environment reached
the pipeline as text and crashed it. Alert batches are now created,
tagged
alertand linked to their alert exactly. - The scheduler skipped data after an alert batch. The next scheduled window started at the alert batch's creation time; minutes before the alert window were never analysed. Scheduled windows now continue from the previous scheduled batch's end, per deployment.
- Settings → Security showed saved SSO settings as empty after a reload.
- SSO sign-in could not complete on a plain-http install: the handoff
cookie was always
Secure, so the browser dropped it. It isSecurewhenever the install is served over https.
[1.0.2] - 2026-10-14¶
A bug-fix release. Upgrade by setting SEROPS_VERSION=1.0.2 (Docker
Compose) or --version 1.0.2 (Helm). No migrations.
Fixed¶
- Helm: the backend never became ready. The chart set
ALLOWED_HOSTSto the ingress host only, but the kubelet's health checks connect by pod IP, so Django answered 400 and the backend restarted in a loop on every install. The checks now sendHost: localhost, which the chart always allows. - Helm: settings-only upgrades kept the old settings. Backend and Celery pods now restart when the chart's ConfigMap or Secret changes.
- The 7-day trend on the dashboard now includes today.
- The root cause legend shows category names instead of 0, 1, 2.
- AI feed summaries no longer stop at a dot inside a word ("v2.3.4").
- The correlation rate counts an issue linked to both a deploy and a metric once.
- Recent deployments names the CI a service is bound to when it has no runs yet.
- The cluster list loads after login; it was requested on the login page and never retried.
- Settings → Security no longer reports an error on a new organisation's first visit.
- The Critical card reads "All clear" when there are no critical issues.
Changed¶
- The Helm chart prints next steps after
helm install. - Users without an avatar get their initials instead of a stock photo; the unused template images are removed.
Upgrade notes¶
- Helm users on 1.0.1 must not upgrade with
--reuse-valuesalone: it keeps 1.0.1's health-check settings. Pass your values again, or use--reset-then-reuse-values(Helm 3.14+).
[1.0.1] - 2026-10-13¶
A security and bug-fix release. Upgrade by setting SEROPS_VERSION=1.0.1
(Docker Compose) or --version 1.0.1 (Helm); the database migration runs on
start.
Security¶
- Integration secrets are encrypted and write-only. Credentials kept in an
observability integration's
extra_config(Datadogapi_keyandapp_key, bearer tokens for Prometheus, VictoriaMetrics and Mimir, and similar) were stored in plain text and returned by the integrations API to every member of the organisation, viewers included. They are now encrypted at rest and never returned; responses list which ones are set insecret_fields_set. Migrationintegrations.0010encrypts existing rows. - AWS CloudWatch never uses the server's own AWS credentials. An integration without an access key used to fall back to the host's environment, instance profile or pod role. Both halves of the key are now required, as Google Cloud and Azure already required their own credentials.
- The backend refuses to start while a secret still holds the
change-meplaceholder from.env.example.
Fixed¶
- AWS CloudWatch works. The AWS SDK (
boto3) was missing from the image, so the integration could not load in 1.0.0, and the keys entered in Settings were saved under names the adapter did not read. The access key ID is now the integration's username and the secret its (encrypted) password; Settings and the onboarding wizard ask for region, key ID and secret. - The Distributed Traces settings entry is always visible, so OTLP ingest keys can be created before any trace exists.
- The SAML option is gone from Security settings: SAML has no login flow yet. Use OpenID Connect.
- Chat labels replies with the provider's display name ("Google Gemini" instead of "gemini").
- Documentation URLs without a trailing slash no longer redirect out of
/docs.
Changed¶
- Open registration closes automatically once the first organisation
exists.
REGISTRATION_ENABLEDunset means automatic; set it toTrueto keep sign-up open for everyone, orFalseto close it from the start. - Quick start: images are pinned with
SEROPS_VERSION, migrations run on start, and localhost is served over HTTPS by Caddy.
Upgrade notes¶
- CloudWatch integrations created on 1.0.0 must be edited once: open Settings → Global Integrations and enter the access key ID and secret access key again. The fields saved by 1.0.0 were never read.
- If you rely on open sign-up, set
REGISTRATION_ENABLED=Truebefore upgrading; otherwise new accounts are by invitation once an organisation exists.
[1.0.0] - 2026-10-11¶
First public release: images ghcr.io/getserops/backend:1.0.0 and
ghcr.io/getserops/frontend:1.0.0, Helm chart
oci://ghcr.io/getserops/charts/serops 1.0.0. The entries below are what
changed between 0.9.0 and 1.0.0.
Added — Notification delivery model¶
SerOps notifications now follow the Grafana / Alertmanager / Sentry pattern: one uniform table of delivery targets plus one routing table that decides which targets fire for which incident.
- Settings → Delivery Channels replaces Settings → Notifications.
Email, Slack, Microsoft Teams, PagerDuty, and OpsGenie are all
channel kinds in a single table. Email is no longer a special
case with its own page. Recipients for an email channel live in the
channel's
extra_config.to(single address, list, or comma-separated string). - Settings → Routing Rules is new. Each rule declares a matcher — minimum severity, environments, services, event types, all AND-ed, with an empty value meaning "no filter on this axis" — and a set of target channels. The dispatcher walks every active rule, takes the union of matching targets, and de-duplicates so a channel matched by several rules is still contacted once.
- Per-organisation alert-ingest secret (rotate from Settings →
Delivery Channels). Inbound Alertmanager / Grafana / Datadog
webhooks authenticate with
Authorization: Bearer <secret>. The plaintext is shown exactly once on rotation; SerOps stores only its SHA-256 hash. Deployments that used the globalALERT_WEBHOOK_SECRETSsetting keep working — the per-org secret takes precedence only when set.
Added — Distributed-trace evidence in root-cause analysis¶
- Trace spans now reach the AI prompt as first-class evidence. A batch whose window contains a slow or failing span gets that span cited by ID in the resulting hypothesis, letting the analysis name a database lock or an upstream timeout instead of stopping at the surface symptom.
Added — Quality and accessibility test infrastructure¶
- Real-prod gauntlet (
backend/tests_gauntlet/): 68 synthetic but realistic batches covering PII leakage, prompt injection, cross-tenant isolation, Sentinel edge cases, provider failure, 100k-event volume noise, multi-hop cascades, misleading CI/CD signals, and log-format chaos. See Testing. - UI invariants (
frontend/tests/e2e-invariants/): a Playwright suite asserting no console errors, no object-coercion artefacts in rendered text, dark-mode legibility, mobile layout integrity, i18n completeness, and zero criticalaxe-coreaccessibility violations.
Changed¶
- Batch re-analysis is now explicit about intent. The batch list offers Re-run primary analysis (rewrites the batch's primary hypothesis and refreshes its issues) separately from Compare against another model (records a second opinion without touching the primary). Previously "Re-Analyze" only ever did the latter, so it appeared to do nothing.
- Analysis comparison and promotion. A batch with more than one analysis shows them side by side; any alternative can be promoted to primary, which re-runs issue de-duplication so existing triage state survives.
- Escalation is controlled by rules alone. The organisation-wide
escalation_enabledtoggle is gone; escalation now happens when anEscalationRulematches, and does not when none does. - Correlation confidence is calibrated. HIGH / MEDIUM / LOW now have documented meanings tied to explicit time-window and sample-count thresholds rather than ad-hoc scoring.
- Batch Detail is a root-cause page, not a log dump. The AI hypothesis, detected issues, and evidence tabs lead; raw logs sit below in a real table with timestamp, level, and service columns.
Fixed¶
- Correlations no longer disappear on batches without a deployment
chain. Staged code changes are used as evidence when no
Deploymentrecord links them, restoring commit correlation for self-hosters who push code events directly. - A failed AI call no longer leaves the UI spinning. Batches whose analysis fails now record a terminal state, so the detail page shows the error instead of an indefinite loading indicator.
- Alert-to-project resolution prefers wired projects. When several projects share a service name, the one with SCM and CI/CD integrations connected wins over an empty placeholder.
- Transient AI provider errors are retried with exponential backoff instead of failing the batch on the first 5xx.
- The AI hypothesis renders as prose. A serialisation bug could store the raw analysis object in the narrative field, producing a wall of braces on the batch detail page.
- Mobile layout no longer scrolls horizontally on the dashboard, batch list, issues list, or batch detail.
- Accessibility: labelled every previously unlabelled search input, checkbox, filter select, and icon-only button across the batch and issue lists.
Removed¶
org_settings.NotificationSettingsand its/api/settings/notifications/endpoints. Delivery configuration moved tonotifications.IncidentNotificationChannel(see Added — Notification delivery model above). Existing email, Slack, and Teams settings are migrated automatically into channel rows on upgrade, and a catch-all routing rule is created per organisation so delivery behaviour is unchanged. The legacy/dash/settings/notificationsand/dash/settings/incident-channelsURLs redirect to/dash/settings/delivery.
Documentation¶
- Corrected container names throughout: services are
serops-postgres,serops-redis,serops-backend,serops-frontend, andserops-caddy(hyphens, not underscores) since the RFC-compliance rename. - Clarified that AI provider keys are configured in the UI only (Settings → AI → API Keys) and are never read from environment variables — a shared env-var key would pool quota and billing across organisations on a multi-tenant self-host.
[0.9.0] - 2026-09-07¶
Added — Universal Deployment Topology (Batches 47-55)¶
ProjectDeploymentmodel: One row per (environment × cluster × region × namespace) instance of a project. Multi-region, multi-cluster, and namespace-partitioned projects now analyse each copy independently. See Deployments.IntegrationScopemodel +priority_tier: Observability integrations now carry four scope dimensions (cluster, environment, region, namespace) plus a three-level priority tier (primary/fallback/tertiary). Match-scoring routes each deployment to its most specific integration, with tier-based failover on adapter errors.- Batch pipeline switch:
create_batches_for_all_projectsnow iteratesproject.deployments.filter(is_active=True)instead of environments; batches carry adeploymentFK so pipeline output is scoped correctly. - Multi-row Observability panel: Settings → Observability now lists all integrations per capability with tier badges + scope pills + health status. Add / edit / delete inline.
DeploymentContext(frontend): Composed filter across cluster / environment / region / namespace / deployment, persisted as a single JSON blob inlocalStorage. Dashboard, batches, and analytics all forward the composed filter to the backend. LegacyClusterContextimport path preserved via re-export shim.- Deployments API:
GET/POST/PATCH/DELETE /api/projects/deployments/+GET /api/projects/deployments/suggest/?cluster={id}for post-cluster-registration flows. - Pre-creation Sentinel gate: Sentinel decisions can now short-circuit batch persistence (
should_skip_batch_pre_creation), preventing multi-region × multi-env × N-project fanouts from writing hundreds of noise batch rows per hour. Opt-out viaSentinelConfig.pre_creation_gate_enabledfor audit-trail-first users. - Progressive disclosure: Project detail page auto-hides the Deployments tab when a project has ≤ 1 deployment (SMB projects never see the concept). Multi-deployment projects get a full tabbed view.
- 58 new backend tests across
ProjectDeployment,IntegrationScope, scope matching, tier-sliced uniqueness, failover chain, and pre-creation gate. 8 new Vitest specs forDeploymentContext.
Migration notes¶
- Zero user action required. Data migrations seed one
ProjectDeploymentper (project × active env × project.cluster) and oneIntegrationScopeper existing integration (mirroring today's cluster field). Post-save signals keep new rows in sync. - Backwards compatibility:
useCluster()hook is a thin alias foruseDeployment(), legacyserops.cluster.selectedlocalStorage key is migrated on first read, and_best_integration()still accepts the oldcluster=kwarg alongside the newdeployment=kwarg.
[Unreleased] - 2026-02-22¶
Added¶
- Per-Organisation Batch Interval: Batch generation interval is now configurable per-organisation from Settings > Data (5 min to 12 hours). Default changed from 10 to 15 minutes. The old
BATCH_GENERATION_INTERVALenv var remains as a system-wide fallback. - Interval-Aware Scheduler: Celery Beat now ticks every 1 minute (
BATCH_SCHEDULER_TICK_RATE) and checks each organisation's configured interval before dispatching batch creation tasks. - Comprehensive API View Tests (181 tests): Full test coverage for all major view endpoints across the backend:
- Middlewares (29): RBAC permission classes, subscription middleware, query timeout, permission backend.
- Organisations (20): Onboarding status/skip/reset views, model methods, admin-only enforcement.
- Data (55): Batch CRUD, analytics (issue stats, trends, system health), dashboard (MTTR, sentinel, correlations), settings (security, audit log, retention), metrics.
- Projects (45): Project CRUD, service management, SCM/CICD binding lifecycle, webhook receivers (GitLab/GitHub HMAC validation).
- Services (20): Polymorphic ServiceViewSet, SCM/Infra/Custom sub-ViewSets, write-only credential fields.
- Integrations (15): ObservabilityIntegration CRUD, health check, available providers, org isolation, duplicate provider constraint.
- Local Test Database: New
api/test_settings.pywith local PostgreSQL container for stable, fast test runs (2.3s for full suite).
Fixed¶
- Test Suite Auth: Fixed 40+ test failures caused by tests using DRF
Tokenmodel while the project uses Knox authentication. All tests now useforce_authenticate(). - Test Fingerprint Constraints: Fixed 9 test errors from Issue creation without fingerprints violating the
unique_open_issue_per_fingerprint_orgconstraint. - Race Condition Test Resilience: Added UUID-based unique names and retry-on-deadlock teardown to
TransactionTestCasetests for stable runs on remote databases.
[Unreleased] - 2026-02-20¶
Fixed¶
- Webhook Secret Lifecycle:
CICDBinding.webhook_secretis now auto-generated on creation — every binding has a secret from the start. - Webhook URL Mismatch: GitLab webhook registrations now use per-binding URLs (
/webhooks/gitlab/{binding_id}/) with the secret token, instead of the old generic/gitlab/webhook/path that couldn't resolve bindings.
Added¶
setup-webhookAction: NewPOST /api/projects/cicd-bindings/{id}/setup-webhook/endpoint to register webhooks with CI/CD providers automatically. Supports GitLab, GitHub, and Bitbucket API registration; returns manual config URL for Jenkins and Azure DevOps.- Payload-Based Binding Resolution: Legacy webhook URLs (without
binding_id) now fall back to resolving the binding from the payload'sproject.idfield, ensuring backwards compatibility. - Legacy GitLab Webhook Route: Added
/webhooks/gitlab/route for existing webhooks registered with the old URL pattern.
[Unreleased] - 2026-02-19¶
Sentinel Tiered Intelligence (Phase 2 & 3)¶
- Active Gating: Sentinel now gates AI analysis — quiet batches skip AI when active mode is enabled, saving ~80-90% of AI API calls.
- Per-Org Configuration: New
SentinelConfigmodel withactive_modetoggle and threshold overrides (error spike multiplier, z-score threshold, max quiet batches). - Settings UI: New Settings → Sentinel page with active mode toggle and threshold controls.
- Sentinel Stats API: New
GET /api/data/analytics/sentinel/endpoint returning decision distribution, skip rate, and estimated token savings. - Dashboard Card: New "Sentinel Intelligence" card on the dashboard showing AI skip rate, decision breakdown, and savings summary.
- Batch List Badges: Colored sentinel decision badges (alert/quiet/first/shadow) in the batch list table.
- Forced Periodic Safety Net: Even in active mode, AI is forced after N consecutive quiet batches (configurable, default 12).
- AI Analysis Tracking:
record_ai_analysis()resets quiet counters after successful AI completion. - 35 Tests: Comprehensive test coverage for sentinel config, active gating, stats API, and model tests.
[Unreleased] - 2026-02-16¶
Deduplication Hardening¶
- Database-Level Uniqueness: Partial unique constraint on
(fingerprint, project)for OPEN/MUTED issues — prevents duplicate issues at the DB level, not just application logic. - Race Condition Fix (TOCTOU):
select_for_update()+F()expressions with IntegrityError retry loop — concurrent Celery workers can no longer create duplicate issues. - Organisation Isolation: All log deduplication calls now pass the
organisationfilter, preventing cross-tenant dedup leakage. - Distributed Task Locking: Celery batch tasks use Django cache-based locks (
cache.addatomic set-if-not-exists) to prevent overlapping runs. - Time-Windowed Log Dedup:
deduplicate_logs()now respectstime_tolerance_seconds— identical errors are only grouped when they occur within the tolerance window. - Scalability: Log uniqueness filter uses
fetchmany()chunked iteration + 30-day lookback cap to prevent unbounded memory growth. - SQL Injection Prevention:
_escape_like()escapes%,_,\in project names used in ILIKE queries. - Legacy Cleanup: Removed dead code in
Data/utils/(olddeduplicate_logsandremove_duplicate_logs).
Performance (Phase 2)¶
- Database Indexes: Added composite indexes on Issue model for common query patterns (100x query speedup).
- ServiceHealthView N+1 Fix: Replaced per-service
.count()queries with.aggregate()— 75% query reduction, dashboard 90% faster (3-5s to <500ms). - Redis Caching: Dashboard and stats views cached with 5-15 min TTL. Cache invalidation on Issue save/delete. 80%+ cache hit rate.
- Aggregation Optimization: RecommendationStatsView uses database
COUNT()instead of Python loops — memory usage from 1GB to <10MB. - Celery Worker Concurrency: Configurable concurrency, 6x faster batch processing (25 min to 3-4 min).
- Task Routing & Priorities: Separate Celery queues for analysis, ingestion, and notifications. Priority-based scheduling.
Fixed (Phase 1)¶
- Undefined Variable Bug: Fixed
cpu_metricsundefined inData/tasks.pycausing crashes during batch processing. - Missing Retry Logic: Added exponential backoff retry (3 attempts) to all batch creation Celery tasks.
- N+1 Query in Deduplication: Optimized issue deduplication — 10x query speedup, 90% memory reduction.
- Race Condition in Issue Dedup: Added atomic operations with row-level locking to prevent duplicate issues.
- Sequential Batch Processing: Batch creation now runs in parallel via Celery (5x speedup).
- AI Cost Tracking: New
AITokenUsageandOrganisationAIQuotamodels for token usage tracking and monthly quota enforcement.
Added¶
- Provider Encryption Improvements: Updated credential encryption in provider integrations.
[Unreleased] - 2026-01-24¶
Added¶
- AI Provider Extensibility: Plugin-based architecture to support any AI provider via adapters.
- Provider Management UI: New Settings > AI > Manage Providers section to:
- Add custom providers (e.g., Local Ollama).
- Configure adapters (Gemini, Claude, OpenAI Compatible).
- Set custom API keys and Base URLs.
- Multi-Provider Support: Native integration for Anthropic Claude, DeepSeek, and Google Gemini.
- Dynamic Model Selection: Chat and Batch Analysis dropdowns now dynamically list all active providers.
Fixed¶
- Provider Save Error (405): Fixed
PUTmethod support in provider settings API. - Missing Models: Fixed
AvailableModelsViewto include system-wide active providers even without custom config. - Batch Analysis Auth: Fixed
batch.projectattribute error in async tasks. - Log Noise: Clarified that 403 errors in logs are due to harmless demo data.
[Unreleased] - 2026-01-20¶
Added¶
- Add Service Wizard: New 3-step guided flow for connecting services.
- Step 1: Choose Type - Visual cards for Application, Infrastructure, or Custom services.
- Step 2: Connect Code - Seamless Integration -> Repository selection with smart defaults.
- Step 3: CI/CD - Optional pipeline configuration step.
- Auto-Fill: Service Name is automatically extracted from repository name (e.g.,
docsfromgroup/docs). - Integrations UI Overhaul: Modernized
Settings > Integrationspage. - Grid Layout - Clean, visual cards for all supported providers.
- Badge Status - Clear Active/Inactive indicators.
- Coming Soon - Placeholders for future integrations (JIRA, Slack, etc.).
Fixed¶
- Service Creation: Standardized
service_typevalidation (unifiedapplicationtype for all SCM providers). - Repository Loading: Fixed
getReposAPI call and improved response parsing (handles array, paginated, and direct object formats). - Legacy Cleanup: Removed deprecated Add Service modal and cleaned up unused code.
[Unreleased] - 2026-01-17¶
Added¶
- Smart Issue Deduplication (v3): AI now classifies errors with
error_classanderror_targetfor more precise issue grouping. - 20 error categories: COMMAND_NOT_FOUND, MODULE_NOT_FOUND, CONNECTION_REFUSED, AUTH_FAILED, TEST_ASSERTION, etc.
- Different errors of the same type now create separate issues (e.g.,
chmod9vschmod10not found) - Backward compatible: existing issues unchanged, new issues get enhanced classification
Fixed¶
- CI/CD Trace Storage: Traces now update existing ES documents instead of creating duplicates.
- Date Value Out of Range: Fixed anomaly detection crash when metric timestamps are invalid.
[Unreleased] - 2026-01-13/14¶
Added¶
- Robust Deployment Sync: Direct GitLab API sync fallback for webhook failures, periodic sync every 10 minutes via Celery beat.
- CI/CD Trace Capture & Display:
- Full job traces stored in Elasticsearch with preprocessing
- Traces displayed in batch detail UI with "--- Job Output ---" section
- Preprocessed
trace_errorsfield (max 20 error lines) for AI token efficiency - Code Changes Enhancement:
service_namefield shows which service each commit belongs to- Gray badge in Code Changes UI displaying service name
- Full diffs included in batch data (truncated to 500 chars per file for AI)
- Dynamic Service Filtering: CI/CD logs now show actual service name (backend/frontend) in dropdown filter instead of hardcoded "CI/CD".
- AI Analysis Improvements:
repair_json()helper for robust JSON parsing- CI/CD Pipeline Outputs section added to AI prompt for failed job correlation
Fixed¶
- 405 Method Not Allowed: Fixed
/api/data/batches/reanalyze/endpoint (URL pattern ordering). - Tuple Unpacking Error: Fixed
reanalyze_batch_with_modeltask. - Trace Storage Bug: Fixed
job_instance.log→job_instance.logsfield name. - Environment Import: Fixed
detect_environment_genericimport for trace indexing.
[Unreleased] - 2026-01-12¶
Added¶
- Issue Deduplication v2: Intelligent fingerprint-based deduplication to prevent duplicate issues across batches.
- 25+ issue types (MEMORY_HIGH, CPU_HIGH, DATABASE_ERROR, API_ERROR, etc.)
- Scope-based classification (SERVICE, INFRASTRUCTURE, PIPELINE)
- Component normalization for consistent fingerprinting
- Tiered matching with infrastructure promotion
- Intra-batch deduplication
- Issue Management Actions: Manual issue lifecycle control.
- Resolve - Mark issues as fixed (auto-reopens if same fingerprint detected)
- Mute - Suppress notifications for 1/7/30/90 days or forever
- Reopen - Bring back resolved or muted issues
- Enhanced Issues Table: New columns and UI improvements.
- Type column (MEMORY_HIGH, API_ERROR, etc.)
- Component column (affected service)
- Occurrence count badge (2×, 5×)
- Status column (OPEN, MUTED, RESOLVED)
- Action buttons (resolve, mute, reopen)
- New Filters: Status filter (Open, Muted, Resolved) added to Issues page.
- New API Endpoint:
POST /api/data/issues/{id}/{action}/for resolve, mute, reopen actions.
Fixed¶
- Legacy Batch Compatibility: Batches analyzed before v2 now fall back to parsing
analysis_textJSON. - Issues link regression: Fixed batch-specific issues page showing 0 issues for legacy batches.
- Component Identification: AI now uses
service_namefrom log/code change metadata instead of guessing from log content.
[Unreleased] - 2026-01-07¶
Added¶
- Environment-Based Data Isolation: Batch creation now runs per-environment (development, staging, production) with user-defined branch patterns.
- Project Environments UI: New section in "Create Project" modal with:
- Editable branch patterns per environment
- Add custom environments (e.g., qa, uat)
- Remove custom environments (default 3 cannot be removed)
- Environment Badge in Data Page: Color-coded badges (🟢 Production, 🟡 Staging, 🔵 Development) in batch list.
- Batch Creation Safeguards (3-Level Protection):
- L1: Skip projects with 0 services
- L2: Skip batches with 0 data points (logs + cicd + changes + metrics)
- L3: Skip AI API call if batch has no meaningful data
- API Enhancement: Environment filter parameter added to batch list endpoint (
GET /api/data/batches/?environment=development).
Fixed¶
- Project Isolation Bug: Fixed issue where projects without services were creating batches and consuming AI API quota.
- Empty Batch Prevention: Batches are no longer created for environments with no data.
Removed¶
- Metrics Page Environment Filter: Removed redundant filter (metrics are host-level, not environment-specific).
[Unreleased] - 2026-01-04¶
Added¶
- Enhanced Batch Re-Analysis: Multi-select batches and re-analyze with different AI models (Gemini, DeepSeek).
- Model Comparison: Store analysis history per batch, enabling side-by-side comparison of results from different AI models.
- Action Dropdown Menu: New dropdown in Data page with options: "Re-Analyze with Gemini", "Re-Analyze with DeepSeek", "Chat about Batch", "Compare Model Results".
- New API Endpoints:
POST /api/data/batches/reanalyze/- Queue re-analysis for selected batches with specific model.GET /api/data/batches/<batch_id>/history/- Get analysis history for model comparison.- Backend: Added
analysis_historyJSONField to AIAnalyzedBatch model for storing multiple analysis results. - Celery Task: New
reanalyze_batch_with_modeltask for background re-analysis.
[Unreleased] - 2026-01-03¶
Added¶
- Multi-Tenancy Metrics Isolation: Metrics now filtered by
org_id + environment + project_idfor complete tenant isolation. - Organisation-Level Deployment Filtering: Added
organisation_idparameter toDeploymentService.get_deployments_for_batch()for query-level org isolation.
Fixed¶
- Deployment Webhook: Now captures ALL pipeline statuses (pending, running, failed, success) instead of only successful ones.
- CI/CD Logs Security: Removed dangerous wildcard fallback (
ci_cd-logs-*) that could leak cross-project data. - Environment Detection: Moved environment detection before metrics fetch to ensure correct filtering.
Security¶
- P1 Fix: Code Changes now query-filtered by organisation at database level (prevents cross-org data in memory).
- P2 Fix: CI/CD logs query skipped entirely if no project name (prevents wildcard data leakage).
[Unreleased] - 2026-01-01¶
Added¶
- GitLab-Style Settings UI: Refactored major settings pages (
General,Team,Notifications,AI,Data,Security,Integrations) to use a consistent, collapsible section layout. - Localization (i18n):
- Complete French translations for "System Health" Dashboard, Metrics, and Charts.
- Added missing translation keys for Notification Panel and Settings.
- Error Handling: Improved error reporting for Organization Logo upload (now shows specific backend error messages).
Fixed¶
- Dashboard UI:
- Fixed "100%" text overlap on System Health gauge chart by adjusting font size and position.
- Resolved mixed English/French text on Dashboard cards (MTTR, Status, Trends).
- Data Page:
- Fixed pagination logic error where filtering by "All Projects" failed due to string mismatch.
- Issues Page:
- Corrected "Errors" column alignment to be left-aligned (
text-start).
- Corrected "Errors" column alignment to be left-aligned (
- Notification System:
- Fixed "Unread" count pluralization issue (e.g., "19 Unread").
- Fixed Notification Settings toggle switches visibility (was hidden due to missing
display: block). - Fixed
NotificationPanelinteractivity and navigation.
Changed¶
- Styling: Centralized
NotificationPanelstyles intoNotificationPanel.css. - Refactoring: Updated multiple components to use
react-router-domfor smoother navigation.