Skip to content

Releases: frousselet/cairn

v0.28.2

16 Jun 16:03

Choose a tag to compare

Added

  • Manage role responsibilities from the UI: the role detail page now lets you add, edit and delete responsibilities (description, RACI type, related activity) directly from the Responsibilities section. An Add button in the section header and per-row edit / delete actions open an HTMX drawer; the section refreshes in place after each change. Actions are gated by the context.role.update permission. Previously responsibilities could only be managed through the API / MCP tools (create_responsibility, update_responsibility, delete_responsibility), which remain available. Changing a role's responsibilities now sends the role back to its draft state (resetting approval and bumping the version) so it is re-validated; the demotion is recorded in the role's change history. This applies whether the change is made from the UI or through the REST API, except for roles in a terminal state (archived / cancelled), which are left untouched. The role's History section now also merges its responsibilities' own history into the role timeline, so adding, editing or deleting a responsibility is visible there (a deletion shows the removed responsibility's details, tagged as a "Responsibility" entry).
  • Generic CSV bulk import (suppliers first): a new reusable, entity-by-entity bulk-import framework (core/imports) modelled on the framework import. Each importable entity declares an EntityImporter with its column specification and registers it; the generic views, URLs (/imports/<entity>/), templates and sample-file generation then drive the same upload -> preview -> confirm wizard for every entity. Suppliers are the first consumer: an Import button above the supplier list opens a CSV upload in a modal, the file is validated row by row (type coercion, allowed values, FK/M2M resolution) and a preview lists the rows to import (flagging those that already exist) and the rows skipped with their errors before confirmation. Owners are resolved by email (blank falls back to the importing user), supplier types by name (must exist), scopes by reference or name (must exist) and tags by name (created on the fly). Duplicate handling is decided per row in the preview: a row whose exact name already matches an existing supplier shows a Replace checkbox, so for each match the user chooses to overwrite the existing supplier or keep it unchanged (a name matching several existing suppliers is reported as an ambiguous error). On replacement the supplier's original creation date is preserved. The importer can also carry over the original creation date of newly created suppliers from a legacy tool (a created_at column written via a post-save update so it is not overwritten by auto_now_add). A downloadable CSV sample with a per-column documentation panel is provided. Suppliers already expose programmatic bulk creation through the existing batch_create_suppliers MCP tool and the /api/v1/assets/suppliers/ batch endpoint.

Fixed

  • Role detail page crashed (500): the assigned-users list referenced the non-existent user.username attribute (the User model is email-based with no username field), raising a VariableDoesNotExist on every /context/roles/<id>/ view. It now falls back to user.email.
  • Dashboard progress-bar heights aligned: the "Active objectives progression" bars used the Bootstrap default height (16px) while the "Compliance by framework" bars were 8px. Both now render at 8px for a consistent look.
  • Modal select dropdowns clipped / hidden behind the modal: TomSelect dropdowns opened inside a form drawer were clipped by the scrollable modal body and could render behind the modal. They are now attached to <body> (dropdownParent) with a z-index above the modal, so the full option list is always visible regardless of the field's position in the form.

Full changelog

v0.28.1

16 Jun 13:15

Choose a tag to compare

Changed

  • Administration menu reorganised: the sidebar's Administration section is now structured into four collapsible groups instead of a flat list - General (Company, Tags, Versioning, Calendar subscriptions, Trust Center), Access (Users, Groups, Permissions), Ask Cairn (Semantic index, Feedback) and Logs (Access log, Action log). Each group only renders when the user can see at least one of its items, preserving the existing per-item permission checks. The Django admin link was removed from the sidebar.
  • Trust Center moved to Administration: the Trust Center is now entirely an administration concern. Its settings page (publish switch, branding, custom domain and CSS) is reached from the Administration menu, and the standalone Trust Center entry was removed from the Governance / Strategy menu. The content curation hub is now reached through a "Manage content" link on the settings page; it keeps the public-page link and continues to host the day-to-day curation of certifications, subprocessors, measures and documents.
  • Frameworks menu simplified and import as a modal: the sidebar "Frameworks" entry is now a direct link to the framework list instead of a collapsible submenu (List / Import). Importing a framework is now triggered by an Import button above the list (next to "New framework") that opens the import form in a modal; submitting it runs the existing analyze -> preview -> confirm wizard. The full-page import view is preserved as the submit target and validation-error fallback.
  • Self-documenting framework import samples: the downloadable JSON and Excel sample files now embed their own field-and-values documentation (English-only, as a stable technical reference independent of the user's locale). The JSON sample carries a leading _instructions block (ignored on import) listing every framework / section / requirement field, whether it is required, and the allowed code -> label values for the enumerated fields (framework type and category, requirement type and category). The Excel sample gains header-cell comments and a dedicated Documentation sheet describing each column, which row type it applies to, and the same allowed-values tables. The allowed values are generated from the model choices, so they stay in sync with what the importer accepts. The Excel sample's requirement references were aligned with their section prefixes (e.g. SEC.1.1.1) so the sample now imports cleanly with correct nesting.
  • Action plans kanban header: the page now follows the standard header convention with a "Compliance" eyebrow and module accent above the title.

Fixed

  • Action plans kanban mispositioned after navigation: the kanban board is a fixed-position layer whose top offset was computed by a DOMContentLoaded handler, which never fires on HTMX-boosted navigation (e.g. clicking "Action plans" in the sidebar). The board was left anchored to the bottom of the viewport with a large empty gap above it (and drag-and-drop was not wired up). Initialisation now runs on first load, on every boosted swap (htmx:afterSettle) and on resize, so the board is always positioned directly below the header.

Full changelog: v0.28.0...v0.28.1

v0.28.0

15 Jun 11:37

Choose a tag to compare

Added

  • Trust Center: a new public, unauthenticated page that advertises the organisation's security and compliance posture, built directly into Cairn and optionally servable on a separate domain. It is an explicit curation layer: a dedicated trust_center app whose models reference internal frameworks, suppliers and reports through public-only entries (public label, description, ordering), so internal GRC data never reaches the public surface. Four content sections, each governed by a trust_center_publication lifecycle workflow: certifications, subprocessors, security measures and documents. A dual publish gate means an item is public only when its own publication state is "published" AND its source object is still validated/active; a global publish switch takes the whole Trust Center offline. Data-leakage safety is enforced by dedicated public DRF serializers (hardcoded field whitelist), anonymous rate-limiting, no raw /media/ exposure, and strict allowlist sanitization of every rendered SVG logo. Public page at /trust/ (read API under /trust/api/); internal curation UI at /trust-center/manage/. Full REST API under /api/v1/trust-center/, MCP tools, and new trust_center.* permissions assigned to the six system roles.
  • Trust Center branding and rich text: the public page leads with the company name as the hero title (with its logo) and uses it as the favicon; the browser UI theme-color follows the configured accent. The intro and the certification / measure / document descriptions are authored with the rich-text editor and rendered as sanitized HTML. The settings gain an optional custom CSS field injected into the public page, sanitized to prevent style-tag breakout and active content.

Changed

  • Dependency graph header layout: the page now follows the standard header convention with an "Assets" eyebrow and module accent above the title. The stats, the colour legend and the zoom controls were merged into a single compact toolbar on the header row (the legend moved into a popover instead of a full-width inline strip), reclaiming vertical space for the graph canvas, which is now repositioned on window resize. The force layout was tuned so disconnected components stay in frame without overlapping (bounded local repulsion, gentle centre gravity, label-aware collision radius).

Full Changelog: v0.27.2...v0.28.0

v0.27.2

15 Jun 08:25

Choose a tag to compare

Added

  • Dashboard risk treatment flow (Sankey): a new Sankey (cash-flow style) chart on the home dashboard, displayed above the risk matrices, visualises how treatment moves each risk from its current severity level (before treatment) to its residual level (after treatment). Each column lists the severity levels present (highest at the top, lowest at the bottom), coloured with the configured risk-level palette, and each flow's thickness is the number of risks making that transition - so a heavy downward flow reads as effective treatment and a flat flow as untreated risk. Levels are derived from the likelihood/impact pairs (with the same default 5x5 ISO 27005 fallback as the matrices), so the chart stays consistent with the matrices below even when no risk criteria are configured. The chart honours light/dark mode and is rendered with Apache ECharts. Built from a new build_risk_treatment_flow() helper in risks/views.py.
  • Ask Cairn: OpenAI and OpenAI-compatible providers: the assistant gains an openai backend (AI_ASSISTANT_PROVIDER=openai) that targets OpenAI (ChatGPT, e.g. gpt-4o-mini) out of the box and, via AI_ASSISTANT_BASE_URL, any other endpoint implementing the OpenAI /chat/completions and /embeddings API (vLLM, LiteLLM, LocalAI, Together, Groq...). The shared request/response handling was extracted into a generic OpenAICompatibleClient; the existing MistralClient is now a thin subclass of it (Mistral already exposes an OpenAI-compatible API), so behaviour is unchanged for Mistral users. AI_ASSISTANT_BASE_URL now defaults to empty and each provider falls back to its own endpoint (mistral -> api.mistral.ai, openai -> api.openai.com, anthropic -> api.anthropic.com); set it only to target a custom gateway.
  • Ask Cairn: Claude (Anthropic) provider: a native anthropic backend (AI_ASSISTANT_PROVIDER=anthropic) talks to Claude through the Messages API (POST /v1/messages, x-api-key header, top-level system, content block list) - Claude is not OpenAI-compatible, so it has its own client. Routing uses forced tool use (a plan tool whose input_schema is the routing schema) and no temperature/thinking is sent (both 400 on the current Opus family). Set AI_ASSISTANT_MODEL to a Claude model id (e.g. claude-opus-4-8). Semantic search is not available with this provider, since Anthropic has no embeddings API.
  • Ask Cairn: automatic semantic index maintenance: the requirement semantic index now stays fresh without a manual command. A post_delete signal prunes a deleted requirement's embedding immediately (no provider call); the index is refreshed in a guarded background thread when a server process starts (when AI_ASSISTANT_SEMANTIC_ENABLED); and a dedicated Administration -> Semantic index page shows an index-status panel (indexed / total requirements, last updated, embedding model) with an "Update the index now" button (gated by system.config.update) that triggers a background rebuild. Embedding stays off the request path - requirement saves never embed inline; the documented daily rebuild_semantic_index cron remains the self-healing backstop. The rebuild logic was extracted into assistant.semantic.rebuild_index / rebuild_index_async (cache-locked to dedupe overlapping triggers) and reused by the management command.
  • Ask Cairn: supplier requirements and dependencies: the assistant can now answer "Quelles sont les exigences du fournisseur X ?" and "De quels fournisseurs dépend <l'actif> ?". New catalog tools list_supplier_requirements (a supplier's contractual / security requirements, found in two steps: locate the supplier, then list its requirements), list_supplier_dependencys (the suppliers a support asset depends on) and list_site_supplier_dependencys (the suppliers a site depends on). The two dependency tools now expose read-only supplier_name / support_asset_name / site_name companion fields (model properties) so the answer names the actual supplier instead of an opaque identifier, and their record cards link to the supplier page.
  • Ask Cairn: sites, activities and stakeholders are now answerable: the assistant catalog gains list_sites (physical premises, with their postal address), list_activitys (business activities and processes, filterable by criticality) and list_stakeholders (interested parties). Previously the planner had no tool for these entities and routed questions like "Quelle est l'adresse du site Lyon HQ ?", "Liste-moi les activités critiques" or "Dis m'en plus sur la partie intéressée Industrial Customers" to the nearest wrong tool (scopes, risks, ISMS changes) and answered with empty data. list_suppliers now also feeds the supplier's description, country and contract end date to the summary, so "Quelle est l'activité de ce fournisseur ?" is answered from its description instead of reporting it as missing.

Fixed

  • Ask Cairn: SWOT analyses and "who is responsible" questions: two more feedback follow-ups, verified live. (1) "Liste-moi les analyses SWOT" had no catalog tool and mis-routed to semantic requirement search; added list_swot_analysiss. (2) "Qui est responsable de <X> ?" found the record but could not name the owner, which only existed as a stripped owner_id. Suppliers, objectives, activities, essential assets and support assets now expose an owner_name companion (the responsible user's display name, same pattern as scope manager_names), so the assistant answers "David Morel est responsable de FacilEnergie Services" instead of "aucun responsable mentionné".
  • Ask Cairn: supplier category, expired suppliers and count over-filtering: follow-ups from assistant feedback, verified end to end against the live Mistral planner. (1) list_suppliers now surfaces a type_name companion (the supplier's category), so "Quelle est l'activité / la catégorie de ce fournisseur ?" is answered ("HRline est un fournisseur SaaS...") instead of reported as missing. Because the new list_activitys tool made the planner mis-route "l'activité de <company>" to internal activities, the activities signature now states it is for internal processes only and a routing example sends a company's line of business to list_suppliers. (2) A new expired filter on the supplier list tool returns suppliers whose contract has expired (active suppliers with a past contract end date, mirroring Supplier.is_contract_expired), so "Liste-moi les fournisseurs expirés" works; the generic list machinery gained an optional derived-filter hook to express it, a worked routing example steers the planner to the expired flag instead of an invalid status="expired" guess, and the supplier output now carries is_contract_expired so the summary names the expired supplier instead of contradicting itself. The summary prompt also now states present records affirmatively (never "none found" while records are shown). (3) Count questions like "Combien de biens essentiels ?" were over-filtered by the planner (it added status="identified", which matched none); a worked count example in the routing prompt now steers the planner to query broadly and rely on the returned total.
  • Ask Cairn: "how many" questions now report the real count: the list tools return a total count alongside a sample of records, but the engine dropped it before the summary, so "Combien de biens essentiels ?" could only be answered from the (possibly truncated) sample. The engine now feeds total to the summary, the summary prompt explains it is the full count, and the planner is told not to add a status filter to count questions unless one is named (so "combien" queries count everything instead of an over-constrained subset).
  • Ask Cairn: status filters now spell out their allowed values to the planner: the routing-prompt tool signatures for the status-filtered list tools (list_objectives, list_action_plans, list_compliance_assessments, list_frameworks, list_indicators, list_issues, list_suppliers, list_essential_assets, list_support_assets) now enumerate the exact status enum values, like the risk and management-review tools already did. Previously these signatures showed a bare status parameter, so the planner had to guess: asking "Quels sont les objectifs complétés ?" made it filter on an invalid status and return an empty list instead of the objectives at 100%. list_objectives now also documents that a completed / met objective has status achieved (and not_achieved means finished but the target was missed); the criticality and indicator-type enums are spelled out too. Surfaced by a thumbs-down through the assistant feedback channel.

Full changelog: v0.27.1...v0.27.2

v0.27.1

14 Jun 16:01

Choose a tag to compare

Fixed

  • Command palette no longer opens in a French locale: the Ask Cairn palette script embedded {% trans %} strings inside single-quoted JS literals, and French translations contain apostrophes (e.g. "L'assistant est injoignable…") that terminated the string, throwing a SyntaxError that killed the whole palette script. Translated strings embedded in the palette JS are now escaped with |escapejs. (Surfaced only in production, which runs in French; English dev was unaffected.)
  • Clearer error when the Mistral API key is missing: rebuild_semantic_index and chat failed with a cryptic httpx.LocalProtocolError: Illegal header value b'Bearer ' when AI_ASSISTANT_API_KEY was empty. MistralClient now validates the key up front and raises a clear "Mistral API key is not configured" message; rebuild_semantic_index exits with a clean error instead of a traceback.

Full changelog: v0.27.0...v0.27.1

v0.27.0

13 Jun 21:55

Choose a tag to compare

Added

  • Ask Cairn, an optional AI question mode in the command palette: the command palette (Ctrl+K) gains an "Ask Cairn" entry that answers simple natural-language questions like "Quelles décisions ont été prises lors de la dernière revue de direction ?". The LLM backend is a pluggable provider (AI_ASSISTANT_PROVIDER): Mistral AI (third-party, EU-hosted; default model mistral-small-latest) by default, with a self-hosted Ollama provider still selectable for an on-premises, no-egress deployment. The model only routes the question to a curated allowlist of 24 read-only MCP tools executed in-process with the requesting user (existing permissions and scope filters apply, nothing is bypassed); the answer shows the real matching records as clickable cards plus a short AI-labeled summary sentence in the user's language. Internal identifiers are stripped before the summary call. The feature is disabled by default (AI_ASSISTANT_ENABLED), degrades gracefully when the backend is unreachable, and ships with a REST endpoint (POST /api/v1/assistant/ask/) and an ask_assistant MCP tool. Each answer carries a thumbs up/down feedback control with an optional comment: the captured feedback (prompt, interface language, LLM summary and returned records, provider/model, rating and comment) is stored as AssistantFeedback, browsable and exportable as JSON from the in-app Administration area (sidebar "Assistant feedback") and the Django admin (and via GET /api/v1/assistant/feedback/export/ or the list_assistant_feedback MCP tool, gated by system.assistant_feedback.read) so a set of feedback can be handed to an LLM to improve the service. Feedback can be marked corrected once acted on (in-app button, admin action, or POST /api/v1/assistant/feedback/{id}/resolve/), which excludes it from future exports by default (the in-app list defaults to open feedback and the export, REST export and list_assistant_feedback MCP tool all drop corrected rows unless include_resolved). Optionally (AI_ASSISTANT_SEMANTIC_ENABLED), a semantic, cross-language requirement search (semantic_search_requirements) lets topic questions match control content regardless of language (e.g. French question, English ISO controls): requirement embeddings are stored portably (no pgvector) via manage.py rebuild_semantic_index and ranked by in-Python cosine similarity. "Who is responsible for scope X?" questions are now answered: the list_scopes MCP tool exposes a read-only manager_names field (from a new Scope.manager_names property) and the assistant feeds it to the summary, so the responsible managers are named instead of reported as missing.

Full changelog: v0.26.3...v0.27.0

v0.26.3

12 Jun 14:13

Choose a tag to compare

Added

  • Company identity on the dashboard: when a company name is configured (Company settings page), it replaces the "Dashboard" title in the page header, with the company logo displayed beside it; the page identity moves to the eyebrow. The {% page_header %} component gains a generic logo parameter (image rendered in place of the icon). Without a configured name, the header is unchanged.
  • Demo dataset seed script: scripts/seed_demo_data.py (with scripts/seed_demo_tables.py) populates a fresh database with the fictional "Voltara Energy" company: users in every system group, scopes, sites, stakeholders, issues, objectives, SWOT, roles, activities, essential and support assets with dependencies and SPOFs, suppliers with contractual requirements, the full ISO/IEC 27001:2022 Annex A plus NIS2, GDPR and an internal baseline (133 requirements), audits with findings and action plans, an ISO 27005 risk assessment (threats, vulnerabilities, analyses, risks, treatment plans, acceptances), an EBIOS RM study (workshops 0-3), indicators with measurement history, and management reviews. Documented in docs/installation.md.

Fixed

  • Report downloads rendered as binary in the page: the global hx-boost intercepted clicks on file-download links (report list, management review PPTX/DOCX exports, risk register and assessment exports, framework import samples) and swapped the binary attachment into the page instead of letting the browser download it. Download links now opt out of boosting (hx-boost="false" + download), and a safety net in the boosted-navigation module cancels the swap and hands the URL to the browser whenever a response carries Content-Disposition: attachment.
  • Calendar "Upcoming events" showed negative day counts (#112): ranged items already in progress (action plans, treatment plans, compliance assessments) displayed their range start with badges like "in -131 days" and always floated to the top of the list. The card now consumes a dedicated /api/calendar-upcoming/ endpoint that reuses the dashboard's next-milestone logic (shared build_upcoming_deadlines() helper): ranged items show their start date until they begin, then their end/target date; past-due deadlines carry a red "Overdue" badge; concluded items are excluded; sorting uses the milestone date; and each row names the nature of the date in a small chip, like the dashboard.
  • Search palette ignored the user language: the navigation and quick-action entries of the command palette (Ctrl+K) were translated once at server start instead of per request, so they always showed up in the import-time language (typically English) regardless of the user's language. The labels are now lazily translated.

Changed

  • Search palette contrast: the command palette dialog was 85% translucent and blended into the blurred page behind it, reading as grey-on-grey. It now uses a near-opaque frosted surface (new --surface-glass-strong token, light and dark), a slightly darker backdrop scrim, and stronger group labels.
  • README rewritten for accessibility: the public README is now a short overview (what Cairn does, quick start, documentation links, tech stack). The detailed content moves to docs/: feature tables to docs/features.md, the full MCP tool reference to docs/mcp-server.md, installation and scheduled-command details to docs/installation.md, plus a new REST API overview (docs/api.md) and a documentation index (docs/README.md).
  • Documentation screenshots refreshed: all docs/screenshots/ captures retaken in 4:3 (1440x1080) on the current brand with the demo dataset, and embedded in the README (dashboard) and docs/features.md (one per module section).

Full Changelog: v0.26.2...v0.26.3

v0.26.2

12 Jun 09:27

Choose a tag to compare

Fixed

  • Predefined compliance indicators disagreed with the dashboard: the "Global compliance rate" predefined indicator averaged the stored compliance_level field over every reportable framework (drafts and superseded included), while the dashboard computes, per active framework, the proportion of applicable requirements whose latest assessment result is compliant. The computation is extracted into a shared service (compliance.services) now used by the dashboard page, the dashboard WebSocket refresh (which averaged the stored field too, so a live update could overwrite the page value with a different number) and both predefined indicators (global_compliance_rate and framework_compliance_rate).
  • Roles could not be assigned from the UI: the role create / edit modal had no "Assigned users" field, even though the model, the API and the MCP tools expose it (and the dashboard nags about mandatory roles without a user). The second step of the modal becomes "Assignment & status" and gains a multi-select of active users.

Changed

  • SPOF and calendar deadlines fold into Today's actions: the dashboard's standalone SPOF warning banner and "Upcoming events" card are gone. Single points of failure now appear as actionable items in the "To plan" group (one entry per dependency type, each linking to its list). Deadlines and events render as a section inside the Today's actions card, server-side (the client-side fetch is removed): upcoming dates for the next 30 days plus overdue deadlines (reviews, target dates, expiries) from the last 90 days. Ranged items (action / treatment plans, audits) now show their next milestone - the start date until they begin, then the target date - instead of always showing the range start, which produced nonsensical "in -131 days" badges; anything past due is flagged with a red "Overdue" badge instead of a negative day count. Overdue deadlines count toward the card's attention counter, and the list collapses beyond five items. Concluded items (closed or cancelled action plans, completed treatment plans, achieved objectives, revoked or renewed acceptances) stay on the calendar but leave the dashboard list: a closed plan is not "overdue". Each row names the nature of the date in a small chip (Review, Expiry, Effective date, Target date, Start date, Valid until, Audit start / end, Assessment or Analysis date) so an entry reads as "what is due", and the title drops the redundant "Review: " / "Expiry: " prefixes there.
  • Reports and Management reviews move under a Strategy group: the sidebar's Governance section gains a collapsible "Strategy" group (compass icon) after Indicators, holding the Reports and Management reviews entries, which leave the top-level General block (Dashboard and Calendar remain there).
  • Forms adopt the same design language: form fields take the recipe of the sidebar search field - glass card resting on the surface with a soft shadow lift, brightening on hover, surfacing to solid with the accent ring on focus (globally, in the modal form drawer, on Tom Select controls, input-group addons, the image-upload button and the scope tree containers). Fields use dedicated --field-* tokens: in light mode the fill is more opaque and the hairline border visible (pure glass is invisible on light surfaces), in dark mode they match the sidebar glass. The modal form drawer itself moves to the flat page-level background, like the sidebar panel, so the fields float over it the same way; its header, body and footer become transparent. The Jodit rich-text editor loses its default grey segmented chrome in both themes: the whole editor becomes one soft well that surfaces on focus, with a transparent toolbar, calm icon hovers, fading hairlines between toolbar / canvas / status bar, and themed popups. Tom Select controls follow the same well treatment and their dropdown becomes frosted glass like the other floating menus, as do the icon-picker popover and the scope-count popover. The modal wizard stepper softens: number chips rest on the muted well tones and connectors dissolve toward the next step. The drawer header / footer and the duplicated modal header / footer rules (which were overriding the theme-aware ones) get the fading hairlines, and the scope tree widget becomes a soft well whose embedded search is borderless over a fading hairline - with the selected row tinted like an active sidebar link. Input-group addons and the image-upload button align on the well tones.
  • The sidebar design language spreads to the rest of the interface: the visual vocabulary introduced by the sidebar redesign (frosted glass, fading hairlines, sentence-case labels) now applies across the UI. Floating elements pick up the translucent backdrop-blurred glass treatment: the mobile menu button, the sidebar collapse toggle, the bulk-actions bar (which loses its heavy accent border - the accent-coloured count is enough), dropdown menus, the global search dialog (which now keeps the material of the sidebar search field it morphs from), the toasts (semantic tints kept but translucent) and the modal backdrop. Hard border lines under headers are replaced by hairlines fading at their ends, echoing the sidebar's right-edge demarcation: card headers, modal header / footer, the search overlay input row, drawer section titles, the calendar timeline month labels and the styleguide section titles. All small UPPERCASE labels move to sentence case like the sidebar section labels did: table column headers, page-header eyebrows, stat / KPI card labels, detail-page card section titles (the text-uppercase utility is removed from ~140 headings), SWOT and risk matrix axis labels, calendar weekday headers, drawer and metadata labels, the OAuth consent screen and the collapsed-sidebar flyout titles. Reference codes (.ref) deliberately stay uppercase mono - they are audit-grade identifiers, not labels. The --sidebar-glass tokens are generalized as --glass / --glass-hover, and the notification list inside the sidebar adopts the invisible scrollbar.
  • CI actions upgraded to Node 24 runtimes: GitHub deprecates Node 20 action runtimes (forced to Node 24 on June 16, 2026; removed from runners on September 16, 2026). The workflows move to the latest majors, all running on Node 24: actions/checkout v4 -> v6, actions/setup-python v5 -> v6, docker/setup-buildx-action v3 -> v4, docker/login-action v3 -> v4, docker/metadata-action v5 -> v6, docker/build-push-action v6 -> v7.

Full changelog: v0.26.1...v0.26.2

v0.26.1

11 Jun 21:30

Choose a tag to compare

Changed

  • Dashboard alerts become "Today's actions": the red global-alerts banner at the top of the dashboard is replaced by a calm "Today's actions" card. The same signals (critical risks, non-compliant requirements, overdue action plans, unassigned mandatory roles, ownerless critical activities, end-of-life assets, expired supplier contracts, expiring risk acceptances) are now phrased as actionable to-do items ("Treat 3 critical risk(s)" instead of "3 critical risk(s)"), grouped by priority (Priority / To plan / To watch, each on a soft-tinted panel with a semantic dot), and each item links to the page where the user can act. The card carries a navy top accent, an icon chip and a count badge in the header, and items render as raised rows with a calm hover lift. Renders in three columns on desktop and stacks on mobile, in both themes.
  • Bolder overall-compliance score: the large percentage on the dashboard's "Overall compliance" card moves from weight 600 to 700 (the heaviest Inter weight allowed by the brand guidelines) so the headline figure stands out.
  • Sidebar redesign: the main menu becomes a flat, flush panel: page-background colour, no border or rounded corners, glued to the window edges, with a subtle hairline on its right edge and an invisible scrollbar. Two floating glass elements (translucent, backdrop-blurred) frame the scrollable menu: a search field at the top showing the platform-aware shortcut (Cmd K on macOS, Ctrl K elsewhere) and opening the global search overlay, and a user footer at the bottom (avatar, name, email) whose ellipsis expands an inline Profile / Sign out menu that closes after use. Menu entries slide beneath the glass while scrolling. Section labels move to sentence case, and the user avatar and its dropdown leave the floating top-right bubble (search, about and notifications stay there). In collapsed mode the search shrinks to an icon and the footer to the avatar.
  • Search overlay entrance animation: opening the search from the sidebar field morphs the dialog from the trigger's position and shape to its centered resting place (FLIP transform, 320 ms ease-out-expo). Ctrl+K keeps the plain fade and prefers-reduced-motion disables the flight.
  • Everything moves into the sidebar; the top-right bubble is gone: notifications live in the user footer - the bell (with its unread badge) replaces the ellipsis next to the avatar and expands an inline panel above the user row, animated like the user menu (both are Bootstrap collapses, mutually exclusive, closed by outside clicks and Escape); when the sidebar is collapsed a notification dot shows on the avatar instead. The About entry joins the user menu (Profile / About / Sign out) and the About modal gains a link to the GitHub repository. With search, notifications and About now in the sidebar, the floating top-right button bubble is removed, along with the dashboard's real-time connection dot (the live updates themselves are untouched). The brand area loses its border for a gradient veil under which scrolling entries fade out progressively, and the menu's right hairline fades out toward the top and bottom of the window.

Full changelog: v0.26.0...v0.26.1

v0.26.0

11 Jun 19:08

Choose a tag to compare

Fixed

  • Overall-compliance caption counted every requirement: the dashboard's "Overall compliance" card claimed "N requirements tracked" using the full requirement inventory, while the displayed average only covers validated active frameworks, so a draft framework's requirements inflated the caption. The caption now counts the applicable requirements of the frameworks that actually feed the average (new tracked_requirement_count), the inventory stat card keeps the full count, and the live WebSocket refresh applies the same reportable filter to the average as the page render. The caption's French translation also gains a real singular / plural form (it previously rendered "3 exigence suivie" because of an illegal filter inside blocktrans).
  • Modal step gating broken by rich-text fields: the step-completion check of the modal form engine read the first input inside each required field wrapper, which on rich-text fields is an unnamed internal input injected by the Jodit editor (always empty), so forms like the scope create / edit modal refused to advance past a step whose required fields were all filled. The check now reads the first named control of the wrapper (the real, synced form field). Also hardened two sidebar event handlers against non-element event targets (console TypeError on text-node hover).

Changed

  • List tables show a single lifecycle column: every domain list table now renders one Status column carrying the element's lifecycle state (workflow_badge), and the legacy Status / Approval column pair is gone. The 27 list views are aligned: the bespoke status badges (context binary toggles, asset ITAM states, compliance and risk workflows, management reviews) are replaced by the unified badge, the per-table "Approval" column (Approved / Pending) is removed everywhere, and the lifecycle column is sortable on workflow_state (this also repairs the scope / SWOT / risk-criteria headers, whose sort key did not match the view since the publication-status retirement; the risk-criteria list also still rendered the removed status field as a permanently empty badge). The asset, supplier and site dependency lists and the requirement list, which only showed the approval flag, gain the sortable lifecycle column in its place. The now-unused approval_enabled_for template tag and its versioning_tags library are deleted. Operational state filters above the tables (e.g. active / inactive stakeholders) are untouched: they filter the non-governing attribute, which remains visible on detail pages.

Removed

  • Legacy approval bar retired: the per-page "Pending approval / Approve" banner is removed from all 25 detail pages, along with the approval_banner styleguide component, its template tag and its CSS - the lifecycle stepper carries the state and the validation action (the Validate step is the approval act). The approve endpoints remain for API / MCP compatibility as deprecated aliases.
  • Publication status fields folded into the lifecycle: the Scope, Site, SWOT analysis and Risk criteria models lose their status field (and the matching enums) - their draft / active / archived vocabulary is now fully carried by the unified lifecycle (active and validated fold into the validated state, archived stays archived, data migrations included with history). Everything that exposed those statuses moves to the lifecycle: forms (the status selects disappear, transitions go through the stepper), scope and site pickers, list filters and sortable columns, Django admin, the REST serializers / filters / ordering (the status field is replaced by workflow_state), the MCP tools (filter and fields renamed; the state changes through transition_*), and the templates now render the workflow_badge. The scope archive API action becomes a lifecycle transition (archiving a draft is now correctly rejected) and the SWOT validate action drives the approval axis. Framework and Requirement deliberately keep their status (under_review / deprecated / superseded are versioning semantics the 4-state lifecycle does not cover - spec option (b)).

Added

  • Lifecycle workflow documentation: the canonical framework spec lands in docs/modules/governance/workflow.md (architecture, the default and the fifteen specific workflows with their governance flags, the as-built rules, the REST / MCP / UI surfaces and the recorded decisions); the entity files of the four retired publication statuses point at it, the README feature table describes the unified lifecycle, and the CLAUDE.md development guidelines now reference the generic stepper (WorkflowStepperMixin + includes/workflow_stepper.html) and the workflow registry instead of the removed bespoke implementations.
  • Workflow framework (foundation): a new core/workflow.py introduces the lifecycle engine that will unify the approval and per-model status systems (see issue #105). A Workflow is an ordered set of State objects, each carrying governance flags (counts_in_reports, linkable, deletable, is_initial, is_terminal), plus the allowed Transition objects (required permission action, optional mandatory comment, declarative side effects). The module ships the default 4-state lifecycle (draft -> pending -> validated -> archived), a workflow registry, permission-aware transition validation (validate_transition / allowed_transitions / apply_transition) and queryset helpers (reportable_states / linkable_states / deletable_states). Pure-Python and fully unit tested (27 tests); no model, database or UI wiring yet (those land in the following phases).
  • Action plan specific workflow: the compliance action plan is the first entity to run its own registered lifecycle workflow (action_plan), generated from the existing transition constants so the 8-state machine keeps a single source of truth. Each state carries its governance flags: new / to_define are deletable drafting states, to_validate onwards count in reports, to_implement / implementation_to_validate / validated are linkable, closed / cancelled are terminal; refusals keep their mandatory comment and per-step permissions (update, validate, implement, close, cancel) are enforced per transition. The model's transition_to() is now routed through the framework while preserving its legacy contract (ValueError on an illegal transition or missing refusal comment, completion fields auto-filled on close, ActionPlanTransition audit rows); the legacy status field and workflow_state are kept in sync both ways during the migration period, and a data migration aligns existing rows (including history). Linking and deletion governance now use the real action plan states (e.g. only to_implement / implementation_to_validate / validated plans can be linked to a treatment plan). Workflows can now also be declared per model in code (WORKFLOW_NAME), with the DB assignment still taking precedence.
  • Compliance assessment specific workflow: the compliance assessment now runs its own registered lifecycle workflow (compliance_assessment), generated from the existing ASSESSMENT_STATUS_TRANSITIONS constants. Per-state governance: only draft assessments can be deleted; planned / in_progress / completed / closed count in reports and on the calendar while draft and cancelled do not; closed / cancelled are terminal. The model's transition_to() is routed through the framework while keeping its legacy contract (single status argument, ValueError on an illegal transition, EVALUATED-results reset when completing) and status / workflow_state stay in sync both ways, with a data migration aligning existing rows including history.
  • Management review specific workflow: the management review (ISO 27001 clause 9.3) now runs its own registered lifecycle workflow (management_review), generated from the existing transition constants. Per-state governance: only a planned review can be deleted; cancelled reviews leave reports; closed / cancelled are terminal. The closure transition (held -> closed) is declared with the approve permission action, matching the rule the API already enforced, and cancellation keeps its mandatory comment, now enforced declaratively. The model's transition_to() is routed through the framework while keeping its legacy contract (ValueError, closure preconditions via can_close(), held_date auto-set, ManagementReviewTransition audit rows, snapshot flow untouched); status / workflow_state stay in sync both ways, with a data migration aligning existing rows including history.
  • Asset specific workflows: essential and support assets now run their own registered lifecycle workflows (essential_asset, support_asset). Their statuses had no transition constants (freely editable), so the workflows encode the natural ITAM progressions (essential: identified -> active <-> under review -> decommissioned; support: in stock -> deployed -> active <-> under maintenance -> decommissioned -> disposed, with decommissioning reachable from any active state). Governance: every state stays reportable (decommissioned and disposed assets belong to audit history), decommissioned / disposed assets are no longer linkable (declarative version of RS-04) and cannot be deleted; only each model's creation-default states remain deletable (identified for essential assets, in stock / active for support assets). Legacy free status edits keep working through the status / workflow_state sync, now factored into a shared sync_legacy_status() helper used by all five reconciled entities, and a data migration aligns existing rows including history.
  • Risk process specific workflows: the risk, treatment plan, risk acceptance and vulnerability now run their own registered lifecycle workflows, encoding the natural ISO 27005 progressions (these statuses were freely editable). ...
Read more