Skip to content

feat: add tests and CI, and remove the module template scaffolding - #7

Merged
engels74 merged 9 commits into
masterfrom
feat/tests-ci-and-caddyfile-cleanup
Aug 21, 2026
Merged

feat: add tests and CI, and remove the module template scaffolding#7
engels74 merged 9 commits into
masterfrom
feat/tests-ci-and-caddyfile-cleanup

Conversation

@engels74

Copy link
Copy Markdown
Collaborator

Summary

Removes the caddy-dns template scaffolding this module still shipped, adds the
tests and CI it had none of, and expands the documentation. Structure follows
caddy-dns/cloudflare.

Template scaffolding

The module still carried the template's placeholder comments, including three
// TODO: This is just an example markers and, on the UnmarshalCaddyfile doc
comment, the line:

**THIS IS JUST AN EXAMPLE AND NEEDS TO BE CUSTOMIZED.**

That doc comment is published verbatim on pkg.go.dev, so it was the first thing
a prospective user read about configuring the module.

Caddyfile parsing

Restructured along the lines of caddy-dns/cloudflare: the directive name is
consumed once rather than in a loop, and the inline and block forms are now
mutually exclusive rather than partially overlapping. Both supported syntaxes
are unchanged from a user's point of view:

tls {
	dns njalla {env.NJALLA_API_TOKEN}
}
tls {
	dns njalla {
		api_token {env.NJALLA_API_TOKEN}
	}
}

Provision now reports an empty API token instead of passing it through. A
placeholder such as {env.NJALLA_API_TOKEN} resolves to an empty string when
the variable is not set in the process running Caddy, which otherwise surfaces
much later as an authentication failure against the Njalla API. This is a
common cause of confusion when Caddy runs under systemd, which does not inherit
the invoking shell's environment.

No token format validation is included. caddy-dns/cloudflare can do this because
Cloudflare's token formats are documented; Njalla publishes no such format, and
guessing a pattern risks rejecting valid tokens.

Tests

The module previously had none. The new tests cover both Caddyfile syntaxes,
the argument and subdirective error paths, placeholder resolution during
provisioning, the empty-token rejection, and module registration.

CI

Three jobs:

  • formatting, go vet, and race-enabled tests;
  • an xcaddy build that asserts dns.providers.njalla appears in
    caddy list-modules, which a plain package build does not prove;
  • a Docker image build.

Docker

Adds a Dockerfile mirroring the one in caddy-dns/cloudflare, building Caddy
with this module via xcaddy. It builds an image locally and CI builds it on
every run so it cannot rot. Publishing to a registry is deliberately not
configured here, since that is an organisation-level decision; caddy-dns/
cloudflare does publish to GHCR on tags, and the same could be added later if
wanted.

Documentation

Adds Caddyfile examples alongside the existing JSON one, including the global
acme_dns form, and covers building with xcaddy or Docker.

Documents Njalla's ACME token option, which grants exactly the permissions the
DNS-01 challenge needs, and adds troubleshooting notes for the two failure modes
reported in this repository: the build error in #5 and the DNS challenge cleanup
failure in #6.

Validation

go vet ./...          clean
go test -race ./...   ok
gofmt -l .            clean

Built with xcaddy against Caddy v2.11.4; dns.providers.njalla registers, and
caddy adapt produces the expected TLS automation policy for both Caddyfile
syntaxes while rejecting an unknown subdirective with a clear message.

Also built with libdns/njalla#6 applied, confirming the updated provider links
and registers correctly.

Follow-up

This PR does not change go.mod. The module currently pins libdns/njalla at a
2025 commit pseudo-version, because that repository has never been tagged. Once
libdns/njalla#6 merges and a release is tagged, a follow-up should bump this
dependency to that version, which is what delivers the DNS challenge cleanup fix
tracked in #6 here.

The module still carried the caddy-dns template's placeholder comments,
including "THIS IS JUST AN EXAMPLE AND NEEDS TO BE CUSTOMIZED" on the
UnmarshalCaddyfile doc comment, which is published on pkg.go.dev.

The parser is restructured along the lines of caddy-dns/cloudflare: the
directive name is consumed once, and the inline and block forms are
mutually exclusive rather than partially overlapping.

Provision now reports an empty API token instead of letting it through.
A placeholder such as {env.NJALLA_API_TOKEN} resolves to an empty string
when the variable is unset, which otherwise surfaces much later as an
authentication failure.

Claude-Session: https://claude.ai/code/session_014sP5zuZiTmWEzSvL6JxaTZ
The module had no tests. These cover both supported syntaxes, the
argument and subdirective errors, placeholder resolution, and the module
registration itself.

Claude-Session: https://claude.ai/code/session_014sP5zuZiTmWEzSvL6JxaTZ
Mirrors the one in caddy-dns/cloudflare, building Caddy with this module
via xcaddy. It builds an image locally; no registry publishing is
configured.

Claude-Session: https://claude.ai/code/session_014sP5zuZiTmWEzSvL6JxaTZ
Checks formatting, vet, and race-enabled tests. A separate job builds
Caddy with the module through xcaddy and asserts that
dns.providers.njalla is registered, which a plain package build does not
prove. A third job builds the Docker image so it cannot rot; it does not
publish.

Claude-Session: https://claude.ai/code/session_014sP5zuZiTmWEzSvL6JxaTZ
Adds Caddyfile examples alongside the existing JSON one, including the
global acme_dns form, and explains building with xcaddy or Docker.

Documents Njalla's ACME token option, which grants exactly the
permissions the DNS challenge needs, and adds troubleshooting notes for
the failure modes seen in #5 and #6.

Claude-Session: https://claude.ai/code/session_014sP5zuZiTmWEzSvL6JxaTZ
Restructured into Install, Authentication, Usage, Troubleshooting, and
Testing, matching the layout used in libdns/njalla so the two read as a
pair.

Troubleshooting becomes a symptom-to-cause table, and the Caddyfile
examples are ordered per-site, global, then the block form. Every
Caddyfile snippet in the file adapts cleanly against Caddy v2.11.4.

Also removed the AI writing tells the text had picked up: three em
dashes, adverbs, and passive constructions.

Claude-Session: https://claude.ai/code/session_014sP5zuZiTmWEzSvL6JxaTZ
"Issue for the Njalla domain" read as a noun. Reworded so the
instruction is unambiguous.

Claude-Session: https://claude.ai/code/session_014sP5zuZiTmWEzSvL6JxaTZ
The restructured parser consumed the inline argument and then returned
without reading the block, so a config specifying both silently used the
argument and discarded the block. The previous parser rejected this.

Both forms are still accepted on their own; supplying both now reports
the ambiguity.

Claude-Session: https://claude.ai/code/session_014sP5zuZiTmWEzSvL6JxaTZ
Replaces the 2025 commit pseudo-version with the first tagged release,
which carries the corrected SetRecords and DeleteRecords behaviour.

DeleteRecords no longer lists records to find the one to remove, so the
ACME DNS-01 challenge cleans up correctly with a token scoped to the
_acme-challenge prefix. That is the failure reported in #6.

Claude-Session: https://claude.ai/code/session_014sP5zuZiTmWEzSvL6JxaTZ
@engels74
engels74 merged commit c586dc9 into master Aug 21, 2026
3 checks passed
@engels74
engels74 deleted the feat/tests-ci-and-caddyfile-cleanup branch August 21, 2026 18:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant