Skip to content

Controls module: register, effectiveness tests, SoA coverage; rich text sanitization - #184

Open
frousselet wants to merge 9 commits into
mainfrom
feat/ui-audit-framework
Open

frousselet wants to merge 9 commits into
mainfrom
feat/ui-audit-framework

Conversation

@frousselet

Copy link
Copy Markdown
Owner

Summary

A new Controls module (module 8) : the register of the security controls the organisation operates (ISO/IEC 27001:2022 clause 6.1.3, 8.1, 9.1), linked to the requirements they satisfy (any framework), the risks they treat, the treatment plans and EBIOS PACS measures that create them, the support assets they apply to, the objectives they serve and the documents that describe them. Effectiveness is never declared : it is derived from test runs that are frozen on submission and validated by someone other than the person who performed or recorded them. A failed run can raise a finding, and the Statement of Applicability now lists the implementing controls of every applicable requirement. Exposed on the web, the REST API and MCP. Specified first in docs/specs/m8-controls/.

The branch also carries a platform-wide security fix (stored rich text rendered unsanitized) and the specifications of the next two modules (training and awareness, business continuity), which are not implemented yet.

Related issue

None.

Type of change

  • Bug fix
  • New feature
  • Refactor / tech debt
  • Documentation
  • Build / CI / tooling

Changes

  • 79da3f3 Spec : docs/specs/m8-controls/ (README + four entity files); the specs that anticipated a future Measure entity now point at Control.
  • 011ebfa Domain : Control (CTRL), ControlTest (CTST), ControlTestRun (CTRN), write-once ControlTestEvidence (SHA-256); three lifecycles with a guarded archived exit; derived effectiveness and next due date; segregation of duties; Finding.control_test_run and the control_test source; services for "create from requirements" and requirement coverage; EBIOS W5 measures linkable while under way; 10 permission codenames, 3 notification types.
  • 80e2230 Specs of modules 9 and 10 (training and awareness, business continuity) : not implemented in this PR.
  • 67a2b21 Security : a |rich filter sanitizes stored rich text at render time and replaces |safe on every user-authored field (about forty pages and PDF reports); JSON embedded in <script> elements is escaped; findings raised by an incident or a control test are filed under that parent's scopes (scope_parent_alternates).
  • 2c332c0 REST API under /api/v1/controls/ (controls, tests, runs, from-requirements, raise-finding), and a filter set on findings.
  • 1218041 MCP : CRUD / transitions / history for the three entities plus create_controls_from_requirements, get_control_effectiveness, list_overdue_control_tests, list_my_control_tests_due, raise_finding_from_run, get_requirement_coverage; the MCP finding update / delete tools now check scopes.
  • e5f36af Web interface : both registers, the three detail pages, drawer forms, create from requirements, evidence upload / download / removal, raise a finding, sidebar, accent, help banners, user guide.
  • dd0a7b9 Integrations : Controls cards on seven detail pages, the enriched SoA, search, calendar, dashboard widget, kanban, two indicators, the controls_sweep reminders, the Voltara seed.
  • de55887 Docs : README, CHANGELOG, screenshots, French catalogue, generated reference, spec marked implemented.

Screenshots

docs/screenshots/controls.png, control-detail.png, control-tests.png (2560x1440). Full crawl of 336 pages in light / dark at 1600 px and 390 px (1,344 loads) : no regression against the previous baseline, every controls page HTTP 200 with no horizontal overflow and no console error.

Checklist

  • Tests added or updated, and pytest passes
  • ruff check passes
  • New feature exposed as MCP tools in mcp/tools.py (accurate docstrings and parameter descriptions)
  • New feature has REST API endpoints under the app's api/ (serializers, viewsets, routes under /api/v1/)
  • UI renders correctly in light and dark mode
  • UI renders correctly on mobile (multi-selects, sticky bars, form layouts)
  • User-facing strings use _() / {% trans %} with French translations in locale/fr/LC_MESSAGES/django.po (no duplicate msgid; compilemessages passes)
  • Lifecycle / workflow respected (state metadata and generic stepper UI; no hardcoded status values)
  • README.md updated (features, MCP tools, tech stack, install) when behaviour changed
  • CHANGELOG.md updated under ## [Unreleased]
  • Brand guidelines respected (docs/brand/brand-guidelines.md); no em dash characters
  • Relevant spec under docs/specs/ updated in the same PR
  • Project / documentation screenshots captured at 2560x1440 (16:9, 1440p)
  • Audit-grade rigor preserved (approval workflows, versioning, history, permission checks not bypassed)

