Integrate CI and Dependency-Track

This document explains how to enable and configure the two quality/security features of gitrust:

  1. The integrated CI (Dagger) which executes the builds/tests/lints on each push.
  2. The dependency tracker (Syft + Dependency-Track) which scans code components with each push and detects known vulnerabilities.

These two systems are independent: one can be activated without the other.


1. General architecture

flowchart TB
  subgraph Client
    Dev[Développeur]
  end
  subgraph Gitrust[Instance Gitrust]
    HTTP[:4000 HTTP/Git]
    SSH[:2222 SSH/Git]
    Worker[CiWorker
tokio task] Sbom[SbomService
tokio spawn] DB[(PostgreSQL)] end subgraph Builder[Serveur de build] Docker[Docker/Podman] Dagger[Dagger CLI] CiEngine[/opt/gitrust-ci/ci-engine/] end subgraph Security[Stack sécurité optionnelle] Syft[syft] Dtrack[Dependency-Track] end Dev -->|git push| HTTP Dev -->|git push| SSH HTTP --> Worker SSH --> Worker HTTP --> Sbom SSH --> Sbom Worker -->|SSH + rsync| Builder Builder -->|logs streamés| Worker Worker --> DB Sbom -->|scan workspace| Syft Sbom -->|PUT BOM| Dtrack Dtrack -->|findings| Sbom Sbom --> DB

Three components operate in parallel:

  • CiWorker: Tokio task which consumes CiTask from an mpsc channel, limited by a Semaphore to CI_MAX_CONCURRENT simultaneous pipelines.
  • SbomService: executed in a tokio::spawn after each push, totally decoupled from the CI.
  • Build server: remote machine (or localhost) that runs Docker + Dagger. Gitrust sends the workspace there by rsync and launches Dagger by SSH.

2. Set up the CI

2.1 Build server prerequisites

The build server can be the same machine as Gitrust (CI_REMOTE_HOST=localhost) or a dedicated machine. He must have:

Outil Rôle
Docker ou Podman Containers Dagger
Dagger CLI Moteur d'exécution
SSH (accès sortant depuis Gitrust) Transport
rsync Copie du workspace
git, tar Extraction du tree du commit

Recommended automatic installation:

# Depuis la machine Gitrust (l'utilisateur doit pouvoir SSH vers le builder)
./deployment/setup-remote-ci.sh .env

The script executes:

  1. Checking SSH connectivity
  2. Installing Docker if absent
  3. Installing Dagger CLI if absent
  4. Creating the remote working directory
  5. Synchronization of the ci-engine
  6. Smoke test (versions)

2.2 Gitrust configuration (.env file)

Add to Gitrust's .env:

# Activer globalement le CI
CI_ENABLED=true

# Chemin du ci-engine sur le serveur de build
CI_ENGINE_PATH=/opt/gitrust-ci/ci-engine

# Limite de parallélisme
CI_MAX_CONCURRENT=4
CI_DEFAULT_TIMEOUT=3600
CI_WORKSPACE_PATH=/tmp/gitrust-ci

# Serveur de build (mettre localhost pour "même machine")
CI_REMOTE_HOST=builder.example.com
CI_REMOTE_USER=ci-runner
CI_REMOTE_PATH=/opt/gitrust-ci
CI_REMOTE_SSH_PORT=22
# CI_REMOTE_SSH_KEY=/home/gitrust/.ssh/id_ed25519   # si pas ssh-agent

Restart Gitrust: systemctl restart gitrust (or cargo run --release).

2.3 Activate CI on a repository

In the web interface: go to the repository → SettingsCI.

  • Check CI enabled (required — default false)
  • Check Trigger on push (activates execution on each push)
  • Optional: Auto-cancel (cancels current pipelines when a new one starts)
  • Optional: Allowed branches (e.g. main,develop — empty = all)

2.4 Choose mode: Easy or Power

flowchart LR
  Push[Commit
poussé] --> Tree{Arbre du
commit contient ?} Tree -->|.dagger/| Power[Mode Power
dagger call -m .dagger/ ci] Tree -->|.gitrust-ci.yml| Easy[Mode Easy
dagger call -m ci-engine test-pr] Tree -->|rien| None[Pas de pipeline] Power --> Run[Exécution
distante SSH] Easy --> Run

Create .gitrust-ci.yml at the root of the repository:

# Raccourci : charge un profil pré-configuré (rust | python | node)
language: rust

build:
  command: "cargo build --release"

checks:
  lint: "cargo clippy -- -D warnings"
  format: "cargo fmt -- --check"

tests:
  command: "cargo test --release"

The available profiles are located in deployment/ci-engine/profiles/ (rust.yaml, python.yaml, node.yaml) in the source repository.

Power mode

For advanced users, create a complete Dagger module in .dagger/:

.dagger/
├── dagger.json
├── src/
│   └── main.py         # ou Go/TypeScript

The ci function of the module is called directly:

dagger call -m .dagger/ ci

Advantage: access to the Daggerverse, composition, pipeline testing. See the Dagger documentation.

2.5 Monitoring a pipeline

After a git push, an entry appears in the CI tab of the repository:

stateDiagram-v2
  [*] --> Pending: create_pipeline
  Pending --> Running: worker picks CiTask
  Running --> Success: exit 0
  Running --> Failure: exit != 0
  Running --> Cancelled: timeout / auto_cancel / manuel
  Success --> [*]
  Failure --> [*]
  Cancelled --> [*]

The stdout/stderr logs are streamed line by line in the ci_logs table and visible live in the UI. If it fails, a notification is sent to the repository owner.


3. Set up the Dependency Tracker

