- Rust 98.9%
- Shell 0.5%
- PLpgSQL 0.3%
- Dockerfile 0.3%
| .forgejo/workflows | ||
| migrations | ||
| scripts | ||
| src | ||
| tests | ||
| .gitignore | ||
| .releaserc.cjs | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CHANGELOG.md | ||
| Dockerfile | ||
| LICENSE | ||
| openapi.json | ||
| README.md | ||
| renovate.json | ||
| rust-toolchain.toml | ||
osc-api
Rust backend (axum) for skins.sulej.net. The UI lives in osc_dev/osc-skins-ui.
Stack
- Rust 2024, axum 0.8 (tokio / tower)
- sea-orm 1.1 + sqlx (Postgres)
- reqwest (osu! API + Forgejo)
- aws-sdk-s3 (Garage S3 for media + CI log fallback)
- utoipa + utoipa-axum (OpenAPI generated from the code)
Local dev
cargo build
# minimum env to boot; see src/config.rs for the full list
export DATABASE_URL='postgres://osc:osc@localhost:5432/oscweb' \
SESSION_SECRET=x FORGEJO_TOKEN=x OSU_CLIENT_ID=1 OSU_CLIENT_SECRET=x \
GARAGE_ACCESS_KEY=x GARAGE_SECRET_KEY=x WEBHOOK_SECRET=x BOT_TOKEN=x \
ADMIN_OSU_IDS='[]'
cargo run # serves on 0.0.0.0:8000
cargo run -- --dump-openapi # print the OpenAPI spec and exit (no DB needed)
Schema: production Postgres is owned by Alembic on the Python side through cutover, so the Rust binary never migrates prod — it attaches to the existing schema. migrations/0001_schema.sql reproduces that schema only to bootstrap fresh/test databases.
Tests
scripts/test.sh # full suite, safely (recommended)
scripts/test.sh --coverage # + merged llvm-cov report (target/llvm-cov/html)
cargo test --lib # unit tests only — no containers, instant
cargo test --test health # a single integration binary
Each tests/*.rs binary boots the app in-process against an ephemeral Postgres + MinIO (testcontainers, fresh DB per test), with Forgejo and the osu! API faked at the HTTP boundary (wiremock). Plain cargo test launches every binary's containers at once and will exhaust the host — scripts/test.sh runs the binaries one at a time (set JOBS=N for bounded concurrency) and reaps containers between them. cargo clippy -- -D warnings and cargo fmt --check are the lint gates.
Deployment
CI on push to main builds the image, validates the generated OpenAPI spec, and pushes git.sulej.net/osc_dev/osc-api:latest (:beta on the beta branch). The server at /home/arlind/docker/oscbot/ runs docker compose pull && up -d to roll forward.
Traefik routes skins.sulej.net/api/* → osc-web-backend:8000.
OpenAPI
The spec is generated from the code (utoipa) and served live at /api/openapi.json, rendered at /api/docs (Scalar). It is not committed — the code is the single source of truth. osc-skins-ui runs npm run sync-types to generate matching TypeScript types from the live spec.
Permissions
| Action | Anyone | Owner | Admin |
|---|---|---|---|
| Browse | ✓ | ✓ | ✓ |
| Edit own repo | ✓ | ✓ | |
| Edit any repo | ✓ |
License
Licensed under AGPL-3.0-only. The LICENSE file was added in 2026; all prior versions, releases, and container images (which predate the LICENSE file in the source tree) are also offered under AGPL-3.0 at the discretion of the copyright holder.