Build and verify the repository
Run commands from the repository root unless a code block changes directory.
You need Go 1.27 or newer (all modules and go.work declare 1.27), Node.js
20 or newer, npm, and network access to download locked dependencies.
Python 3.9+ is used by the documentation checker and package examples. Docker is
optional for images and the MariaDB integration fixture. A local build does not
need a Kubernetes cluster or production credentials.
Go workspace
There are three independent Go modules, wired by root go.work: controller,
frontend and CMS. The repository root is not itself a Go module; do not assume
go test ./... at the root tests them all. These commands use workspace-aware
module patterns and do not change the current directory:
gofmt -l controller frontend cms
go vet ./controller/... ./frontend/... ./cms/...
go test ./controller/... ./frontend/... ./cms/...
go build ./controller/... ./frontend/... ./cms/...
gofmt -l must print nothing; its exit status alone does not signal formatting
violations. For a CI-style failing format check in a POSIX shell:
test -z "$(gofmt -l controller frontend cms)"
Tests cover generated resources/schema validation, file serving, authentication,
CSRF, storage durability, rendering and publication. Ordinary tests use fixtures
and do not apply Kubernetes resources or contact a production IdP. Browser and
real-database integration tests are opt-in below. go vet performs static
checks; go build compiles; neither replaces go test.
All modules are present in this repository. GOWORK=off is useful only when
intentionally testing one module in isolation; it is not required to work around
an absent CMS module. Do not run go mod tidy just to test a documentation change:
it edits dependency files and is intended for dependency maintenance.
Editor dependencies and bundle
(cd cms/editor && npm ci && npm test && npm audit --audit-level=high && npm run build)
npm ci installs exactly the committed lockfile and recreates node_modules.
Unit tests use Node's test runner/jsdom. Audit contacts the registry; a network
failure is different from a reported vulnerability. The build writes ignored
cms/editor/dist/ static assets. It does not start a CMS or package an image.
There is no Node.js runtime in production.
Browser integration
Install a compatible Chrome/Chromium executable, then run:
(cd cms/editor && BROWSER_PATH=/usr/bin/chromium npm run test:browser)
Use your actual executable path. The command builds the editor, sets
VIKING_BROWSER_TEST=1 and runs the Go API browser tests. playwright-core does
not itself install a browser. Without an override, the harness looks for local
Chrome or a Playwright-installed Chromium. Missing prerequisites can skip browser
tests: verify the output shows execution, not only a successful process exit.
The harness starts temporary projects and loopback servers. It checks actual rendered previews, media, themes, packages, publication and session recovery under the CMS CSP. Identity is a test fixture; these tests do not exercise a real provider's account/login configuration. See editor internals.
TestAuthoringBrowser seeds 50 Markdown articles and 50 media assets, uses a
theme without navigation, and checks page switches, current theme titles, saved
source and one shell request per switch/save. It logs observed browser timings
without imposing machine-dependent performance thresholds.
TestGalleriesBrowser installs all four gallery ZIPs, inserts their blocks,
changes properties and checks save/reload, opaque previews and publication.
It exercises both loop boundaries, autoplay/pause, keyboard controls, reduced
motion, responsive columns, small/empty collections and a JavaScript-disabled
fallback. Repository checkouts use the real example manifests; standalone CMS
Docker contexts use small fixture packages for the same runtime contract.
For backend scaling measurements, run from repository root:
go test -run '^$' -bench '^BenchmarkAuthoringSite$' -benchtime=8x -count=1 ./cms/internal/api
This compares page reads, ordinary saves and theme-shell rendering at 1, 50 and 200 Markdown pages with one media asset per page. Temporary directories use the host's temporary filesystem. Results there do not establish latency on a replicated CSI volume: measure that storage separately, including metadata operations, synchronization latency and CMS CPU throttling.
TestBlogBrowser installs the Blog ZIP, converts Markdown and HTML pages, checks
creator/time fields, URI validation, field blocks and Blog-only repeaters, then
publishes and visits the resolved URL. Its manifest fixture lives under
cms/editor/test/fixtures so standalone editor/CMS Docker contexts work; the
editor tests compare it with the example package when repository sources exist.
WordPress database integration
From the root, with Docker running and permission to use it:
scripts/test-wordpress-mysql.sh
This pulls mariadb:11, starts a disposable container on a dynamically allocated
loopback port, seeds test tables, reduces the fixture user's access to SELECT,
and runs the MySQL integration test. It removes the container on exit and mounts
no host data. It needs image-download access; it does not connect to your own
WordPress database.
Container builds include verification
From repository root, with Docker running:
docker build -f controller/Dockerfile --build-arg VERSION=local-check -t viking-cms-controller:local .
docker build --build-arg VERSION=local-check -t viking-cms-frontend:local frontend
docker build --build-arg VERSION=local-check -t viking-cms-cms:local cms
Frontend/CMS contexts are their module directories. Controller uses repository
root context so its tests can compare the actual deploy CRD/RBAC copies with
canonical manifests. Root/Dockerfile-specific ignore rules exclude generated
assets/dependencies. Every Dockerfile
runs format/vet/Go tests inside the same builder that compiles its binary, after
a single cached go mod download. Vet, tests and final compilation reuse Go's
module and compilation caches. GOFLAGS=-trimpath keeps verification and
final compilation flags aligned so library builds can be reused. Test failures
prevent image output. A cached
verification layer is reused only when its input source/dependencies are unchanged.
The CMS has a Node 20 editor stage using locked npm ci, unit tests, high-severity
audit and Vite build. Its Go 1.27 Debian builder receives that bundle/dependencies
and Node, installs Chromium, and runs all Go tests with browser integration
enabled. No separate CI artifact or prebuilt host dist directory is needed.
There is no Docker fallback to the placeholder UI. This builder uses Debian for
browser compatibility; frontend/controller builders continue to use Alpine.
Toolchains/Chromium/Node do not enter the scratch runtime.
All runtime binaries are static with CGO disabled, user 65532:65532. CMS/controller
include CA certificates for outbound TLS. Builds need network access to image
registries, module/npm sources, audit and the CMS builder's APT packages.
VERSION stamps internal/buildinfo.Version; without stamping it is dev.
Multi-architecture publication depends on the inherited template/platform;
Go verification executes for the builder's native architecture, then the frontend
binary honors TARGETARCH when supplied.
For plugins/themes, scripts/build-examples.sh builds all language toolchains,
packages and verifies actual CMS installation/rendering/publication. Its scratch
output is an artifact carrier, not a deployed server image. See
examples for individual build scripts and registry distribution.
GitLab pipeline
.gitlab-ci.yml extends the TLSPU container build/manifest
template for each component; the builds themselves enforce application tests.
The former controller/frontend/CMS/editor/browser test jobs and editor artifact
handoff are removed. The test stage remains only for independent GitLab security
analyzers, not duplicate application verification.
The build-stage example-packages job builds the example plugins and themes,
verifies them through the CMS, then uses TLSPU's
/templates/generic-repo/publish.yaml to upload the ZIPs to the project's generic
registry. It also retains job artifacts for a week. See
registry naming and variables.
The tag-only documentation-publish job runs in the publish stage. It composes
the Viking authentication, optional Markdown preparation, branch deletion,
upload and publication fragments from /templates/viking/template.yaml.
VIKING_FILES selects docs, screenshots and contributing. Preparation stages
copies with URI-safe filenames, rewrites page/image links and updates the upload
file list without making HTTP requests. Upload sends screenshots as normal media
assets and creates hidden named image objects; for example,
screenshots/Viking-CMS_in_action.png serves its PNG bytes at
/screenshots/Viking-CMS_in_action.png. Markdown uses these named URLs instead
of asset-ID URLs. Preparation preserves source
files, code examples and Markdown format. Links to unselected repository files
point to the tagged commit's source browser. Markdown README files publish at
their containing directory: docs/README.md becomes /docs/,
docs/user/README.md becomes /docs/user/, and screenshots/README.md becomes
/screenshots/. Links to these files and directories use the same URLs, retaining
queries and section fragments. Staged files remain Markdown.
Preparation validates local destinations and section fragments before deletion.
The job lists pages and deletes only URI descendants beneath /screenshots,
/docs and /contributing, preserving their landing/index pages and all other draft paths. It then
uploads staged content with menu visibility disabled and publishes the whole
site's saved drafts. Hidden child pages remain available to dynamic indexes.
Uploading the selected README files replaces the /docs, /screenshots and /contributing
landing pages and hides them from menus, just like the other uploads. A landing
page keeps its content and menu settings when its README is excluded from the
selection. Individual descendant deletions are separate
requests; an error stops the job before publication but can leave partial draft
changes. Saved changes elsewhere are also included in the whole-site publication.
The fixed resource group serializes documentation jobs. Configure the Ipseity
inputs and VIKING_URL as CI variables; none of their values belong in YAML.
The shared template changes must be available in tlspu/ci-utils before running
the job. The live CMS needs named image publication (object.publishImage) and
the Markdown heading-ID renderer for section links. Deploy the updated CMS before
using these templates; building a container does not deploy it automatically.
The shared templates are referenced without ref pins in this checkout, so inherited publishing behaviour lives outside this repository. Enabled security includes SAST, dependency scanning and secret detection. Container scanning is commented out; SBOM/provenance are planned. Inspect actual pipeline results. Local builds/checks do not upload, push, tag or deploy by themselves.
Documentation-only verification
python3 scripts/check-docs.py
git diff --check
The checker validates local Markdown links/anchors and every docs directory's direct-child index. Read documentation conventions before adding or relocating a page. Application/browser tests are not necessary for pure prose/link edits unless code or executable examples are also changed.