This part is completely independent of the CI. It scans the pushed code and produces a CycloneDX SBOM, then (optionally) sends it to Dependency-Track for vulnerability scanning.

3.1 Install Syft

On the Gitrust machine (the scan is done locally, not on the builder):

# Installation officielle
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh \
  | sh -s -- -b /usr/local/bin

# Vérification
syft --version

In .env:

CI_SBOM_ENABLED=true
CI_SYFT_BIN=/usr/local/bin/syft   # optionnel, défaut: syft dans PATH

At this stage: with each push, a CycloneDX SBOM is generated and stored (without external upload). Visible in the Security tab of the repository: number of components, sha256 of the BOM.

3.2 Deploy Dependency-Track

Dependency-Track is a Java application that stores SBOM and correlates with CVE/OSV/NVD databases. Recommended Docker deployment:

mkdir -p /opt/dtrack && cd /opt/dtrack
curl -L -o docker-compose.yml \
  https://dependencytrack.org/docker-compose.yml
docker compose up -d

L'API est disponible sur http://localhost:8081 et l'UI sur http://localhost:8080. Login initial : admin / admin (à changer immédiatement).

3.3 Create an API key

In Dependency-Track → AdministrationAccess ManagementTeams:

  1. Create (or reuse) a gitrust team.
  2. Give it permissions:
  3. BOM_UPLOAD
  4. PROJECT_CREATION_UPLOAD
  5. VIEW_PORTFOLIO
  6. VIEW_VULNERABILITY
  7. Generate an API key and copy it.

3.4 Configure Gitrust

Add to .env:

CI_DTRACK_ENABLED=true
CI_DTRACK_URL=http://localhost:8081
CI_DTRACK_API_KEY=odt_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Restart Gitrust. With each push:

sequenceDiagram
  participant Push as post-receive
  participant Sbom as SbomService
  participant Git as git archive
  participant Syft
  participant Dtrack as Dependency-Track
  participant DB as sbom_reports

  Push->>Sbom: process_push(sha, ref)
  Sbom->>DB: upsert status=pending
  Sbom->>Git: archive sha | tar -x tmpdir
  Sbom->>Syft: scan dir:tmpdir -o cyclonedx-json
  Syft-->>Sbom: BOM bytes
  Sbom->>DB: update sha256
  Sbom->>Dtrack: PUT /api/v1/bom (base64)
  Dtrack-->>Sbom: token
  loop max 30s
    Sbom->>Dtrack: GET /api/v1/bom/token/{token}
    Dtrack-->>Sbom: processing ?
  end
  Sbom->>Dtrack: GET /api/v1/finding/project/{uuid}
  Dtrack-->>Sbom: findings[]
  Sbom->>DB: update status=success
+ critical/high/medium/low

3.5 Read the results

Security tab of the repository → SBOM insert:

  • Number of components detected
  • Counters by severity: Critical / High / Medium / Low
  • Direct link to project in Dependency-Track (if UUID is resolved)
  • Hash sha256 from BOM (traceability)

If Dependency-Track takes more than 30s to analyze, the status remains processing — a subsequent sweeper will search for the findings.


4. Debugging

Common CI Problems

Symptôme Cause probable Vérifier
Pipeline reste pending Worker non démarré, ou channel saturé Logs CI worker started, CI_MAX_CONCURRENT
Échec rsync vers le serveur de build SSH bloqué, clé absente ssh -p ${CI_REMOTE_SSH_PORT} ${CI_REMOTE_USER}@${CI_REMOTE_HOST} manuel
dagger: command not found Dagger non installé sur le builder Relancer setup-remote-ci.sh
Status Cancelled inattendu Timeout (CI_DEFAULT_TIMEOUT) ou auto-cancel Augmenter le timeout, vérifier pipelines concurrents

Common SBOM Issues

Symptôme Cause probable Vérifier
SBOM generation disabled CI_SBOM_ENABLED=false .env
syft spawn failed Binaire introuvable which syft, CI_SYFT_BIN
invalid commit sha SHA non hex 40 chars Rare, signale un bug
Dtrack upload 401 API key invalide ou permissions manquantes Régénérer, vérifier les 4 permissions
Status processing indéfiniment Dtrack surchargé, analyse lente Attendre, ou relancer un push

Useful logs

# Logs Gitrust (systemd)
journalctl -u gitrust -f | grep -E "CI|SBOM|sbom|pipeline"

# Vérifier un pipeline en DB
psql $DATABASE_URL -c "SELECT id, status, commit_sha, created_at FROM ci_pipelines ORDER BY created_at DESC LIMIT 10;"

# Vérifier un SBOM
psql $DATABASE_URL -c "SELECT commit_sha, status, components_count, critical_count, high_count FROM sbom_reports ORDER BY created_at DESC LIMIT 10;"

5. Summary checklist

CI : - [ ] Docker + Dagger installés sur le serveur de build (setup-remote-ci.sh) - [ ] CI_ENABLED=true et CI_REMOTE_* dans .env - [ ] Gitrust redémarré - [ ] CI activée dans Settings → CI pour chaque dépôt - [ ] Fichier .gitrust-ci.yml (Easy) ou .dagger/ (Power) commité - [ ] Push → pipeline visible dans l'onglet CI

Dependency Tracker : - [ ] Syft installé sur la machine Gitrust - [ ] CI_SBOM_ENABLED=true dans .env - [ ] (Optionnel) Dependency-Track déployé + API key créée avec les 4 permissions - [ ] (Optionnel) CI_DTRACK_ENABLED=true, CI_DTRACK_URL, CI_DTRACK_API_KEY dans .env - [ ] Gitrust redémarré - [ ] Push → SBOM visible dans l'onglet Security