lib/README.md

9.9 KiB
Raw Permalink Blame History

go/lib — Shared Go library for the Keenan Vision service mesh

go/lib (module code.tnxs.net/vernonkeenan/lib) is the shared toolchain every Go microservice in the Keenan Vision mesh pins in its go.mod. It is not a service — it ships no server, no Dockerfile, no compose entry — it is a library app package (InitConfig/InitDB/InitForce, config accessors, zap logging, Prometheus/CORS middleware, generic marshal helpers) plus a set of go-swaggergenerated typed HTTP clients (api/) against the sibling services' own swagger specs. Because every mesh service pins the same module, a lib bump is a constellation-wide rebuild (KV-C6a).

Constellation context

  • Toolchain member of the Keenan Vision Go mesh governed by ../../kv-meta/ (see ../../kv-meta/CONSTELLATION.md §1.3, contract KV-C6). Not a deployed service: no swagger server, no port, no entry in the docker/kvweb compose on pluto.
  • KV-C6a: every mesh service (auth, cache, crm, members, pdf, plex, render, research, sf-gate, stash) pins an explicit code.tnxs.net/vernonkeenan/lib tag in its own go.mod; consumption is a per-consumer go.mod bump, never automatic.
  • Distribution is via a world-readable Gitea pull-mirror at code.tnxs.net/vernonkeenan/lib (and work/lib), enabling credential-free go get code.tnxs.net/vernonkeenan/lib@vX.Y.Z from Docker/CI/dev boxes even though the GitHub repo itself is private (ADR-KV-014). Everything committed here is treated as published, permanently — a gitleaks CI gate makes leaking a secret a build failure, not a review nit.
  • CI (self-hosted runner, go build/vet/test ./... + gitleaks on every push/PR) landed 2026-07-12 as lib's first-ever pipeline (ADR-KV-014) — lib was the only one of the 12 Go-roster repos with no CI at all going into the 2026-07-12 test-harness audit, so this closes out that gap. The test job is lib's instance of the mesh-wide unit-test-gate program (ADR-KV-009, amended by ADR-KV-013, which scopes lib as one of its 12 governed repos); the gitleaks job is ADR-KV-014's public-mirror secret-scan gate, specific to lib because it's the one repo mirrored world-readable.
  • api/ also acts as lib's own internal client of the mesh: app/auth.go's CheckAPIUser calls auth's generated client to validate an API key, so lib is simultaneously a library and a consumer of one sibling service.

Package surface