Verification : full suite 3,663 passed, ruff clean, generate_docs --check and build_wiki.py --check clean, compilemessages clean.

Known limits (spec §11) : no automatic residual risk from control effectiveness, no ingestion endpoint for automated test results, no maturity scoring, no sampling helpers.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FaEkJnhS3VNDeb6jrdn6MC

…ests

Module 8 : Control (CTRL), ControlTest (CTST), ControlTestRun (CTRN) and
write-once ControlTestEvidence, with the RG-CTL business rules, three
lifecycles, permissions, API, MCP tools, notifications and UI. Controls
link to requirements, risks, treatment plans, PACS measures, support
assets, objectives and documents; effectiveness is derived from
independently validated runs; failed runs can raise a finding; the SoA
lists the implementing controls. The entity specs that anticipated a
future Measure entity now point at Control.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FaEkJnhS3VNDeb6jrdn6MC
A new controls app (module 8) with its four models, three lifecycles,
permissions and notifications, implementing the RG-CTL rules of
docs/specs/m8-controls/:

- Control (CTRL): ISO 27002 theme, nature and automation, owner, links
  to requirements, risks, treatment plans, PACS measures, support
  assets, objectives and documents (reverse accessor `controls` on each);
  proposed / planned / implemented / retired, with the implementation
  date stamped on declaration and the tests retired with the control.
- ControlTest (CTST): method, procedure, acceptance criteria, frequency
  and tester; activation needs a planned or implemented control and a
  pass criterion; the next due date is derived from the latest
  validated run.
- ControlTestRun (CTRN): result, period, sample and observations,
  frozen from submission; validated by someone who neither performed
  nor recorded it (superusers included); validation and withdrawal recompute the test's
  due date and the control's derived effectiveness in one transaction;
  a validated partial or failed run raises one finding on demand.
- ControlTestEvidence: files with their SHA-256, added or removed only
  while the run is in progress.

Finding gains a control_test_run link and a "Control test" source. The
commented-out Measure placeholders are gone, and EBIOS RM workshop 5
measures become linkable while planned, in progress or overdue, so a
control can name the measure that creates it. Ten permission codenames
are attached to the system groups and three notification types added.
Shared services create proposed controls from a framework's uncovered
requirements and compute the per-requirement coverage behind the SoA.
The web views are placeholders until the interface lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FaEkJnhS3VNDeb6jrdn6MC
Module 9 (training and awareness): a course catalogue with validity,
competencies required by roles and groups, training campaigns with
write-once enrolments (trainer recording, self-attestation, CSV import
with a dry run) and the derived competency matrix, on an audience
engine extracted from the documents acknowledgement campaigns.

Module 10 (business continuity): business impact analyses with impact
grids and MTD / RTO / RPO written to the essential assets on
validation, continuity plans with ordered recovery steps and a
feasibility check against the covered RTOs, exercises that move the
next exercise date and can raise a finding, and plan activations from
an incident with a write-once log.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FaEkJnhS3VNDeb6jrdn6MC
…ident findings

Rich text written by the pell editor reaches the database as submitted
(forms, REST and MCP alike) and some forty detail pages, previews and PDF
reports rendered it with |safe : any contributor could store markup that
ran in a reader's browser. A new |rich filter in the UI framework renders
it through the existing allow-list sanitizer, and every user-authored
field now uses it; the Statement of Applicability sanitizes the stored
justification it embeds. JSON placed inside <script> elements (lifecycle
graphs, the dependency graph, the lifecycle editor) is escaped so a name
can no longer close the element.

Nonconformities raised by a security incident were visible to every
finding reader whatever their scopes : core.scoping learns
scope_parent_alternates, and a finding is filed under its assessment,
its incident or its control test run.

