Skip to content
Luc Garrabos edited this page May 6, 2026 · 1 revision

CI / CD

Continuous integration, security testing, deployment, and the bsctl management CLI.


Table of contents


CI pipeline

The CI pipeline is defined in .github/workflows/ci.yml and runs on push (all branches) and pull requests to main.

Pipeline stages

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)"]
Loading

Job details

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 testing

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.

Hardening roadmap

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.

Deployment workflow

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.gz containing bookstorage, bsctl, and deploy/bookstorage.service

See Installation for how to use the artifact on a server.


bsctl CLI reference

bsctl (BookStorage Control) is a bash script for managing the application in both development and production.

Service commands (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)

Development commands

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

Production / maintenance 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

Update modes

  • Interactive: sudo bsctl update presents a menu: 1 / 2 = last two major tags vX.0.0, 3 = type any tag
  • Non-interactive: BSCTL_UPDATE_TAG=v5.8.0 sudo -E bsctl update skips the menu
  • Branch: sudo bsctl update main fast-forwards from origin/main

Backup configuration

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).

Version string

APP_VERSION in Makefile and scripts/bsctl should stay in sync for release builds. The version is injected via -ldflags -X main.Version=....


Makefile targets

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

Tab completion

Development

source scripts/bsctl.completion.bash

Production

After 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.


Contributing

  1. Fork and branch from main
  2. Run tests, gofmt, and golangci-lint locally — CI must be green
  3. Do not commit .env or secrets; use .env.example and config/site.json.example as templates
  4. For user-facing behavior changes, update the relevant docs under docs/ (and docs/fr/ for French)

Local CI check

make ci-local

Or manually:

gofmt -w .
golangci-lint run
go test ./... -coverprofile=coverage.out
go test -race ./...

Troubleshooting — Next: solutions to common issues.

Clone this wiki locally