CalDAV and CardDAV checkers sharing a single Go module. Discovery follows RFC 6764 (/.well-known + SRV/TXT), authenticated probes cover principal, home-set, collections and a minimal REPORT query on top of go-webdav. Common shape in internal/dav/; CalDAV adds a scheduling rule. Surfaces its context URL (and each secure-SRV target) as TLS endpoints via the EndpointDiscoverer interface, so the dedicated TLS checker can pick them up without re-parsing observations. HTML report foregrounds common misconfigs (well-known returning 200, missing SRV, plaintext-only SRV, missing DAV capability, skipped auth phase) as action-item callouts before the full phase breakdown.
82 lines
2.7 KiB
Go
82 lines
2.7 KiB
Go
package dav
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
sdk "git.happydns.org/checker-sdk-go/checker"
|
|
)
|
|
|
|
func relatedFrom(t *testing.T, payload any) sdk.RelatedObservation {
|
|
t.Helper()
|
|
b, err := json.Marshal(payload)
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
return sdk.RelatedObservation{Key: TLSRelatedKey, Data: b}
|
|
}
|
|
|
|
func TestFoldTLSRelated_expiringCertProducesCallout(t *testing.T) {
|
|
exp := time.Now().Add(5 * 24 * time.Hour)
|
|
related := []sdk.RelatedObservation{relatedFrom(t, map[string]any{
|
|
"host": "dav.example.com",
|
|
"port": 443,
|
|
"not_after": exp,
|
|
})}
|
|
sums, callouts := foldTLSRelated(related)
|
|
|
|
if len(sums) != 1 || sums[0].Address != "dav.example.com:443" || sums[0].Status != "warn" {
|
|
t.Fatalf("summary: %+v", sums)
|
|
}
|
|
if len(callouts) != 1 || callouts[0].Severity != "warn" {
|
|
t.Fatalf("expected a warn callout, got %+v", callouts)
|
|
}
|
|
if !strings.Contains(callouts[0].Title, "expires in") {
|
|
t.Errorf("callout title: %q", callouts[0].Title)
|
|
}
|
|
}
|
|
|
|
func TestFoldTLSRelated_expiredCertCrit(t *testing.T) {
|
|
exp := time.Now().Add(-2 * 24 * time.Hour)
|
|
_, callouts := foldTLSRelated([]sdk.RelatedObservation{relatedFrom(t, map[string]any{
|
|
"host": "dav.example.com", "port": 443, "not_after": exp,
|
|
})})
|
|
if len(callouts) != 1 || callouts[0].Severity != "crit" {
|
|
t.Fatalf("expected crit for expired cert, got %+v", callouts)
|
|
}
|
|
}
|
|
|
|
func TestFoldTLSRelated_chainInvalid(t *testing.T) {
|
|
_, callouts := foldTLSRelated([]sdk.RelatedObservation{relatedFrom(t, map[string]any{
|
|
"host": "dav.example.com", "port": 443, "chain_valid": false,
|
|
})})
|
|
if len(callouts) != 1 || callouts[0].Severity != "crit" {
|
|
t.Fatalf("expected crit for broken chain, got %+v", callouts)
|
|
}
|
|
}
|
|
|
|
func TestFoldTLSRelated_explicitIssueWinsOverFlags(t *testing.T) {
|
|
_, callouts := foldTLSRelated([]sdk.RelatedObservation{relatedFrom(t, map[string]any{
|
|
"host": "dav.example.com", "port": 443,
|
|
"chain_valid": false, // would normally synthesize a callout
|
|
"issues": []map[string]any{
|
|
{"code": "weak_cipher", "severity": "warn", "message": "TLS 1.0 offered", "fix": "disable TLS <1.2"},
|
|
},
|
|
})})
|
|
// When explicit issues exist, we do not also emit synthesized callouts;
|
|
// the TLS checker is the source of truth for severity and wording.
|
|
if len(callouts) != 1 || callouts[0].Severity != "warn" {
|
|
t.Fatalf("want single warn callout, got %+v", callouts)
|
|
}
|
|
if !strings.Contains(callouts[0].Body, "disable TLS") {
|
|
t.Errorf("fix text lost: %q", callouts[0].Body)
|
|
}
|
|
}
|
|
|
|
func TestFoldTLSRelated_empty(t *testing.T) {
|
|
if sums, callouts := foldTLSRelated(nil); sums != nil || callouts != nil {
|
|
t.Errorf("expected nil,nil on nil input, got %+v %+v", sums, callouts)
|
|
}
|
|
}
|