The rule (|rich, never |safe) is added to the UI components catalogue
and CLAUDE.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FaEkJnhS3VNDeb6jrdn6MC
/api/v1/controls/ exposes controls/, tests/ and runs/ in the house
pattern (module permissions, scope filtering, lifecycle transitions,
allowed transitions and history), with the filters of the spec and two
actions : controls/from-requirements/ (create proposed controls from a
framework's uncovered applicable requirements, which also needs
compliance.framework.read) and runs/{id}/raise-finding/.

Derived fields (effectiveness, next due date, activation and review
stamps, evidence fingerprints) are read-only; relation ids are checked
against the caller's scopes and linkable_or_linked(); a PATCH on a
submitted run fails with the model's own message; evidence is listed
with a permission-checked download URL, never the file. Findings expose
their originating run, and the findings endpoint gains a filter set
(source, control_test_run, ...).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FaEkJnhS3VNDeb6jrdn6MC
_register_controls_tools() adds the CRUD, transition and history tools
of controls, control tests and test runs (relations checked against the
caller's scopes and linkable_or_linked(), derived fields read-only),
plus create_controls_from_requirements, get_control_effectiveness,
list_overdue_control_tests, list_my_control_tests_due,
raise_finding_from_run and get_requirement_coverage, a `controls` help
topic and the CTRL / CTST / CTRN prefixes. Segregation of duties holds
since the acting user is the authenticated one. The assistant catalogue
gains read-only entries for the register, a control's effectiveness and
a framework's coverage; the reference generator covers the app.

The finding tools accept the control test source and run id, no longer
fail on a finding without an assessment, and update_finding /
delete_finding now check the caller's scopes (they did not).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FaEkJnhS3VNDeb6jrdn6MC
The control register (/controls/) with its rail (implemented controls,
effective rate, overdue tests, never tested), filters and saved views;
the test register; the control, test and run detail pages on the
detail layout with the lifecycle stepper, and their drawer forms with
page fallbacks and delete shells.

- Create from requirements : pick a framework, tick its applicable
  requirements without a control, and proposed controls are created
  with its scopes.
- Runs are recorded from an active test (performer and date prefilled),
  editable only while in progress; evidence is uploaded, listed with its
  size and SHA-256 and removed only while the run is open, and served
  through a permission- and scope-checked download, never a media URL.
- A validated partial or failed run offers "Raise a finding" once, and
  then links to it.

A Controls section in the sidebar, the module accent, breadcrumbs, help
banners for the five pages and a user guide page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FaEkJnhS3VNDeb6jrdn6MC
…d the seed

- A Controls card (one shared include, scope-filtered, gated on
  controls.control.read) on the requirement, risk, treatment plan, EBIOS
  workshop 5, support asset, objective and policy pages, with each
  control's state and effectiveness, a stale flag when a test is
  overdue and retired controls listed last.
- The finding page links to the run that raised it; the register
  filter knows the control test source, which manual entry never offers.
- The Statement of Applicability lists, per applicable requirement, its
  reportable controls with state and effectiveness and an Implementation
  column, and names the controls before the action plans in the
  justification (now escaped).
- Global search, a calendar category (next test due dates), a Controls
  dashboard widget, kanban cards (my tests due and the runs in review I
  may validate in To do, never my own; my draft runs in Doing) and two
  predefined indicators (effectiveness rate, overdue tests).
- controls_sweep : due and overdue reminders and the effectiveness
  recomputation, documented with the other daily sweeps.
- The Voltara seed creates sixteen ISO 27001 Annex A controls from the
  framework, links them across the platform, and records tests, runs
  (passed, partial, failed with a finding, withdrawn, in review, in
  progress) and evidence files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FaEkJnhS3VNDeb6jrdn6MC
…spec marked implemented

The README feature table and the CHANGELOG gain the Controls module;
the user guide shows the control register, a control page and the test
register (captured at 2560x1440, added to the capture script); the
French catalogue covers every new string, with a "control" context
where a label collides ("Control" was the verb); the generated reference
is re-rendered. The spec is marked implemented, with its wiring
checklist ticked and three adjustments made during the build : the
recorder of a run cannot validate it either, an active test stays
editable, and the kanban keeps its three columns.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FaEkJnhS3VNDeb6jrdn6MC
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants