From bd75b1b566e8dc40546bd6a3b073b6193b0bc615 Mon Sep 17 00:00:00 2001 From: GermanCoding Date: Mon, 19 Jan 2026 21:32:26 +0100 Subject: [PATCH] feat: Introduce new info error, silence some known issues These days, staging quite often reports server busy errors. There's not much we can do about them. Also, status.io sometimes reports issues that do not affect issuance. Avoid alerting users too much about this, by introducing new "informational" neutral problems. --- cmd/cli/cli.go | 9 ++++++++- generic.go | 24 ++++++++++++++++++------ problem.go | 10 ++++++++++ web/db.go | 6 ++++-- web/templates/layouts/results.tpl | 11 +++++++++-- web/work.go | 19 ++++++++++++++++--- 6 files changed, 65 insertions(+), 14 deletions(-) diff --git a/cmd/cli/cli.go b/cmd/cli/cli.go index fc18f44..7f7a749 100644 --- a/cmd/cli/cli.go +++ b/cmd/cli/cli.go @@ -25,7 +25,14 @@ func main() { os.Exit(1) } - if len(probs) == 0 { + errorProbs := []letsdebug.Problem{} + for _, p := range probs { + if p.Severity != letsdebug.SeverityInfo && p.Severity != letsdebug.SeverityDebug { + errorProbs = append(errorProbs, p) + } + } + + if len(errorProbs) == 0 { fmt.Println("All OK!") return } diff --git a/generic.go b/generic.go index 7bffb1e..56fa177 100644 --- a/generic.go +++ b/generic.go @@ -7,10 +7,6 @@ import ( "encoding/pem" "encoding/xml" "errors" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" - "golang.org/x/net/idna" - "golang.org/x/text/unicode/norm" "net" "os" "regexp" @@ -18,6 +14,11 @@ import ( "strings" "sync" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "golang.org/x/net/idna" + "golang.org/x/text/unicode/norm" + "github.com/eggsampler/acme/v3" "fmt" @@ -462,7 +463,7 @@ func statusioNotOperational(status string, updated time.Time) Problem { Explanation: fmt.Sprintf(`The current status as reported by the Let's Encrypt status page is %s as at %v. `+ `Depending on the reported problem, this may affect certificate issuance. For more information, please visit the status page.`, status, updated), Detail: "https://letsencrypt.status.io/", - Severity: SeverityWarning, + Severity: SeverityInfo, } } @@ -787,12 +788,20 @@ func (c *acmeStagingChecker) Check(ctx *scanContext, domain string, method Valid authz, err := c.client.FetchAuthorization(c.account, authzURL) if err != nil { - unhandledError(err) + if p, stagingBroken := translateAcmeError(domain, err); p.Name != "" { + if stagingBroken { + stagingFailures.With(prometheus.Labels{"method": string(method)}).Inc() + } + probs = append(probs, p) + } else { + unhandledError(err) + } return } chal, ok := authz.ChallengeMap[string(method)] if !ok { + // TODO: we sometimes run into this if an authorization is reused unhandledError(fmt.Errorf("Missing challenge method (want %v): %v", method, authz.ChallengeMap)) return } @@ -830,6 +839,9 @@ func translateAcmeError(domain string, err error) (problem Problem, stagingBroke urn := strings.TrimPrefix(acmeErr.Type, "urn:ietf:params:acme:error:") switch urn { case "rejectedIdentifier", "unknownHost", "rateLimited", "caa", "dns", "connection": + if strings.Contains(acmeErr.Detail, "Service busy; retry later") { + return infoProblem("ServiceBusy", "The Let's Encrypt staging service refused our request for a test dry-run. The test outputs may not be accurate. Please retry the test at a later time.", "Let's Encrypt Staging Sever busy."), true + } // Boulder can send error:dns when _acme-challenge is NXDOMAIN, which is // equivalent to unauthorized if strings.Contains(acmeErr.Detail, "NXDOMAIN looking up TXT") { diff --git a/problem.go b/problem.go index 1a2689f..50a84ca 100644 --- a/problem.go +++ b/problem.go @@ -19,6 +19,7 @@ type Problem struct { } const ( + SeverityInfo SeverityLevel = "Info" // Represents informational messages which are not necessarily a problem. SeverityFatal SeverityLevel = "Fatal" // Represents a fatal error which will stop any further checks SeverityError SeverityLevel = "Error" SeverityWarning SeverityLevel = "Warning" @@ -73,3 +74,12 @@ func debugProblem(name, message, detail string) Problem { Severity: SeverityDebug, } } + +func infoProblem(name, message, detail string) Problem { + return Problem{ + Name: name, + Explanation: message, + Detail: detail, + Severity: SeverityInfo, + } +} diff --git a/web/db.go b/web/db.go index e55ce20..9225d0c 100644 --- a/web/db.go +++ b/web/db.go @@ -5,13 +5,14 @@ import ( "database/sql/driver" "embed" "fmt" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" "log" "sort" "strings" "time" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/lib/pq" "encoding/json" @@ -79,6 +80,7 @@ func (probs problems) Less(i, j int) bool { type resultView struct { Error string `json:"error,omitempty"` Problems problems `json:"problems,omitempty"` + IsOk bool `json:"ok"` } func (rv *resultView) Scan(src interface{}) error { diff --git a/web/templates/layouts/results.tpl b/web/templates/layouts/results.tpl index b4a7af8..09e1859 100644 --- a/web/templates/layouts/results.tpl +++ b/web/templates/layouts/results.tpl @@ -32,6 +32,10 @@ color: #eee; background: rgb(0, 77, 0); } +.problem-Info, .problem-Info a, .problem-Info a:visited { + background: lightgray; + color: black; +} .problem-Debug, .problem-Debug a, .problem-Debug a:visited { background: lightskyblue; color: black; @@ -115,7 +119,8 @@

Unfortunately something went wrong when running the test.

{{ .Test.Result.Error }}
- {{ else if not .Test.Result.Problems }} + {{ else }} + {{ if .Test.Result.IsOk }}
@@ -130,7 +135,8 @@
- {{ else }} + {{ end }} + {{ if gt (len .Test.Result.Problems) 0 }}
{{ range $index, $problem := .Test.Result.Problems }}
@@ -146,6 +152,7 @@ {{ end }}
{{ end }} + {{ end }}

Submitted {{ .Test.SubmitTime }}. {{ if .Test.QueueDuration }}Sat in queue for {{ .Test.QueueDuration }}.{{ end }} diff --git a/web/work.go b/web/work.go index 04c7881..c27a1e8 100644 --- a/web/work.go +++ b/web/work.go @@ -2,11 +2,12 @@ package web import ( "encoding/json" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" "log" "sync/atomic" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/letsdebug/letsdebug" ) @@ -56,8 +57,20 @@ func (s *server) work() { HTTPExpectResponse: req.Options.HTTPExpectResponse, HTTPRequestPath: req.Options.HTTPRequestPath, }) + isOk := false + if err == nil { + isOk = true + for _, p := range res { + if p.Severity != letsdebug.SeverityInfo && p.Severity != letsdebug.SeverityDebug { + isOk = false + break + } + } + } else { + isOk = false + } testsRun.With(prometheus.Labels{"method": string(method)}).Inc() - result := resultView{Problems: res} + result := resultView{Problems: res, IsOk: isOk} if err != nil { testsFailed.With(prometheus.Labels{"method": string(method)}).Inc() result.Error = err.Error()