Skip to content
DiagravoDocsOpen editor

Docs Capacity, warnings and attack scenarios

Capacity, warnings and attack scenarios

How Diagravo decides a component would be overloaded, where to read the result, and how to test a design against hostile traffic.

Two things in Diagravo tell you whether a design holds up: the capacity dots and warnings, which answer “would this component cope with the traffic I described?”, and the attack scenarios, which answer “what gets through if the traffic is hostile?”. Both are illustrations built from the numbers on your components.

How capacity is worked out#

Where the load comes from#

Each Client has activeUsers (an HMI Panel has activeOperators). Diagravo treats that number as requests per second and carries it outward from the client along every connection, to every component reachable from it. A component reached from several clients, or by several routes, adds up everything that reaches it. Data stores and the other end-of-the-line components (see data stores and sinks) count the load that reaches them but never pass it on, exactly as in playback — so two backends sharing one database do not add to each other’s load.

This is deliberately a worst case, not a prediction. The figure answers “how loaded could this component get via any path?”, so a load balancer does not divide the load between its backends: each backend is shown the whole of it. (During Play the balancer really does pick one target per request; the dots stay on the safe side.) The one thing that does reduce load on its way through is a rate limiter admitting only part of a flood — see below.

What it is compared with#

Each component type has one setting that is its capacity. The load that reaches it is divided by that setting:

Capacity setting per component type
ComponentCapacity settingUnit
BackendrequestsPerSecper second
Databaseiopsper second
Load BalancermaxConnectionsper second
ProxyrateLimitPerSecper second
QueuethroughputPerSecper second
MicrocontrolleroperationsPerSecper second
PLCmaxOperationsPerSecper second
TurnstilemaxThroughputPerMinper minute
Badge ReaderscansPerSecper second
Secrets ManagerrequestsPerSecper second
Monitoring/LoggingeventsPerSecper second
DNS ResolverresolutionsPerSecper second
ADCsamplingRateHzper second
DACoutputRateHzper second
API GatewayrateLimitPerSecper second
Auth/Identity ServicetokensPerSecper second
Search IndexqueriesPerSecper second
Serverless FunctionconcurrencyLimitper second
Email ServiceemailsPerSecper second
SMS/Push NotificationmessagesPerSecper second
Payment GatewaytransactionsPerSecper second
Edge GatewayrateLimitPerSecper second

A component with no capacity setting, or one set to 0 or missing, simply shows no dot: that means “not modelled”, never “fine”.

Green, amber and red#

Capacity thresholds
Load vs capacityDotConsole line
Below 70%GreenNothing — it is healthy.
70% up to 100%Ambernear capacity — 83%
100% or moreRedOVERLOADED — 150% of capacity

Hover a dot to read its figure. The dots update the moment you change a number — you do not need to press Play. A diagram where 150 users hit a backend sized for 100 requests per second gives:

Backend (backend-1): OVERLOADED — 150% of capacity

Memory pressure and bandwidth#

Request rate is not the only way to run out of room, so some components are checked on a second or third measure. The dot shows whichever is worst.

Memory pressure compares the data in flight — each client’s activeUsers times its payloadSizeKb — with the component’s memory. It applies to:

Components checked for memory pressure
ComponentMemory setting
BackendramMb
DatabaseramMb
Object StorageramMb
Auth/Identity ServiceramMb
Serverless FunctionmemoryMb

Bandwidth compares that same data per second with a throughput ceiling in megabits per second. It applies to:

Components checked for bandwidth
ComponentThroughput setting
Object StoragebandwidthMbps
Memory ChipreadWriteSpeedMbps
CDNbandwidthMbps

The Console labels each one separately — high memory pressure, memory pressure OVERLOADED, high bandwidth usage, bandwidth OVERLOADED — so you can tell a node that is busy from one that is too small.

Where to read the results#

The bottom panel (View → Bottom panel) has three result tabs next to the Terminal.

Console#

The step-by-step narration of Rule-based playback, with warnings amber and errors red. See reading the Console.

Snapshot#

A table of every component with its worst figure, such as request-rate capacity: 150%, sorted so the most worrying are at the top. Components with no modelled capacity say not modeled. It is computed straight from your settings, so it works without playing anything — and it always agrees with the dots, because it is the same calculation.

Stats#

A live tally of the current Rule-based walkthrough, reset on every fresh Play: requests served; cache hits and misses with the hit rate; DDoS requests admitted and rejected, plus unmitigated floods and per-source blocks and evasions; SQL injection and session-theft attempts blocked or unmitigated; crawler traffic allowed or blocked; and capacity warnings and errors.

Attack scenarios#

