Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ root = true
indent_style = space

# Code files
[*.{cs,csproj,slnx,props,json}]
[*.{cs,csproj,slnx,props,targets,json}]
indent_size = 2
insert_final_newline = false
charset = utf-8
Expand Down Expand Up @@ -225,6 +225,8 @@ dotnet_diagnostic.SA1502.severity = none
dotnet_diagnostic.SA1508.severity = none
# SA1516 Elements should be separated by blank line (but reports false positives)
dotnet_diagnostic.SA1516.severity = none
# SA1201 An element within a C# code file is out of order in relation to the other elements in the code.
dotnet_diagnostic.SA1201.severity = none


# TODO TBD
Expand Down
5 changes: 5 additions & 0 deletions .github/actions/setup-runner/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,8 @@ runs:
- name: Restore .NET tools
shell: bash
run: dotnet tool restore

- name: Install Containerlab
if: runner.os == 'Linux'
shell: bash
run: bash -c "$(curl -sL https://get.containerlab.dev)"
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ obj/
#*.idea
.idea/.idea.Drift/.idea/watcherTasks.xml
.idea/.idea.Drift/.idea/encodings.xml
.idea/.idea.Drift.Build/.idea/encodings.xml
.air/
*.DotSettings
*.received.*
artifacts/
Expand All @@ -14,4 +16,5 @@ TestResults/
build.binlog
build.binlog-warnings-only.log
publish.binlog
publish.binlog-warnings-only.log
publish.binlog-warnings-only.log
containerlab/*/
14 changes: 14 additions & 0 deletions .nuke/build.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,13 @@
"Test",
"TestE2E",
"TestE2E_Binary",
"TestE2E_Clab",
"TestE2E_Container",
"TestE2E_General",
"TestLocal",
"TestSelf",
"TestUnit",
"TestUnitLocal",
"UpdateOui"
]
},
Expand Down Expand Up @@ -137,6 +139,10 @@
"allOf": [
{
"properties": {
"ClabTopology": {
"type": "string",
"description": "Run only this topology (e.g. 'simple-test'). Runs all topologies if not specified"
},
"Commit": {
"type": "string",
"description": "Commit - e.g. '4c16978aa41a3b435c0b2e34590f1759c1dc0763'"
Expand Down Expand Up @@ -167,6 +173,10 @@
"description": "GitHubToken - GitHub token used to create releases",
"default": "Secrets must be entered via 'nuke :secrets [profile]'"
},
"KeepClabRunning": {
"type": "boolean",
"description": "Keep Containerlab topology running after tests"
},
"MsBuildVerbosity": {
"type": "string",
"description": "MsBuildVerbosity - Console output verbosity - Default is 'normal'"
Expand Down Expand Up @@ -218,6 +228,10 @@
"description": "ReleaseType - None (default/safe), PreRelease, or Release",
"$ref": "#/definitions/ReleaseType"
},
"SkipClabDeploy": {
"type": "boolean",
"description": "Skip Containerlab deployment (useful for debugging when topology is already running)"
},
"Solution": {
"type": "string",
"description": "Path to a solution file that is automatically loaded"
Expand Down
91 changes: 91 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# AGENTS.md

This file provides guidance to AI agents when working with code in this repository.

## Project Overview

Drift is a .NET 10 CLI tool for network drift detection — it compares a declarative YAML spec (desired network state) against live network scanning results and reports differences. It supports distributed scanning via agents communicating over gRPC.

## Build System

The build uses [NUKE](https://nuke.build/). Entry point is `dotnet nuke`.

Common targets:

```sh
dotnet nuke Build # Restore + compile
dotnet nuke TestUnit # Unit tests only (fast)
dotnet nuke Test # All tests (unit + E2E)
dotnet nuke TestE2E # E2E tests (General, Binary, Container image, Container network topologies using Containerlab)
dotnet nuke PublishBinaries # Self-contained binary (
dotnet nuke BuildContainerImage
```

Run a single test class or filter by name using standard `dotnet test` filters:

```sh
dotnet test src/Domain.Tests --filter "FullyQualifiedName~MyTest"
```

## Architecture

### Source layout (`src/`)

The solution is split into focused projects. The main ones:

| Project | Role |
|---|------------------------------------------------------------------------------------------|
| `Cli` | Entry point; commands: `init`, `scan`, `agent start`; AOT-compiled |
| `Cli.Abstractions` | Shared CLI constants: exit codes, env var names, port numbers, file names |
| `Cli.Settings` | User settings file (`~/.config/drift/settings.json`) |
| `Domain` | Core value types: `Network`, `Device`, `Inventory`, `CidrBlock`, `Port`, `Scan`, `AgentId` |
| `Spec` | YAML spec parsing and validation (YamlDotNet + JsonSchema.Net) |
| `Scanning` | Network discovery: ARP, ping, port scanning with rate limiting |
| `Diff` | Compares declared spec state vs. discovered scan state to produce drift report |
| `Networking.PeerStreaming.*` | Abstract P2P streaming protocol + gRPC implementation (`peer.proto`) |
| `Networking.Cluster` | Multi-agent coordination |
| `Agent.Hosting` | Agent runtime (`AgentHost`, `Identity`) |
| `Agent.PeerProtocol` | Agent-specific peer messaging |
| `Serialization` | Cross-module serialization helpers |
| `ArchTests` | ArchUnitNET tests enforcing dependency rules and naming conventions |

Schema generators live in `Spec.SchemaGenerator.Cli` and `Cli.Settings.SchemaGenerator.Cli` — they produce JSON Schema from C# types.

### Data flow

```
YAML spec → Spec (parse/validate) → Domain types (declared state)
Network → Scanning → Domain types (discovered state)
Diff → Drift report → Cli (render)
```

Agents (remote Drift instances) report discovered state back to the coordinator over gRPC, extending scan coverage across subnets.

### Key conventions

- **Central package management**: all NuGet versions in `Directory.Packages.props`; do not add `Version=` attributes to `<PackageReference>` in individual project files.
- **Shared project defaults**: `Directory.Build.props` applies nullable refs, implicit usings, and logging config to all projects.
- **InternalsVisibleTo**: test projects access internal members for white-box testing; this is intentional.
- **Snapshot testing**: `Verify.NUnit` is used for golden file comparisons. Run tests to regenerate snapshots when output changes; committed `.verified.*` files are the source of truth.
- **AOT**: `Cli` is published with `PublishAot=true`. Avoid reflection-heavy patterns in the CLI project; use source generators instead.
- **Embedded resources**: schemas, default specs, and scripts are embedded in project assemblies under `embedded_resources/`.
- **`Networking.*` are role-agnostic**: No "Agent", "Peer", "Coordinator", or "Server" in type names, property names, parameter names, method names, or log strings inside `Networking.*`. These assemblies implement the transport layer only (streams, messages, connections). Role-specific concerns belong in `Agent.*`, `Coordinator.*`, or `Cli.*`.

## Testing

- **Unit tests**: `*.Tests` projects using NUnit 4 and NSubstitute for mocking.
- **E2E tests**: `Cli.E2ETests.*` projects — General (Testcontainers), Binary (published binary), Container (Docker image), Containerlab (real multi-node topologies).
- **Architecture tests**: `ArchTests` project validates project dependency graph and naming rules.

Containerlab tests require Containerlab installed and use topology files in `containerlab/`.

## Terminology (from domain model)

- **Spec**: declarative YAML definition of desired network state
- **Declared resource**: a device/subnet defined in the spec
- **Discovered resource**: a device/subnet found by scanning
- **Drift**: difference between declared and discovered state
- **Device ID**: one or more addresses (MAC, IPv4, IPv6, hostname) that uniquely identify a device; spec addresses with `is_id: false` are metadata only
- **Agent**: a Drift instance in agent mode that reports scan results to peers
1 change: 1 addition & 0 deletions CLAUDE.md
8 changes: 8 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@
</ItemGroup>
<ItemGroup Label="Direct">
<PackageVersion Include="CsvHelper" Version="33.1.0" />
<PackageVersion Include="Google.Protobuf" Version="3.35.1" />
<PackageVersion Include="Grpc.AspNetCore" Version="2.80.0" />
<PackageVersion Include="Grpc.Core.Api" Version="2.80.0" />
<PackageVersion Include="Grpc.Net.Client" Version="2.80.0" />
<PackageVersion Include="Grpc.Tools" Version="2.82.0" />
<PackageVersion Include="HLabs.Containers" Version="1.0.0-preview.1" />
<PackageVersion Include="HLabs.ImageReferences" Version="1.0.0-preview.3" />
<PackageVersion Include="HLabs.ImageReferences.Extensions.Nuke" Version="1.0.0-preview.3" />
<PackageVersion Include="Humanizer" Version="3.0.10" />
Expand All @@ -18,6 +24,7 @@
<PackageVersion Include="JsonSchema.Net.Generation" Version="7.3.10" />
<PackageVersion Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="4.14.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.9" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.9" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.9" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.9" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="10.0.9" />
Expand All @@ -41,6 +48,7 @@
<PackageVersion Include="StyleCop.Analyzers" Version="1.1.118" />
<PackageVersion Include="System.CommandLine" Version="2.0.9" />
<PackageVersion Include="System.Text.Json" Version="10.0.9" />
<PackageVersion Include="System.Threading.Channels" Version="10.0.9" />
<PackageVersion Include="System.Threading.RateLimiting" Version="10.0.9" />
<PackageVersion Include="Testcontainers" Version="4.12.0" />
<PackageVersion Include="TngTech.ArchUnitNET.NUnit" Version="0.13.3" />
Expand Down
9 changes: 6 additions & 3 deletions Drift.Build.slnx
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
<!-- https://github.com/microsoft/vs-solutionpersistence/blob/main/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/Slnx.xsd -->
<Solution>
<Folder Name="/Workflows/">
<File Path=".github\workflows\audit.yaml" />
<File Path=".github\workflows\ci.yaml" />
<File Path=".github\workflows\codeql.yml" />
<File Path=".github\workflows\prerelease.yaml" />
<File Path=".github\workflows\release.yaml" />
<File Path=".github\workflows\renovate.yaml" />
</Folder>
<Folder Name="/Workflows/Actions/" />
<Folder Name="/Workflows/Actions/runner-setup/">
<File Path=".github\actions\setup-runner\action.yml" />
</Folder>
<Project Path="build\_build.csproj" Type="C#" />
<Project Path="build-utils\Build.Utilities.Tests\Build.Utilities.Tests.csproj" Type="C#" />
<Project Path="build-utils\Build.Utilities\Build.Utilities.csproj" Type="C#" />
<Project Path="build\_build.csproj" />
<Project Path="build-utils\Build.Utilities.Tests\Build.Utilities.Tests.csproj" />
<Project Path="build-utils\Build.Utilities\Build.Utilities.csproj" />
</Solution>
Loading
Loading