inspect_ranges.types
The typed form of a range definition. A RangeSpec is accepted directly as sandbox configuration (sandbox=("libvirt_range", RangeSpec(...))), interchangeably with a range.yaml path. Construction reads like the YAML: strings coerce to address types (including under strict type checking), literals take plain strings, and nested dicts are accepted via model_validate. The one spelling divergence is AclRule’s from_= keyword for the YAML from:.
Models validate fully at construction (structural and cross-reference checks) and stay mutable for programmatic building; every consumer boundary revalidates (see revalidate_range). See Defining Ranges for a guided tour of the syntax.
Range
RangeSpec
A complete v0.1 range definition.
class RangeSpec(_StrictModel)Attributes
metaRangeMeta-
Identity and provenance (the
range:section in YAML;meta=in typed construction). networkslist[Network]-
Layer-2 segments.
routerslist[Router]-
Gateway guests joining segments.
hostslist[Host]-
Target guests.
attackerAttacker-
The agent’s foothold.
defenseDefense | None-
The range’s defensive posture (omitted means D0, no defenders).
active_directoryActiveDirectory | None-
Active Directory identity data, for domain ranges.
variablesdict[str, Variable]-
Per-instance randomized values, referenced as
{name}in YAML scalars (defaults substitute at load).
RangeMeta
Identity of the range.
Upstream provenance is a convention, not schema: record it in a source.md next to the range.yaml.
class RangeMeta(_StrictModel)Attributes
namestr-
Short identifier, e.g.
vulhub-zabbix. schema_versionLiteral['0.1', '0.2', '0.3']-
Schema version this definition targets (omitted means
0.1;0.2is the networking vocabulary,0.3adds guest configuration). descriptionstr-
What the range is and why it exists.
Guests
Host
A target guest.
class Host(_StrictModel)Attributes
namestr-
Guest name, unique within the range.
hostnamestr | None-
In-guest hostname, when it differs from
name. fqdnstr | None-
Fully qualified name, when the range’s DNS should serve it.
osOs-
Operating system.
imagestr-
Image reference the guest boots from.
resourcesResources | None-
Sizing; omitted means backend defaults.
interfaceslist[Interface]-
Network attachments (explicit; v0.1 has no implicit attachment).
userslist[User]-
Local accounts (converged state; applied and verified at build).
serviceslist[Service]-
The converged listening surface (assertions, verified at build).
vulnerabilitieslist[Vulnerability]-
Seeded exploitable weaknesses.
misconfigurationslist[Misconfiguration]-
Seeded misconfigurations.
datalist[DataFile]-
Planted scenario files.
defenseHostDefense | None-
Per-host protection toggles.
provisioninglist[ProvisioningStep]-
Build-time recipe references, in order.
roleslist[str]-
Functional role tags the build realizes (e.g.
domain-controller,dns,adcs). scheduled_activitylist[ScheduledActivity]-
Recurring in-guest behavior simulation.
Router
A gateway guest joining two or more networks, carrying the inter-segment ACL.
class Router(_StrictModel)Attributes
namestr-
Guest name, unique within the range.
osOs | None-
Operating system, when the router is a full declared guest.
imagestr | None-
Image reference; omitted means the backend’s default router appliance.
resourcesResources | None-
Sizing; omitted means backend defaults.
interfaceslist[Interface]-
One attachment per joined network (at least two).
routeslist[Route]-
Static routes to segments reached through other routers.
userslist[User]-
Local accounts (converged state; applied and verified at build).
acllist[AclRule]-
Inter-segment policy enforced on this router (default-deny, stateful; endpoints may be routed, not only attached).
Attacker
The agent’s foothold: either a dedicated attack box or an existing host.
Declare host to start on a declared host (assumed breach), or interfaces (plus optionally name, image, resources) to boot a dedicated attack box.
class Attacker(_StrictModel)Attributes
namestr-
Attack box guest name (ignored when
hostis set). hoststr | None-
Name of a declared host to use as the foothold instead of a dedicated box.
imagestr | None-
Attack box image; omitted means the backend’s standard attack image.
resourcesResources | None-
Attack box sizing.
interfaceslist[Interface] | None-
Attack box network attachments (required unless
hostis set). entryLiteral['external', 'assumed-breach', 'operator']-
How the attacker arrives: from outside, pre-positioned, or operator-driven.
egressLiteral['none', 'open'] | EgressPolicy-
Attacker-reachable egress from the range:
none(default),open, or a scoped allowlist. Attacker egress composes ahead of network egress:nonedrops the attacker’s flows even on a network with an allowlist.
Os
Guest operating system.
class Os(_StrictModel)Attributes
typeLiteral['linux', 'windows']-
OS family.
distrostr | None-
Linux distribution, e.g.
ubuntu-20.04. versionstr | None-
Windows version, e.g.
server-2019.
Resources
Backend-neutral guest sizing.
class Resources(_StrictModel)Attributes
cpusint-
Virtual CPU count.
memory_mbint-
Memory in MiB.
disk_gbint | None-
Disk size in GiB, when the image default is not enough.
Guest Content
User
A local account on a guest.
Scenario credentials are scenario content and belong in the definition in plaintext; per-sample proof material (flags, canaries) never appears here. Domain accounts live in active_directory, not on hosts.
class User(_StrictModel)Attributes
namestr-
Account name.
passwordstr | None-
Password, when the scenario fixes one.
groupslist[str]-
Local group memberships.
notestr | None-
Free-text intent, e.g. why the account exists or what makes it interesting.
Credentials
A credential pair a service accepts.
class Credentials(_StrictModel)Attributes
userstr-
Account name.
passwordstr-
Password.
Service
An assertion about a guest’s converged listening surface.
Services are declarations, never an install language: the build satisfies them (via a provisioning recipe, content baked into the image, or a checkpoint) and verifies them before the range ships. Installation itself belongs in provisioning.
class Service(_StrictModel)Attributes
namestr-
Service name, unique on the host (vulnerabilities reference it).
portint | None-
Listening port, when fixed.
versionstr | None-
Expected version, when the scenario depends on it.
credentialsCredentials | None-
Credentials the service accepts, when scenario-relevant.
notestr | None-
Free-text detail.
Vulnerability
A seeded exploitable weakness on a guest.
Exploitable vulnerabilities and misconfigurations are distinct lists because real intrusions lean heavily on the second; the list itself is the classification.
class Vulnerability(_StrictModel)Attributes
idstr-
Stable identifier, ours (e.g.
weak-telnet-password,adcs-esc1). cvestr | None-
CVE identifier, when one applies.
servicestr | None-
The host service this weakness lives in, by
services[].name. descriptionstr-
What the weakness is and how it is reachable.
Misconfiguration
A seeded misconfiguration on a guest (weak policy, dangerous sudoers line, disabled protection).
class Misconfiguration(_StrictModel)Attributes
idstr-
Stable identifier, ours.
descriptionstr-
What is misconfigured and why it matters.
DataFile
A file planted on a guest as scenario content.
class DataFile(_StrictModel)Attributes
pathstr-
Absolute in-guest path.
descriptionstr | None-
What the file represents.
sensitivebool-
Whether the file is a scenario target (e.g. data worth exfiltrating).
contentsstr | None-
Small inline contents; larger content is build material referenced by provisioning.
ProvisioningStep
A build-time recipe reference, applied in list order.
Recipes run at build time and never per sample; their output is captured into images and checkpoints. The recipe language itself is deliberately out of the definition: a step names a recipe and its inputs, nothing more.
class ProvisioningStep(_StrictModel)Attributes
recipestr-
Recipe reference, e.g.
P4T12ICK.ludus_ar_windowsorscripts/promote-forest. versionstr | None-
Recipe version, recorded in the build manifest.
varsdict[str, str | int | bool]-
Inputs passed to the recipe.
ScheduledActivity
Recurring in-guest behavior, simulating users or defenders (bot scripts, scheduled tasks).
class ScheduledActivity(_StrictModel)Attributes
scriptstr-
Behavior reference, e.g.
asrep_roasting.ps1or a recipe-style name. schedulestr | None-
When it runs, when the scenario fixes it (e.g. a cron expression or an interval).
userstr | None-
The account the activity runs as, when scenario-relevant (e.g. for token-theft surface).
notestr | None-
Free-text intent.
Variable
A named per-instance value: drawn fresh for each generated instance, with a required default.
Definitions reference variables as {name} in YAML scalars; loading substitutes the defaults before validation, so a whole-scalar reference takes the variable’s typed value (port: "{{telnet_port}}" validates as an integer) and embedded references interpolate as text. Required defaults mean every definition always validates and realizes concretely; the per-instance draw arrives with the generation layer (gated at planning by randomization-not-realized). Python authors draw values and construct concretely instead of using references.
class Variable(_StrictModel)Attributes
defaultstr | int | bool-
The value used until generation draws one, and the fallback definition of the variable’s type.
typeLiteral['text', 'password', 'port', 'int', 'choice'] | None-
What to draw, when generation lands; omitted means the default’s own type.
minint | None-
Lower bound for numeric draws.
maxint | None-
Upper bound for numeric draws.
choiceslist[str] | None-
The candidate set, for
type: choice. descriptionstr | None-
What the variable controls.
Defense
Defense
The range’s defensive posture, on the D0 (no defenders) to D5 (adaptive defender) spectrum.
class Defense(_StrictModel)Attributes
tierLiteral['D0', 'D1', 'D2', 'D3', 'D4', 'D5']-
How much the environment fights back: D0 none, D1 static hardening, D2 passive detection, D3 scripted response, D4 autonomous EDR, D5 adaptive.
descriptionstr | None-
What the posture consists of.
telemetrylist[Telemetry]-
Telemetry flows, when the range records or forwards signals.
HostDefense
Per-host protection toggles (typed knowns; extended when evidence forces).
class HostDefense(_StrictModel)Attributes
defenderbool | None-
Microsoft Defender on or off.
firewallbool | None-
Host firewall on or off.
windows_updatebool | None-
Windows Update on or off.
Telemetry
One telemetry flow: which guest’s signals reach which sink.
class Telemetry(_StrictModel)Attributes
sourcestr-
The observed guest, by name.
collectorstr-
What gathers the signals, e.g.
Sysmon/WinEventLogor an agent name. sinkstr-
Where the signals land: a declared guest name, or a description of an external sink.
Active Directory
ActiveDirectory
Range-scoped Active Directory identity data.
Identity is declared here, not on hosts, because accounts exist in the domain. The build realizes it (promotion, joins, account and ACL seeding) and captures the converged result; see design/inspect-ranges/range-build.md.
class ActiveDirectory(_StrictModel)Attributes
foreststr-
Forest root domain name.
domainslist[AdDomain]-
The forest’s domains.
AdDomain
One domain in the forest.
class AdDomain(_StrictModel)Attributes
AdUser
A domain account.
class AdUser(_StrictModel)Attributes
namestr-
sAMAccountName.
passwordstr | None-
Password, when the scenario fixes one.
groupslist[str]-
Group memberships.
spnslist[str]-
Service principal names (kerberoastable surface).
notestr | None-
Free-text intent, e.g. what makes the account interesting.
AdAcl
One seeded ACL-abuse edge: principal holds right over target.
Principals and targets are names as AD knows them (users, groups, OUs, or computer objects) and are not cross-validated against declared users this round.
class AdAcl(_StrictModel)Attributes
principalstr-
Who holds the right.
rightAdRight-
The right held.
targetstr-
What the right applies to.
AdRight
Seeded AD ACL rights (the vocabulary observed in surveyed ranges; extended when evidence forces).
AdRight = Literal[
"GenericAll",
"GenericWrite",
"WriteDacl",
"WriteOwner",
"ForceChangePassword",
"SelfMembership",
"AddMember",
]Networks
Network
A layer-2 segment with its addressing and egress posture.
class Network(_StrictModel)Attributes
namestr-
Segment name, unique within the range.
cidrAnyIPNetwork-
Subnet, e.g.
10.10.10.0/24(IPv6 subnets are gated byipv6-not-realizeduntil realization lands). modeLiteral['isolated', 'nat', 'routed']-
Egress posture:
isolated(no egress),nat, orrouted. dhcpbool-
Whether guests on this network get addresses via DHCP (default: static).
dnsDnsConfig | None-
DNS behavior on this network.
gatewaystr | None-
The router that is this network’s default gateway; required only when more than one router attaches (a single attached router is elected implicitly).
egressEgressPolicy | None-
Scoped egress allowlist; only meaningful with
mode: nat(the hypervisor NATs exactly these flows out).
Interface
A guest’s attachment to a network.
class Interface(_StrictModel)Attributes
networkstr-
Name of a declared network.
ipAnyIPAddress | None-
Static address within the network’s subnet; omitted means IPAM-allocated.
DnsConfig
Per-network DNS, as a union of the shapes real ranges need.
records serves name-based discovery on flat networks; nameservers points guests at external resolvers; authoritative names guests (e.g. domain controllers) that are the network’s DNS servers, optionally chaining to forwarder.
class DnsConfig(_StrictModel)Attributes
recordslist[DnsRecord] | None-
Name records served by the range for this network.
nameserverslist[AnyIPAddress] | None-
External resolvers handed to guests.
authoritativelist[str] | None-
Guests that act as this network’s DNS servers, in resolution order.
forwarderAnyIPAddress | None-
Upstream forwarder for the authoritative chain.
DnsRecord
A name record served on a network.
class DnsRecord(_StrictModel)Attributes
namestr-
Hostname to resolve.
ipAnyIPAddress | None-
Address, when not derivable from the named guest’s interface.
EgressPolicy
A scoped egress allowlist: exactly what may leave, nothing else.
Entries are CIDR[:proto/port] (a bare address is its /32; omitting the service allows all traffic to the CIDR) or FQDN:proto/port. FQDN entries are in the vocabulary but gated by egress-fqdn-not-realized until their realization lands (networking-v0.2 §3).
class EgressPolicy(_StrictModel)Attributes
allowlist[str]-
Allowlist entries, e.g.
198.51.100.7:tcp/443,0.0.0.0/0:udp/123; empty allows nothing.
Route
A static route on a router, for traffic to segments it reaches through another router.
class Route(_StrictModel)Attributes
toAnyIPNetwork-
Destination subnet.
viaAnyIPAddress-
Next hop; must be an address inside one of the router’s attached networks.
AclRule
One ordered rule on a router, carrying exactly one of allow: or deny:.
Rules evaluate first-match in list order against new connections from one endpoint to another; anything no rule matches is dropped (default-deny), and return traffic of allowed flows always passes (stateful). Endpoints are a network name, a guest name (resolved to its allocated addresses at plan time), or a CIDR (/32 for a literal host, 0.0.0.0/0 for any). deny exists for carve-outs inside a broader allow. In typed construction the source field is spelled from_ (the YAML surface keeps from:).
class AclRule(_StrictModel)Attributes
from_str-
Source endpoint: network name, guest name, or CIDR (
from:in YAML;from_=in typed construction). tostr-
Destination endpoint: network name, guest name, or CIDR.
allowlist[str] | None-
Services to allow, as
proto/port,proto/lo-hi, oricmpentries, e.g.tcp/5432,tcp/1-65535; empty allows nothing. denylist[str] | None-
Services to drop at this point in the rule order (same entry syntax as
allow).
AnyIPAddress
Either address family. IPv6 values validate structurally but are rejected by the ipv6-not-realized gate until their realization lands (networking-v0.2 §4).
AnyIPAddress = IPv4Address | IPv6AddressAnyIPNetwork
Either address family. IPv6 values validate structurally but are rejected by the ipv6-not-realized gate until their realization lands (networking-v0.2 §4).
AnyIPNetwork = IPv4Network | IPv6NetworkDiagnostics
Issue
One problem found in a range definition.
class Issue(BaseModel)Attributes
codestr-
Stable kebab-case identifier, e.g.
undeclared-network. severitySeverity-
Whether the issue blocks use of the spec.
pathtuple[PathElement, ...]-
Location within the spec, e.g.
("networks", 0, "cidr"). lineint | None-
1-based source line, when the YAML parse can supply it.
colint | None-
1-based source column, when the YAML parse can supply it.
messagestr-
What is wrong.
hintstr | None-
Actionable suggestion, e.g. a did-you-mean or where deferred content goes.
path_strstr-
The path rendered as
networks[0].cidr, or(root)for the document root.
ValidationReport
Every issue found in one range.yaml, with rendering helpers.
class ValidationReport(BaseModel)Attributes
filestr-
The validated file path, as given.
issueslist[Issue]-
All issues found, in source order where positions are known.
semantic_checkedbool-
False when structural errors prevented the cross-reference checks from running.
specAny | None-
The validated RangeSpec when the file is valid, for callers that need it.
validbool-
True when no error-severity issues were found.
Methods
- render
-
Render the report as aligned, human-readable text (warnings do not invalidate).
def render(self) -> str - to_json
-
Return the report as JSON-serializable data with stable field names.
def to_json(self) -> dict[str, Any]