Set a Client’s intent to something other than legitimate and Rule-based playback sends hostile traffic from it instead: markers and labels change colour (DDoS, SQLi, Hijack, Bot) and the components that can defend against it get a chance to. Each scenario has one defence, which is a setting on a component:

Attack scenarios and their defences
intentWhat it sendsDefended by
ddosA flood: activeUsers requests per second from sourceCount machines.Rate limit (rateLimitPerSec) and per-source limit (perSourceLimitPerSec) on a Proxy, API Gateway or Edge Gateway.
sqlInjectionA request carrying a SQL-injection payload.sanitizesInput on a Backend, Serverless Function, Microcontroller, PLC or Auth Service.
sessionStealingA replayed, already-stolen session token (or cloned badge).detectsSessionHijack on a Proxy; verifiesCredential on an API Gateway, Turnstile, Badge Reader or Door Lock.
crawlerAutomated bot traffic.allowsCrawlers policy on a Proxy or gateway; a Cache or CDN always misses for it.

DDoS#

A rate limiter admits traffic up to its rateLimitPerSec and rejects the rest — it does not drop the whole flood, and two limiters in a row each trim what reached them. Only traffic labelled ddos is limited this way; a legitimate client sharing the same proxy is untouched. Because the limiter itself has to absorb the flood, it is expected to read as overloaded while the backend behind it stays healthy.

The per-source check looks at the flood per machine: the volume divided by the client’s sourceCount. Few machines sending a lot each are caught and blocked. The same total from thousands of machines slips under the per-source limit — real attackers spread a flood for exactly this reason, so Diagravo narrates the evasion instead of hiding it. Five thousand requests per second from three machines, in front of a 300 requests-per-second limit:

Proxy (proxy-1): OVERLOADED — 1667% of capacity
Proxy (proxy-1): admitted 300 req/s, rejected 4700 req/s of DDoS traffic (5000 req/s exceeds the 300 req/s rate limit)
Proxy (proxy-1): per-source anomaly detected — ~100 req/s per source across 3 source(s) exceeds the 50 req/s per-source limit, traffic blocked
Proxy (proxy-1): responding (blocked)

And 250 requests per second spread over five thousand machines, which the limiter lets through entirely:

Proxy (proxy-1): near capacity — 83%
Proxy (proxy-1): DDoS traffic passing through unmitigated — 250 req/s
Proxy (proxy-1): per-source check passed — ~0 req/s per source across 5000 source(s) is within the per-source limit (traffic distributed across many sources, evading per-source detection)

Try it in the Rate-Limited Public API template

SQL injection#

An injection chain either meets a component that sanitises its input and is stopped there, or passes through. If it passes all the way to a real data store (Database, Object Storage, Secrets Manager, Memory Chip, Search Index), the Console records a simulated breach in red. With sanitizesInput on:

Client (client-1) → Backend (backend-1): request (SQL injection)
Backend (backend-1): input sanitized — SQL injection payload blocked
Backend (backend-1): responding (blocked)
Backend (backend-1) → Client (client-1): response

And with it off:

Client (client-1) → Backend (backend-1): request (SQL injection)
Backend (backend-1): input not sanitized — SQL injection payload passed through unmitigated
Backend (backend-1) → Database (database-1): request
SQL injection payload reached Database (database-1) — simulated unauthorized data access
Database (database-1): responding directly
Database (database-1) → Backend (backend-1): response
Backend (backend-1) → Client (client-1): response

Session stealing#

This models an attacker who already holds a valid stolen token (or a cloned badge) and replays it. It does not model the theft — that happens outside anything the diagram draws. A component with its credential check on catches the replay and stops it; a connected Alarm Panel then sounds a siren line in the Console. Without the check, the request passes with an amber warning.

Proxy (proxy-1): session anomaly detected — stolen session token rejected
Proxy (proxy-1): responding (blocked)

Crawlers#

Bot traffic is the neutral one. Allowing or blocking crawlers is a policy, not a security win or loss, so both outcomes are plain information, never a warning or breach. A proxy with allowsCrawlers off stops them:

Proxy (proxy-1): crawler traffic blocked by robots policy
Proxy (proxy-1): responding (blocked)

Crawlers also never benefit from a cache, because they request many different long-tail pages rather than a few popular ones:

Cache (cache-1): MISS — crawler traffic bypasses cache — forwarding

What this is not#

The attack scenarios are teaching illustrations of where a defence sits and what it can and cannot stop. They are not a security assessment, they do not test real code, and passing them does not mean a real system is safe. Treat a clean run as a prompt for the next question — what else could reach that database? — not as an answer.

Last updated . Something unclear or out of date? Tell us.