Architecture

CodeScoring.Save uses a microservice architecture. Backend API and authentication / authorization are split into separate services: Save API service and cs-auth (Auth/RBAC service).

Technology Stack

  • Development language: Go 1.25+.
  • Metadata storage: PostgreSQL 14+ (recommended for production) or SQLite 3.x.
  • Object storage: S3-compatible storage (MinIO, AWS S3, Yandex Object Storage) or local file system.
  • Authentication: RSA-2048 JWT with JWKS, issued by cs-auth and validated locally by Save through the public key.

Architecture Diagram

Database schema

In a PostgreSQL deployment, both services can share one database instance and one schema; data is separated by table name prefixes. In a SQLite deployment, each service uses a separate database file.

System Components

Save API service

The main backend service that processes incoming requests to repositories and the administrative API.

Functions:

  • Processing HTTP/HTTPS requests from package managers and the web interface.
  • Token validation and integration with the dedicated Auth/RBAC service.
  • Routing requests to the storage backend.
  • Integration with CodeScoring.OSA through OSA Proxy for artifact scanning when downloads are routed through the proxy.
  • Applying security policies and cleanup policies.
  • Structured logging and Prometheus metrics export.

Technical characteristics:

  • Stateless architecture for horizontal scaling.
  • Graceful shutdown during updates.
  • Health checks for Kubernetes.

Auth/RBAC service

A dedicated authentication and authorization service deployed separately from Save API service.

Functions:

  • Authentication of users and service accounts.
  • Issuing and refreshing JWT tokens (RSA-2048, alg=RS256).
  • Managing roles and permissions at global / project / repository levels.
  • Managing API keys, robot accounts, and project membership.
  • Audit of access-related and system-wide operations.
  • Internal API for interaction with Save API service.
  • OCI Distribution Spec token endpoint for Docker / Helm / oras clients.

Technical characteristics:

  • Separate codebase and separate entry point.
  • Dedicated PostgreSQL schema in a shared database instance, or a separate SQLite file.
  • Horizontal scaling independently from Save API service.
  • Required scaling condition: all replicas must share the same RSA key for signing JWT tokens.

Storage Backend

Artifact storage subsystem:

  • Metadata Store — PostgreSQL or SQLite for metadata.
  • Blob Store — object storage for artifacts: S3-compatible storage or file system.

Operations: storing and retrieving artifacts, version management, checksum generation.

Background Workers

Background processes for deferred tasks. The components are split into three primary roles: a scheduler, a job queue (Redis), and workers.

Scheduler

  • Responsible for scheduling periodic and delayed jobs (cron-like): cleanup, bulk metadata operations, notifications, etc.
  • Implemented in save/backend/cmd/scheduler/main.go.
  • Enqueues jobs into Redis with job type and payload metadata; jobs should be idempotent and include retry/attribution metadata.

Queue (Redis)

  • Central job queue (Redis-backed pub/sub or list-based queue). Provides durable delivery, visibility, retry mechanisms and optional DLQ (dead-letter queue).
  • Recommended to enable persistence and, under high load, run Redis in clustered mode.
  • The Save API service may also enqueue ad-hoc jobs (e.g., on upload events).

Workers

  • Workers consume jobs from Redis and operate on the Metadata DB and Object Storage (artifact deletion, metadata recalculation, replication, etc.).
  • Implemented in save/backend/cmd/worker/main.go.
  • Workers emit audit events to cs-auth (internal API) when required.
  • Workers scale horizontally; implementations must handle concurrent access control, timeouts and retries.

Web UI

Web interface for managing projects, repositories, artifacts, and access settings. Module capabilities are described on the Functional characteristics page.

Service Interaction

  • External clients (Web UI and package managers) access only Save API service through ingress; cs-auth is not exposed outside the cluster.
  • Save API service delegates authentication, role checks, and token issuing to Auth/RBAC service.
  • Both services can use separate or shared PostgreSQL instances, but they work in separate schemas/databases.
  • Save API service works directly with metadata store and object storage; cs-auth works only with metadata store and has no access to object storage.
  • Save calls cs-auth in several cases:
    • Proxying part of the administrative API — Save forwards requests without processing them itself.
    • Checking credentials that are not present in the local pod cache — Basic Auth, API key, NuGet API key, NPM token, Docker token.
    • Sending audit events — one event log for all services.
  • All internal endpoints are additionally protected by a shared secret.
  • On the hot path, Save validates Bearer JWT locally using a cached JWKS public RSA key without a network call to cs-auth.

Data Model

Main Entities

Project

- ID
- Name
- Description
- Owner
- Created/Updated timestamps

Repository

- ID
- Project ID
- Name
- Type (proxy/hosted)
- Format (maven, npm, docker, nuget, pypi, go, deb, rpm, raw)
- Configuration
- Storage Backend
- Cleanup Policies
- Created/Updated timestamps

Artifact

- ID
- Repository ID
- Group/Namespace
- Name
- Version
- Format-specific metadata
- Size
- Checksums (MD5, SHA1, SHA256)
- Upload date
- Last accessed

User

- ID
- Username
- DisplayName
- Email
- PasswordHash (bcrypt)
- IsActive
- AuthSource   (local / ldap / oidc)
- LastLoginAt
- Created/Updated timestamps

