Balam Security Platform
- TypeScript 55%
- Go 44.1%
- Shell 0.7%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
security-scan / security-scan (push) Successful in 1m15s
test / web (push) Successful in 2m22s
codecov/project 34.78% (No base report)
codecov/patch Patch coverage: N/A (not in PR context)
test / go (push) Successful in 5m5s
test / coverage-badge (push) Successful in 3m36s
Reviewed-on: #39 |
||
| .forgejo/workflows | ||
| api | ||
| cmd/server | ||
| deploy | ||
| internal | ||
| scripts | ||
| web | ||
| .dockerignore | ||
| .gitignore | ||
| .ojoignore | ||
| AGENTS.md | ||
| DESIGN.md | ||
| go.mod | ||
| go.sum | ||
| Makefile | ||
| PRODUCT.md | ||
| README.md | ||
| renovate.json | ||
| STATUS.md | ||
| TODO.md | ||
Balam
Self-hosted vulnerability management with a DefectDojo-style API and a modern UI. Go API · PostgreSQL · React/TypeScript frontend.
Features
- Multi-tenant — every record is isolated by organization; RBAC roles
owner > admin > writer > reader. - Auth — Argon2id passwords with account lockout, short-lived JWT access tokens, rotating refresh tokens (stored hashed), personal API tokens, and UI-configurable OIDC SSO (PKCE + state + nonce).
- Resources — product types, products, engagements, tests, findings, endpoints, tags (DefectDojo parity).
- Scan import — Trivy, Semgrep, and generic SARIF reports, with hash-based finding deduplication.
- Integrations — Jira and Linear issue creation with status sync-back, Slack notifications. Credentials are encrypted at rest (AES-256-GCM).
- Security baseline — security headers, rate limiting, audit logging, tenant-scoped data access, secrets never serialized to API clients.
Quick start (local)
# Requires Go 1.24+ and a PostgreSQL instance.
export BALAM_DATABASE_URL="postgres://balam:balam@localhost:5432/balam?sslmode=disable"
export BALAM_JWT_SECRET="$(openssl rand -base64 32)"
make run
On first start the server migrates the schema and bootstraps a default
organization plus an admin user (BALAM_BOOTSTRAP_EMAIL /
BALAM_BOOTSTRAP_PASSWORD, default [email protected] / admin). Change the
admin password immediately in production.
The API is served at /api/v2; interactive docs at
/api/v2/oa3/swagger-ui/.
Docker Compose
docker compose -f deploy/docker/docker-compose.yml up --build
Configuration
All configuration is via BALAM_* environment variables:
| Variable | Default | Purpose |
|---|---|---|
BALAM_ENV |
development |
production enables HSTS and quiet logs |
BALAM_HTTP_ADDR |
:8080 |
Listen address |
BALAM_DATABASE_URL |
local postgres DSN | PostgreSQL connection |
BALAM_JWT_SECRET |
dev placeholder | Required. Signs JWTs and derives the secret-encryption key |
BALAM_ACCESS_TOKEN_TTL |
15m |
Access token lifetime |
BALAM_REFRESH_TOKEN_TTL |
720h |
Refresh token lifetime |
BALAM_PUBLIC_URL |
http://localhost:8080 |
Used for OIDC redirect URIs |
BALAM_CORS_ORIGINS |
localhost dev origins | Comma-separated allowed origins |
BALAM_BOOTSTRAP_EMAIL / _PASSWORD / _ORG |
admin defaults | First-run seed |
Development
make build # compile the server
make test # run all tests (crypto, parsers, auth, tenant isolation)
make vet # static analysis
Source of truth for validation is the CLI (go build ./..., go vet ./...,
go test ./...). Tests use in-memory SQLite; production runs on PostgreSQL.
Layout
cmd/server entrypoint (config, migrate, bootstrap, serve)
internal/config env-driven configuration
internal/models GORM domain models (OrgScoped tenant boundary)
internal/crypto Argon2id, AES-256-GCM SecretBox, token hashing
internal/database connect, AutoMigrate, bootstrap seed
internal/auth JWT, refresh rotation, API tokens, RBAC, OIDC
internal/api chi router + middleware + handlers
internal/parsers scanner import framework (Trivy/Semgrep/SARIF)
internal/integrations Jira/Linear/Slack + status sync worker
api/openapi.yaml OpenAPI 3 spec (served via Swagger UI)
web/ React + TypeScript + Vite frontend
deploy/ Docker and Kubernetes manifests