Repository navigation
CI CD
Continuous integration, security testing, deployment, and the bsctl management CLI.
- CI pipeline
- Security testing
- Deployment workflow
- bsctl CLI reference
- Makefile targets
- Tab completion
- Contributing
The CI pipeline is defined in .github/workflows/ci.yml and runs on push (all branches) and pull requests to main.
flowchart LR
Lint["Lint\n(gofmt + golangci-lint)"] --> Tests["Unit Tests\n(go test + coverage)"]
Lint --> Race["Race Tests\n(go test -race)"]
Tests --> Build["Build Linux Binary\n(go build)"]
Race --> Build
Build --> Smoke["HTTP Smoke Tests\n(curl /, /login, /register)"]
| Job | What it does |
|---|---|
| Lint |
gofmt -l . must produce no output; golangci-lint run
|
| Unit tests |
go test ./... -coverprofile=coverage.out (coverage uploaded as artifact) |
| Race tests | go test -race ./... |
| Build Linux binary |
go build -o bookstorage ./cmd/bookstorage (uploaded as artifact) |
| HTTP smoke tests | Downloads the built binary, starts the app, waits for /, then curls /, /login, /register
|
Execution order is staged: Lint first, then Unit tests and Race tests in parallel, then Build, then Smoke tests.
CI uses workflow concurrency (cancel-in-progress) to automatically cancel outdated runs on the same branch.
All jobs must pass before merging.
Security-oriented jobs run in parallel with the core pipeline on the same triggers (push / PR). They use continue-on-error so they never block a merge (observability mode).
| Job | Tool | What it checks |
|---|---|---|
| SAST | gosec |
Static analysis for common Go security issues |
| Dependency vulnerabilities | govulncheck |
Known CVEs in Go module dependencies |
| Secrets scan | gitleaks |
Leaked credentials, API keys, tokens in git history |
| DAST smoke | scripts/ci/security_smoke.sh |
Live checks: security headers, API auth (401), wrong methods (405), CSRF origin blocking (403), rate limiting (429), admin route protection |
Each job uploads a report artifact (JSON or TXT) for review.
| Phase | Strategy |
|---|---|
| Phase 1 (current) | Observability only — all jobs are continue-on-error: true. Review artifacts after each run. |
| Phase 2 | Remove continue-on-error on gosec and govulncheck so High/Critical findings block PRs. |
| Phase 3 | Tighten to Medium+ severity; add gitleaks to required checks. |
The deployment workflow .github/workflows/deploy.yml builds a Linux amd64 binary with CGO and packages it as a tarball.
-
Trigger: manual (
workflow_dispatch) -
Output:
bookstorage-linux-amd64.tar.gzcontainingbookstorage,bsctl, anddeploy/bookstorage.service
See Installation for how to use the artifact on a server.
bsctl (BookStorage Control) is a bash script for managing the application in both development and production.
| Command | Description |
|---|---|
bsctl start |
Start the systemd service |
bsctl stop |
Stop the service |
bsctl restart |
Restart the service |
bsctl status |
Show service status |
bsctl logs |
Show real-time logs (journalctl -f) |
| Command | Description |
|---|---|
bsctl build |
Compile the application (go build) |
bsctl build-prod |
Optimized binary with -ldflags and version injection |
bsctl run |
Start dev server (go run ./cmd/bookstorage) |
bsctl clean |
Remove compiled binary |
bsctl help |
Show all available commands |
| Command | Description |
|---|---|
bsctl install |
Install systemd service |
bsctl uninstall |
Uninstall service |
bsctl update |
Interactive release update: choose from last two major tags or enter any tag |
bsctl update main |
Fast-forward update from origin/main + build + restart |
bsctl update <branch> |
Update from origin/<branch> + build + restart |
bsctl fix-perms |
Fix file permissions |
bsctl backup |
Snapshot the SQLite database |
-
Interactive:
sudo bsctl updatepresents a menu: 1 / 2 = last two major tagsvX.0.0, 3 = type any tag -
Non-interactive:
BSCTL_UPDATE_TAG=v5.8.0 sudo -E bsctl updateskips the menu -
Branch:
sudo bsctl update mainfast-forwards fromorigin/main
| Variable | Default | Description |
|---|---|---|
BOOKSTORAGE_BACKUP_DIR |
/var/lib/bookstorage/backups |
Backup output directory |
BOOKSTORAGE_BACKUP_RETENTION_DAYS |
14 |
Days to keep old backups |
Uses sqlite3 .backup when available, otherwise falls back to cp.
To enable daily scheduled backups, use INSTALL_WITH_BACKUP_TIMER=1 during installation (see Installation).
APP_VERSION in Makefile and scripts/bsctl should stay in sync for release builds. The version is injected via -ldflags -X main.Version=....
| Target | Purpose |
|---|---|
make build |
Debug build |
make build-prod |
Optimized binary with version injection |
make run |
go run ./cmd/bookstorage |
make clean |
Remove binary |
make test |
Unit tests with coverage |
make test-race |
Race detector tests |
make lint |
gofmt + golangci-lint
|
make ci-local |
Local CI parity (lint + test + test-race) |
make help |
Print help |
source scripts/bsctl.completion.bashAfter sudo bsctl install or running deploy/install.sh, completion is installed to:
/etc/bash_completion.d/bsctl/usr/share/bash-completion/completions/bsctl
Open a new shell or run source /etc/bash_completion.d/bsctl. After bsctl update, Tab suggests main, tags, and branch names when Git can see the BookStorage repo.
- Fork and branch from
main - Run tests,
gofmt, andgolangci-lintlocally — CI must be green - Do not commit
.envor secrets; use.env.exampleandconfig/site.json.exampleas templates - For user-facing behavior changes, update the relevant docs under
docs/(anddocs/fr/for French)
make ci-localOr manually:
gofmt -w .
golangci-lint run
go test ./... -coverprofile=coverage.out
go test -race ./...Troubleshooting — Next: solutions to common issues.