Documentation / Topics / Architecture

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.

Repository layout

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 apiserver backend component.

  • clomonitor-archiver contains the source code of the archiver backend component.

  • clomonitor-core: contains the source code of the core backend modules, like linter and score.

  • clomonitor-linter: contains the source code of linter CLI tool.

  • clomonitor-registrar: contains the source code of the registrar backend component.

  • clomonitor-runner: contains the source code of the external tool runner.

  • clomonitor-tracker: contains the source code of the tracker backend 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.

Layers

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, registrar and tracker. These applications rely on the database and core library layers 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 apiserver to interact with the backend. Please see the web application section for more details.

Database

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
        └── ...

Core library

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 tool and the tracker rely on it. The linter is able to run multiple check sets on each repository. Each check set defines a number of checks that will be run on the repository. For more details about what checks are run on each check 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.

Backend applications

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.

Runner

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-afdocs runs AFDocs. It has no secrets, receives no GitHub token, and can only egress to DNS and public HTTP/HTTPS destinations.
  • runner-scorecard runs OpenSSF Scorecard. The tracker sends a GitHub token only to this profile in the Authorization: Bearer header, and the runner injects it as GITHUB_TOKEN only 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.

Linter CLI

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

Web application

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.html file 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.

Development environment setup

For more information about how to setup your development environment, please see this document.