Architecture
This document describes the architecture of CLOMonitor, detailing each of the components, what they do and where they are located in the source repository.
The following directories present at the top level of the repository represent some of the key locations in the codebase:
clomonitor
├── .github
├── chart
├── clomonitor-apiserver
├── clomonitor-archiver
├── clomonitor-core
├── clomonitor-linter
├── clomonitor-registrar
├── clomonitor-runner
├── clomonitor-tracker
├── database
├── docs
└── web
-
.github: contains the Github Actions workflows.
-
chart: contains the CLOMonitor Helm chart, which is the recommended installation method.
-
clomonitor-apiserver contains the source code of the
apiserverbackend component. -
clomonitor-archiver contains the source code of the
archiverbackend component. -
clomonitor-core: contains the source code of the
core backend modules, like linter and score. -
clomonitor-linter: contains the source code of
linter CLItool. -
clomonitor-registrar: contains the source code of the
registrarbackend component. -
clomonitor-runner: contains the source code of the external tool runner.
-
clomonitor-tracker: contains the source code of the
trackerbackend component. -
database: contains all code related to the database layer, such as the schema migrations, functions and tests.
-
docs: contains the project documentation.
-
web: contains the source code of the
web application.
CLOMonitor is structured in multiple layers, each of them providing a set of services to adjacent layers.
-
Database: this layer provides data services, controlling the database schema and its migrations and providing a set of functions that will act as an API for outer layers, abstracting them in many cases from the internal database structure. CLOMonitor uses PostgreSQL as datastore. Please see the database section for more details.
-
Core library: this layer represents a set of Rust APIs that allow performing core operations supported by CLOMonitor, such as linting a repository or calculating scores. Please see the core library section for more details.
-
Backend applications: this layer represents the applications that form the backend:
apiserver,registrarandtracker. These applications rely on thedatabaseandcore librarylayers to perform their tasks. Please see the backend applications section for more details. -
Runner: this layer executes external tools for tracker runs. Please see the runner section for more details.
-
Linter CLI: this layer represents a CLI tool that allows projects to lint their repositories locally or from their CI workflows. Please see the linter CLI section for more details.
-
Web application: this layer represents the CLOMonitor’s web user interface. It uses the HTTP API exposed from the
apiserverto interact with the backend. Please see the web application section for more details.
The database layer is defined by the database schema and a set of functions, which are handled using migrations. Migrations use Tern, and are automatically applied during the installation and upgrades by a Kubernetes job named dbmigrator. There are unit tests available for both the schema and the functions.
database
├── migrations
│ ├── functions
│ │ └── ...
│ └── schema
│ └── ...
└── tests
├── functions
│ └── ...
└── schema
└── ...
This layer represents a set of Rust APIs that provide some core functionality to other layers, like the backend applications or the CLI tool.
It’s composed of two modules:
-
linter: this module implements the core linting functionality of CLOMonitor. All checks currently run by CLOMonitor are handled by this module, and both the
CLI tooland thetrackerrely on it. The linter is able to run multiplecheck setson each repository. Eachcheck setdefines a number of checks that will be run on the repository. For more details about what checks are run on eachcheck set, please see the checks documentation. -
score: this module is in charge of scoring reports produced by the linter. The linter will produce different reports for each of the kinds supported, and each of the reports will be scored differently as well. In addition to the reports’ scoring functionality, this module provides some score related features as well, like rating a given score or merging multiple scores.
The Agent Readiness section has its own score, but it does not count toward the global project score or rating.
The backend applications are apiserver, archiver, registrar and tracker. They are located in the clomonitor-apiserver, clomonitor-archiver, clomonitor-registrar and clomonitor-tracker directories respectively. Each of the applications’ directory contains a Dockerfile that will be used to build the corresponding Docker image.
.
├── clomonitor-apiserver
│ ├── Cargo.toml
│ ├── Dockerfile
│ ├── src
│ └── templates
├── clomonitor-archiver
│ ├── Cargo.toml
│ ├── Dockerfile
│ └── src
├── clomonitor-registrar
│ ├── Cargo.toml
│ ├── Dockerfile
│ └── src
├── clomonitor-runner
│ ├── Cargo.toml
│ ├── Dockerfile
│ └── src
└── clomonitor-tracker
├── Cargo.toml
├── Dockerfile
└── src
-
apiserver: this component provides an HTTP API that exposes some endpoints used by the web application layer, plus some extra functionality like badges configuration, reports summary, etc. It is also in charge of serving the web application static assets.
-
archiver: this component is in charge of creating snapshots of projects’ data periodically. It’s launched periodically from a Kubernetes cronjob.
-
registrar: this component is in charge of registering the projects available on each foundation’s data file in the database. It’s launched periodically from a Kubernetes cronjob.
-
tracker: this component is in charge of linting and scoring all projects and repositories registered in the database. It’s launched periodically from a Kubernetes cronjob.
The clomonitor-runner component is a small Axum HTTP service that executes
external tools for the tracker. It exposes POST /run/{tool} and returns the
tool name, detected tool version, duration, and the tool’s JSON output:
{
"tool": "afdocs",
"tool_version": "0.20.0",
"duration_ms": 1234,
"output": {}
}
The runner supports afdocs and scorecard. Each request is executed as a
supervised subprocess with a scrubbed environment, a per-run temporary working
directory, a per-run memory cap (a 256 MiB Node.js heap for AFDocs, a 256 MiB
Go memory limit for scorecard), output caps, admission control, and a
request-wide deadline that includes queue time. A full bounded queue returns
503 with a Retry-After header. Each subprocess leads its own process group;
timed out or disconnected requests kill and reap the whole group, so processes
spawned by the tool do not outlive the run.
The same clomonitor/runner image is deployed as two separate profiles with
different trust boundaries:
runner-afdocsruns AFDocs. It has no secrets, receives no GitHub token, and can only egress to DNS and public HTTP/HTTPS destinations.runner-scorecardruns OpenSSF Scorecard. The tracker sends a GitHub token only to this profile in theAuthorization: Bearerheader, and the runner injects it asGITHUB_TOKENonly into the scorecard subprocess. Its egress is limited to DNS and public destinations on TCP 443 (the network policy cannot pin it to GitHub because GitHub IP ranges change), so the token is protected from the cluster and private networks, not from other public hosts.
Runner pods use the same hardening baseline: service account token automounting is disabled, they run as non-root numeric users, the root filesystem is read-only, privilege escalation is disabled, Linux capabilities are dropped, and the RuntimeDefault seccomp profile is used.
AFDocs requests have a 240 s runner deadline and a 270 s tracker client timeout.
Scorecard requests have a 480 s runner deadline and a 510 s tracker client
timeout. The tracker uses bounded retries only for connection errors, 429, and
503.
The tracker uses runner.afdocsUrl and runner.scorecardUrl to reach the two
profiles and never runs the tools locally (its image does not ship them). If
runner.afdocsUrl is absent, the agent readiness checks are reported as
failed. If runner.scorecardUrl is absent, the scorecard backed checks are
reported as failed. External tool failures are soft failures for the affected
checks, so the rest of the report is still stored.
The runner rejects AFDocs targets whose host is a localhost name or a
loopback, link-local, private, shared or unspecified IP literal before running
the tool, as a defence in depth measure independent of the network policy.
The linter CLI tool allows projects to lint their repositories locally or from their CI workflows. It generates a report by using the linter module available in the core library, it scores it and prints the results nicely.
$ export GITHUB_TOKEN=<your token>
$ clomonitor-linter --help
clomonitor-linter
Checks repository to verify it meets certain project health best practices
USAGE:
clomonitor-linter [OPTIONS] --path <PATH> --url <URL>
OPTIONS:
--afdocs <AFDOCS> AFDocs execution mode (agent readiness checks, requires
afdocs 0.20.x) [default: local] [possible values: local,
disabled]
--check-set <CHECK_SET> Sets of checks to run [default: code community] [possible
values: code, code-lite, community, docs]
--format <FORMAT> Output format [default: table] [possible values: json, table]
-h, --help Print help information
--pass-score <PASS_SCORE> Linter pass score [default: 75]
--path <PATH> Repository local path (used for checks that can be done
locally)
--scorecard <SCORECARD> OpenSSF Scorecard execution mode (scorecard backed
security checks) [default: local] [possible values: local,
disabled]
--url <URL> Repository url [https://github.com/org/repo] (used for some
GitHub remote checks)
-V, --version Print version information
The CLOMonitor’s user interface is a single page application written in TypeScript using React. Its source code can be found in the web directory.
web
├── public
└── src
├── api
├── context
├── hooks
├── layout
├── styles
└── utils
-
public: contains the base
index.htmlfile as well as some static assets, like images. -
src/api: contains a wrapper to interact with the HTTP API exposed by the
apiserver. -
src/context: context used for the preferences across the entire app.
-
src/hooks: contains some custom React hooks.
-
src/layout: contains all React components. They are organized in different folders corresponding to the section of the UI they belong to.
-
src/styles: contains the stylesheets for the light and dark themes.
-
src/utils: contains some utilities used by the components.
For more information about how to setup your development environment, please see this document.