112 lines
3.9 KiB
Markdown
112 lines
3.9 KiB
Markdown
# CodeVault
|
|
|
|
A small HTTP service that stores string values under access codes: write a
|
|
value with `setValue` under a code, later retrieve it with `getValue` using
|
|
that code. Basic Auth protects writes; reads are open but rate-limited by
|
|
failed-lookup count per client IP to slow down code guessing.
|
|
|
|
## Features
|
|
|
|
- `POST /api/v1/setValue` — store a value under a code (Basic Auth required).
|
|
- `POST /api/v1/getValue` — retrieve a value by code (public, rate-limited).
|
|
- Interactive API docs at `/api` (Swagger UI, embedded assets — no CDN).
|
|
- Prometheus metrics for HTTP requests and business events (successful/failed
|
|
gets and sets).
|
|
- OpenTelemetry logging, with optional OTLP export.
|
|
- SQLite storage (pure Go driver, no CGO).
|
|
- Configurable trusted proxies so client IPs are resolved correctly behind a
|
|
reverse proxy (e.g. nginx).
|
|
|
|
## Running
|
|
|
|
### Locally
|
|
|
|
```sh
|
|
go build
|
|
./codevault config-example ./config.yaml # write a starter config
|
|
./codevault add-user --db-path ./codevault.db --login admin # prompts for a password
|
|
./codevault run --config ./config.yaml
|
|
```
|
|
|
|
Or via the Makefile: `make build`, `make config-example`, `make add-user`,
|
|
`make run`.
|
|
|
|
### Docker
|
|
|
|
```sh
|
|
cp docker-compose.yaml.example docker-compose.yaml
|
|
go run . config-example ./config.yaml # or hand-write one, see Configuration below
|
|
docker compose up -d --build
|
|
docker compose exec codevault ./codevault add-user --db-path /app/data/codevault.db --login admin
|
|
```
|
|
|
|
The compose file mounts `config.yaml` read-only and keeps the SQLite database
|
|
in a named volume (`codevault-data`). Edit `server.trusted_proxies` in your
|
|
`config.yaml` to match the proxy/network actually in front of the container
|
|
(gin needs IPs/CIDRs, not hostnames).
|
|
|
|
## Configuration
|
|
|
|
`config-example` writes a documented starting point. Key sections:
|
|
|
|
```yaml
|
|
environment: development # development | production
|
|
server:
|
|
address: :8080
|
|
trusted_proxies: # IPs/CIDRs allowed to set X-Forwarded-For / X-Real-IP
|
|
- 172.16.0.0/12 # empty/omitted = trust nothing, use the raw remote address
|
|
database:
|
|
path: ./codevault.db
|
|
rate_limit:
|
|
max_failures: 10 # failed getValue lookups per IP before 404-ing everything
|
|
window: 1m0s # sliding window for max_failures
|
|
observability:
|
|
logging:
|
|
stderr: INFO # DEBUG|INFO|WARNING|ERROR|PANIC|FATAL, empty disables
|
|
files:
|
|
INFO: ./info.log # per-level log files, optional
|
|
exporter: # optional OTLP log export
|
|
level: INFO
|
|
endpoint: http://127.0.0.1:4317/v1/logs
|
|
transport: grpc # grpc | http
|
|
metrics:
|
|
host: 127.0.0.1
|
|
port: 9092 # Prometheus /metrics endpoint
|
|
```
|
|
|
|
## API
|
|
|
|
Full OpenAPI spec: [internal/api/openapi.yaml](internal/api/openapi.yaml).
|
|
When the server is running, browse it interactively at `/api`, or fetch the
|
|
raw spec from `/api/openapi.json`.
|
|
|
|
- `POST /api/v1/getValue` `{"code": "..."}` → `200 {"value": "..."}` /
|
|
`404` (not found or rate-limited) / `400` (bad body).
|
|
- `POST /api/v1/setValue` `{"code": "...", "value": "..."}` (Basic Auth) →
|
|
`204` / `400` (bad body) / `401` (bad credentials).
|
|
|
|
## Metrics
|
|
|
|
Exposed on `http://<metrics.host>:<metrics.port>/metrics`:
|
|
|
|
- `http_requests_total`, `http_request_duration_seconds` — generic per-route
|
|
HTTP metrics.
|
|
- `codevault_get_value_success_total{code}` — successful getValue lookups, by
|
|
code.
|
|
- `codevault_get_value_failed_total{reason}` — failed lookups, `reason` is
|
|
`not_found` or `rate_limited`.
|
|
- `codevault_set_value_success_total{user}` — successful setValue writes, by
|
|
authenticated login.
|
|
- `codevault_set_value_failed_total{reason}` — failed writes, `reason` is
|
|
`bad_request` or `unauthorized`.
|
|
|
|
## Development
|
|
|
|
```sh
|
|
make build # go build
|
|
make lint # golangci-lint
|
|
make generate # regenerate internal/api from openapi.yaml (oapi-codegen)
|
|
make test # go test ./...
|
|
make docker-build
|
|
```
|