Role / Robot account

- ID
- Name
- Description
- Permissions (global / project / repository scopes)
- IsAdmin
- IsSystem
- API keys (only for robot accounts)
- Created/Updated timestamps

APIKey

- ID
- UserID            (FK to user with IsService=true)
- KeyPrefix         (first 12 hex characters of the plaintext key, used for O(1) lookup)
- KeyHash           (bcrypt(plaintext))
- Description
- ExpiresAt         (NULL = no expiration)
- LastUsedAt
- CreatedAt

The full plaintext key is returned to the client only once, when it is created.

Cleanup Policy

- ID
- Name
- Type (cleanup/security)
- Rules
- Repositories
- Enabled
- Created/Updated timestamps

Installation Options

CodeScoring.Save supports several installation profiles. Requirements, profile differences, and deployment steps are described in Installation Options.

Security

Authentication and Authorization

  • JWT tokens for API, issued by Auth/RBAC service
  • Basic Auth / API keys for package managers and service accounts
  • Role-based access control (RBAC) with three scopes (global / project / repository), managed by the dedicated Auth/RBAC service
  • Inter-service token validation through the JWKS endpoint

Client-side authentication methods are described in detail in Authentication.

Data Encryption

Save and cs-auth services do not perform application-level encryption; encryption is provided by the underlying components:

  • Encryption at rest is provided by the selected object storage (S3 server-side encryption, MinIO encryption-at-rest) and PostgreSQL (through TDE extensions or volume-level encryption).
  • Encryption in transit is provided by TLS on ingress / load balancer and in inter-service connections.
  • User passwords and robot account API keys are stored as bcrypt hashes in cs-auth.

Audit

  • Complete logging of all operations into a unified event log used by both services.
  • Export to machine-readable format (JSON) and HTML. A single export can contain up to 10,000 records.
  • Supported filters for list/export: from, to, username, action, resource_type, q, user_id. In the web UI, search is available only by username, resource type, and action.

Performance

Optimizations

  • Caching:

    • In-process TTL cache credential -> PermissionSet in each Save API service pod, removing the round trip to cs-auth for repeated requests with the same credentials.
    • Local Bearer JWT validation through the JWKS public key, without a network call to cs-auth on the hot path. JWKS is refreshed periodically in the background.
  • Connection pooling:

    • Database connection pool.
    • Reused HTTP clients for upstream repositories.
  • Parallel processing:

    • Concurrent uploads / downloads through goroutines.
    • Batch (bulk) operations API.
  • Streaming large files:

    • Artifacts are transferred through MultiWriter without buffering the full file in memory.
    • Atomic disk writes through temp-file rename to avoid corruption during concurrent writes.

Target Metrics

For a basic installation:

  • Latency (p95): < 100 ms for cached requests
  • Throughput: 300+ requests/sec
  • Concurrent uploads: 100+
  • Max artifact size: 5 GB

Scaling

Horizontal Scaling

  • Save API service: stateless, scaled by adding replicas.
  • Auth/RBAC service: stateless, scaled by adding replicas. Required condition: all replicas must share the same RSA key for signing JWT tokens (AUTH_JWT_RSA_KEY_PATH).
  • PostgreSQL: vertical scaling + read replicas if needed.
  • Object storage: scaled horizontally by the provider (S3, MinIO in a cluster).

Vertical Scaling

  • Increasing pod resources.
  • Increasing PostgreSQL capacity.
  • Expanding object storage.

Monitoring and Observability

Metrics (Prometheus)

Save exports metrics in OpenTelemetry format with Prometheus exporter.

HTTP metrics:

  • http_requests_total{method,path,status} — HTTP request counter.
  • http_request_duration_seconds{method,path,status} — latency histogram.
  • http_requests_active — active request gauge.

Operation metrics:

  • storage_operations_total{operation,backend,success} — storage operations.
  • artifact_uploads_total{artifact_type,repository} — artifact uploads.
  • artifact_downloads_total{artifact_type,repository} — artifact downloads.
  • proxy_requests_total{artifact_type,repository,cache_hit,success} — proxy requests. Cache hit rate is calculated as rate(proxy_requests_total{cache_hit="true"}[5m]) / rate(proxy_requests_total[5m]).
  • cleanup_operations_total{policy_type,repository,artifacts_deleted,success} — cleanup operations.

Logging

  • Structured logs in JSON format (or text, depending on configuration).
  • Levels: debug, info, warn, error.
  • Output: stdout, stderr, or file.
  • Compatible with any log aggregator that can process JSON (ELK, Loki, Vector).

Availability and Resilience

CodeScoring.Save does not implement automatic failover, point-in-time recovery, or built-in backup on its own. These capabilities are provided by the standard tools of the infrastructure where the service is deployed:

  • Multiple Save and cs-auth replicas in Kubernetes behind a load balancer provide availability if one pod fails.
  • PostgreSQL replication and database backup are configured through the PostgreSQL operator or managed service.
  • Object storage snapshots and replication are handled by the S3-compatible storage provider.
  • Multi-node Kubernetes cluster provides resilience to node failure.

Save does not lose data on restart because all state is external: metadata is stored in the database and artifacts are stored in object storage. Stateless Save architecture allows scaling and pod recreation without data loss.

Was this page helpful?