gonemaster architecture
Last reviewed: 2026-05-17.
1. System overview
gonemaster tests DNS zones for delegation, configuration, and
protocol problems. A test run executes a fixed suite of testcases
against a zone and emits a structured stream of findings; each
finding carries a severity, a tag, and machine-readable arguments.
Findings aggregate into a numeric score and letter grade. The engine
is exposed through four surfaces: a local CLI (gonemaster), a
Nagios-compatible probe (gonemaster-nagios), an HTTP service with
embedded web UIs (gonemaster-server), and a CLI client for that
service (gonemaster-client).
[gonemaster] [gonemaster-nagios] [gonemaster-client]
| | |
| | | HTTP
| | v
| | [gonemaster-server] <--> [Database]
| | |
+------------------+---------------------+
|
v
[engine] --> [DNS]Each binary instantiates its own engine. The engine itself has no shared state across binaries.
2. Component map
gonemaster ships four binaries and three web UIs. The UIs are built
to static assets and embedded into gonemaster-server with
go:embed.
Binaries
| Binary | Source | Role | External I/O |
|---|---|---|---|
gonemaster | cmd/gonemaster/ | Local CLI test runner. Runs the engine in-process. | DNS; local files (cache, profile). |
gonemaster-server | cmd/gonemaster-server/ | HTTP service. Admin and public APIs, job queue, persistence, embedded UIs. | DNS; configured database. |
gonemaster-client | cmd/gonemaster-client/ | CLI client for the admin API. | gonemaster-server. |
gonemaster-nagios | cmd/gonemaster-nagios/ | Nagios-compatible probe. Runs the engine in-process and exits with a Nagios status code. | DNS. |
gonemaster, gonemaster-nagios, and gonemaster-server are
self-contained: each can run without the others. gonemaster-client
requires gonemaster-server.
Embedded UIs
gonemaster-server serves three independent Svelte 5 + Vite
frontends.
| UI | Source | Mount | Audience |
|---|---|---|---|
| Admin | ui/ | / | Trusted operators. Job, batch, domain, tag, cohort, and settings management. |
| Public | ui-public/ | /public/ | Internet users. Single-domain test page. |
| Analysis | analysis-ui/ | /analysis/ | Internet users. Read-only cohort dashboards. |
Build tags:
noguidrops all three UIs. API routes are unaffected; UI routes return404 ui not available.badkeys_embedembeds the badkeys blocklist into the binary.
HTTP surfaces
| Path | API | Audience |
|---|---|---|
/ | - | Admin UI. |
/api/v1/ | Admin | gonemaster-client, admin UI, scripts. |
/public/ | - | Public UI. |
/analysis/ | - | Analysis UI. |
/pub/api/v1/ | Public | Internet-facing. Rate-limited; scoped to public jobs and analysis reads. |
/ and /api/v1/ have no built-in authentication. Deployments
restrict them to a trusted network or place them behind a
reverse-proxy auth layer. /public/, /analysis/, and
/pub/api/v1/ are designed for direct internet exposure behind a
rate-limiting reverse proxy.
Further reading: docs/cli/ , docs/server/ , docs/client/ , docs/nagios.md , docs/analysis/ .
3. Request lifecycles
Three concrete flows through gonemaster-server, each shown as the
ordered steps between HTTP entry and terminal state.
3.1. Single-domain test (public API)
Entry: POST /pub/api/v1/jobs β handlePublicCreateJob
(server/handlers_public.go
).
- Validate and normalize the domain.
- Create an in-memory
Jobwithstatus=JobQueued. - Persist the job via
Store.Create. - Enqueue at
PriorityNormalviaQueue.Enqueue. - A worker dequeues, acquires the engine concurrency limiter, and
transitions the job to
JobRunning(server/worker.go ). - Worker calls
engine.Run, thenStore.GraduateJob, which writes aRunrow and itsEntriesand deletes theJobrow.
State: JobQueued β JobRunning β JobSucceeded (or JobFailed,
JobCanceled).
Result fetch: GET /pub/api/v1/jobs/{publicID}/result reads either
the still-queued Job or the graduated Run and its Entries.
3.2. Batch submission (admin API)
Entry: POST /api/v1/jobs/batch β handleJobsBatch
(server/handlers.go
).
- Resolve the domain list directly or via a
from_taglookup. - Create one
Jobper domain, sharing aBatchIDandPriority=PriorityBatch. - Persist all jobs; enqueue each at
PriorityBatch. - Persist a
Batchrow recordingDomainCountand metadata. - Workers consume the batch tier only after the normal tier is empty (server/queue.go ).
- Each batch job follows the same
runJobβengine.RunβGraduateJobpath as a single-domain test.
State per job: JobQueued β JobRunning β JobSucceeded. A batch
completes when every job graduates.
Poll: GET /api/v1/batches/{id} aggregates the in-flight Jobs
and the graduated Runs for the batch to produce counts and the
grade distribution.
3.3. Cohort snapshot read (public API)
Entry: GET /pub/api/v1/analysis/cohorts/{tag}/snapshots/{slug}/overview
β handlePublicAnalysisOverview
(server/handlers_public_analysis.go
).
- Resolve the public cohort by source tag.
- Resolve the snapshot by slug, or fall back to the cohort’s default snapshot.
- Reject the request unless the snapshot has
Status=CapturedandIsPublic=true. - Read the pre-aggregated row from
analysis_snapshot_overviewsviaStore.GetSnapshotOverview. - Return the aggregated payload with cache headers: immutable
max-age=1yfor an explicitly named captured snapshot,no-cache, must-revalidatefor default-snapshot resolution.
Snapshot population is upstream of this read: batch jobs graduate
into Runs, the worker projects each run into fact tables via
analysis.ProjectRun, and a periodic loop materializes overview
rows via analysis.CaptureCompletedSnapshots.
Further reading: docs/server/ , docs/analysis/ .
4. Data model
gonemaster-server stores two layers of persistent entities. Both
are defined in server/models.go
and persisted
across backends through the Store interface.
Core entities
| Entity | Purpose | Cardinality |
|---|---|---|
Job | In-flight or queued test request. Graduates into a Run when complete. | Many per domain over time. |
Run | Immutable record of a completed test. Carries score, grade, and severity totals. | One per completed Job. |
Entry | One log line emitted during a run; has severity, tag, module, testcase, and JSON args. | Many per Run. |
Domain | Persistent domain registry. Stores the latest run’s denormalized result so common filters do not scan all historical runs. | One per distinct tested domain. |
Tag | User-defined domain collection. Many-to-many with Domain. | One per collection. |
Batch | Metadata for one batch submission. Groups its Jobs (and later their Runs) by a shared BatchID. | One per batch submission. |
Profile | Named server-stored test configuration. Referenced by Job and Run via ProfileID. | Many per server. |
Domain and Tag records are shared metadata, not owned by any one
batch. Deleting a batch does not remove the domains it tested.
Analysis layer
A second layer sits above Run for cohort analysis.
| Entity | Purpose | Cardinality |
|---|---|---|
AnalysisCohort | Admin overlay on one source Tag: label, public/analysis flags, default snapshot, sort order. | One per published cohort. |
AnalysisCohortSnapshot | Point-in-time view of a cohort, backed by exactly one snapshot-intent Batch. | Many per cohort. |
analysis_run_* projections | Per-run facts (domain summary, tags, nameservers, addresses, ASNs, prefixes), materialized into each cohort by analysis.ProjectRun. | Many per (run, cohort). |
analysis_snapshot_* views | Per-snapshot pre-aggregated rows, materialized by analysis.CaptureCompletedSnapshots. Public read paths serve these directly. | Many per snapshot. |
Projection and snapshot capture are read-optimized materializations: per-run projection lets cohort listings avoid scanning entries; snapshot capture lets public reads avoid scanning facts.
Lifecycle
POST --> Job --graduate--> Run + Entries
|
v per (run, cohort)
analysis_run_* projections
|
v on snapshot-intent batch complete
Snapshot + analysis_snapshot_* viewsFurther reading: docs/server/database.md , docs/analysis/ .
5. Persistence backends
gonemaster-server supports four storage backends, selected at
startup with --db-driver or GONEMASTER_DB_DRIVER.
| Backend | Use when | Concurrent writes | Connection pool |
|---|---|---|---|
memory | Development, tests, short-lived scripts. State is lost on restart. | n/a | n/a |
sqlite | One server with small or medium data. | Serialized (single writer). | 1 open. |
postgres | High-volume analysis or heavy JSON-args querying. | Concurrent. | 25 open, 5 idle, 5-minute lifetime. |
mariadb | Existing MariaDB or MySQL infrastructure. | Concurrent. | 25 open, 5 idle, 5-minute lifetime. |
The three SQL drivers share schema migrations; a dialect layer (server/store_sql_dialect.go ) translates one statement template into per-driver SQL.
Startup recovery
On a persistent backend, the server performs three steps before accepting requests:
- Run pending schema migrations.
- Mark any
Jobleft inrunningstate at the last shutdown asfailed. - Re-enqueue any
Jobstill inqueuedstate.
memory skips this; the queue starts empty.
Retention
--db-retention-days N (or database.retention_days) runs an
hourly purge of terminal Job and Run rows older than N days.
0 keeps results forever. Queued, running, and paused jobs are
never purged automatically. Manual batch deletion is a separate
operation and ignores the retention window.
Further reading: docs/server/database.md , docs/server/database-setup.md .
6. Concurrency model
gonemaster-server runs tests on a fixed worker pool fed from a
two-tier priority queue. The engine itself is parallel-safe and is
the same code used by gonemaster and gonemaster-nagios.
Engine isolation
engine.Run is re-entrant. Each call constructs isolated per-run
state from its arguments; nothing is shared between concurrent runs
through global variables. A binary may call engine.Run from many
goroutines without external synchronization.
Worker pool
gonemaster-server starts WorkerCount worker goroutines on
startup (default 16,
server/config.go
). Each worker loops:
- Dequeue the next job.
- Mark the job
running; register a per-job cancel function. - Acquire the engine limiter if one is configured.
- Call
engine.Run. - Graduate the job to a
Runplus itsEntries.
Workers can be resized without restarting the server. Scaling down
cancels the last N worker contexts and they exit after their
current job (server/worker.go
).
Priority queue
The queue has two tiers (server/queue.go ):
PriorityNormal- interactive single-domain submits.PriorityBatch- batch and tag-sweep submits.
Workers always drain PriorityNormal before PriorityBatch. FIFO
within each tier. Interactive requests are not starved by an active
batch.
Engine concurrency limit
MaxConcurrentJobs caps the number of concurrent engine.Run
calls when set above zero (default 0: no extra cap; only the
worker pool bounds concurrency). Useful when the engine is
bottlenecked on something other than worker goroutines, e.g.
resolver capacity or DNS rate budgets.
Cancellation
The server keeps a map of jobID β context.CancelFunc
(server/cancel.go
). Canceling a job calls
the function, which cancels the per-run context. engine.Run
returns promptly; the worker records the terminal state as
canceled.
Further reading: docs/server/configuration.md , docs/server/performance.md .
7. Build and distribution
Build is driven by the Makefile . CI runs on Woodpecker .
Build targets
| Target | Output | Notes |
|---|---|---|
make build | All four binaries into bin/. | Builds the embedded UIs first. |
make build-gonemaster-server | bin/gonemaster-server with all three UIs embedded. | Default. Requires Node >= 20 and npm >= 9. |
make build-gonemaster-server-noui | bin/gonemaster-server without UIs. | Uses build tag nogui. |
make build-gonemaster[-server]-badkeys-embed | Variant with the badkeys blocklist baked in. | Uses build tag badkeys_embed. Downloads the blocklist via badkeys-update-embed. |
make ui-build | dist/ assets in each of server/{ui,public,analysisui}/ for go:embed. | Three independent Vite builds. |
Build tags
noguidrops all three embedded UIs. API routes are unchanged; UI routes return404 ui not available. Used when Node is not available in the build environment.badkeys_embedembeds the gzipped badkeys blocklist into the binary. Without the tag, the blocklist is read fromshare/badkeys/at runtime.
The tags compose: -tags "nogui badkeys_embed" is a valid build.
CI pipelines
.woodpecker.yml defines two pipelines.
Default pipeline (every push and pull request):
ui_checks- lint, test, and build the admin UI.spec_check- validate testcase specs; check tag catalog, log args, and i18n placeholder drift.go_test-go test ./...withGOMAXPROCS=4.integration_test- server tests against PostgreSQL 17 and MariaDB 11 services started in-pipeline.build_server_with_ui- confirmgonemaster-serverbuilds with UI embedding.deploy_pages(main branch only) - build the Hugo docs site and force-push tocodeberg.org/pawal/gonemaster:pages.
A second pipeline for release artifacts is declared in .woodpecker.yml but has not yet been exercised; see Chapter 15 .
Further reading: Makefile , .woodpecker.yml .
8. Configuration and deployment
Configuration sources
Config is applied with this precedence (later wins):
- Built-in defaults.
- JSON config file (
--config PATH). GONEMASTER_*environment variables.- Command-line flags.
gonemaster-server --dump-config prints the effective config and
exits.
Key settings
The full settings catalog lives at docs/server/configuration.md . The architecturally load-bearing sections:
| Section | Examples |
|---|---|
| Listener | listen_addr, read_timeout, write_timeout, idle_timeout, max_body_size. |
| Workers | worker_count, max_concurrent_jobs. |
| Database | database.driver, database.dsn, database.retention_days. |
| Reverse proxy | trusted_proxy_cidrs, public_url. |
| Public API | public_api.rate_limit_*, public_api.allow_private_undelegated_ip. |
| Engine defaults | profile_path, min_level, resolver overrides. |
Database DSNs belong in environment variables
(GONEMASTER_DB_DSN); everything else fits in the JSON config
file.
Deployment topologies
gonemaster-server is a single binary. It does not terminate TLS,
does not authenticate admin paths, and binds to one listener.
Single host (dev):
user -> gonemaster-server -> SQLite
Trusted network:
browser --HTTPS--> proxy --HTTP--> gonemaster-server -> Postgres/MariaDB
Internet-facing:
internet --HTTPS--> proxy --HTTP--> gonemaster-server -> DB
(proxy adds TLS, rate-limit, ACL; forwards only /public/, /analysis/, /pub/api/v1/)Reverse-proxy expectations:
- TLS terminates upstream;
gonemaster-serverspeaks plain HTTP. - The proxy sets
X-Forwarded-For;trusted_proxy_cidrslists the proxy IPs whoseX-Forwarded-Foris honored. - For internet-facing deployments, restrict
/and/api/v1/at the proxy. - Rate limiting can run at the proxy or at the server
(
public_api.rate_limit_*); they compose.
Profiles
Profile resolution has two layers:
- A process-wide base profile, built from the engine default plus
profile_path. - Stored profiles in the database. Jobs, batches, public profile dropdowns, and tag defaults reference one by ID.
Stored profiles are sparse: they record only the overrides above the base profile. Each carries the engine schema version it was last edited against; the admin UI flags profiles that need review after an engine update.
Further reading: docs/server/configuration.md , docs/server/public-api-and-proxy.md , docs/server/operations.md .
9. Security posture
Authentication
/ and /api/v1/ have no built-in authentication.
gonemaster-server expects either a reverse proxy to enforce
authentication on those routes or the listener to be bound to a
private interface. Public routes (/public/, /analysis/,
/pub/api/v1/) are designed to require no authentication.
Content Security Policy
Three CSP policies are applied per route in server/server.go :
| Route prefix | Policy summary |
|---|---|
/api/v1/, /pub/api/v1/ | default-src 'none'. API responses serve no UI; nothing should load from them. |
/analysis/ | Includes script-src 'self' 'unsafe-inline' for SvelteKit’s bootstrap script and style-src 'self' 'unsafe-hashes' sha256-... for the SvelteKit announcer. |
/, /public/, other UI/static | default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; connect-src 'self'; frame-ancestors 'none'. No 'unsafe-inline'. |
server/middleware_test.go
asserts
that the admin and public CSP must not regress to include
'unsafe-inline'. Inline style attributes and Svelte style:
directives in those UIs are CSP violations and rejected in review.
Public API restrictions
The public API (docs/server/public-api-and-proxy.md ) is shaped for safe internet exposure:
- Job lookups use opaque public IDs only; internal job and run IDs never leave the public surface.
POST /pub/api/v1/jobsacceptsprofile_idonly when the stored profile is marked public.profile_overridesare rejected: public users cannot inject arbitrary resolver settings.public_api.allow_private_undelegated_ipdefaults tofalse, blocking loopback, link-local, private, CGNAT, multicast, and broadcast IPs as undelegated NS targets.
Rate limiting
Public API rate limiting is off by default and is required for
internet exposure. Configure with public_api.rate_limit_enabled,
rate_limit_max, and rate_limit_window. The limit applies to
POST /pub/api/v1/jobs, keyed by client IP after
X-Forwarded-For resolution.
Trusted proxies
trusted_proxy_cidrs lists the CIDRs of reverse proxies allowed to
set X-Forwarded-For. The default is empty: with no trusted
proxies, the server uses RemoteAddr and ignores
X-Forwarded-For. Set this to the proxy’s IP or CIDR before
relying on rate limiting or per-client logs in a public deployment.
Secrets
Database DSNs and CI release tokens are passed via environment variables, never via the JSON config file:
GONEMASTER_DB_DSNcarries the database connection string.CODEBERG_PAGES_TOKENandCODEBERG_RELEASE_TOKENare injected into CI publish steps (.woodpecker.yml ).
There are no API keys to manage; access control to admin routes is host-level.
Supply chain
The badkeys blocklist (compromised public-key fingerprints) is updated by an explicit operator step, not as part of normal builds:
make badkeys-update # fetch into share/badkeys/
make badkeys-update-embed # additionally gzip for embedded buildsBuilds without the badkeys_embed tag read the blocklist from
share/badkeys/ at runtime. The CI pipeline does not refresh the
blocklist on its own.
Further reading: docs/server/public-api-and-proxy.md .
10. Observability
gonemaster-server exposes three observability surfaces: a health
probe, a metrics endpoint with JSON and Prometheus formats, and
standard-output logs.
Health probe
GET /api/v1/healthz -> 200 {"status": "ok"}Returns 200 unconditionally when the server is up. There is no separate readiness probe; the same endpoint serves both checks.
Metrics
GET /api/v1/metrics # JSON snapshot
GET /api/v1/metrics?format=prom # Prometheus expositionThe JSON snapshot has seven sections: health, jobs, api,
quality, insights, trends, and metadata
(schema_version, generated_at). Common fields:
health.queue_depth,health.in_flight_jobs.jobs.completed_total.quality.outcomes.{success_rate, failed_rate, failed_total}.quality.severity.totalsper severity level.trends.windows.{1h, 6h, 24h, 48h}.points[].
The Prometheus form exposes low-cardinality counters and gauges
under the gonemaster_ prefix: server gauges (build, worker
counts, queue depth, in-flight), DNS counters, job lifecycle
counters and status gauges, API request counters and latency
histograms, job-duration histograms, and locale usage.
High-cardinality data (insight tables, trend point series) and
precomputed ratios are JSON-only; Prometheus consumers derive
ratios from counters and histograms.
Both formats share a 1-second response cache keyed by query parameters.
Logs
gonemaster-server writes plain-text logs to stdout via Go’s
standard log package. Coverage includes server lifecycle, worker
and queue events, API errors, and panic recovery (with stack). Logs
are not JSON-structured.
Further reading: docs/server/metrics.md .
11. Testing strategy
Tests run at three levels: Go unit and integration tests, frontend tests, and spec-coherency checks. CI (.woodpecker.yml ) runs all of them on every commit.
Layers
| Layer | Target | Scope |
|---|---|---|
| Go unit / integration | make test-go | All Go packages, go test ./.... In-memory store by default. |
| Cross-driver integration | make test-integration | server/... tests against SQLite, PostgreSQL 17, and MariaDB 11 (Docker Compose). |
| Race detector | make race | go test -race ./.... Run periodically; not in default CI. |
| Vet | make vet | go vet ./.... |
| Admin and public UIs | make ui-test, make ui-public-test | npm test in each frontend. |
| Analysis UI | make ui-analysis-test | Run separately; not bundled into make test. |
| CSP regression | make ui-csp-check | Grep for inline style=... attributes and style: directives in admin and public UI .svelte sources. |
| Spec coherency | make spec-check | Four substeps (see below). |
make test is the canonical “did I break something” target. It
runs ui-test, ui-public-test, test-go, spec-check, and
ui-csp-check in that order.
Spec coherency
make spec-check runs four substeps; any drift is a CI failure,
not a warning:
spec-validate- canonical testcase specs match implementation metadata (name, module, severity floors).spec-check-tags- per-module tag catalog markdown files match the current tag registry.spec-check-coherency- the log-args inventory regenerated fromappendLog*call sites equals the committed one.spec-check-i18n-placeholders- i18n template placeholders are on the allowlist; no legacy placeholders sneak in.
Each substep is runnable in isolation for fix-and-recheck loops.
Cross-driver integration
make test-integration starts PostgreSQL 17 and MariaDB 11 in
Docker Compose, points the test suite at them via
TEST_POSTGRES_DSN and TEST_MARIADB_DSN, and runs the
server/... test packages against all three drivers (SQLite is
in-process and always runs). The CI pipeline mirrors this with
services declared in .woodpecker.yml
.
Further reading: docs/dev.md , docs/specifications/log-args-coherency.md .
12. Specification and i18n discipline
Testcase metadata is partially generated and CI-enforced to stay coherent with the code. This chapter summarises what is generated, where it lives, and how drift is caught.
What lives where
| Location | Contents | Source of truth |
|---|---|---|
engine/test/ | Testcase implementation: appendLog* calls, severity floors, module structure. | Runtime. |
| docs/specifications/tests/ | Per-testcase specs: algorithm, emitted tags, arguments, severity, upstream differences. | Documentation. |
| docs/specifications/tags/ | Per-module tag catalogs: each tag’s severity and i18n coverage. | Generated from code. |
| implemented-testcases.md | Authoritative list of implemented testcases. | Generated. |
| possible-tags-by-testcase.md | All possible tags per testcase. | Generated. |
| log-args-inventory.md | Every entry.args key emitted, its tag, value shape, and producer file. | Generated. |
share/lang/*.po | Gettext-style translations for log entry messages. | Manual. |
| known-intentional-gaps.md | Upstream testcases intentionally not implemented, with rationale. | Manual. |
| known-behavior-divergences.md | Behavior divergences observed during investigation. | Manual. |
Generation tools
Under tools/specifications/ and tools/i18n/ :
export-implementedrebuilds the implemented-testcases inventory.generate-tag-catalogrebuilds the per-module tag catalog markdown.export-log-argsrebuilds the log-args inventory from the engine’sappendLog*call sites.validatecross-checks canonical specs against implementation metadata.i18n/check-placeholdersvalidates that template placeholders match the allowlist.
make spec-export runs the refresh path; make spec-check runs
the verification path used by CI.
Enforcement
CI runs make spec-check on every commit
(.woodpecker.yml
). The four substeps already
listed in Chapter 11
apply: spec
validation, tag catalog drift, log-args inventory coherency, i18n
placeholder allowlist. Drift in any of them is a build failure.
After any change to appendLog*, message tags, or testcase
metadata, the change author runs make spec-check locally before
pushing.
i18n discipline
Log messages are localised through share/lang/*.po gettext-style
catalogs (da, es, fi, fr, ja, nb, sl, sv).
Templates use a fixed set of placeholders. New placeholders are
rejected unless added to the allowlist consumed by
tools/i18n/check-placeholders. This prevents one-off translator
syntax from leaking into the runtime contract.
Further reading: docs/specifications/ , docs/specifications/log-args-coherency.md .
13. IP and licensing boundary
Project license
gonemaster is released under the BSD-2-Clause license
(LICENSE
). Copyright is held by Patrik WallstrΓΆm,
the Swedish Internet Foundation, and AFNIC. The license file
records contributor copyright on incorporated upstream code.
This chapter is the public licensing boundary only. Commercial extensions, hosted-service architecture, and customer-specific integrations do not appear in this document.
Direct Go dependencies
| Module | Role |
|---|---|
codeberg.org/miekg/dns | DNS protocol library; the wire format used by the engine. |
github.com/go-sql-driver/mysql | MariaDB / MySQL driver. |
github.com/lib/pq | PostgreSQL driver. |
modernc.org/sqlite | Pure-Go SQLite driver. |
github.com/ulikunitz/xz | xz / LZMA compression for badkeys data. |
golang.org/x/{net,sync,text} | Go standard-library extensions: networking, sync, i18n / IDNA. |
All direct dependencies are permissive OSS (BSD / MIT / MPL-2.0 family). Indirect dependencies are pinned in go.sum . An authoritative third-party-license inventory is open work (see Chapter 15 ).
Frontend dependencies
The three embedded UIs are Svelte 5 + Vite projects. JavaScript dependencies are pinned per UI in ui/package-lock.json , ui-public/package-lock.json , and analysis-ui/package-lock.json . Major direct dependencies are Svelte (MIT), Vite (MIT), and SvelteKit (MIT, analysis UI only).
Data assets
| Path | Source | License / status |
|---|---|---|
share/named.root | IANA root hints. | Public-domain reference. |
share/iana-ipv*-special-registry.csv | IANA special-purpose address registries. | Public-domain reference. |
share/badkeys/ | Blocklist of compromised public-key fingerprints. Refreshed via tools/badkeys-update/ . | Inherits the upstream badkeys project licence; operator-driven refresh. |
Further reading: LICENSE , go.mod .
14. External dependencies and vendors
gonemaster depends on external infrastructure only for builds,
distribution, and runtime DNS testing. Hosting choices for any
hosted offering are not part of this document.
Runtime DNS targets
The engine performs delegation tests by querying the public DNS hierarchy directly:
- Root zone servers, enumerated in share/named.root . The file ships with the binary; operators refresh it manually when IANA publishes updates.
- TLD and authoritative servers for the zone under test.
- The operator’s local resolver, only when explicitly configured as a fallback.
No DNS data is sent to a vendor-controlled resolver as part of normal operation.
Build and CI vendors
| Vendor | Purpose |
|---|---|
| Codeberg | Source hosting (codeberg.org/pawal/gonemaster), CI (Woodpecker), docs site (Codeberg Pages). |
Go module proxy (proxy.golang.org) | Build-time fetch of Go dependencies. |
npm registry (registry.npmjs.org) | Build-time fetch of frontend dependencies. |
| Docker Hub | Build-time pulls of postgres, mariadb, golang, node, and alpine images for CI services. |
The release-artifact distribution channel is open work and not yet described here; see Chapter 15 .
Operator-driven external fetches
| Source | Mechanism | Frequency |
|---|---|---|
| badkeys blocklist | tools/badkeys-update/ | Explicit operator step. |
IANA registries (named.root, special-purpose CSVs) | Manual replacement of files in share/. | When IANA publishes updates. |
Further reading: .woodpecker.yml , go.mod .
15. Known limitations
This chapter records what is open, mitigated but not yet fixed, or shaped by pragmatic compromise.
Open engineering work
| Area | State | Reference |
|---|---|---|
| Built-in admin authentication | Not implemented. Deployments rely on a reverse proxy or network isolation. | Chapter 9 . |
| Structured (JSON) logs | Not implemented. Logs are plain text from Go’s log package. | Chapter 10 . |
| Release artifact pipeline | Declared in .woodpecker.yml
but not yet exercised; no v* tag has been published. Format, distribution channel, and signing are deferred until first release. | Chapter 7 , Chapter 14 . |
| Generated third-party-licence inventory | Not generated. Direct dependencies are known; an indirect-dependency licence report is open work. | Chapter 13 . |
Testcase coverage
| Item | State | Source of truth |
|---|---|---|
| Intentional upstream gaps | dnssec12 (scope-deferred) and nameserver14 (upstream numbering hole). | docs/specifications/known-intentional-gaps.md . |
| Behaviour divergences from upstream | Several open and tracked (zone07, nameserver13, recursor cache and bailiwick handling). | docs/specifications/known-behavior-divergences.md . |
These files are the source of truth for missing or divergent testcase behaviour.
Operational risk areas
- Public API rate limiting is off by default (Chapter 9 ). Internet-facing deployments that forget to enable it can be saturated by a single client.
trusted_proxy_cidrsdefaults to empty. Without it, per-client rate limiting and access logs key on the reverse proxy’s address, not the originating client.- No built-in backup tooling. Database backup is the operator’s responsibility; the server does not snapshot itself.
memorybackend loses in-flight jobs on restart. Use a persistent backend (SQLite, PostgreSQL, MariaDB) outside of development.
Not yet documented
Topics that warrant their own chapters as the system grows:
- Threat model. Tracked separately;
docs/security/threat-model.mdwill land alongside the next security review. - Performance benchmarks. Some operational guidance lives in docs/server/performance.md ; SLO-style numbers do not exist yet.
16. Glossary
Batch. A group of jobs submitted together, often for the domains in a tag.
Cohort. A curated public dataset backed by one source tag.
Entry. A single log line emitted during a run; carries a severity, a tag, and machine-readable arguments.
Grade. A letter (A+ through F) derived from the score.
Job. A queued test request in gonemaster-server. Graduates into
a run when complete.
Profile. A configuration document that controls engine behavior: which modules and testcases run, resolver settings, severity overrides.
Run. An immutable record of a completed test, with its entries and metadata.
Score. A numeric value from 0 to 100 derived from a run’s entries.
Severity. One of DEBUG3, DEBUG2, DEBUG, INFO, NOTICE,
WARNING, ERROR, CRITICAL.
Snapshot. An immutable view of a cohort, captured from one snapshot-intent batch.
Tag. Two unrelated namespaces. (1) In engine/ and run output:
the identifier of a kind of entry, e.g. NS_SAME_IP. (2) In the
admin UI and analysis: a user-defined named collection of domains.
Testcase. A single named test executed during a run, e.g.
dnssec01. Testcases are grouped into modules.
Further reading: docs/scoring.md , docs/analysis/ , docs/specifications/ .
17. Appendix: Directory map
Top-level directories tracked in the repository.
| Path | Contents |
|---|---|
| cmd/ | Binary entry points: gonemaster, gonemaster-server, gonemaster-client, gonemaster-nagios. |
| engine/ | DNS test engine. Parallel-safe; each engine.Run builds isolated per-run state. |
| server/ | HTTP handlers, job queue, batches, snapshots, persistence drivers. |
| scoring/ | Score and grade computation from run entries. |
| share/ | Embedded assets: default profile, named.root, IANA registries, translations, badkeys data. |
| tools/ | Code-generation and spec tooling: testcase metadata, log-args inventory, i18n placeholders, badkeys-update. |
| ui/ | Admin UI source (Svelte 5 + Vite). Embedded into gonemaster-server. |
| ui-public/ | Public UI source. Embedded. |
| analysis-ui/ | Cohort analysis UI source. Embedded. |
| site/ | Hugo source for the documentation site, using the Relearn theme. Mounts docs/ as content. |
| docs/ | User and developer documentation. Source of truth for the docs site. |
Build outputs (bin/, embedded dist/ directories) are gitignored
and not part of the source tree.