-
Notifications
You must be signed in to change notification settings - Fork 2
Specs Governance Workflow
core.lifecycle - the single, standardised engine every domain element runs on.
History. This document was originally the spec for the first-generation
core.workflowengine (issue #105). That engine, its per-appworkflows.pymachines, theWorkflowStepperMixin, the separate boolean approval axis (is_approved/approved_by/approved_at) and theVersioningConfigadmin have all been removed. Everything below describes the current state: a singlecore.lifecycleengine, with validation expressed purely as reaching a reportable lifecycle step. The engine internals are documented inlifecycle.md; this file is the governance / cross-cutting-rules reference.
Every domain element runs a lifecycle: an ordered set of steps with the allowed transitions between them. Governance is metadata carried by each step, so the cross-cutting rules (inclusion in reports / KPIs / the calendar, linking, deletion, notifications) read step flags instead of hardcoded status values.
Declared in code, assigned per model, governed by flags:
-
Step:code, translatablelabel, UItone(badge colour),kind(StepKind.DRAFT- the single entry;StepKind.INTERMEDIATE;StepKind.ARCHIVED- the detached exit shown on the stepper's single line but separated by a gap with no connector to the main flow), and the governance flags:
-
counts_in_reports- included in reports, KPIs, the calendar and exports; -
linkable- may be targeted by a new link; -
deletable- may be deleted. A step also carries an optional list oftriggers(type+config), fired when the entity enters the step. The first type isconfirm: a Yes/No confirmation modal shown before the move (optionalconfig["message"], blank ⇒ the default translated "Are you sure?"). Several triggers per step are allowed; unknown types round-trip untouched, so new types slot in without a schema change. In the JSON definition :"triggers": [{"type": "confirm"}], toggled per step from the Cairn admin editor's Confirm column.
-
Transition:target,source(a specific step orANY), translatablelabel,permission_action(permission action suffix, resolved against the entity'smodule.featurenamespace) andrequires_comment. -
Lifecycle: name + steps + transitions +layout(line/graph); invariants validated at construction (exactly one Draft, at least one Archived). Every performed transition is recorded as an immutablecore.models.LifecycleEvent(actor, from, to, comment, form data, timestamp). -
Registry :
register_lifecycle(lifecycle)populates the name -> lifecycle map. Specific lifecycles are registered from each app'sAppConfig.ready()(assets/lifecycles.py,compliance/lifecycles.py,risks/lifecycles.py,reports/lifecycles.py,trust_center/lifecycles.py,context/lifecycles.py). -
Assignment : the model's
LIFECYCLE_NAMEclass attribute names its lifecycle; a model that declares none runs the default lifecycle.resolve_lifecycle(model)never returnsNone.
Model API (context.models.base.BaseModel): workflow_state field (indexed),
get_lifecycle(), lifecycle_label, lifecycle_tone, the governance properties
(counts_in_reports, is_linkable, is_deletable, is_terminal_state),
available_transitions(user), transition_to(target, user, comment=..., enforce_permission=...)
and a workflow_perm_namespace property (overridden where the permission feature
differs from the model name, e.g. compliance.action_plan). A new-element save
snaps workflow_state to the lifecycle's initial step. Models with a domain status
enum (Risk, Objective, ...) mix in LegacyStatusMixin, which aliases obj.status
and obj.get_status_display() onto workflow_state.
Queryset helpers (core.lifecycle): reportable(qs), linkable(qs),
linkable_or_linked(qs, linked_qs) plus the state-set functions (reportable_states,
linkable_states, deletable_states). All no-op for models without a lifecycle
(plain child models).
Applies to every model without a specific lifecycle.
| Step | In reports | Linkable | Deletable | Kind |
|---|---|---|---|---|
draft (initial) |
no | no | yes | draft |
pending |
no | no | no | intermediate |
validated |
yes | yes | no | intermediate |
archived |
no | no | no | archived |
| Verb | Transition | Permission | Effect |
|---|---|---|---|
| Submit | draft -> pending | .update |
notify owner |
| Send back to draft | pending -> draft | .update |
- |
| Validate | pending -> validated | .approve |
element counts in reports |
| Archive | validated -> archived | .approve |
- |
Validation is no longer a separate boolean: an element is "approved" exactly when
it sits on a step that counts_in_reports (here, validated), reached through the
permission-gated transition. There is no approval reset or version-on-major-field
machinery.
The registered specific lifecycles preserve the operational semantics that the 4-step default does not cover. Their domain step codes equal the historical status values.
Universal Draft / Archived bookends. Every lifecycle is bookended by the generic
draft entry and archived exit (the scope / supplier pattern), so every stepper
graph starts at Draft and ends at Archived. When a specific lifecycle's
domain states do not already provide draft / archived, the port helper prepends /
appends them and auto-wires draft -> <domain initial>, any -> archived and
archived -> draft (restore). A new element therefore starts in Draft; the domain's
former initial / terminal states (identified, closed, planned, ...) become ordinary
steps that keep their governance flags and lead into the Archived exit.
| Lifecycle | Model | Highlights |
|---|---|---|
action_plan |
compliance.ComplianceActionPlan | 8 steps; refusals require a comment; per-step permissions (update, validate, implement, close, cancel); to_implement / implementation_to_validate / validated linkable; new / to_define deletable; transitions logged in ActionPlanTransition
|
compliance_assessment |
compliance.ComplianceAssessment | only draft deletable; cancelled leaves reports / the calendar; EVALUATED-results reset on completion preserved |
management_review |
reports.ManagementReview | closure (held -> closed) carries .approve; cancellation requires a comment; can_close() preconditions and the closure snapshot preserved |
essential_asset / support_asset
|
assets | natural ITAM progressions; decommissioned / disposed not linkable (RS-04) and not deletable; every step stays reportable (audit history) |
risk |
risks.Risk |
identified is the draft analog (not in the register, not linkable); monitoring -> analysis review loop; closed terminal but reportable |
risk_treatment_plan |
risks.RiskTreatmentPlan | automated overdue flip preserved; cancelled leaves reports |
risk_acceptance |
risks.RiskAcceptance | renewal cycle; revoked terminal; every step reportable (audit trail) |
vulnerability |
risks.Vulnerability | direct false-positive closure |
risk_assessment |
risks.RiskAssessment | rework loop from completed; validated_by stamp on validation |
ebios_workshop |
risks (EBIOS) | review verdicts; rejection requires a comment; rework loop |
ebios_study_framework, ebios_security_baseline, ebios_summary, ebios_baseline_gap, ebios_pacs_measure
|
risks (EBIOS) | natural deliverable progressions |
scope / site
|
context | perimeter / location flows on the directed-graph layout; in_force + review (scope) and operational + review (site) count in reports |
publication / document_request
|
trust_center | publishing gated by the trust-center permission |
Decisions recorded during the rollout:
-
Binary toggles (Stakeholder, Role, Activity, AssetGroup, Threat, Indicator) and
outcome trackers (Objective, Issue, StakeholderFeedback) keep their
statusas a non-governing operational attribute over the default lifecycle. A toggle has no terminal step, so it is not a lifecycle. -
Publication statuses retired: Scope, Site, SwotAnalysis and RiskCriteria lost
their legacy
statusfield entirely. Framework and Requirement keepstatusas a versioning attribute (under_review/deprecated/supersededcarry semantics the lifecycle does not).
-
RG-LC-01 : an element whose step has
counts_in_reports = falseis excluded from generated reports (SoA, risk register), computed KPI rates, the compliance donut and the calendar. Dashboard inventory count tiles deliberately stay full (product decision: counts are a working inventory). Assessment-scoped documents (audit report, ISO 27005, management review exports) keep the full content of the explicitly chosen assessment. -
RG-LC-03 / RG-LC-04 (target-side linking) : a new link may only target a
linkableelement; already-linked elements stay selectable so an edit never drops an existing link; an element in a terminal step cannot gain new links; unlinking is always allowed. Authoring links from a draft element is allowed by design. -
RG-LC-05 : deletion is blocked at the model level (
BaseModel.delete()raisesLifecycleProtectedError) unless the step isdeletable. Cascade and bulk deletes bypass it by design. -
RG-LC-06 / RG-LC-09 (notifications) : transitions that notify (Submit on the
default lifecycle) notify, in fallback order: the element's own
managers(scope-like containers), the managers of its scopes, the holders of the entity's.approvepermission, then the creator. The actor and inactive users are never notified. Delivery: in-appaccounts.Notificationrows (rendered in the recipient's language) + email ontransaction.on_commit(per-useremail_notificationsopt-out) + a per-user WebSocket badge push (/ws/notifications/). -
RG-LC-07 : each transition requires its declared permission action, resolved
against the entity's
module.featurenamespace.
-
REST :
GET /api/v1/<entity>/<pk>/transition/lists the caller's permitted transitions;POSTperforms one (target_state, optionalcomment). Lifecycle lists accept?workflow_state=a,b. Provided byaccounts.api.mixins.LifecycleAPIMixin; the bespoke transition endpoints (assessment required-fields gating, action plan, management review closure) keep their extra side effects and shadow the generic action. -
MCP :
transition_<entity>(id, target_state, comment)and<entity>_allowed_transitions(id)for every CRUD entity. Link tools enforce the linking rules with explicit error lists. Domain approvals that are real lifecycle actions keep dedicated tools (approve_trust_center_document_request,reject_trust_center_document_request). -
UI : every detail page renders the generic stepper
(
includes/lifecycle_stepper.html, context built byaccounts.mixins.LifecycleStepperMixin) - a single centred line drawn directly on the page background (no card) holding the main flow pills and the archived off-ramp (detached, no connector); cyclic lifecycles use the directed-graph layout. Both the forward next step and an allowed backward move are clickable pills, with the shared comment modal gated by each transition'srequires_comment. Transitions post toworkflow:transition(/workflow/<app>/<model>/<pk>/transition/, validated-referer redirect) or to the entity's bespoke endpoint (lifecycle_transition_url_name). State badges render via{% workflow_badge obj %}(helpers.templatetags.workflow_tags).
Built from docs/ at v0.36.0. Edits made here are overwritten by the next release : open a pull request against the source instead.
- Administration
- Ask Cairn
- Assets and suppliers
- Compliance
- The dashboard
- Finding your way
- Getting started
- Incidents
- How records move
- Organisational context
- Reports and management review
- Risks
- Trust Center
- Architecture
- Configuration
- Contributing
- The documentation system
- Installation
- Internationalisation
- Operations
- Release process
- Security
- Testing
- Adding an assistant provider
- Adding a dashboard widget
- Adding a domain entity
- Declaring a lifecycle
- Adding an MCP tool
- Adding a REST endpoint
- Adding a report
- Interface conventions
- Dashboard widgets
- Lifecycles
- MCP tools
- MCP tool parameters : Assets
- MCP tool parameters : Compliance
- MCP tool parameters : Governance and context
- MCP tool parameters : General
- MCP tool parameters : Incidents
- MCP tool parameters : Reports and management review
- MCP tool parameters : Risks
- MCP tool parameters : System and administration
- MCP tool parameters : Trust Center
- Management commands
- Models
- Permissions
- REST endpoints
- Environment variables
- MCP server
- REST API
- Assistant module (Ask Cairn)
- Module 0: User Management and Access Control
- Module 1: Context and Organization
- Module 2: Asset Management
- Module 3: Compliance
- Module 4: Risk Management
- Module 4 bis - EBIOS Risk Manager
- Module 5 : Trust Center
- Module 6 : Security Incident Management
- Management review : ISO 27001:2022 compliance (clause 9.3)