Ownware
Home›Cyresora›Manual
Cyresora · Manual

Cyresora Manual, as shipped in the download

Cyresora — User Manual

A NIS2 and CRA incident-reporting register: what you became aware of, when, which reporting clocks that started, what has actually been submitted, and what is still running. The API reports version 1.0.4 [src: app/controllers/api.php:17].

About this manual

Every statement here was written by reading Cyresora's own source, and each one carries the file it came from in a bracketed src marker. Paths are relative to the folder this docs directory sits in. If a sentence disagrees with the application, the application is right and this manual has a bug.

This manual is not legal advice and does not verify either instrument. Articles, durations and dates below are reported as what the product implements — check them against the Official Journal and, for NIS2, against your own Member State's transposition, which the product deliberately does not model [src: app/src/Clock.php:38].

What Cyresora is

The clock engine is pure, offline, and never reads the system time — every function takes "now" as an argument, so tests pin real instants instead of hoping the suite does not run at midnight [src: app/src/Clock.php:3].

That is not a testing detail. It is why the deadlines in this manual could be reproduced exactly, by running the engine rather than describing it.

⭐ Four anchors, not two ladders

The obvious model — two ladders of 24 h / 72 h / final, both counted from the moment you found out — is wrong, and the source says it is wrong in the direction that produces a confident, late filing [src: app/src/Clock.php:9].

Read the instruments and there are four different anchors [src: app/src/Clock.php:11]:

RegimeStageCounted fromLength
CRA — actively exploited vulnerabilityearly warningbecoming aware24 h
notificationbecoming aware72 h
final reporta corrective or mitigating measure being available14 days
CRA — severe incidentearly warning / notificationbecoming aware24 h / 72 h
final reportsubmission of the incident notification1 month
NIS2 — significant incidentearly warningbecoming aware24 h
notificationbecoming aware72 h
intermediate reporta CSIRT asking for one—
final reportsubmission of the notification1 month
final report after handlingthe handling being completed1 month

The regimes and the provision each rests on are declared in one place [src: app/src/Clock.php:70], and every stage carries the article it comes from and the instrument's own wording [src: app/src/Clock.php:87].

⭐ Three consequences the register has to carry

*A deadline can be not started yet.* The CRA's fourteen days does not begin until a corrective or mitigating measure exists. Showing a due date before then would be an invented date, so the engine returns pending and names the event that will start it [src: app/src/Clock.php:33]. In the ladder that looks like this — a Friday-evening discovery with no remedy yet, run through the engine:

early    Early warning                anchor=awareness  due=2026-09-19 19:00:00  state=open     weekend=YES
notify   Vulnerability notification   anchor=awareness  due=2026-09-21 19:00:00  state=open     weekend=no
final    Final report                 anchor=remedy     due=(none)               state=pending  weekend=no

The one-month clocks run from the actual submission, not from the deadline [src: app/src/Clock.php:36]. Notify at hour 40 and the final report is due a month after hour 40. Executed on a NIS2 incident notified at 23:30 on 5 May:

final    Final report   anchor=notification   due=2026-06-05 23:30:00

  the 72-hour deadline would have been    2026-05-07 08:00:00
  a month from that deadline              2026-06-07 08:00:00   ← two days later than the truth

A product that anchored on the deadline rather than the filing would have shown a due date two days late. This one does not.

NIS2 is a Directive. What binds an entity is its Member State's transposition. The engine models the Directive's own stages and the register records the national authority; it does not pretend to know a national variation [src: app/src/Clock.php:38].

⭐ Two arithmetic hazards, both of them "wrong by a day" bugs

In a product whose entire value is the date, these are not tidiness [src: app/src/Clock.php:42].

Calendar months. PHP's own modify('+1 month') from 31 January returns 3 March — a deadline later than the law allows, silently. Every calendar-month deadline here clamps to the last day of the target month instead [src: app/src/Clock.php:45]. Both, side by side, from the running engine:

2026-01-31 09:00   PHP: 2026-03-03 09:00      Cyresora: 2026-02-28 09:00
2026-01-30 09:00   PHP: 2026-03-02 09:00      Cyresora: 2026-02-28 09:00
2026-03-31 12:00   PHP: 2026-05-01 12:00      Cyresora: 2026-04-30 12:00

Daylight saving. Twenty-four and seventy-two hours are absolute durations computed on UTC instants, where a clock change cannot touch them. "One month" is a calendar expression: it is computed in the business timezone and converted back, so it lands at the same wall-clock time — which is what a deadline in months means to the person who has to meet it [src: app/src/Clock.php:48]. Executed across both European changeovers, business timezone Europe/Bratislava:

one month from 2026-02-25 13:00 UTC  ->  2026-03-25 13:00 UTC     (14:00 local -> 14:00 local)
one month from 2026-09-25 13:00 UTC  ->  2026-10-25 14:00 UTC     (15:00 local -> 15:00 local)

24 h from 2026-10-24 13:00 UTC       ->  2026-10-25 13:00 UTC     (absolute, untouched)
72 h from 2026-10-24 13:00 UTC       ->  2026-10-27 13:00 UTC     (absolute, untouched)

The second month-deadline moves by an hour in UTC precisely because it did not move in local time.

