Changelog System
Overview
The changelog system provides staff users with context-aware release information, including what changed, whether changes affect their specific deployment, and what actions are needed after upgrading. It replaces the basic "new version available" notification with structured, filterable changelogs that include security alerts, impact analysis, and deployment-specific relevance matching.
Architecture
flowchart TD
A[Release script generates<br/>changelog JSON per version] --> B[Published to<br/>docs.waldur.com/latest/changelog/]
B --> C[GET /api/version/<br/>fetches index.json, cached 1h]
C --> D{New version<br/>available?}
D -->|Yes| E[changelog_summary +<br/>security_alert in response]
D -->|Yes| F[Celery: compute_changelog_impact<br/>background task]
E --> G[Frontend: badge +<br/>security banner]
F --> H[ChangelogImpactAnalysis<br/>model in DB]
H --> I[GET /api/changelog/pending/<br/>merges static + analysis]
I --> J[Frontend: /administration/changelog/]
Components
| Component | Location | Purpose |
|---|---|---|
| Changelog JSON files | docs.waldur.com/latest/changelog/releases/ |
Structured release data (static) |
index.json manifest |
docs.waldur.com/latest/changelog/index.json |
Version list with summary stats |
waldur_core.changelog app |
src/waldur_core/changelog/ |
Backend API, models, utils |
ChangelogImpactAnalysis |
Database model | Stores background analysis results |
changelog/schema.json |
Repo root | JSON Schema for release files |
assemble_changelog |
Management command | Assembles fragments into release files |
Changelog Data Format
Each release has a structured JSON file following changelog/schema.json. Key fields per entry:
Entry structure
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | |
Entry types
| Type | Description |
|---|---|
breaking |
Backward-incompatible changes |
security |
Security fixes (must include security object) |
deprecation |
Will be removed in a future version |
feature |
New functionality |
improvement |
Enhancement to existing functionality |
fix |
Bug fix |
Scope
| Value | Meaning | Relevance filtering |
|---|---|---|
core |
Affects all deployments | Always shown |
plugin |
Requires specific plugins | Filtered by relevant_when |
infra |
Deployment infrastructure only | Always shown (same as core - component isn't consulted for relevance) |
dev |
Development/testing only | Hidden in production views |
Component
Array of stack layers affected: backend, frontend, helm, docker, site-agent, sdk.
Categories
marketplace, auth, identity, openstack, slurm, invoices, ai_assistant, reporting, policy, proposal, support, ui, infrastructure, notifications.
Impact and risk
| Risk | Meaning |
|---|---|
high |
Breaking change, data migration, or service disruption |
medium |
Behavior change that may affect workflows |
low |
Minor change, unlikely to affect workflows |
none |
Informational, no action needed |
affected_scope provides a broad impact category when a specific Django model doesn't apply: all_users, all_resources, infrastructure, api_consumers, none.
affected_resources with model and filter enables the Celery task to run live count queries (e.g., "47 pending orders affected"). Both model and the keys of filter are checked server-side against an explicit allowlist (ALLOWED_IMPACT_MODELS in changelog/tasks.py) before any query runs — this JSON is remote, unauthenticated input, so only pre-approved (model, field) combinations are queryable, with exact-match values only (no __ lookups). Currently allowlisted: marketplace.Resource.state, marketplace.Offering.{state,type}, marketplace.Order.{state,type}, and is_staff/is_support/is_active for affected_users. state fields are FSMIntegerFields, so filter values must be the numeric state (e.g. {"state": 1}), not a display string like "pending-consumer" — a non-matching model, field, or value type is skipped (logged, not counted) rather than erroring. Extending the allowlist is a deliberate, reviewed code change in tasks.py, not something a changelog entry can request on its own.
Security entries
Entries with type: security must include a security object:
1 2 3 4 5 6 7 8 9 10 11 | |
Security urgency levels control frontend notification behavior. changelog_summary.security_alert (and the badge/banner it drives) is only ever populated for critical/high — build_changelog_summary filters on exactly those two (utils.py) — so moderate/low entries never reach any dedicated notification; they appear only as regular entries wherever the changelog is listed, ranked by their own impact.risk:
| Urgency | UI behavior |
|---|---|
critical |
Red banner (SecurityAlertBanner, bg-danger), persistent, cannot dismiss; red footer badge |
high |
Orange/warning banner (bg-warning), dismissible per session (sessionStorage); orange footer badge |
moderate |
No dedicated banner or badge — standard changelog entry only |
low |
No dedicated banner or badge — standard changelog entry only |
Version model (stable and RC)
Waldur uses SemVer with -rc.N pre-releases. Each release file contains:
entries[]— cumulative since the previous stable releasesince_previous[]— incremental since the immediately preceding version (RC or stable)component_activity— per-repo commit counts with compare URLs
This supports three views: stable-to-stable, RC-to-RC, and RC-to-stable.
API Endpoints
All endpoints require IsAuthenticated + IsStaffOrSupportUser.
| Endpoint | Description |
|---|---|
GET /api/version/ |
Returns version + changelog_summary with security alerts |
GET /api/changelog/pending/ |
Cumulative changelog from current to latest, with relevance and impact analysis |
GET /api/changelog/{version}/ |
Full changelog for one version |
GET /api/changelog/{version}/delta/ |
Only since_previous entries |
GET /api/changelog/compare/{from}/{to}/ |
Merged deltas between arbitrary versions |
GET /api/changelog-entries/ |
Flat, paginated, filterable list of entries across all pending versions (table view) |
Version endpoint response
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
Pending endpoint response
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | |
Flat entries endpoint
GET /api/changelog-entries/ flattens every pending version's entries into one paginated list — for the standard Waldur table component, rather than the per-release grouping pending returns. Query parameters:
| Param | Description |
|---|---|
type |
Filter by entry type |
risk |
Filter by impact.risk |
scope |
Filter by scope |
version |
Filter to entries from one release version |
highlight |
true/1 — only entries with highlight: true |
relevant_only |
true/1 — only entries relevant to this deployment |
search |
Case-insensitive match against title/description |
page, page_size |
Pagination (page_size clamped to 1-200) |
Results are sorted relevant-first, then by risk (high to none). Each entry additionally carries version, release_date, release_type (from the release it belongs to).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
Relevance Matching
Entries are matched against the deployment's configuration:
- Plugins:
relevant_when.pluginschecked againstINSTALLED_APPS - Feature flags:
relevant_when.feature_flagschecked against the features registry - Settings:
relevant_when.settingschecked for non-default constance values
Entries with scope: core or scope: infra, or empty relevant_when arrays, are always relevant.
Background Impact Analysis
The compute_changelog_impact Celery task runs automatically when /api/version/ detects a new release. It computes:
- Affected resource counts — runs
Model.objects.filter(**filter).count()for entries withaffected_resources.model, restricted to theALLOWED_IMPACT_MODELS/ALLOWED_USER_IMPACT_FIELDSallowlist (see "Impact and risk" above) - Settings diffs — captures current vs default values for referenced constance settings
- Plugin state — records which referenced plugins are installed
Results are stored in the ChangelogImpactAnalysis model and refreshed every 24 hours. The /api/changelog/pending/ endpoint merges these results into the response.
Configuration
Disabling the changelog
Set in override.conf.py or Helm values:
1 | |
1 2 3 4 | |
When disabled:
/api/version/returns only{version}— no changelog data/api/changelog/*endpoints return 404- The Celery impact analysis task is a no-op
- No frontend changelog UI elements are rendered
Management Command: assemble_changelog
Assembles changelog fragments from changelog/next/ into a release file:
1 2 3 4 5 6 | |
Options
| Flag | Required | Description |
|---|---|---|
--release-version |
Yes | Version string (e.g., 8.0.8 or 8.0.8-rc.1) |
--date |
Yes | Release date (ISO 8601) |
--release-type |
No | stable (default) or rc |
--base-stable |
No | Previous stable version for cumulative entries |
--previous |
No | Immediately preceding version |
--stable-target |
No | Target stable version (for RC releases) |
--summary |
No | Release summary text |
--no-clear |
No | Don't clear changelog/next/ after assembly |
--dry-run |
No | Validate and print without writing |
Fragment format
Each fragment in changelog/next/ is a JSON file with the same structure as an entry, minus the id field (auto-assigned):
1 2 3 4 5 6 7 8 9 10 | |
Validation rules
Each assembled entry is validated against changelog/schema.json (the $defs/entry sub-schema) via jsonschema — schema.json is the source of truth, so the constraints below track it automatically rather than needing to be kept in sync by hand:
typemust be one of:breaking,security,deprecation,feature,improvement,fixcategorymust match the predefined category listscopemust becore,plugin,infra, ordevcomponentvalues must be from:backend,frontend,helm,docker,site-agent,sdkimpact.riskmust behigh,medium,low, ornone
One rule the schema can't express and is checked separately: security entries (type: security) must include a security object with urgency, affected_versions, exploitability, and mitigation.
Schema Versioning
The JSON schema at changelog/schema.json includes a schema_version field (currently 1.0.0). Release files include this version for forward compatibility — consumers can check the schema version before parsing.
Release Script Integration
Changelog entries are generated at release time by waldur-docs/scripts/release.sh — a local, interactive script a dev runs to cut a release (./scripts/release.sh <VERSION>). It's not CI-driven: there's no dedicated pipeline job for changelog generation, staff/support-facing or otherwise. The script already collects git log data across all core repos (mastermind, homeport, helm, docker-compose) between the previous tag and the new one, and drives two independent Claude Code (claude --print) calls against that same commit data:
scripts/prompts/changelog-prompt.md— produces free-form Markdown, prepended todocs/about/CHANGELOG.md. This is the pre-existing, human-facing changelog and is unaffected by the structured system described in this document.scripts/prompts/changelog-json-prompt.md— produces a single{summary, entries[]}JSON object classifying the same changes into this schema's fields (type,category,scope,component,impact,relevant_when, etc.). Each entry inentries[]is written to its own file underwaldur-mastermind/changelog/next/(a fragment, matching this document's fragment format above), thenassemble_changelogvalidates and assembles them intochangelog/releases/{version}.jsoninside this repo. That file is copied intowaldur-docs/docs/changelog/releases/{version}.json, andscripts/update_changelog_index.pyupserts its summary row intowaldur-docs/docs/changelog/index.json.
Both stable and RC releases go through this same flow — there's no separate "daily RC" cadence script.
Publishing happens for free: docs/changelog/ lives in waldur-docs' normal docs_dir, so the site's existing "Deploy MkDocs pages" CI job (mkdocs build + mike deploy $TAG latest --update-aliases, unchanged by this) picks it up like any other doc content. Because mike nests the built site under version-prefixed paths (docs.waldur.com/8.0.9/...), the changelog is only reachable at a stable, unversioned URL via mike's latest alias — docs.waldur.com/latest/changelog/... — which is why CHANGELOG_BASE_URL in utils.py points at /latest/changelog, not /changelog, and why the alias must be kept up to date on every stable release (mike already does this via --update-aliases).
release.sh also commits changelog/releases/{version}.json directly into this repo (waldur-mastermind, develop branch) as an audit trail, independent of waldur-docs — that commit is not required at runtime (the API only ever fetches from docs.waldur.com), it just keeps the generated release data in this repo's history too.