- Rust 92.6%
- Shell 4.9%
- TypeScript 2%
- Dockerfile 0.2%
- JavaScript 0.2%
StorageError::Io carried a String, so every fs call erased the io::Error to
text via `.map_err(|e| StorageError::Io(e.to_string()))?`, losing ErrorKind
and the source chain (RI-19 error-erasure: storage was 20+ of 44, over the
budget of 40).
Type the variant as `Io(#[from] std::io::Error)`:
- ~23 `.map_err(|e| StorageError::Io(e.to_string()))?` collapse to `?`
(auto-conversion via #[from]); the real io::Error is preserved.
- non-io constructions (hash-pin "record failed", JoinError "task panicked",
one test mock) wrap their message via `std::io::Error::other(..)`.
- Network(String) is left untyped on purpose: it is matched on its payload
(s3.rs `Network(msg) =>`), so #[from] would break that arm.
No StorageError::Io payload is pattern-matched anywhere, so the variant-shape
change is safe; Display is unchanged ("IO error: {0}"; io::Error: Display).
RI-19 erasure 44 -> 21 (under budget). cargo fmt + clippy -D warnings clean;
1434 tests pass. Net -44 lines (map_err boilerplate removed).
|
||
|---|---|---|
| .clusterfuzzlite | ||
| .config | ||
| .github | ||
| deploy | ||
| dist | ||
| docs-ru | ||
| docs-site | ||
| fuzz | ||
| nora-registry | ||
| scripts | ||
| tests | ||
| .dockerignore | ||
| .git-blame-ignore-revs | ||
| .gitignore | ||
| .gitleaks.toml | ||
| .trivyignore | ||
| _typos.toml | ||
| ARCHITECTURE.md | ||
| artifacthub-repo.yml | ||
| BENCHMARKS.md | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CHANGELOG.md | ||
| cliff.toml | ||
| clippy.toml | ||
| CODE_OF_CONDUCT.md | ||
| COMPAT.md | ||
| CONTRIBUTING.md | ||
| deny.toml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| GOVERNANCE.md | ||
| LICENSE | ||
| llms.txt | ||
| Makefile | ||
| MONITORING.md | ||
| README.md | ||
| renovate.json | ||
| ROADMAP.md | ||
| rust-toolchain.toml | ||
| SECURITY.md | ||
| tarpaulin.toml | ||
NORA
The artifact registry that grows with you. Starts with docker run, scales with your needs.
docker run -d -p 4000:4000 -v nora-data:/data getnora/nora:latest
Open http://localhost:4000/ui/ — your registry is ready.
Why NORA
- Zero-config — single binary, no database, no dependencies.
docker runand it works. - 13 registries — Docker, Maven, npm, PyPI, Cargo, Go, Raw, RubyGems, Terraform, Ansible Galaxy, NuGet, Pub (Dart/Flutter), Conan (C/C++).
- Secure by default — OpenSSF Scorecard, signed releases, SBOM, fuzz testing, 1200+ tests.
< 27 MB binary | < 50 MB RAM idle | 3s startup | 13 registries
Supported Registries
| Registry | Mount Point | Upstream Proxy | Auth |
|---|---|---|---|
| Docker Registry v2 | /v2/ |
Docker Hub, GHCR, any OCI, Helm OCI | ✓ |
| Maven | /maven2/ |
Maven Central, custom | ✓ |
| npm | /npm/ |
npmjs.org, custom | ✓ |
| Cargo | /cargo/ |
crates.io | ✓ |
| PyPI | /simple/ |
pypi.org, custom | ✓ |
| Go Modules | /go/ |
proxy.golang.org, custom | ✓ |
| Raw files | /raw/ |
— | ✓ |
| RubyGems | /gems/ |
rubygems.org | ✓ |
| Terraform | /terraform/ |
registry.terraform.io | ✓ |
| Ansible Galaxy | /ansible/ |
galaxy.ansible.com | ✓ |
| NuGet | /nuget/ |
api.nuget.org | ✓ |
| Pub (Dart/Flutter) | /pub/ |
pub.dev | ✓ |
| Conan (C/C++) | /conan/ |
ConanCenter | ✓ |
Helm charts work via the Docker/OCI endpoint —
helm push/pullwith--plain-httpor behind TLS reverse proxy.
Quick Start
Docker (Recommended)
docker run -d -p 4000:4000 -v nora-data:/data getnora/nora:latest
Binary
# x86_64
curl -fsSL https://github.com/getnora-io/nora/releases/latest/download/nora-linux-amd64 -o nora
# ARM64 (Raspberry Pi, Graviton, Apple Silicon VMs)
curl -fsSL https://github.com/getnora-io/nora/releases/latest/download/nora-linux-arm64 -o nora
chmod +x nora && ./nora
./nora listens on 127.0.0.1:4000. To expose it on a network, set the bind
address and the public URL clients should use for download links:
NORA_HOST=0.0.0.0 NORA_PUBLIC_URL=https://registry.example.com ./nora
Kubernetes (Helm)
helm repo add nora https://getnora-io.github.io/helm-charts
helm install nora nora/nora
From Source
cargo install nora-registry
nora
Usage
# Docker
docker tag myapp:latest localhost:4000/myapp:latest
docker push localhost:4000/myapp:latest
# npm
npm config set registry http://localhost:4000/npm/
npm publish
# Go
GOPROXY=http://localhost:4000/go go get golang.org/x/text@latest
See full documentation for all registries.
Features
- Web UI — dashboard with search, browse, i18n (EN/RU)
- Proxy & Cache — transparent proxy to upstream registries with local cache
- Curation — blocklist, allowlist, namespace isolation, integrity verification, min-release-age filter, digest quarantine
- Token RBAC — read/write/admin roles, expiry tracking, deferred last_used flush
- Mirror CLI — offline sync for air-gapped environments (
nora mirror) - Backup & Restore —
nora backup/nora restore - S3 Storage — AWS S3, Ceph RGW, any S3-compatible backend
- Prometheus Metrics —
/metricsendpoint, Grafana dashboard - Rate Limiting — configurable per-endpoint rate limits
Configuration
NORA works out of the box. For advanced setup — auth, S3, retention, curation — see getnora.dev/configuration.
# Auth
docker run -d -p 4000:4000 \
-v nora-data:/data \
-v ./users.htpasswd:/data/users.htpasswd \
-e NORA_AUTH_ENABLED=true \
getnora/nora:latest
# Curation — block packages younger than 7 days
docker run -d -p 4000:4000 \
-v nora-data:/data \
-e NORA_CURATION_MODE=enforce \
-e NORA_CURATION_MIN_RELEASE_AGE=7d \
-e NORA_CURATION_ALLOWLIST_PATH=/data/allowlist.json \
getnora/nora:latest
Performance
| Metric | NORA | Nexus | JFrog |
|---|---|---|---|
| Startup | < 3s | 30-60s | 30-60s |
| Memory | < 50 MB idle | 2-4 GB | 2-4 GB |
| Binary | < 27 MB | 600+ MB | 1+ GB |
Roadmap
Mirror CLI✅ v0.4.0Garbage Collection & Retention✅ v0.6.0Helm Chart✅ v0.6.1Signed releases & SBOM✅ v0.6.4Curation layer & 13 registry formats✅ v0.7.0Min Release Age✅ v0.7.1Hash Pin Store, auth rate limiting, Cache-Control✅ v0.8.0Outbound proxy, structured audit log✅ v0.8.3Circuit breaker, OIDC, hot reload, arm64, streaming uploads✅ v0.9.0NuGet V3 stabilization, Cargo ETag, 1049 tests✅ v0.9.1Prometheus metrics, Ansible Galaxy v3, security fixes, 1086 tests✅ v0.9.2Security hardening, null byte protection, config refactor, 1204 tests✅ v0.9.3Multi-upstream PyPI, conditional-request revalidation, single-flight coalescing, per-registry metrics✅ v0.9.4Digest quarantine across all registries, trusted upstream dates, token access-control hardening✅ v0.9.5- Image Signing Policy — cosign verification on upstream pulls
- Semver contract — stable API, configuration format, and storage layout
See ROADMAP.md for the full roadmap and CHANGELOG.md for release history.
Security & Trust
See SECURITY.md for vulnerability reporting.
Documentation
Full documentation: https://getnora.dev
Author
Created and maintained by Pavel Volkov
Contributing
NORA welcomes contributions! See CONTRIBUTING.md for guidelines.
License
MIT License — see LICENSE
Copyright (c) 2026 The NORA Authors