43. Framework scores, manual evidence and signed reports
This guide describes Lawliet 1.5.14.s (the current release). Screens, commands and procedures may change in later versions; the usage guide is updated with each release. Check the version your server runs under Settings > Platform or with ./lawliet version, and see the Releases page for what changed.
Compliance > Frameworks gives a score per framework - CIS, DISA STIG, NIST SP 800-53 r5, ISO 27001:2022, PCI DSS 4.0, GDPR, FSTEC orders 17, 21 and 239, GOST R 57580.1, NIS2, DORA - for a group of hosts, rolled up per requirement from the control results through the framework mappings (40.1). It also holds the manual evidence for requirements no check can measure, and produces signed reports and evidence packs an auditor can verify.
Permissions:
| Task | Permission | Four-eyes |
|---|---|---|
| See scores, requirements, history | View compliance | - |
| Upload evidence for a manual requirement | Manage compliance | no (it counts only once someone else accepts it) |
| Accept someone else's evidence | Accept requirement evidence | yes - critical action "Accept requirement evidence"; never the uploader's own |
| Withdraw evidence (API) | Manage compliance | no |
| Generate a signed PDF or HTML report, or an evidence pack | Manage evidence | no |
| List and download reports, download the public key and key history, verify a file | View evidence | no |
| Rotate the evidence signing key (API) | Rotate the evidence signing key | yes - critical action "Rotate the evidence signing key" |
Demo (sandbox) data and real data never mix in a score or a report: a sandbox account sees only reports made from demo data.
43.1 What the page shows#
Path: Compliance > Frameworks.
- Host group list (top right): All hosts, the built-in groups Windows workstations, Windows member servers, Domain controllers, Linux servers, and every host group (42.8), each with its host count. Refresh reloads.
- One card per framework: its score, and the counts beside it - met, not met, accepted risk, not assessed, partial, manual, not covered - and "N of M requirements assessed (P%)". Click a card to open it.
- The framework detail: its scope ("<group> - N host(s) - results older than 30 days count as not assessed - catalog <version>"), the score history line, the generate buttons, a Status filter and the requirement table (43.2).
- Signed reports and evidence packs (43.4), with Public key, Key history and Verify a report or evidence pack.
How the score is calculated#
score = met / (met + not met)Accepted risk, not assessed, partial, manual and not covered requirements are counted beside the score, never folded into it. A score without them would overstate what was measured.
| Requirement status | When |
|---|---|
| Met | Every mapped control is compliant on every host in scope it applies to |
| Not met | Any mapped control fails on any host in scope. A failure older than 30 days still counts, marked "stale failure (still counts)" |
| Accepted risk | A failure is covered by an approved exception (25.2) |
| Not assessed | A mapped control could not be checked, or its pass is older than 30 days (FRAMEWORK_RESULT_MAX_AGE_DAYS) |
| Partial: not every host checked | Results are compliant, but not every host it applies to was checked. Hosts checked shows "checked / applies to", by platform and role |
| Manual: evidence required | An organisational requirement, or one only manual checks map to, with no accepted evidence |
| Manual: evidence provided | Accepted evidence is on file. A failing check still makes it not met |
| Not covered: no check maps to it yet | A technical requirement with no check in this release |
A score point is recorded whenever results, exceptions or evidence change; the line under the title shows it ("<score> on <date> to <score> on <date>").
43.2 Procedure: read a framework for an audit scope#
- Open Compliance > Frameworks and choose the Host group of the audit scope.
- Click the framework's card.
- Use Status to show, for example, only Not met.
- The table shows Requirement (id and title), Status, Hosts checked, Controls (the mapped control ids, or "process requirement") and Failing hosts.
- To fix what fails, open the failing hosts in the planner (chapter 41); to accept a risk instead, request an exception (25.2).
43.3 Manual requirements: upload and accept evidence#
Procedure: upload evidence#
Permission: Manage compliance. Four-eyes: no; it counts only after another person accepts it.
On a requirement marked as a process requirement, press Evidence.
Fill Evidence for <id>:
Field What to enter Title At least 3 characters, for example "Information security policy v3, approved by the board" Valid until (optional) The date the evidence stops counting Note Free text (up to 4000 characters) File (up to 20 MB) The document. A file or a note is needed Press Record evidence. You see "Evidence recorded against the requirement." It is listed under Evidence awaiting a second person.
"Evidence counts once a second person accepts it; it never outweighs a failing check and does not change the measured score."
Procedure: accept evidence#
Permission: Accept requirement evidence. Four-eyes: yes (critical action "Accept requirement evidence"); the uploader can never accept their own.
- Under Evidence awaiting a second person, read the entry (requirement, title, file, uploader).
- Press Accept. With dual control on, approve and execute the request.
What you see: "Evidence accepted: it now counts toward the requirement." The requirement reads Manual: evidence provided, and the evidence moves to Manual evidence on file.
If it fails: "the uploader cannot accept their own evidence: a second person must" (403); "this evidence was withdrawn" (409).
To withdraw evidence, there is no console button in this release: DELETE /api/v1/compliance/framework-scores/{framework}/evidence/{evidence_id} (Manage compliance). The requirement returns to "Manual: evidence required".
43.4 Signed reports and evidence packs#
Each installation has its own evidence signing key. Every report and pack carries a detached Ed25519 signature (a .sig file) made with it, over the file and over the signature document (time, name, key fingerprint).
| Kind | Content |
|---|---|
| PDF report / HTML report | Summary; the per-requirement table; control evidence (command, output, host, time); exceptions with reason, approver and expiry; the changes the hardening executor made, with requester and approver; the catalog version. PDF fonts are embedded; nothing is fetched when a report is opened or generated |
| Evidence pack | A zip of JSON and CSV for every result (secrets in command output redacted), the requirements, mappings, exceptions, executor changes and manual evidence, with a SHA-256 manifest signed inside the pack |
Procedure: generate and hand over a signed report#
Permission: Manage evidence (the Analyst role holds it; so do Run scans API keys). Four-eyes: no.
- Choose the Host group and the framework (43.2).
- Press PDF report, HTML report or Evidence pack ("Signing..." while it works).
- The file and its
.sigdownload. You see "Generated and signed. The file and its .sig were downloaded." - Press Key history (downloads
lawliet-evidence-keys.json: every evidence key with its retirement time). Optionally Public key (lawliet-evidence-key.pem). - Give the auditor the file, its
.sigand the key history.
The table lists every report of the framework: File, Scope, Score, Generated (time and by whom), and File / .sig download buttons.
Procedure: verify a report in the console#
Permission: View evidence.
- Under Verify a report or evidence pack, choose the File and its Signature (.sig).
- Press Verify.
What you see: "Valid: signed by this installation (<file name>)." - with ", with a key retired <time>, before which this report was issued" when an earlier key signed it - or "Invalid: <reason>." Both show the file's SHA-256. Files larger than the upload limit are refused with "file too large to verify here; use verify_lawliet_signature.py".
API: POST /api/v1/compliance/framework-reports/verify (multipart file and signature).
Verify offline#
The offline check is a small Python script, tools/verify_lawliet_signature.py in the installation directory (no network, no Lawliet server; it is the same for every installation, so an auditor can take a copy). First save the key history: Compliance > Frameworks > Key history (lawliet-evidence-keys.json). On the server, ./lawliet verify-report runs it with this host's Python 3 when it has the cryptography package, and otherwise inside the backend container (3.24 verify-report):
./lawliet verify-report REPORT.pdf --key-history lawliet-evidence-keys.json # REPORT.pdf.sig beside itAnywhere else (an auditor's computer with Python 3 and cryptography):
python3 verify_lawliet_signature.py --key-history lawliet-evidence-keys.json REPORT.pdf REPORT.pdf.sig| Exit | Output | Meaning |
|---|---|---|
| 0 | VALID: signed <time> by key <fingerprint> | Signed by the installation's current key. Compare the fingerprint with the one printed in the report |
| 1 | INVALID: <reason> | Altered, or not signed by any key of this installation |
| 2 | - | Usage error or unreadable input |
| 3 | UNCONFIRMED: intact, but signed by a key retired at <time>... | Intact, but a retired key's signature can be confirmed only by the installation (verify in the console) |
| 4 | WARNING: intact signature ... --public-key alone ... | Run with --public-key only: a retired key cannot be detected. Use --key-history |
Rotating the evidence signing key (API)#
Rotate when the key may be exposed (for example a server backup left your control). Earlier reports still verify.
Permission: Rotate the evidence signing key. Four-eyes: yes.
- Send
POST /api/v1/compliance/framework-reports/rotate-keywith an administrator's session. With dual control on it is held; a second administrator approves it, and you execute it from Approvals > My requests. - The answer gives the retired and the new fingerprint. Download the new Key history and give it to your auditors.
A retired key's signature is accepted only for reports this installation issued before the retirement, so a copy of an old key cannot sign new reports. Risk: none to existing reports. Rollback: none; a retired key is never reactivated.

