Skip to content

Commit b6b2af0

Browse files
committed
docs: add agents documentation
1 parent 9258a5a commit b6b2af0

File tree

2 files changed

+309
-0
lines changed

2 files changed

+309
-0
lines changed

AGENTS.md

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
# Sysdig LSP – Unified Assistant Context & Repository Guidelines
2+
3+
## 1. Project Overview
4+
5+
**Sysdig LSP** is a Language Server Protocol (LSP) implementation written in Rust. It integrates container image vulnerability scanning and Infrastructure-as-Code (IaC) analysis directly into code editors (e.g. VS Code, Helix, Neovim).
6+
7+
It is designed to detect issues early in the development workflow by scanning:
8+
9+
* Dockerfiles
10+
* Docker Compose files
11+
* Kubernetes manifests
12+
* Other IaC files
13+
14+
The server is built on top of the `tower-lsp` framework and integrates with Sysdig’s Secure backend via a dedicated scanner binary and HTTP APIs.
15+
16+
### Key Features
17+
18+
* Vulnerability scanning of base images and dependencies.
19+
* Code Lens support (e.g. “Scan base image” on `FROM` lines).
20+
* Layered analysis for container images.
21+
* Integration with Sysdig’s Secure backend APIs through a CLI scanner binary.
22+
23+
---
24+
25+
## 2. Project Structure & Architecture
26+
27+
The project follows a modular, three-layer, Hexagonal-like architecture that cleanly separates domain logic, application orchestration, and infrastructure concerns.
28+
29+
### 2.1 Workspace & Modules
30+
31+
* Rust workspace with entrypoint in `src/main.rs` (initializes `LSPServer` with `tower-lsp` and configures logging).
32+
* Library exports in `src/lib.rs`, which also enforces linting rules (denies `unwrap` / `expect` in production code).
33+
* LSP orchestration / use-cases live in `src/app`.
34+
* Domain types and business logic live in `src/domain`.
35+
* Adapters and integrations (infrastructure) live in `src/infra`.
36+
* Integration tests and shared fixtures live under `tests/`:
37+
* `tests/general.rs`
38+
* `tests/common.rs`
39+
* `tests/fixtures/` (sample Dockerfiles, scan results, etc.)
40+
* Documentation for user-facing capabilities is under `docs/features/`.
41+
* Build tooling and shortcuts are defined in `Justfile` and `flake.nix`.
42+
43+
### 2.2 Domain Layer (`src/domain/`)
44+
45+
The domain layer contains pure business logic and domain models.
46+
47+
Key module:
48+
49+
* `scanresult/`: defines core entities and value objects:
50+
* `ScanResult`: core aggregate representing a full scan result.
51+
* `Vulnerability`: CVE, severity, package details, etc.
52+
* `Package`: name, version, package type.
53+
* `Layer`: container image layer information.
54+
* `Policy`: policy evaluation results.
55+
* Value objects such as `Severity`, `Architecture`, `OperatingSystem`.
56+
57+
### 2.3 Application Layer (`src/app/`)
58+
59+
The application layer orchestrates domain and infrastructure components and implements LSP-specific behavior.
60+
61+
Key components:
62+
63+
* **`LSPServer` (`lsp_server/`)** – main LSP implementation built on `tower-lsp`:
64+
* `lsp_server_inner.rs`: core LSP protocol handlers (initialize, text sync, code lenses, commands, diagnostics, hover, etc.).
65+
* `commands/`: concrete LSP command implementations (e.g. `scan_base_image`, `build_and_scan`).
66+
* `command_generator.rs`: generates Code Lens entries and associated commands.
67+
* `supported_commands.rs`: registry of available commands exposed to the client.
68+
* **`LspInteractor`** – manages communication with the LSP client and document state.
69+
* **`ImageScanner`** – trait for scanning container images (implemented by infrastructure components).
70+
* **`ImageBuilder`** – trait for building Docker images.
71+
* **`DocumentDatabase` (`document_database.rs`)** – in-memory store for:
72+
* Document text
73+
* Diagnostics (LSP warnings/errors for vulnerabilities)
74+
* Hover documentation (detailed vulnerability explanations)
75+
* **`markdown/`** – formats scan results into Markdown tables for display in editors.
76+
* **`ComponentFactory`** – abstract factory for dependency injection and component creation.
77+
78+
### 2.4 Infrastructure Layer (`src/infra/`)
79+
80+
The infrastructure layer implements technical concerns and external integrations.
81+
82+
Key components:
83+
84+
* **`SysdigImageScanner`**
85+
* Integrates with the Sysdig CLI scanner binary and Sysdig Secure backend.
86+
* Downloads and manages scanner binary versions.
87+
* Parses JSON scan results (e.g. via `sysdig_image_scanner_json_scan_result_v1.rs`).
88+
89+
* **`DockerImageBuilder`**
90+
* Builds container images using Bollard (Docker API client).
91+
92+
* **Dockerfile / Compose AST Parsers**
93+
* Parse Dockerfiles to extract image references from `FROM` instructions (including multi-stage builds).
94+
* Parse Docker Compose YAML (e.g. service `image:` fields).
95+
* Handle complex scenarios such as build args and multi-platform images.
96+
* Implemented via modules like `ast_parser.rs`.
97+
98+
* **`ScannerBinaryManager`**
99+
* Downloads the Sysdig CLI scanner binary on demand.
100+
* Caches binaries and checks GitHub releases for the latest version compatible with the current platform.
101+
102+
* **`LSPLogger`**
103+
* `tracing` subscriber that logs diagnostics and events to the LSP client or stderr.
104+
105+
* **`ConcreteComponentFactory`**
106+
* Production wiring of dependencies implementing the `ComponentFactory` trait.
107+
108+
### 2.5 LSP Protocol Flow
109+
110+
The high-level LSP flow is:
111+
112+
1. **Initialize** – Client sends configuration (e.g. `api_url`, `api_token`) via `initializationOptions`.
113+
2. **`didOpen` / `didChange`** – Document updates trigger parsing and analysis.
114+
3. **`codeLens`** – The server generates “Scan base image” code lenses on relevant lines (e.g. Dockerfile `FROM` instructions).
115+
4. **`executeCommand`** – Clicking a lens triggers commands like `scan_base_image` or `build_and_scan`.
116+
5. **`publishDiagnostics`** – Vulnerability findings are sent as diagnostics to the editor.
117+
6. **`hover`** – Hovering on diagnostics or vulnerable elements shows detailed vulnerability information.
118+
119+
### 2.6 Document State Management
120+
121+
Document state is managed in-memory via `InMemoryDocumentDatabase` (an implementation of `DocumentDatabase`), maintaining per-document:
122+
1. Raw document text.
123+
2. Diagnostics with vulnerability details.
124+
3. Pre-computed hover documentation.
125+
126+
This allows the LSP to provide rich, contextual information without re-running scans on every request.
127+
128+
---
129+
130+
## 3. Development Environment & Tooling
131+
132+
### 3.1 Nix & Development Shell
133+
134+
* `nix develop` – enter a reproducible development shell with the exact Rust toolchain and dependencies required by the project, as defined in `flake.nix`. You can assume the user already started the development shell.
135+
136+
### 3.2 Build Commands
137+
138+
* `cargo build` – build the server in debug mode.
139+
* `cargo build --release` – build an optimized release binary.
140+
* `nix build .#sysdig-lsp` – Nix-based build, with cross targets available (e.g. CI or other architectures).
141+
* Cross-compilation example: `nix build .#sysdig-lsp-linux-amd64`.
142+
143+
The resulting `sysdig-lsp` binary is designed to be run by an LSP client (editor), rather than directly by users.
144+
145+
### 3.3 Testing & Quality Commands
146+
147+
The project uses `just` as a command runner to encapsulate common workflows.
148+
149+
* `just test`
150+
* Runs the test suite via `cargo nextest run` (primary test runner).
151+
* Some tests require the `SECURE_API_TOKEN` environment variable.
152+
153+
* `just lint`
154+
* Runs `cargo check` and `cargo clippy` for quick static analysis.
155+
156+
* `just fmt`
157+
* Runs `cargo fmt` according to `rustfmt.toml`.
158+
159+
* `just fix`
160+
* Runs `cargo fix` and `cargo machete` / `cargo machete --fix` to clean up unused dependencies and minor issues.
161+
162+
* `just watch`
163+
* Provides a watch mode to run tests (or other commands) on file changes.
164+
165+
Additional helpful commands:
166+
167+
* `cargo test -- --nocapture` – run tests with full output when debugging.
168+
169+
### 3.4 Pre-commit Hooks
170+
171+
Pre-commit hooks are configured in `.pre-commit-config.yaml` to run:
172+
173+
* Formatting (`cargo fmt`).
174+
* `cargo check`.
175+
* `cargo clippy`.
176+
177+
These should run cleanly before opening a PR.
178+
They are automatically executed before a commit is done.
179+
If they are not executed, you need to execute: `pre-commit install` to configure it.
180+
If any of the steps of the pre-commit fails for whatever reason, you need to understand that the commit was not created.
181+
182+
---
183+
184+
## 4. Coding Style, Technologies & Design Patterns
185+
186+
### 4.1 Languages & Key Libraries
187+
188+
* **Language:** Rust (Edition 2024).
189+
* **LSP Framework:** `tower-lsp`.
190+
* **Async Runtime:** `tokio`.
191+
* **HTTP Client:** `reqwest`.
192+
* **Serialization:** `serde`.
193+
* **Logging:** `tracing` (plus `LSPLogger` integration).
194+
* **CLI Args:** `clap`.
195+
* **Testing Libraries:** `rstest`, `mockall`, `serial_test`, along with `cargo nextest`.
196+
197+
### 4.2 Code Style & Naming Conventions
198+
199+
* Use standard Rust formatting (`rustfmt`) with 4-space indentation.
200+
* **Naming:**
201+
* `snake_case` for modules and functions.
202+
* `CamelCase` for types.
203+
* `SCREAMING_SNAKE_CASE` for constants.
204+
* Import ordering uses `reorder_imports = true` in `rustfmt.toml`.
205+
* Prefer trait-based abstractions over concrete types for testability and clear architecture boundaries.
206+
* Keep public APIs documented and keep modules small, mirroring the `app` / `domain` / `infra` boundaries.
207+
* Use `tracing` for structured logging, sending logs to the LSP client or stderr via `LSPLogger`.
208+
209+
### 4.3 Error Handling
210+
211+
Error handling is intentionally strict:
212+
213+
* **No `unwrap()` or `expect()` in non-test code.**
214+
* Enforced by clippy rules and `src/lib.rs` configuration.
215+
* Use `Result` types with explicit error propagation.
216+
* Prefer `thiserror` for custom error types with rich context.
217+
* Optionally use `anyhow::Context` style patterns for additional context at call sites.
218+
* Convert domain-level errors to appropriate LSP-facing errors at the application boundary.
219+
220+
### 4.4 Dependency Injection via `ComponentFactory`
221+
222+
The `ComponentFactory` trait centralizes creation of major application components and supports testing:
223+
224+
* Receives configuration (e.g. `api_url`, `api_token`) from the client.
225+
* Produces `Components` such as:
226+
* `ImageScanner` implementations.
227+
* `ImageBuilder` implementations.
228+
* `ConcreteComponentFactory` wires real components in production.
229+
* Tests can provide mock factories to inject fake scanners/builders for deterministic behavior.
230+
231+
### 4.5 Async / Await & Concurrency
232+
233+
All I/O operations, including scanning, building, and LSP communication, are asynchronous using the `tokio` runtime.
234+
235+
* Shared state within the LSP server uses `RwLock` (or similar primitives) to support concurrent reads with controlled writes.
236+
237+
---
238+
239+
## 5. Testing Strategy & Guidelines
240+
241+
### 5.1 Testing Strategy
242+
243+
* Integration tests live in the `tests/` directory, using real fixtures (e.g. Dockerfiles, sample scan results).
244+
* Fixtures are stored under `tests/fixtures/`.
245+
* **`serial_test`** is used to prevent parallel execution conflicts (e.g. sharing global resources or temporary directories).
246+
* **`mockall`** is used for mocking traits like `ImageScanner` in unit tests.
247+
* `rstest` can be used for parameterized tests.
248+
* Environment: tests may require `SECURE_API_TOKEN` for scenarios that depend on authenticated scanning.
249+
250+
### 5.2 Testing Guidelines
251+
252+
* Primary test runner is `cargo nextest` (via `just test`).
253+
* Add integration coverage in `tests/*.rs` and reuse fixtures in `tests/fixtures/`.
254+
* Name tests descriptively (`should_*` or behavior-oriented names).
255+
* Avoid direct network calls inside tests; prefer fixture-based or mocked interactions instead.
256+
* Add focused unit tests alongside modules using `#[cfg(test)]` for local behavior.
257+
* Broader flows and end-to-end LSP interactions belong in `tests/general.rs`.
258+
* For debugging, `cargo test -- --nocapture` can be used to see all test output.
259+
260+
---
261+
262+
## 6. Configuration, Security & Runtime Usage
263+
264+
### 6.1 LSP Initialization & Client Configuration
265+
266+
Clients configure Sysdig LSP via `initializationOptions` in the LSP initialize request, for example:
267+
268+
```json
269+
{
270+
"sysdig": {
271+
"api_url": "https://secure.sysdig.com",
272+
"api_token": "optional, falls back to SECURE_API_TOKEN env var"
273+
}
274+
}
275+
```
276+
277+
Key points:
278+
* `api_url` should be validated and not hard-coded to environment-specific endpoints in code.
279+
* `api_token` is optional; if absent, the server falls back to the `SECURE_API_TOKEN` environment variable.
280+
281+
### 6.2 Security & Secrets
282+
283+
* Do **not** commit API tokens or other secrets to the repository.
284+
* Prefer environment variables (e.g. `SECURE_API_TOKEN`) or editor initialization options (`sysdig.api_token`).
285+
* Always validate URLs provided via configuration (`sysdig.api_url`).
286+
287+
### 6.3 Supported Usage Pattern
288+
289+
* The `sysdig-lsp` binary is not meant to be run manually; it is launched and driven by an LSP client (such as VS Code, Helix, or Neovim) that speaks the Language Server Protocol.
290+
291+
---
292+
293+
## 7. Commit & Pull Request Guidelines
294+
295+
To keep history clean and reviews manageable:
296+
297+
* Use conventional-style commits similar to existing history, e.g.:
298+
* `feat(scope): message`
299+
* `fix(scope): message`
300+
* `refactor: message`
301+
* Before opening a commit, run at least:
302+
* `just fmt`
303+
* `just lint`
304+
* `just test`
305+
* Any relevant `nix build` invocations when touching build tooling.
306+
* (You can assume they are executed before the commit is created, see Section 3.4)
307+
* Keep commits scoped and reversible; smaller, reviewable PRs are preferred over large, monolithic changes.
308+
* You must also modify AGENTS.md and README.md if applicable for any change you create, so both files are in sync with the project and the documentation does not become obsolete.

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@AGENTS.md

0 commit comments

Comments
 (0)