Path What it is
app/root.go InitConfig(systemName, level) — loads /etc/vernonkeenan/<systemName>.yaml via viper, one-time init guard
app/config.go Configuration struct + Get*/Is* accessors (DBMS, DSN, log level, metrics, service accounts, workers, email, chunk/cache sizing)
app/mysql.go InitDB() — opens MyDB *sql.DB against the configured MySQL DSN
app/force.go InitForce(serviceAccountName) — opens a Salesforce go-force API connection from a configured service account
app/auth.go CheckAPIUser(token) — validates an API key against auth's generated client
app/prometheus.go SetupPrometheusHandler — CORS + request-count/duration middleware
app/service-helpers.go Pointer helpers (String/Bool/Int64/…), GetFieldsAndValues reflection helper (unit-tested)
app/user.go, user-helpers.go, tenantuser.go, userrole.go, address.go First-class domain structs + swagger marshal/unmarshal helpers shared by consumers
app/logger/logger.go Thin zap.SugaredLogger wrapper (New(level), level constants)
api/{auth,crm,members,plex,research,sfgate,stash}/ go-swaggergenerated typed clients + models, one directory per sibling service, regenerated from that service's own spec
swagger/*.yaml, swagger/defs/, swagger/external/ Copies of each sibling service's spec (the KV-C6b spec-copy problem — no sync mechanism besides make regen), shared component defs, and host/path-rewritten copies for external doc publishing; also carries legacy vendored Kazoo/Clerk specs from lib's pre-mesh history

Build, run, test

go build ./...
go vet ./...
go test ./...          # table-driven unit tests today: app/service-helpers.go pure helpers
make install-swagger    # install the pinned go-swagger CLI (SWAGGER_VERSION in Makefile)
make regen               # aka `make swagger` — regenerate api/ from sibling specs
make release VERSION=vX.Y.Z
make release-dry-run VERSION=vX.Y.Z

go test ./... is CI-gating on every push and PR (ADR-KV-009/013), same as the rest of the mesh; lib is a library so there is nothing to "run."

make regen requires the sibling repos auth, crm, stash, sf-gate, research, members, plex cloned adjacently — it reads each one's swagger/<service>-vernonkeenan.yaml, copies it into ./swagger and ./swagger/external, and regenerates every client under api/, rewriting the external specs' scheme/host/path the same way the old make swagger ritual did. It fails fast, before touching anything, if any sibling spec is missing. Review git status/git diff, commit, open a PR, and merge it to main like any other change — client regen is never bundled into the release step; make regen runs a non-fatal go build ./... at the end as an early warning, but the real gate is CI on that PR.

Known gap (resolved for the current spec set, but can recur): if any sibling spec has an operation with no top-level tags:, go-swagger routes it into a fallback operations package whose import path in <name>_client/<name>_client.go doesn't respect --client-package — reproduced across go-swagger v0.33.2 through v0.35.0 while building this tooling. The one instance found, sf-gate-vernonkeenan.yaml's PUT /researchprojectservices (no tags:), was fixed at the source (sf-gate #3 added the missing tags: entry) and regenerated clean in the v0.7.5 feat/regen-clients-processor-token PR — api/sfgate has no fallback operations package today. If a future sibling spec change reintroduces an untagged operation, make regen's non-fatal go build ./... step will fail with this same signature; fix it at the source (add a tags: entry in that service's spec) rather than hand-patching generated code, since the next regen would just reintroduce it.

Configuration

lib reads no config file of its own. app.InitConfig(systemName, level) loads config on behalf of the calling service: viper reads /etc/vernonkeenan/<systemName>.yaml (YAML), with environment-variable overrides via prefix VERNONKEENAN_ (. replaced by _ in key names), unmarshalled into app.ConfigurationAppName, BackendID, DBMS/DBMSHost/DBMSName/DBMSUsername/DBMSPassword, DSN, Environment, LogLevel, GelfURI, Metrics (address/enabled), ServiceAccounts (a map of external-system credentials, e.g. the auth service account CheckAPIUser reads its own API key from), Workers, Email, CacheSizes/Chunks. The concrete /etc/vernonkeenan/<name>.yaml file lives on each deploy host, not in this repo — see the calling service's own README for its file name and required keys.

Versioning & pinning contract (KV-C6a)

  • Module: code.tnxs.net/vernonkeenan/lib, fetched via the Gitea anonymous mirror (not GitHub directly — the GitHub repo is private).

  • Pin, don't float: every consumer pins an explicit vX.Y.Z tag in its go.mod. Bumping the pin is a normal PR in the consumer repo; there is no auto-bump mechanism.

  • Release is one command: make release VERSION=vX.Y.Z (scripts/release.sh) from a clean main checkout that matches origin/main:

    1. Validates VERSION is vMAJOR.MINOR.PATCH and strictly greater than the latest existing tag.
    2. Requires you're on main, the tree is clean, and local main matches origin/main (no local-only commits).
    3. Runs go build ./... and go vet ./... as a last sanity check.
    4. Creates an annotated tag at HEAD, pushes it, and runs gh release create with generated notes.
    5. POSTs to the Gitea mirror-sync API for vernonkeenan/lib and work/lib (skipped with a warning if GITEA_TOKEN is unset — there is no existing Gitea/tnxs token variable defined anywhere on this workstation today; GITEA_TOKEN is a new name, not a rename of something already in use).

    make release-dry-run VERSION=vX.Y.Z runs steps 1-3 and prints what steps 4-5 would do, without tagging, pushing, publishing, or syncing anything.

  • A lib bump is constellation-wide: any breaking change to app.Configuration, InitConfig/InitDB/InitForce, or a generated client's shape ripples to every pinned service on its next go.mod bump.

  • Branch-per-version is retired (ADR-KV-014, 2026-07-12): lib moved to main + v* tags, replacing the old three-web-UI-plus-CLI manual release ritual. ~70 legacy vX.Y.Z branches (one per pre-migration release; git branch --list 'v*') remain in the repo as historical artifacts of the old convention, not the active release mechanism.

  • Prerequisites for a release: the sibling repos (for make regen) cloned adjacently; gh authenticated with push access to vernonkeenan/lib; GITEA_TOKEN exported for the mirror-sync step (optional — see above).

Release & deploy

main + PR flow: land changes on main via PR (CI runs build/vet/test + gitleaks on the PR and on push to main), then cut a release with make release VERSION=vX.Y.Z, which tags main, publishes a GitHub release, and triggers the Gitea mirror-sync. Unlike the deployed mesh services, lib has no Dockerfile, no container image, and no deploy step — it is never built into hub.tnxs.net and never rolled out via the docker/kvweb compose on pluto. "Release" means "a new tag other repos can pin," full stop; downstream rollout happens when each consumer bumps its own go.mod line for code.tnxs.net/vernonkeenan/lib to the new tag and goes through its own release/deploy path.