Building from source is worth doing if you want to run TRUSTIVAN outside a container, contribute to it, or produce your own image. The backend is a single Go module that builds three binaries.

The toolchain requirement

Two constraints, neither of them chosen: Building without the experiment fails with a long import chain ending in:
That message names a standard library package and says nothing about the cause or the fix, which is why the requirement is set in four independent places rather than written down once: the Makefile exports it for every Go target, the Dockerfile sets it in the build stage, CI sets it at the workflow level, and scripts/ci/check-toolchain.sh verifies it and prints the fix. Set it once per machine and bare go build works too:
An in-code guard that produced a friendlier error was tried and removed: Go resolves imports before type-checking, so the encoding/json/v2 failure fires first and the friendly message is never reached.

The three binaries

That is the whole of it. There is no command-line client — everything a person or a pipeline does goes through the HTTP API, documented in the API reference. cmd/api can run the worker in-process, which is the default. A single api binary with a PostgreSQL and a Redis is a complete TRUSTIVAN. cmd/worker exists so that the durability claim is testable rather than aspirational: a worker that can only run inside the API process cannot be restarted independently of it.

Building

Or directly, for all three:
Expect a long first build on a cold module cache. Importing the scanning engine pulls roughly 380 modules into the dependency graph. That is accepted deliberately: the alternative is parsing the engine’s CLI output, which trades a compile-time contract for a string-matching one and turns every upstream output change into a silent runtime failure instead of a build error.

Running

You still need PostgreSQL and Redis. The simplest arrangement is to run those two from Compose and the Go processes on the host:
Then configure and start the API:
In development, unset secrets are generated randomly per process and the backend logs that it did so, so there is no setup step. Sessions do not survive a restart, which is the intended trade — see Environment variables. Migrations run automatically at startup, so the first launch prepares an empty database on its own. To run the worker as its own process instead of in-process, set SCAN_WORKER_ENABLED=false for the API and start the worker separately:

Building an image

The Dockerfile at backend/Dockerfile builds both the API and the worker into one image and selects between them by command. Two details are worth knowing if you adapt it:
  • The final stage runs as an unprivileged trustowl user. The image previously ran as root with WORKDIR /root/, which gave a process handling untrusted customer input full privileges inside the container.
  • /cache is created and owned by that user, because a worker that cannot write its cache re-downloads the vulnerability database on every scan.

Verifying the build

make ci-guards runs the same architecture guards CI runs, including the toolchain preflight that produces the readable version of the encoding/json/v2 error. The end-to-end scan is separate because it pulls roughly 100 MB from a real registry:

Next