Skip to content

Milestone 1: design proposal, normalized event model and alert sinks - #1

Merged
dylanpatriarchi merged 1 commit into
mainfrom
feat/m1-foundations
Aug 1, 2026
Merged

dylanpatriarchi merged 1 commit into
mainfrom
feat/m1-foundations

Conversation

@dylanpatriarchi

Copy link
Copy Markdown
Owner

Milestone 1 — foundations

Argus is an educational project. It demonstrates how endpoint detection works; it is not a production EDR and must not be relied on as a security control. It is read-only and defensive by construction: it observes and reports, and never injects into, tampers with, hides from, or modifies another process. That scope is stated in the README, the design doc, every module header, and the CLI itself.

This PR does two things: it proposes the contract in docs/design.md, and it implements the first milestone against it.

The proposal — docs/design.md

  • Normalized Event schema and its JSON wire form, plus the dotted field paths rules will address (actor.exe, target.remotePort, raw.*).
  • Collector interface — one abstract base with start / stop / privileges / available, and a table of the privilege each planned collector needs, why it needs it, and the degraded fallback available without it.
  • Rule format — YAML, the full operator set, all/any/not composition, and the windowed correlation shape for milestone 6.
  • Seven-milestone plan, plus what is explicitly future (eBPF, a second platform) and what is explicitly never (anything offensive).

The implementation

  • Event model (src/argus/types.nim). Target is a variant, so a file event carrying a remote port is unrepresentable rather than merely unset. The category is derived from the action rather than passed in, so the two cannot disagree. Unknown pid/uid stay explicitly unknown instead of defaulting to 0, which would read as root.
  • Serialization (src/argus/serialization.nim). Hand-written, because the wire format is a contract other tools consume. Output is deterministic — sorted maps, fixed key order — so two runs are byte-identical and diffable. Parsing is defensive: unknown actions are rejected, and a doctored category is re-derived rather than trusted. Includes JSONL trace load/save, the input format for milestone 2's replay tests.
  • Alert model (src/argus/alert.nim). Rule identity, severity, ATT&CK mapping with a derived canonical URL, and the events that are its evidence.
  • Sinks (src/argus/sink.nim, src/argus/sinks/). Console (severity-colored, color auto-disabled when not a terminal), JSONL to stdout or file, and memory for tests. SinkGroup fans out and tolerates partial failure — a full disk on the file sink must not cost you the console alert.
  • CLI — argus version, argus demo, argus check-trace FILE.

Verification

98 unit tests across four modules, all green; nimble lint clean; binary builds. CI runs lint, tests, build and a CLI smoke test on every push and PR.

$ nimble test    # 98 [OK], 0 [FAILED]
$ nimble build   # ./argus

tests/data/sample_trace.jsonl is a synthetic ten-event trace — a web server behaving normally, then an nginx worker spawning a shell that writes a cron entry and connects outbound, plus benign apt activity for rules to not fire on. Nothing in it was collected from a real host.

Scope of this milestone

No collectors. Argus observes nothing yet and therefore needs no privilege at all. The pipeline downstream of collection is what is built and tested here.

Next

Milestone 2 — the rule engine: YAML loading, field matching, and trace-replay tests.

Establishes the foundations the rest of Argus is written against.

docs/design.md is the contract: the normalized Event schema and its JSON
wire form, the field paths rules will address, the collector interface with
the privilege each planned collector needs and its degraded fallback, the
YAML rule format (operators, boolean composition, correlation), and the
seven-milestone plan.

Implementation:
- Event model with a variant Target, so a file event cannot carry a remote
  port. Category is derived from the action rather than passed in, so the
  two can never disagree. Unknown pid/uid stay explicitly unknown instead
  of defaulting to zero, which would read as root.
- Hand-written JSON serialization. The wire format is a published contract,
  output is deterministic (sorted maps, fixed key order) so runs are
  diffable, and parsing is defensive: unknown actions and doctored
  categories are rejected rather than trusted.
- JSONL trace loading/saving, the input format for the replay tests that
  milestone 2 will use to exercise rules without any live host activity.
- Alert model carrying rule identity, severity, MITRE ATT&CK mapping and
  the events that are its evidence.
- Sink interface plus console, JSONL (stdout/file) and memory
  implementations. A SinkGroup fans out and tolerates partial failure: a
  full disk on the file sink must not cost you the console alert.
- CLI with version, demo and check-trace. The demo alert is synthetic —
  no host activity is observed to produce it.

98 unit tests, and CI runs lint, tests, build and a CLI smoke test.

No collectors yet, so Argus observes nothing at this milestone and needs no
privilege. The educational, read-only, non-production scope is stated in the
README, the design doc, the module docs and the CLI itself.
@dylanpatriarchi
dylanpatriarchi merged commit 1a78e1b into main Aug 1, 2026
1 check passed
@dylanpatriarchi
dylanpatriarchi deleted the feat/m1-foundations branch August 1, 2026 13:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant