DevITWay | Pavel Volkov ac3a8a7c43 quality: MSRV, tarpaulin config, proptest for parsers (#84)
* fix: proxy dedup, multi-registry GC, TOCTOU and credential hygiene

- Deduplicate proxy_fetch/proxy_fetch_text into generic proxy_fetch_core
  with response extractor closure (removes ~50 lines of copy-paste)
- GC now scans all registry prefixes, not just docker/
- Add tracing::warn to fire-and-forget cache writes in docker proxy
- Mark S3 credentials as skip_serializing to prevent accidental leaks
- Remove TOCTOU race in LocalStorage get/delete (redundant exists check)

* chore: clean up root directory structure

- Move Dockerfile.astra and Dockerfile.redos to deploy/ (niche builds
  should not clutter the project root)
- Harden .gitignore to exclude session files, working notes, and
  internal review scripts

* refactor(metrics): replace 13 atomic fields with CounterMap

Per-registry download/upload counters were 13 individual AtomicU64
fields, each duplicated across new(), with_persistence(), save(),
record_download(), record_upload(), and get_registry_* (6 touch points
per counter). Adding a new registry required changes in 6+ places.

Now uses CounterMap (HashMap<String, AtomicU64>) for per-registry
counters. Adding a new registry = one entry in REGISTRIES const.
Added Go registry to REGISTRIES, gaining go metrics for free.

* quality: add MSRV, tarpaulin config, proptest for parsers

- Set rust-version = 1.75 in workspace Cargo.toml (MSRV policy)
- Add tarpaulin.toml: llvm engine, fail-under=25, json+html output
- Add coverage/ to .gitignore
- Update CI to use tarpaulin.toml instead of inline flags
- Add proptest dev-dependency and property tests:
  - validation.rs: 16 tests (never-panics + invariants for all 4 validators)
  - pypi.rs: 5 tests (extract_filename never-panics + format assertions)

* test: add unit tests for 14 modules, coverage 21% → 30%

Add 149 new tests across auth, backup, gc, metrics, mirror parsers,
docker (manifest detection, session cleanup, metadata serde),
docker_auth (token cache), maven, npm, pypi (normalize, rewrite, extract),
raw (content-type guessing), request_id, and s3 (URI encoding).

Update tarpaulin.toml: raise fail-under to 30, exclude UI/main from
coverage reporting as they require integration tests.

* bench: add criterion benchmarks for validation and manifest parsing

Add parsing benchmark suite with 14 benchmarks covering:
- Storage key, Docker name, digest, and reference validation
- Docker manifest media type detection (v2, OCI index, minimal, invalid)

Run with: cargo bench --package nora-registry --bench parsing

* test: add 48 integration tests via tower oneshot

Add integration tests for all HTTP handlers:
- health (3), raw (7), cargo (4), maven (4), request_id (2)
- pypi (5), npm (5), docker (12), auth (6)

Create test_helpers.rs with TestContext pattern.
Add tower and http-body-util dev-dependencies.
Update tarpaulin fail-under 30 to 40.

Coverage: 29.5% to 43.3% (2089/4825 lines)

* fix: clean clippy warnings in tests, fix flaky audit test

Add #[allow(clippy::unwrap_used)] to 18 test modules.
Fix 3 additional clippy lints: writeln_empty_string, needless_update,
unnecessary_get_then_check.
Fix flaky audit test: replace single sleep(50ms) with retry loop (max 1s).
Prefix unused token variable with underscore.

cargo clippy --all-targets = 0 warnings (was 245 errors)
2026-04-05 10:01:50 +03:00

NORA

The artifact registry that grows with you. Starts with docker run, scales to enterprise.

docker run -d -p 4000:4000 -v nora-data:/data ghcr.io/getnora-io/nora:latest

Open http://localhost:4000/ui/ — your registry is ready.

NORA Dashboard

Why NORA

  • Zero-config — single 32 MB binary, no database, no dependencies. docker run and it works.
  • Production-tested — Docker (+ Helm OCI), Maven, npm, PyPI, Cargo, Go, Raw. Used in real CI/CD with ArgoCD, Buildx cache, and air-gapped environments.
  • Secure by defaultOpenSSF Scorecard, signed releases, SBOM, fuzz testing, 200+ unit tests.

Release Image Size License: MIT

32 MB binary | < 100 MB RAM | 3s startup | 7 registries

Used in production at DevIT Academy since January 2026 for Docker images, Maven artifacts, and npm packages.

Supported Registries

Registry Mount Point Upstream Proxy Auth
Docker Registry v2 /v2/ Docker Hub, GHCR, any OCI, Helm OCI
Maven /maven2/ Maven Central, custom proxy-only
npm /npm/ npmjs.org, custom
Cargo /cargo/
PyPI /simple/ pypi.org, custom
Go Modules /go/ proxy.golang.org, custom
Raw files /raw/

Helm charts work via the Docker/OCI endpoint — helm push/pull with --plain-http or behind TLS reverse proxy.

Quick Start

docker run -d -p 4000:4000 -v nora-data:/data ghcr.io/getnora-io/nora:latest

Binary

curl -fsSL https://github.com/getnora-io/nora/releases/latest/download/nora-linux-amd64 -o nora
chmod +x nora && ./nora

From Source

cargo install nora-registry
nora

Usage

Docker Images

docker tag myapp:latest localhost:4000/myapp:latest
docker push localhost:4000/myapp:latest
docker pull localhost:4000/myapp:latest

Maven

<!-- settings.xml -->
<server>
  <id>nora</id>
  <url>http://localhost:4000/maven2/</url>
</server>

npm

npm config set registry http://localhost:4000/npm/
npm publish

Go Modules

GOPROXY=http://localhost:4000/go go get golang.org/x/text@latest

Features

  • Web UI — dashboard with search, browse, i18n (EN/RU)
  • Proxy & Cache — transparent proxy to upstream registries with local cache
  • Mirror CLI — offline sync for air-gapped environments (nora mirror)
  • Backup & Restorenora backup / nora restore
  • Migrationnora migrate --from local --to s3
  • S3 Storage — MinIO, AWS S3, any S3-compatible backend
  • Prometheus Metrics/metrics endpoint
  • Health Checks/health, /ready for Kubernetes probes
  • Swagger UI/api-docs for API exploration
  • Rate Limiting — configurable per-endpoint rate limits
  • FSTEC Builds — Astra Linux SE and RED OS images in every release

Authentication

NORA supports Basic Auth (htpasswd) and revocable API tokens with RBAC.

# Create htpasswd file
htpasswd -cbB users.htpasswd admin yourpassword

# Start with auth enabled
docker run -d -p 4000:4000 \
  -v nora-data:/data \
  -v ./users.htpasswd:/data/users.htpasswd \
  -e NORA_AUTH_ENABLED=true \
  ghcr.io/getnora-io/nora:latest
Role Pull/Read Push/Write Delete/Admin
read Yes No No
write Yes Yes No
admin Yes Yes Yes

See Authentication guide for token management, Docker login, and CI/CD integration.

Configuration

Environment Variables

Variable Default Description
NORA_HOST 127.0.0.1 Bind address
NORA_PORT 4000 Port
NORA_STORAGE_MODE local local or s3
NORA_AUTH_ENABLED false Enable authentication
NORA_DOCKER_UPSTREAMS https://registry-1.docker.io Docker upstreams (url|user:pass,...)
NORA_LOG_LEVEL info Log level: trace, debug, info, warn, error
NORA_LOG_FORMAT text Log format: text (human) or json (structured)
NORA_PUBLIC_URL Public URL for rewriting artifact links
See full configuration reference for all options.

config.toml

[server]
host = "0.0.0.0"
port = 4000

[storage]
mode = "local"
path = "data/storage"

[auth]
enabled = false
htpasswd_file = "users.htpasswd"

[docker]
proxy_timeout = 60

[[docker.upstreams]]
url = "https://registry-1.docker.io"

[go]
proxy = "https://proxy.golang.org"

CLI Commands

nora              # Start server
nora serve        # Start server (explicit)
nora backup -o backup.tar.gz
nora restore -i backup.tar.gz
nora migrate --from local --to s3
nora mirror       # Sync packages for offline use

Endpoints

URL Description
/ui/ Web UI
/api-docs Swagger UI
/health Health check
/ready Readiness probe
/metrics Prometheus metrics
/v2/ Docker Registry
/maven2/ Maven
/npm/ npm
/cargo/ Cargo
/simple/ PyPI
/go/ Go Modules

TLS / HTTPS

NORA serves plain HTTP. Use a reverse proxy for TLS:

registry.example.com {
    reverse_proxy localhost:4000
}

See TLS / HTTPS guide for Nginx, Traefik, and custom CA setup.

Performance

Metric NORA Nexus JFrog
Startup < 3s 30-60s 30-60s
Memory < 100 MB 2-4 GB 2-4 GB
Image Size 32 MB 600+ MB 1+ GB

See how NORA compares to other registries

Roadmap

  • Mirror CLI — offline sync for air-gapped environments
  • OIDC / Workload Identity — zero-secret auth for GitHub Actions, GitLab CI
  • Online Garbage Collection — non-blocking cleanup without registry downtime
  • Retention Policies — declarative rules: keep last N tags, delete older than X days
  • Image Signing — cosign verification and policy enforcement

See CHANGELOG.md for release history.

Security & Trust

OpenSSF Scorecard CII Best Practices Coverage CI

  • Signed releases — every release is signed with cosign
  • SBOM — SPDX + CycloneDX in every release
  • Fuzz testing — cargo-fuzz + ClusterFuzzLite
  • Blob verification — SHA256 digest validation on every upload
  • Non-root containers — all images run as non-root
  • Security headers — CSP, X-Frame-Options, nosniff

See SECURITY.md for vulnerability reporting.

Author

Created and maintained by DevITWay

GHCR Rust Docs Telegram GitHub Stars

Contributing

NORA welcomes contributions! See CONTRIBUTING.md for guidelines.

License

MIT License — see LICENSE

Copyright (c) 2026 DevITWay

Languages
Rust 95%
Shell 3.2%
TypeScript 1.6%
Dockerfile 0.2%