Quality gates¶
Required pull-request checks cover:
- gofmt, ShellCheck, actionlint, golangci-lint, and Buf lint;
- generated Go, TypeScript, sqlc, and OpenAPI drift;
- Go race tests, DB integration tests, release-target 32-bit cross-compilation, and web/plugin tests and builds;
- real Chromium editor acceptance tests in a pinned Playwright container;
- packaged Scyllaridae PDF conversion with corrected Unicode text and exact image/page-order checks through Poppler;
- OCR build tags and DB-backed ingest/revision acceptance tests;
- isolated backup/restore integrity and expired-job recovery smoke tests;
- gosec, npm audits, and Trivy dependency plus credential scanning with a synthetic detection regression;
- hash-locked segmentor Python transitives, repository dependency and secret scanning, digest-pinned runtime images, and packaged-runtime smoke tests;
- Terraform formatting/init/validation, rendered Compose checks, and the local runtime, Vault-init, and secret-generation script tests;
- Zensical documentation build.
make ci is the local entrypoint and includes the same Trivy high/critical
dependency and secret scan as the hosted workflow. Runtime image scanning is
currently deferred and does not gate CI, deployment, or release. Individual
component commands remain useful for iteration. Reachable Go vulnerability
analysis is optional during development: run
SCRIBE_GOVULNCHECK=true make security to include the pinned govulncheck.
It is not a make ci or hosted CI gate. A manually checked box is
not a substitute for a passing required job. ci/run-ci.sh owns the canonical
contracts, test, browser, recovery, security, and infrastructure
groups; hosted jobs call those same groups in parallel while make ci runs
them locally. The orchestrator creates a unique Compose project from the
reviewed base file (never a developer's local override), lets Docker allocate a
collision-free bridge, waits for MariaDB health before integration tests, and
removes its containers and volumes on success, failure, or interruption. It
does not reuse or stop the normal development stack, so integration tests
cannot silently skip on a clean checkout.
Each npm advisory request has a 60-second transport timeout and at most three attempts. A nonzero result on every attempt still fails the security gate, so a registry outage is bounded without allowing a real advisory finding to pass.
make ocr-build-tags cross-compiles both GoReleaser binaries for linux/386
with the release build tag in the same pinned Go container used for its native
build checks. Hosted CI and the local entrypoint therefore reject constants and
other code that compile on 64-bit development hosts but fail a supported
release target.
make segmentor-lock-check proves every Python requirement is exact and every
accepted distribution has a SHA-256 hash, including the explicitly retained
unsafe setuptools transitive. make segmentor-lock regenerates that file in
the digest-pinned Python image with an exact pip-tools version. Release images
install it with both --require-hashes and --only-binary=:all:.
The code-generation, documentation, and security entrypoints also inspect host tool versions before execution: Buf 1.72.0, sqlc v1.31.1, Zensical 0.0.65, gosec module v2.28.0, and govulncheck module v1.6.0. Fixture tests independently prove that each unreviewed version fails before the tool can operate.
make docs-build is the one strict documentation build path used by local CI,
the hosted infrastructure/documentation job, and GitHub Pages. make docs
remains a convenience alias. The Pages workflow uploads the same ignored
site/ directory produced locally rather than maintaining another build
recipe.
The hosted browser job independently starts MariaDB and sets
SCRIBE_REQUIRE_BROWSER_BACKEND=true; it cannot silently select in-browser
persistence. The CI workflow no longer runs separately on main because the
production workflow invokes the same reusable jobs for that SHA. Pull requests
still run the direct CI workflow, and same-repository previews run the same gate
before any image build or credentialed deployment. Preview head images are
built and smoked as credential-free OCI artifacts; a protected publisher job
is the first step allowed to authenticate to the registry and it never executes
the pull-request checkout.
The backend jobs likewise set SCRIBE_REQUIRE_TEST_DB=true; failure to resolve
the isolated Compose database is a gate failure rather than a unit-only pass.
The full Go suite owns required DB acceptance coverage, while make e2e-smoke
is the focused subset for local ingest/revision iteration and is not rerun in
the same required job.
make test-browser runs Chromium against a Vite harness that imports the
production editor shell, OpenSeadragon geometry functions, editor-session
reducer, annotation adapter, and a fully mounted Mirador/Scribe viewer with a
two-Canvas IIIF fixture. It covers dialog focus/keyboard routing,
offset/scroll/zoom coordinate conversion, dirty-draft background rebasing, and
save/reload/revision-conflict behavior, editable shortcut safety, and active
Canvas event/persistence routing. The standalone persistence fixture is an
in-browser CAS service for fast iteration. In make ci, Playwright instead calls the
generated Connect client through Vite's production proxy configuration and a
real handler backed by the isolated MariaDB project; CI requires that boundary
and fails if it is unavailable. Tenant isolation, ingestion, and job recovery
remain covered by their focused integration and smoke suites.
On an empty Go module cache, compiling the browser fixture can take longer than
the editor scenarios themselves. ci/test-browser.sh therefore waits up to 600
seconds for the fixture by default. Set
SCRIBE_BROWSER_BACKEND_READY_TIMEOUT_SECONDS to an integer from 30 through
900 when a slower or faster runner needs a different bounded startup budget.
make backup-restore-smoke creates isolated source and restore databases plus
blob volumes, migrates the source through the real embedded migrator, restores
the ledger, dump, and upload archive, reruns migration validation, verifies
canonical IIIF and derived-index integrity, checks the blob hash, and confirms
expired job leases recover. Its temporary containers, network, volumes, and
files are removed by an exit trap.
go test ./internal/ocrimages checks the OCR image matrix built from
config/ocr.yaml: every service is emitted with the right baked model, service
names match Terraform's, and invalid catalogs (missing artifacts, unknown
defaults, colliding default filenames, mutable bases, reserved IDs) are
rejected. make ocr-build-tags runs the Kraken installer behavior plus the
default, remoteocr, and localocr Go build combinations. The installer proves
that a matching model digest is accepted and a tampered artifact is rejected
before the file can be copied into the runtime image.
make toolchain-check keeps .go-version, .nvmrc, .tool-versions, Docker
bases, test images, and workflow Terraform versions aligned. make
frontend-image-smoke starts the packaged frontend read-only and fetches its
static application, so an omitted COPY input fails before deployment. make
readiness-fixture-test proves the OCR readiness probe's embedded image matches
the committed deterministic PNG.
Deployment checks¶
Every apply executes finite Scribe and Triplet schema jobs before creating new Cloud Run service revisions. The backend readiness job checks API and worker HTTPS readiness, the immutable deployed API image, and canonical origin. The OCR readiness job sends a real image through the private registered model endpoints. Failed migrations or readiness executions fail deployment.
make generate consumes the reviewed dependency commits in proto/buf.lock.
To upgrade a Buf module deliberately, run cd proto && ../.tools/bin/buf dep
update ., review the lock diff, then regenerate; CI never floats that lock on
its own.
Managed database acceptance is make test-mysql. It runs the full Go suite
against digest-pinned MySQL 8.4 with the deployed Unicode collation, alongside
the local MariaDB contract. Recovery smoke uses the same MySQL family and
verifies migration-ledger, canonical/publication, and expired-lease recovery.