Architecture
OrbitalReg is a Go monolith with a React SPA frontend. State lives in PostgreSQL; artifact bytes live in an S3-compatible object store; session and rate-limiter state lives in Redis. Everything else — scanning, retention, governance, signing — is a goroutine inside the API process.
This page is the externally-rendered companion to docs/ARCHITECTURE.md. The in-repo file remains the canonical engineering source; this page trims internal-team-only sections (release-cadence schedules, postmortems) and keeps the system-shape sections that an evaluating engineer wants.
1. Components
| Layer | Component | Notes |
|---|---|---|
| Ingress | NGINX Ingress + cert-manager | TLS, body-size caps for uploads |
| Frontend | React SPA in nginx | Static bundle, no runtime state |
| API | Go (chi, pgx, minio-go) | Stateless, 3 replicas, HPA-ready |
| DB | PostgreSQL 16 | Bring your own, or use CloudNativePG via the chart |
| Cache | Redis 7 | Session store, rate limiter, metadata cache |
| Object store | External S3-compatible | MinIO, Ceph RadosGW, AWS S3, Cloudflare R2 — anything SigV4-capable |
| Identity | SAML 2.0 / OIDC | Built-in or external — Azure Entra ID, Okta, Keycloak |
| Metrics | Prometheus + Grafana | ServiceMonitor CRD |
| Logs | Loki + Promtail | JSON logs from the Go API |
| Traces | OpenTelemetry / OTLP | Optional, off by default |
2. Storage flow
client ──(stream upload)──► API ──(stream)──► External S3 bucket
│ (path: aa/bb/<sha256>)
└─► Postgres: artifacts(repo_id, path, version,
size, sha256, content_type, metadata)
client ──(GET)──► API ──(302)──► Presigned URL ──► External S3 bucketUploads are content-addressable: the API hashes the request body with a TeeReader while streaming to a staging key, then renames to aa/bb/<digest>. Deduplication is automatic — identical content produces an identical S3 key.
Downloads return HTTP 302 to a presigned S3 URL so artifact bytes never traverse the API process again. The exception is the Docker manifest path, which the API rewrites and serves directly because clients sign the response body.
3. Scanning pipeline
Every uploaded artifact triggers a scan-job DB row. A pool of in-process workers picks rows up, dispatches to the configured scanners (Trivy, Grype, Syft, OSV.dev, format-specific tooling), and writes findings into scan_findings keyed on (artifact_id, scanner, vuln_id).
A single artifact typically produces 10–100 findings across all scanners. The first finding above your project's policy threshold (default: CRITICAL) flips the artifact's quarantined bit, which gates downloads and, if a SecurityBlock matches, hides it entirely.
The full Detection roadmap lives at SCAN-ROADMAP.md.
4. Governance layer
The governance surface is six tables, all admin-CRUDable through both the UI and the REST API:
| Table | Purpose |
|---|---|
security_blocks | Pattern-match block rules with reason + customer message |
retention_policies | Per-repo prune rules (keep-N-newest, keep-by-age, …) |
license_policies | Per-project license allow/block lists |
quarantine_settings | Auto-quarantine threshold + scope per project |
webhook_subscriptions | Outbound HMAC-signed event delivery |
oidc_trust_policies | OIDC-token-exchange rules for keyless CI auth |
Both the Terraform provider and the Kubernetes operator drive the same tables through the same REST endpoints, so what you can express in clicks you can express in HCL or YAML.
5. Authn / authz
- Authn: SAML 2.0 (default), local users, or service-account bearer tokens. OIDC token exchange handles workload identity for CI.
- Authz: Project-scoped roles.
viewer / editor / ownerper project, plus a globaladminrole for platform-wide settings. Service accounts get scoped tokens (e.g.read:project:foo,push:project:foo:repo:bar).
6. Backups
Postgres backups go through CloudNativePG + Barman with PITR. Configurable retention; default 30 days. A weekly verification CronJob restores the latest backup into an ephemeral cluster, runs a smoke suite, and writes the result to backup_verification_runs. Failed verifications fire a Prometheus alert.
The S3 bucket is replicated to a second bucket / region using provider-native replication (S3 → S3, MinIO site-replication, Ceph multi-site).
7. What's NOT in OrbitalReg
To keep the operational surface small, we intentionally don't ship:
- A built-in service mesh (use Linkerd / Istio / Cilium if you want one)
- A built-in identity provider (use SAML / OIDC against your existing IdP)
- A built-in object store for production (use S3-compatible storage)
- A built-in build system (CI integration is via REST + components, not via embedded runners)
The design favours integration with established platform layers over re-inventing them.