Communities
A community makes a population live on its own: each user plays the job assigned to them, and the messages leave minute after minute towards real intakes.
It is the other half of the test bench. A bench is played by hand — you open it, adjust an action, rerun, compare. A community has no “send” button: it runs. Both share the same shape, and that was intended — the bench was written as its prefiguration.
/communautes lists the communities; each one opens six tabs.
What a community remembers
| Setting | What it decides |
|---|---|
| Population | The users, servers and sites — and the time zone the day is played in |
| Company profile | The fallback of the mapping, for those no unit classifies |
| Technologies | The selected generators, and one intake key per technology |
| Destination | One of the 7 SEKOIA regions, or a custom URL |
| Sekoia API | One key — inventories, intakes and asset connectors — in the Settings tab |
| Time zone | Inherited from the population, overridable here — picked from a list |
| Weekend | Saturday and Sunday played like a working day — unticked by default |
| Threat | Scenarios grafted onto compromised workstations and servers, in rotation |
| Assets | The connectors of the daily OCSF inventory |
A community is born stopped. Starting it is the gesture saying the announced figures are acceptable — and the screen announces them beforehand.
The threat is a graft, not an assignment: a compromised workstation carries on with its working day, and the attacker's noise is added to it. Three ways of designating the compromised — a number and always the same hosts, named hosts, or a cohort of the day where the threat changes host every hour. The Threats tab also launches a scenario now, for a bounded duration. The detail is in Attacker background noise.
The mapping: which archetype each user plays
This is what the bench could not do. There, the whole population plays the same workflow; a company is not that. A sales rep does a sales rep's day while an administrator does theirs, and it is that mixture which makes the cross-technology correlation representative.
Two rules, in this order, and the order is everything:
- The user's organisational unit (
org.ou_name), when an archetype claims it. It is the only business signal the corpus carries — and it carries it on all 419 users of the six demonstration populations, in 21 distinct values. - The company profile's mix, as a fallback, for those no unit classifies.
The reverse would give a Development archetype to somebody in the Finance department whose unit said so.
Every row says where its archetype comes from — Unit, Profile, or Manual. That is not a display detail: “their unit says so” can be verified, “drawn from the mix” can be argued with, and conflating the two would silence both.
Across the six populations, four users out of five receive their archetype from their unit — so from a fact of the population, not from a draw.
What we do not guess
Three units of the corpus are claimed by no archetype: Intelligence, Security and Research.
None of the nine business archetypes describes an intelligence cell, a security team or a laboratory.
Giving those units to them by force would be a gamble.
Without a company profile, those users therefore stay unassigned — and the screen names them, rather than merely counting them. The lever is there: pick a profile, or correct them one by one.
A conflict is refused, not arbitrated
A unit claimed by two archetypes assigns nothing. Settling it on the first one found would make the day depend on a read order in the database, and the author of the second archetype would never know theirs does not play. The screen names the conflict and both claimants.
Correcting, and making the correction survive
A row is corrected by hand. It then moves to Manual, and recomputing never touches it again — the same rule as an event type's coverage, where a correction survives a reimport of the corpus.
The fallback, for its part, is a stable draw: adding a user to the population redistributes no other. Adding an archetype to the mix does — that is unavoidable, and it is a deliberate gesture.
The rhythm: plan at night, send minute by minute
The day is computed once, when the calendar day flips at the population, and frozen — until its configuration changes. A setting of the community, or the save of an archetype it plays (assigned, grafted, or called by one of those), makes the next tick rebuild it: only the minutes not yet sent change, and the counters of the “Day of …” card follow. One tick per minute renders the elapsed slice and queues it right away.
That split is not an implementation detail. A community of a hundred users produces on the order of 130,000 messages a day: rendering them all at midnight to let them sleep in Redis until their minute would be a hundred and thirty megabytes of payload waiting. The plan fits in a few thousand counters; the tick renders the minute it sends.
The time zone is picked from a list and not a free field, unlike on a bench: Asia/Tokio would be
accepted by the form and refused by the server, which would let you discover the typo one request too
late. The hint below the field names its provenance — “inherited from the population” is fixed on
the population, “set on this community” here.
The plan is born at 00:00 local, not at 01:00. Archetypes produce gestures from midnight on — the “System noise” resolves names continuously — and planning an hour later would silently lose the first hour, every day.
A single mechanism covers all three cases: the passing of midnight, a restart at three in the morning, and an activation at two in the afternoon.
The weekend: a consequence turned into a setting
The nine business archetypes live from Monday to Friday — that is the default of every action of the workflow. A community therefore produced an empty day on Saturday, and that was not a choice: it was a consequence, which nothing on screen allowed you to change.
The Weekends play out like a working day box opens it. Ticked, Saturday and Sunday lift the active-day filter: every action leaves as on a Tuesday. This is not a second filter on top of the workflow's — it would contradict it — it is the lifting of the first, two days out of seven.
Days, not hours. The actions' time windows do not move: a Saturday is played from 8 am to 6 pm
like a Tuesday, quiet night included. The label says so itself, and the field is called
weekendGeneration rather than roundTheClock: neither promises a round-the-clock day.
A working day, for its part, stays unchanged to the bit: the day filter consumes no draw, so that ticking the box moves no timestamp of an already-simulated day. That is what allows it to be ticked on a running community.
Emission follows within the minute — the cached plan goes stale on the configuration —, and so do the counters of the “Day of …” card: the day is recomputed on the new plan. What already left was counted under the old configuration, so for the rest of the day the remainder mixes the two; the gap comes from the slice already sent, and from it alone.
Starting at 2 pm does not send the morning
And it says so. The gestures already past at planning time are discarded, and counted: the screen announces “9,406 discarded (already past at planning time)”. Subtracting while saying so is not trimming behind your back — it is the rule the bench already holds for an elapsed slice.
A catch-up is bounded, and counted
A backend stopped for three hours does not replay 180 minutes: that would make three hours of a day arrive within the same minute, claiming to be from the morning. At most five minutes are caught up; the rest is counted and displayed.
Following the generators
The Today tab shows, per technology: what is planned, what is sent, what has failed, and whether it is cut off.
The planned comes from the day's plan; the sent and the failed are counted on the dispatches actually posted, never on a counter kept aside. Two columns for a single number end up diverging, and the one that would have diverged is the one you look at.
The page updates itself on every completed dispatch, without reloading — the same mechanism as Dispatches: an announcement serves as a signal to re-read the data, which stays read from the database. A lost announcement therefore never leaves the screen in a false state.
The cut-off: a hundred failures in a row
Beyond 100 definitively failed dispatches in a row, a technology cuts itself off, and the screen shows the reason — what the intake answered, word for word.
Three things are worth knowing.
The grain is the technology, never the community. A wrong intake key is by far the most likely cause of a run of failures, and cutting off the seven technologies that work for the one that fails would be an outage far worse than the one being fixed. The community only stops when there is nothing left emitting — and its reason then names the technologies.
The count bears on dispatches, not messages. A batch carries up to a thousand: counting messages would cross a threshold of a hundred within a single batch. A hundred batches is on the order of two minutes of an active community — enough to absorb an intake outage, too little to let an intake that refuses the key be hammered.
Turning it back on is a manual gesture, and that is essential: the cut-off is automatic, restarting cannot be — somebody has to say the cause has been dealt with. Turning it back on resets the run; without that, the very next failure would cut it off again, and fixing a key would have served no purpose.
A successful dispatch resets the run. Intermediate attempts do not count: a dispatch that will succeed on the next try says nothing about the intake's health.
The intake keys
The contract is exactly a bench's: a saved key is never shown again, the screen only shows its
mask — ••••1a2b — and leaving the field empty keeps it. Erasing it requires an explicit gesture:
emptying the field cannot mean “erase”, since that is what “keep” means.
The key is read at the moment of posting, never before. A batch only carries its key's provenance.
Creating the intakes in Sekoia
Rather than creating each intake by hand in Sekoia and copying its key back, SekoiaCraft can create it, with the community's Sekoia API key. There is only one: set in the Sekoia API card of the Settings tab, it also sends the inventories and creates the asset connectors — see Creating a connector in Sekoia. It must therefore be allowed to configure intakes in the community's space, on top of its asset rights; Sekoia's refusal says so if it is not. It follows the contract of the other keys — only its mask returns, and leaving the field empty keeps it. The card also shows the Sekoia entity the intakes are attached to, once the first one has created it.
Once the key is saved, a technology without an intake key shows a Create in Sekoia button as soon as it is ticked — no need to save the list first. A click:
- reads the key's account (
GET /v1/me) to find its Sekoia community; - creates, the first time only, the community's entity — named
<community> Entity; - creates the intake — named after the Sekoia format and the community,
HarfangLab EDR Team3for instance — and sets its key.
The intake key goes from Sekoia to the database without crossing the screen: only its mask comes back. The twenty-eight technologies of the corpus can all be provisioned, and so can Nozomi Vantage, which SekoiaCraft seeds itself:
| Technology | Sekoia format |
|---|---|
| HarfangLab EDR | HarfangLab EDR |
| Fortinet FortiGate | Fortinet FortiGate |
| Sekoia Agent | Sekoia.io Endpoint Agent |
| Windows | Windows |
| Microsoft Entra ID | Microsoft Entra ID |
| Office 365 Message Trace | Microsoft 365 Message Trace |
| Netskope | Netskope |
| Zscaler ZIA | Zscaler Internet Access |
| VMware vCenter | VMware vCenter |
| VMware ESXi | VMware ESXi |
| Veeam Backup & Replication | Veeam Backup |
| Systancia Cleanroom | Systancia Cleanroom |
| Palo Alto NGFW | Palo Alto NGFW |
| Microsoft IIS | Microsoft IIS |
| Bind | Bind |
| Apache HTTP Server | Apache HTTP Server |
| Microsoft Defender XDR | Microsoft Defender XDR |
| Office 365 | Microsoft 365 |
| Akamai WAF | Akamai WAF |
| CrowdStrike Falcon | CrowdStrike Falcon |
| CrowdStrike Falcon Telemetry | Crowdstrike Falcon Telemetry |
| Github Audit Logs | Github Audit logs |
| Google Workspace | Google Workspace |
| Palo Alto Cortex | Palo Alto Cortex |
| Salesforce | Salesforce |
| SentinelOne | SentinelOne EDR |
| SentinelOne Cloud Funnel | SentinelOne Cloud Funnel |
| SentinelOne Identity | SentinelOne Singularity Identity |
| Nozomi Vantage | Nozomi Vantage |
A technology created with New generator on the Generators screen shows no button: its key is still entered by hand.
On a pool, the delivery grid also creates every possible intake of a team, or of every team, in one gesture — see Creating every intake in one gesture.
In Sekoia, sixteen of these intakes are fed by a collection connector, which pulls the logs from
the vendor: Microsoft Entra ID, Office 365 Message Trace, Microsoft Defender XDR,
Office 365, and the twelve with a module configuration below. Sekoia needs one to create the
intake, so SekoiaCraft creates it with a placeholder configuration, then stops it five seconds
later (POST /v1/symphony/connector-configurations/<uuid>/stop): SekoiaCraft sends the logs to the
intake itself. If Sekoia answers that the connector is still starting (Cannot stop a starting connector), SekoiaCraft waits five more seconds and tries again, for fifteen seconds at most. The
key is set first, before the wait — a creation with a connector takes five to fifteen seconds
longer. If the stop fails, the creation still succeeds, and a warning under
the notice says that the connector is still running, with its configuration and Sekoia's answer:
stop it in Sekoia.
The connectors of Netskope, Akamai WAF, CrowdStrike Falcon, CrowdStrike Falcon
Telemetry, Github Audit Logs, Google Workspace, Palo Alto Cortex, Salesforce,
SentinelOne, SentinelOne Cloud Funnel, SentinelOne Identity and Nozomi Vantage also
need a module configuration, created first (POST /v1/symphony/module-configurations) under the
intake's name, then referenced by the intake.
It is never reused: each click creates its own. If the intake is then refused, the module
configuration stays in Sekoia, and the reason names it, with its UUID, so it can be deleted there.
- The button follows the box, not the saved list: ticking shows it, unticking hides it — without JavaScript too. The click selects that technology, and only it, before creating its intake; the rest of the list still waits for Save the technologies. If Sekoia refuses, the technology stays selected, without a key, and the button stays offered.
- A technology with a key never shows the button. To create a new intake, clear the key first — the previous intake stays in Sekoia.
- The address follows the community's region —
https://app.sekoia.io/api/v1/…for FRA1 —, or the API base of a custom destination, set next to the key in the Settings tab. Without one, the button is disabled and says why. - The entity is reused for the following technologies. If the key leads to another Sekoia space, a new entity is created there.
- A refusal is shown in the card: which step Sekoia refused (the account, the entity, the intake), the HTTP status, a hint — a 403 means the key lacks the rights —, the endpoint, and Sekoia's answer, the key masked.
- Nothing is retried on its own: a creation that timed out may still have happened in Sekoia. Check there before clicking again.
The volume, discovered beforehand
Before activation, the screen can quantify what a whole day will produce: assigned users, messages, requests. It is a gesture — “Count the day” — not an automatic computation: unrolling each user's day takes on the order of a second for a population of a hundred, and api-activity would do nothing else meanwhile, neither schedule nor send. The figure lives in the URL, so the screen stays shareable and the gesture works without JavaScript.
No cap refuses — a community is made to run, and the bench's 25-user bound existed for a manual gesture. But you discover the volume before, not after; it is the same rule as a bench's preview, which never refuses and always counts right.
On demo-metacortex — 101 users, three technologies — a day weighs about 37,800 messages and 2,400
requests.
The three slices
A community unrolls three slices: its users, the servers to which an archetype with subject
SERVER has been assigned, and the sites to which one with subject WEBSITE has.
The servers
Archetypes with subject SERVER do not describe an employee's gesture but what a machine does of its
own accord — a domain controller's directory replication, a DNS server's zone transfers, a backup
server's nightly job, and on every Windows server the antivirus health report and the service its
role opens a port for. Nobody triggers them, and no workstation writes them.
The assignment follows the role the machine's name announces (SRV-DC-01 → directory), inferred
at import. Each of the sixteen roles is claimed by one seeded archetype, so only the machines whose
name announces nothing stay unassigned. Three differences with the users', and each one carries:
- no profile fallback. A company profile is a mix of jobs; inventing one for servers would make the file server write a directory replication. With no claimed role, the machine is not assigned — and the screen names it;
- an unassigned server is normal, where an unassigned user is a defect. The two lists are therefore separated on screen: a machine whose name announces no role — thirteen of the 110 demonstration servers — plays nothing, and that is expected;
- a role claimed by two archetypes assigns nothing and is flagged, exactly like an organisational unit.
The volume stays negligible: a Windows server writes about thirty base messages a day, a domain controller or a DNS server a few hundred — around a thousand messages a day for Metacortex's twenty servers, against ~130,000 for a hundred users.
The sites
A site of the population plays the visits it receives: the request comes from the Internet, it is
not emitted by an employee. It is the only slice feeding the serving technologies — Apache HTTP
Server, Microsoft IIS, the Akamai WAF — whose 56 event types of EXTERNAL_CLIENT scope leave from no
other. Without an assigned site, those three technologies stay silent even when enabled, and nothing
else explains it.
The assignment follows the site_role the dataset declares — the exact opposite of a server,
whose role is inferred from its name. The rest is identical: exact matching, no profile fallback, no
draw, refusal of a role two archetypes claim, sites without a role unassigned and named. A role
the vocabulary does not know is neither refused nor caught up: it matches nothing, and the screen
files it among the roles with no taker.
The seeded archetype “Public website visitor” claims the corpus's thirteen roles, intranet and extranet included. An accepted counterpart: an intranet therefore receives visitors from the Internet. The lever is not to trim that list but a second archetype with internal-visitor facts — and those two roles will then have to be removed from the first, two archetypes claiming the same role assigning nothing.
The volume is modest and is counted in requests: one visit every five minutes, day and night, so 288 gestures per site — about 1,700 a day for six sites, against ~130,000 for a hundred users. But every populated minute makes one batch per technology: the requests, for their part, rise by a good third. That is the figure the “Today” tab gives before activation.
The subject, on both sides
An archetype only plays the gestures of its subject. The editor only offers a server the gestures of a server, and saving refuses the rest: an off-subject action would produce nothing at all, and its author would believe they had described a gesture. The subject is chosen at creation and never changes afterwards — changing it on an already-populated graph would empty its day silently.
Several teams, the same content
For a Capture The Flag session, a community becomes the template of a pool: its teams receive exactly the logs, assets and threats it would have produced, each towards its own intakes, while the template itself is stopped and sends nothing. The production settings — population, time zone, weekend, threat, assignments — are then set on the template or on any of the teams and apply to all of them; a banner says so on every tab. The technologies are chosen on the pool page, and a team's Technologies tab only sets its own intake keys. “Create a pool from it”, at the top of a community, is where a pool is born.
What a community does not simulate yet
- The ambient layer and the alerts: like the bench, it only plays the correlated layer. A real production's volumes would be higher.
- Roles are not editable from the screen: the organisational units, the server roles and the site roles each archetype serves live in the seed. The screen can name a role nobody serves; it cannot fill it yet.
- Traffic does not vary with the site's role: a CDN and a blog receive the same cadence.
- SOC activity will come with the module that produces it. The OCSF assets, for their part, are in place: see OCSF assets.
Trying it locally
With a stub intake rather than a real region:
node apps/web/e2e/mock-intake.mjs
Destination “Custom URL”, http://localhost:4599/batch. The stub accepts the body
{ intake_key, jsons }, GET /received returns what it has received, and POST /batch?status=500
lets you exercise the cut-off.