diff --git a/README.md b/README.md index bac3308..18d52e4 100644 --- a/README.md +++ b/README.md @@ -7,20 +7,22 @@ Zwei Frontends, eine gemeinsame Tool-Logik: | Modus | Binary | Einsatz | |---|---|---| -| **stdio** | `dtrack-stdio` | Arbeitsrechner: von Claude Desktop via `podman run -i` gestartet | -| **HTTP** | `dtrack-http` | Server: StreamableHTTP `/mcp`, Multi-Client, Bearer-Auth | +| **stdio** | `dtrack-stdio` | Lokal: von Claude Desktop via `docker run -i` gestartet | +| **HTTP** | `dtrack-http` | Server: StreamableHTTP `/mcp`, Multi-Client, Bearer-Auth/RBAC, Admin-UI | -> **Status: Stage 2** -- HTTP-Frontend + Bearer-Auth stehen. Admin-UI + -> Permission-Engine + SSO folgen (siehe Roadmap). +> **Status: Stage 3** -- HTTP-Frontend, Bearer-Auth, persistente Config, +> Admin-UI und RBAC-Enforcement stehen. Tool-Sichtbarkeit pro Client (Stufe 2) +> und SSO folgen (siehe Roadmap). ## Architektur ``` -crates/dtrack-config Config (TOML laden/speichern, Secret-Masking) +crates/dtrack-config Config (TOML laden/speichern, Secret-Masking, Persistenz) +crates/dtrack-perms RBAC-Policy (Rollen/Clients, Deny-overrides-Allow) crates/dtrack-core DT-REST-Client (reqwest+rustls, read-only) crates/dtrack-tools rmcp-Server (die Tools) -- transport-unabhaengig, geteilt crates/dtrack-stdio Bin: stdio-Frontend -crates/dtrack-http Bin: HTTP-Frontend (axum + StreamableHTTP) +crates/dtrack-http Bin: HTTP-Frontend (axum + StreamableHTTP + Admin-UI) ``` ## Tools @@ -35,60 +37,178 @@ crates/dtrack-http Bin: HTTP-Frontend (axum + StreamableHTTP) | Var | Pflicht | Bedeutung | |---|---|---| -| `DTRACK_URL` | ja* | Basis-URL der DT-Instanz | +| `DTRACK_URL` | ja* | Basis-URL der DT-Instanz (ohne `/api/v1`, wird angehaengt) | | `DTRACK_API_KEY` | ja* | API-Key eines **read-only** Teams (`VIEW_PORTFOLIO`, `VIEW_VULNERABILITY`) | | `DTRACK_INSECURE` | nein | `1`/`true` -> TLS-Pruefung aus (Notbehelf bei internem CA-Cert) | -| `DTRACK_CONFIG` | nein | Pfad zu einer TOML-Config; hat Vorrang vor den env-Werten | +| `DTRACK_CONFIG` | nein | Pfad zu einer TOML-Config; einmal aus env gebootstrappt, danach massgeblich | +| `DTRACK_PERMISSIONS` | nein | (nur HTTP) Pfad zur RBAC-Policy; gesetzt -> RBAC statt flacher Token-Liste | | `DTRACK_HTTP_TOKENS` | nein | (nur HTTP) kommagetrennte erlaubte Bearer-Tokens; leer = ungeschuetzt | | `DTRACK_HTTP_ADDR` | nein | (nur HTTP) Bind-Adresse, Default `0.0.0.0:8080` | +| `DTRACK_ADMIN_USER` | nein | (nur HTTP) Basic-Auth-User der Admin-UI; leer = UI deaktiviert | +| `DTRACK_ADMIN_PASSWORD` | nein | (nur HTTP) Basic-Auth-Passwort der Admin-UI | \* oder ueber `DTRACK_CONFIG`-Datei. -## Server-Modus testen (z.B. Gaming-PC) +--- + +## Schnellstart: lokal testen (Mac/Linux mit Docker) + +> Beispiele mit `docker`; `podman` funktioniert identisch. + +### Variante A -- aus dem Quellcode bauen (baut nativ fuer deine Architektur) ```sh cp .env.example .env # DTRACK_URL / DTRACK_API_KEY ausfuellen -podman compose up --build +docker compose up --build ``` -MCP-Client auf `http://:8080/mcp` zeigen lassen; falls `DTRACK_HTTP_TOKENS` -gesetzt ist, `Authorization: Bearer ` mitgeben. Health-Check: -`curl http://localhost:8080/health`. +### Variante B -- vorgebautes Release-Image laden -## stdio-Modus (Arbeitsrechner) +Am Release haengen pro Architektur Tarballs. Passenden waehlen +(**arm64** = Apple Silicon, **amd64** = Intel / "nicht Mac"): ```sh -# bauen -cargo build --release --bin dtrack-stdio -podman build -t dtrack-mcp:latest -f Containerfile . +docker load -i dtrack-http-0.1.0-arm64.tar.gz -# transfer ohne Registry -podman save dtrack-mcp:latest | gzip > dtrack-mcp.tar.gz # -> uebertragen -podman load < dtrack-mcp.tar.gz # auf dem Laptop +docker run --rm -p 8080:8080 \ + -e DTRACK_URL=http://host.docker.internal:8081 \ + -e DTRACK_API_KEY=odt_dein_key \ + -e DTRACK_ADMIN_USER=admin -e DTRACK_ADMIN_PASSWORD=geheim \ + dtrack-http:0.1.0-arm64 ``` -Claude Desktop (`--network=host` fuer DT ueber die VPN-Route des Hosts): +Pruefen: +- `curl http://localhost:8080/health` -> `OK` +- `http://localhost:8080/admin` -> Admin-UI (Basic-Auth) + +> Der Server bootet auch ohne erreichbare DT -- nur die Tool-Calls brauchen eine +> echte Instanz. Tipp fuer Persistenz: `-v ~/dtrack-data:/data -e DTRACK_CONFIG=/data/config.toml` +> ergaenzen, dann ueberleben Admin-Aenderungen den Neustart. + +### (optional) Dummy-DependencyTrack zum Testen + +`docker-compose.yml` in einem eigenen Ordner: + +```yaml +services: + dtrack-apiserver: + image: dependencytrack/apiserver + deploy: + resources: + limits: + memory: 4608m + ports: + - "8081:8080" # API -> Host-Port 8081 + volumes: + - dtrack-data:/data + dtrack-frontend: + image: dependencytrack/frontend + environment: + - API_BASE_URL=http://localhost:8081 + ports: + - "8082:8080" # Web-UI -> Host-Port 8082 +volumes: + dtrack-data: {} +``` + +`docker compose up -d` (apiserver braucht ~4 GB RAM + ein paar Minuten beim +Erststart). Dann `http://localhost:8082` (Login `admin`/`admin`), unter +**Administration -> Access Management -> Teams** einen API-Key mit +`VIEW_PORTFOLIO` + `VIEW_VULNERABILITY` erzeugen und ein Projekt anlegen. +Aus dem MCP-Container ist die DT unter `http://host.docker.internal:8081` +erreichbar (nicht `localhost`). + +--- + +## Mit Claude Desktop verbinden + +> **Wichtig:** Der UI-Weg *"Add custom connector"* (URL eingeben) funktioniert +> fuer einen **lokalen** Server **nicht** -- Claude verbindet sich dabei aus +> Anthropics Cloud, die deinen `localhost` nicht erreicht. Fuer lokal geht der +> Weg ueber die `claude_desktop_config.json`. + +Config-Datei (macOS): `~/Library/Application Support/Claude/claude_desktop_config.json` +(oder in Desktop: **Settings -> Developer -> Edit Config**). Den `mcpServers`-Block +neben `preferences` einfuegen, danach Desktop **komplett neu starten** (Cmd+Q). + +### Empfohlen lokal: stdio + +stdio hat keinen HTTP-Session-Handshake -> zuverlaessig. Den HTTP-Container +braucht man dafuer nicht (nur eine laufende DT). + +```sh +docker load -i dtrack-stdio-0.1.0-amd64.tar.gz +``` ```json { "mcpServers": { "dependency-track": { - "command": "podman", - "args": [ - "run", "-i", "--rm", "--network=host", - "-e", "DTRACK_URL", "-e", "DTRACK_API_KEY", "-e", "DTRACK_INSECURE", - "dtrack-mcp:latest" - ], + "command": "docker", + "args": ["run","-i","--rm", + "-e","DTRACK_URL","-e","DTRACK_API_KEY", + "dtrack-stdio:0.1.0-amd64"], "env": { - "DTRACK_URL": "https://dtrack.firma.intern", - "DTRACK_API_KEY": "odt_...", - "DTRACK_INSECURE": "0" + "DTRACK_URL": "http://host.docker.internal:8081", + "DTRACK_API_KEY": "odt_dein_key" } } } } ``` +> Findet Desktop `docker` nicht (eingeschraenkter PATH), `which docker` ausfuehren +> und den vollen Pfad als `command` setzen (z.B. `/usr/local/bin/docker`). +> Das stdio-Release-Image ist amd64 -> laeuft auf Apple Silicon emuliert (ok zum Testen). + +### HTTP als echter Remote-Connector + +Der HTTP-Modus ist fuer den Betrieb als **oeffentlich erreichbarer** Remote-MCP +gedacht (Custom Connector ueber eine echte URL, z.B. hinter Reverse-Proxy/Tunnel). +Der Bridge-Versuch `npx mcp-remote http://localhost:8080/mcp` fuer lokal scheitert +aktuell am rmcp-StreamableHTTP-Handshake (`tools/list` vor `initialized`) -- darum +lokal stdio nutzen. + +Logs bei Problemen: `~/Library/Logs/Claude/mcp*.log`. + +--- + +## RBAC (optional, nur HTTP) + +Standardmaessig regelt `DTRACK_HTTP_TOKENS` den Zugang (flache Token-Liste, +leer = offen). Fuer feinere Rechte `permissions.toml.example` nach +`./data/permissions.toml` kopieren, Tokens/Rollen eintragen und +`DTRACK_PERMISSIONS=/data/permissions.toml` setzen. + +Modell: benannte Rollen mit `allow`/`deny` (`"*"` = alle Tools, **deny schlaegt +allow**), Clients ordnen einen Bearer-Token einer Rolle zu. Ein nicht erlaubter +`tools/call` wird mit **403** abgewiesen. + +```toml +[[roles]] +name = "metrics-only" +allow = ["list_projects", "project_metrics"] + +[[clients]] +name = "dashboard-bot" +token = "GEHEIM" +role = "metrics-only" +``` + +## Admin-UI + +Unter `/admin` (Basic-Auth via `DTRACK_ADMIN_USER`/`_PASSWORD`): zeigt URL + +maskierten API-Key, erlaubt Aendern (Client wird **live** neu gebaut) und +persistiert bei gesetztem `DTRACK_CONFIG`. Aktuell bewusst minimal -- Styling +und Client-/Rollen-Verwaltung folgen. + +## Release bauen (Maintainer) + +In Gitea einen Release veroeffentlichen (oder **Actions -> Release Images -> +Run workflow** mit Tag). Der Workflow baut via buildx Multi-Arch und haengt an: +`dtrack-stdio--amd64`, `dtrack-http--amd64`, `dtrack-http--arm64` +(je `.tar.gz`). Auth laeuft ueber das automatische `gitea.token`. + ## Roadmap | Stage | Inhalt | Status | @@ -96,5 +216,6 @@ Claude Desktop (`--network=host` fuer DT ueber die VPN-Route des Hosts): | 0 | stdio, read-only, 3 Tools, CI, Container | ✅ | | 1 | Config-Layer + geteiltes Tool-Crate | ✅ | | 2 | HTTP-Frontend + Bearer-Auth | ✅ | -| 3 | Admin-UI (URL/Key/Rechte pflegbar, maskiert) + Permission-Engine + Audit | … | +| 3 | Admin-UI + Persistenz + RBAC-Enforcement | ✅ | +| 3.2 | Tool-Sichtbarkeit pro Client (`tools/list` filtern) | … | | 4 | SSO (Gitea-OIDC) | … |