Operators could see that a rate-limit cooldown was active, but not
when it ends, and failure logs omitted most of the CA problem
document. Add a until-timestamp gauge and log the full acme.Error
surface so cooldowns and ACME responses are diagnosable.
Signed-off-by: Ludovic Vielle <ludovic@probo.com>
Several race and validity gaps could leave certificate provisioning
stuck, unusable, or noisy:
- Accept the HTTP-01 challenge only after the key authorization is
committed, so the CA cannot hit the token before this instance can
serve it and invalidate the order.
- Persist challenge metadata under a blocking write-back lock; a row
merely locked by a competing transaction no longer silently drops the
accepted order.
- Abandon a recovered VALID order and restart instead of issuing it
with a freshly generated key that cannot match the existing cert.
- Exclude rate-limited rows from the ten-minute stale reset so the
resumable order survives the ACME cooldown.
- Size the provisioning poll lease to exceed the max processing window
so a released claim lock cannot let another worker process the same
row concurrently.
- Parse Retry-After as unsigned seconds and clamp overflow so malformed
values fall back to the default cooldown instead of disabling it.
- Normalize the acme_errors problem_type label to the RFC 8555 set to
bound Prometheus cardinality.
Signed-off-by: Bryan Frimin <bryan@probo.com>
Rate limits no longer inflate ssl_retry_count into an instant FAILED
path. Centralize outcomes in decideProvisioningOutcome, keep ACME
order state on transient and rate-limit errors, bound each Process
tick with a timeout, and block on FOR UPDATE when persisting a
freshly issued certificate.
Signed-off-by: Ludovic Vielle <ludovic@probo.com>
Signed-off-by: Bryan Frimin <bryan@probo.com>
Pebble skipped real HTTP-01 validation, which hid integration gaps
for compliance-page custom domains. step-ca with a Caddy port-80
proxy exercises the same path production uses while keeping issued
certs persistent across compose restarts.
Signed-off-by: Bryan Frimin <bryan@probo.com>
Replace the Provisioner and Renewer with poll-based provision and renew
workers orchestrated by a certmanager Service. Certificate operations are
now hostname-centric and driven by the certificates table, decoupled from
custom-domain business logic.
Signed-off-by: Bryan Frimin <bryan@probo.com>
The source headers, LICENSE files, and license metadata had drifted
apart. Align the entire project to MIT:
- Convert every source-file header to the MIT text across all comment
styles (Go, TS, TSX, JS, MJS, SQL, CSS, GraphQL, shell), including
SPDX-License-Identifier tags
- Set the root and cookie-banner LICENSE files to the MIT text with a
"MIT License" title line
- Switch the package.json license fields, Docker image label, and
cookie-banner README to MIT
- Update docs and the genmodels header generator accordingly
- Normalize copyright lines to a single format
(Copyright (c) <year(s)> Probo Inc <hello@probo.com>.): unify the
hello@getprobo.com and hello@probo.inc emails to hello@probo.com and
the comma-separated years to a hyphenated range
Genuine third-party references are intentionally left untouched: the
Lucide icon attributions (Lucide is ISC) and the trivy dependency
license allowlist.
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
Allow ACME account keys to be configured via config file to maintain
the same Let's Encrypt account across deployments. Add DecodePrivateKey
function with PEM block type constants to support EC, RSA, and PKCS8
key formats. When no account key is provided, fall back to generating
a new one with a warning.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Introduced ErrHTTPChallengeRequired as a sentinel error and updated the
renewal flow to use errors.Is() for type-safe error checking instead of
string matching.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>