An online automatic compliance checker for Common Ground — the Dutch vision and architecture for open, reusable software in municipalities.
Criteria are grouped into four categories. Each criterion has a requirement level (mandatory / recommended) and a configurable weight that influences the overall score.
| # | Criterion | Level | Standard |
|---|---|---|---|
| 1 | OSI-approved open-source license — LICENSE file with an OSI-approved identifier | Mandatory | opensource.org/licenses |
| 2 | EUPL license preference — explicit check whether the repository uses the European Union Public Licence | Mandatory | EU EUPL |
| 3 | Copyright / IP owner disclosure — probable owner inferred from legal files and metadata | Recommended | opensource.guide/legal |
| 4 | publiccode.yml — government metadata file in the repository root | Mandatory | Standard for Public Code |
| 5 | Contributing guide — CONTRIBUTING file explaining how to contribute | Recommended | GitHub docs |
| 6 | Code of Conduct — CODE_OF_CONDUCT file present | Recommended | opensource.guide |
| 7 | Security policy — SECURITY file with responsible disclosure info | Recommended | GitHub docs |
| # | Criterion | Level | Standard |
|---|---|---|---|
| 8 | API-first / OpenAPI spec — machine-readable OpenAPI or Swagger spec present (required only when "Component is a register" is checked) | Mandatory | API Design Rules |
| 9 | 5-Layer Architecture — component belongs to a recognised Common Ground layer | Recommended | 5-lagen model |
| # | Criterion | Level | Standard |
|---|---|---|---|
| 10 | Docker support — Dockerfile (and optionally docker-compose) present | Mandatory | Haven |
| 11 | Available Docker image — published registry image URL provided | Mandatory | Haven |
| 12 | Helm chart (Kubernetes) — Chart.yaml or K8s manifests present | Mandatory | Haven |
| # | Criterion | Level | Standard |
|---|---|---|---|
| 13 | Actual source code — repository contains real source files, not just docs or config | Mandatory | commonground.nl |
| 14 | SBOM — Software Bill of Materials (SPDX or CycloneDX) published | Recommended | CISA SBOM |
| 15 | Documentation — README, docs folder, or external docs URL | Mandatory | irealisatie.nl |
| 16 | Test suite — automated tests or test configuration present | Recommended | GitHub Actions |
| 17 | Cyclomatic complexity (Lizard) — average complexity (AvgCCN) is measured and compared against an admin-configurable threshold | Recommended | lizard |
| 18 | Semantic versioning — releases or tags following MAJOR.MINOR.PATCH | Recommended | semver.org |
# 1. Install dependencies
npm install
# 2. Set up the database (PostgreSQL required)
cp .env.local.example .env
# Edit .env and configure DATABASE_URL and optionally GITHUB_TOKEN
# 3. Push the Prisma schema and generate the client
npm run db:push
npm run db:generate
# 3b. Install Lizard (required for cyclomatic complexity criterion)
py -m pip install lizard
# 4. Start the development server
npm run devOpen http://localhost:3000 and paste a GitHub repository URL.
A GitHub personal access token in .env is optional but strongly recommended — the unauthenticated GitHub API rate limit is 60 requests/hour, which is quickly exhausted for newer repos.
To scan for leaked credentials/secrets locally with Gitleaks:
# Install Gitleaks once (Windows)
winget install Gitleaks.Gitleaks
# Scan repository history using the local config
npm run security:secretsThe scan uses .gitleaks.toml and runs with --redact so findings are masked in output.
- Next.js 16 (App Router) for UI routes and server API routes in one project.
- React 18 + TypeScript for typed UI and domain models.
- Node.js runtime for check orchestration and API integrations.
- PostgreSQL as the primary data store.
- Prisma ORM + Prisma PostgreSQL adapter (
@prisma/adapter-pg) for type-safe DB access. - Stores:
- repository metadata and discovered locations
- per-run analysis results and evidence
- versioned scoring configurations linked to each run
- Tailwind CSS for styling.
- Lucide React for UI icons.
- Vitest for tests.
- ESLint + TypeScript for static quality checks.
- GitHub REST API for repository content, metadata, and refs.
- Lizard (Python CLI) for cyclomatic complexity checks.
- Spectral (via
npx) for ADR/OpenAPI style validation use cases. - js-yaml for YAML parsing (
publiccode.yml, OpenAPI YAML, Helm-related YAML). - jsPDF for client-side PDF export of analysis results.
The application is built as a single Next.js service with clear layers:
-
Presentation layer (React pages/components)
- Main checker UI (
/) - Admin scoring UI (
/admin) - History UI (
/historyand repository detail pages)
- Main checker UI (
-
API layer (Next.js route handlers under
/api)- Validates input, orchestrates checks, persists results, and serves history/config data.
-
Domain/checker layer (
src/lib/checkers)- Independent criterion checkers (license, OpenAPI, Docker, Helm, docs, tests, complexity, OWASP, etc.).
- A central orchestrator combines checker results into one weighted score.
-
Integration layer
- GitHub API client (
src/lib/github.ts) - External tool invocations (Lizard/Spectral)
- GitHub API client (
-
Persistence layer
- Prisma client singleton (
src/lib/db.ts) + PostgreSQL schema (prisma/schema.prisma).
- Prisma client singleton (
flowchart LR
U[User in browser] --> UI[Next.js UI\nReact pages/components]
UI --> API[Internal API routes\n/api/check, /api/check/stream, /api/admin/scoring, /api/repositories, /api/repo-history]
API --> ORCH[Checker orchestrator\nsrc/lib/checkers/index.ts]
ORCH --> CHK[Criterion checkers\nlicense, openapi, docker, helm, docs, tests, complexity, owasp, ...]
CHK --> GH[GitHub REST API]
CHK --> TOOLS[External tools\nLizard / Spectral]
API --> CFG[Scoring config\nversioned weights + levels]
API --> DB[(PostgreSQL)]
CFG --> DB
DB --> HIST[History and admin pages]
HIST --> UI
### Streamed check sequence (`/api/check/stream`)
```mermaid
sequenceDiagram
participant User as Browser user
participant UI as Next.js UI (/)
participant API as /api/check/stream
participant Orch as Checker orchestrator
participant GH as GitHub REST API
participant Tools as Lizard/Spectral
participant DB as PostgreSQL (Prisma)
User->>UI: Submit repo URL + options
UI->>API: POST /api/check/stream
API-->>UI: stream event: started
API->>GH: fetch repo metadata + files
API-->>UI: stream event: repository loaded
API->>Orch: run criteria checks
Orch->>GH: read file content/refs (as needed)
Orch->>Tools: run complexity/validation tools (as needed)
Orch-->>API: per-criterion results + evidence
API-->>UI: stream progress events
API->>DB: persist repo + analysis + scoring config link
API-->>UI: stream event: completed + final report
```
| Method | Endpoint | Purpose |
|---|---|---|
POST |
/api/check |
Run full analysis and persist result |
POST |
/api/check/stream |
Stream progress/events during analysis |
GET |
/api/admin/scoring |
Retrieve current scoring configuration |
POST |
/api/admin/scoring |
Save new scoring configuration snapshot |
GET |
/api/repositories |
List known repositories with latest summary |
GET |
/api/repo-history |
Return analysis runs/history for repositories |
On the Admin page, the field "Spectral ruleset source" controls which ruleset is used for the NL API Design Rules check.
- Supported values:
- URL (for example:
https://static.developer.overheid.nl/adr/ruleset.yaml) - Local file path (for example:
./rulesets/adr.yamlorC:/rulesets/adr.yaml)
- URL (for example:
- This value is persisted in
ScoringConfigand applied to new analyses. - If the field is empty, the app falls back to the default ADR ruleset URL.
- For local file paths, the file must exist on the machine running the app server (not on a remote end-user browser machine).
- GitHub REST API v3 (authenticated with optional
GITHUB_TOKEN). - PostgreSQL over
DATABASE_URL.
- User submits repo URL and options in the checker form.
/api/check(or/api/check/stream) parses owner/repo and loads remote repo context from GitHub.- Checker orchestrator runs criteria (parallel where possible).
- Weighted score is computed using the selected/persisted scoring config.
- Result + evidence is stored in PostgreSQL and returned to UI.
- History/admin pages query internal APIs to show prior runs and config snapshots.
Each check has a configurable weight (0–1) set via the Admin page. Weights are stored in the database as versioned snapshots; each analysis run is linked to the exact scoring config used.
For the Lizard complexity criterion, the Admin page also stores a configurable average cyclomatic complexity threshold (AvgCCN). The check passes when a repository’s measured AvgCCN is at or below this threshold.
Score formula:
baseScore = round((Σ statusScore × weight) / (Σ weight) × 100)
score = min(100, baseScore)
Status scores: Pass = 1.0 · Warn / Info = 0.5 · Fail = 0.
| Score | Label |
|---|---|
| ≥ 80 | ✅ Compliant |
| 50–79 | |
| < 50 | ❌ Non-compliant |
Note: Automated analysis is indicative only. Architecture checks rely on heuristics. For official certification, contact commonground.nl.
Copyright © 2026 VNG Realisatie
This project is licensed under the European Union Public Licence v. 1.2 (EUPL-1.2). See LICENSE for the full text.