⚠️ The clocks do not stop at the weekend

The source says this out loud because a buyer will assume otherwise: neither CRA Article 14 nor NIS2 Article 23 has a working-day carve-out, and a Friday evening discovery is due on Saturday evening [src: app/src/Clock.php:53].

The engine flags it rather than leaving you to notice — every stage carries a weekend flag computed in your business timezone [src: app/src/Clock.php:187], which is why the Friday example above shows weekend=YES against the 24-hour warning.

What a stage can say

Each stage reports one state [src: app/src/Clock.php:235]: pending when its anchor has not happened, open, due_soon inside the last six hours, overdue, submitted, or submitted_late when the filing came after the due instant [src: app/src/Clock.php:236]. A stage that exists only on request — NIS2's intermediate report — is not_requested until an authority asks [src: app/src/Clock.php:214].

Filing the same stage twice is refused, in the browser and through the API alike, with the same reasoning: "Filing it twice is a duplicate, not a second duty discharged" [src: app/controllers/api.php:155].

Users and roles

Four roles, not the usual three [src: app/controllers/app.php:21]. Executing the product's own permission function rather than reading the map:

audit.view      viewer=Y  member=Y  responder=Y  admin=Y
incident.edit   viewer=n  member=Y  responder=Y  admin=Y
notify.submit   viewer=n  member=n  responder=Y  admin=Y
contact.edit    viewer=n  member=n  responder=Y  admin=Y
settings.edit   viewer=n  member=n  responder=n  admin=Y

responder exists to separate two authorities that look alike. Editing an incident is ordinary work; recording that a notification was submitted to an authority is the act that stops a statutory clock, and only a responder or an admin can do it [src: app/controllers/app.php:26].

⚠️ A viewer can read the audit trail

The audit page and its CSV both require audit.view [src: app/controllers/v3.php:15], and the viewer role holds the wildcard *.view [src: app/controllers/app.php:24], which matches it — shown by the executed table above. If a read-only account is meant not to see who recorded which filing, that is not the behaviour you have. This has been raised against the product.

Backups are gated properly, by contrast: both downloads require settings.edit [src: app/controllers/api.php:521], which no role below admin holds [src: app/controllers/api.php:527].

Webhooks fire from every path

Cyresora declares three webhook events [src: app/src/Webhook.php:20]. incident.opened fires from the browser [src: app/controllers/app.php:609] and the REST API [src: app/controllers/api.php:114]; notification.recorded fires from the browser [src: app/controllers/app.php:689], the REST API [src: app/controllers/api.php:161] and the agent tool [src: app/controllers/api.php:446]; deadline.alert fires from the alert watcher [src: app/controllers/app.php:363].

Deadline alerts

The warning window. "Warn me this many hours before a deadline" (1 to 72, default 6) decides when a running stage shows as due within hours [src: app/controllers/app.php:228]. Before 1.0.4 the setting was saved but the board always used 6.

Alerts to the rota. Switched on in Settings, alerts go out at your alert points (12, 4 and 1 hours before a deadline by default) and once when a deadline passes, but not for a stage that has been overdue for more than a day [src: app/src/Clock.php:286]. The notifiers on the rota for that regime and their deputies are emailed; with nobody on the rota, the organisation's contact email is [src: app/controllers/app.php:310]. The email names the incident reference and title, the stage and its provision, the deadline and a link. A signed deadline.alert webhook fires at the same moments. Each point is latched, so the Clocks screen and the cron route alerts/run?t=<token> never send it twice [src: app/controllers/v3.php:269]. A failed send, a missing mail server or an empty rota is shown on the Clocks screen [src: app/controllers/app.php:440].

The API and agent access

Six tools [src: app/controllers/api.php:299]: four read — every running deadline worst-first, the incident list, one incident, and what applies to a given situation — and two write, opening an incident [src: app/controllers/api.php:373] and recording a notification [src: app/controllers/api.php:405].

The recording tool is gated on notify.submit [src: app/controllers/api.php:407] and refuses a stage that is not running on that incident, naming the ones that are [src: app/controllers/api.php:421].

The instructions given to an agent are the clearest short statement of what this product is for [src: app/controllers/api.php:286]:

"You cannot set a deadline. You record two facts — when the organisation became aware, and when a notification was actually submitted — and the instrument decides the rest."

And the sentence that matters most [src: app/controllers/api.php:292]:

"Never record a notification as sent unless the human has told you it was sent. That record is what stops a statutory clock and what an authority will later be shown."

What Cyresora does not do

It does not read the system clock [src: app/src/Clock.php:3] — every deadline is computed from instants you supply.

It does not invent a due date for a clock that has not started [src: app/src/Clock.php:33].

It does not anchor a one-month report on the deadline [src: app/src/Clock.php:36] — it anchors on the filing.

It does not model your Member State's transposition of NIS2 [src: app/src/Clock.php:38].

It does not pause at weekends [src: app/src/Clock.php:53].

It does not submit anything to an authority. It records that you did.

← Back to Cyresora · Quickstart · API · Test run

Affiliate program
Recommend tools people own — earn 35% on every sale. 90-day tracking, instant delivery, payouts by Lemon Squeezy.
Become an affiliate →