tls.acme names the certificate and jarl: the Jarl server and a token that may only write the challenge record. Steward gets the certificate with DNS-01 (lego), writing the record through Jarl's API into every view that has the zone, renews it with a third of its lifetime left and swaps it in without a restart. A check runs before every order: Jarl, the zone, the token's permission, a test record, the zone's name servers, public resolvers, clean-up; each step says what to fix. Staging by default. With a certificate, each listener serves HTTPS and plain HTTP on one port (redirecting plain HTTP, except from the server itself). steward cert / cert check / cert renew, Server -> Certificate in the web UI, GET /certificate, POST /certificate/check|renew. docs/certificates.md and docs/jarl.md (the Jarl user and the token's grant). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
49 lines
1.7 KiB
Go
49 lines
1.7 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestExampleIsTheDefaults(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "steward.yaml")
|
|
os.WriteFile(path, []byte(Example), 0o644)
|
|
c, err := Load(path, false)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !reflect.DeepEqual(c, Default()) {
|
|
t.Errorf("example differs from the defaults:\n%+v\n%+v", c, Default())
|
|
}
|
|
}
|
|
|
|
func TestErrors(t *testing.T) {
|
|
cases := map[string]string{
|
|
"listen: []": "listen",
|
|
"database: relative.db": "database",
|
|
"session: {cookie_secure: x}": "cookie_secure",
|
|
"tls: {cert_file: /a}": "tls",
|
|
"no_such_setting: 1": "no_such_setting",
|
|
"backup: {retention: 3x}": "duration",
|
|
"tls: {acme: {domain: dhcp.example.com}}": "needs Jarl",
|
|
"jarl: {server: https://dns.example.com}": "token or token_file",
|
|
"jarl: {server: dns.example.com, token: x}": "Jarl's URL",
|
|
"{tls: {cert_file: /a, key_file: /b, acme: {domain: d.example.com}}, jarl: {server: https://j, token: x}}": "can't both",
|
|
"{tls: {acme: {domain: '*.example.com'}}, jarl: {server: https://j, token: x}}": "full name",
|
|
"{tls: {acme: {domain: d.example.com, directory: http://x}}, jarl: {server: https://j, token: x}}": "https://",
|
|
}
|
|
for yml, want := range cases {
|
|
path := filepath.Join(t.TempDir(), "s.yaml")
|
|
os.WriteFile(path, []byte(yml), 0o644)
|
|
if _, err := Load(path, false); err == nil || !strings.Contains(err.Error(), want) {
|
|
t.Errorf("%q: %v", yml, err)
|
|
}
|
|
}
|
|
if _, err := Load("/nonexistent/steward.yaml", true); err != nil {
|
|
t.Errorf("missing file allowed: %v", err)
|
|
}
|
|
}
|