Replace Python test_recheck_caa with Go TestCAARechecking (#8085)

Replace a python integration test which relies on our
"setup_twenty_days_ago" scaffolding with a Go test that uses direct
database statements to avoid any need to do clock manipulation. The
resulting test is much more verbose, but also (in my opinion) much
clearer and significantly faster.
This commit is contained in:
Aaron Gable 2025-03-31 11:10:22 -05:00 committed by GitHub
parent c0e31f9a4f
commit 3438b057d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 112 additions and 43 deletions

View File

@ -90,6 +90,23 @@ func delHTTP01Response(token string) error {
return nil
}
func addCAAIssueRecord(host string, issue string) error {
resp, err := http.Post("http://boulder.service.consul:8055/add-caa", "",
bytes.NewBufferString(fmt.Sprintf(`{
"host": "%s",
"policies": [{"tag": "issue", "value": "%s"}]
}`, host, issue)))
if err != nil {
return fmt.Errorf("adding CAA record: %s", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("adding CAA record: status %d", resp.StatusCode)
}
return nil
}
func makeClientAndOrder(c *client, csrKey *ecdsa.PrivateKey, idents []acme.Identifier, cn bool, profile string, certToReplace *x509.Certificate) (*client, *acme.Order, error) {
var err error
if c == nil {

View File

@ -0,0 +1,95 @@
//go:build integration
package integration
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"database/sql"
"strings"
"testing"
"time"
"github.com/eggsampler/acme/v3"
"github.com/letsencrypt/boulder/test/vars"
)
func TestCAARechecking(t *testing.T) {
t.Parallel()
domain := randomDomain(t)
idents := []acme.Identifier{{Type: "dns", Value: domain}}
// Create an order and authorization, and fulfill the associated challenge.
// This should put the authz into the "valid" state, since CAA checks passed.
client, err := makeClient()
if err != nil {
t.Fatalf("creating acme client: %s", err)
}
order, err := client.Client.NewOrder(client.Account, idents)
if err != nil {
t.Fatalf("creating order: %s", err)
}
authz, err := client.Client.FetchAuthorization(client.Account, order.Authorizations[0])
if err != nil {
t.Fatalf("fetching authorization: %s", err)
}
chal, ok := authz.ChallengeMap[acme.ChallengeTypeHTTP01]
if !ok {
t.Fatalf("no HTTP challenge found in %#v", authz)
}
err = addHTTP01Response(chal.Token, chal.KeyAuthorization)
if err != nil {
t.Fatalf("setting HTTP-01 challenge token: %s", err)
}
defer delHTTP01Response(chal.Token)
chal, err = client.Client.UpdateChallenge(client.Account, chal)
if err != nil {
t.Fatalf("completing HTTP-01 validation: %s", err)
}
// Manipulate the database so that it looks like the authz was validated
// more than 8 hours ago.
db, err := sql.Open("mysql", vars.DBConnSAIntegrationFullPerms)
if err != nil {
t.Fatalf("sql.Open: %s", err)
}
_, err = db.Exec(`UPDATE authz2 SET attemptedAt = ? WHERE identifierValue = ?`, time.Now().Add(-24*time.Hour).Format(time.DateTime), domain)
if err != nil {
t.Fatalf("updating authz attemptedAt timestamp: %s", err)
}
// Change the CAA record to now forbid issuance.
err = addCAAIssueRecord(domain, ";")
if err != nil {
t.Fatalf("updating CAA record: %s", err)
}
// Try to finalize the order created above. Due to our db manipulation, this
// should trigger a CAA recheck. And due to our challtestsrv manipulation,
// that CAA recheck should fail. Therefore the whole finalize should fail.
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatalf("generating cert key: %s", err)
}
csr, err := makeCSR(key, idents, false)
if err != nil {
t.Fatalf("generating finalize csr: %s", err)
}
_, err = client.Client.FinalizeOrder(client.Account, order, csr)
if err == nil {
t.Errorf("expected finalize to fail, but got success")
}
if !strings.Contains(err.Error(), "CAA") {
t.Errorf("expected finalize to fail due to CAA, but got: %s", err)
}
}

View File

@ -1170,49 +1170,6 @@ def test_expiration_mailer():
if mailcount != 2:
raise(Exception("\nExpiry mailer failed: expected 2 emails, got %d" % mailcount))
caa_recheck_setup_data = {}
@register_twenty_days_ago
def caa_recheck_setup():
client = chisel2.make_client()
# Issue a certificate with the clock set back, and save the authzs to check
# later that they are valid (200). They should however require rechecking for
# CAA purposes.
numNames = 10
# Generate numNames subdomains of a random domain
base_domain = random_domain()
domains = [ "{0}.{1}".format(str(n),base_domain) for n in range(numNames) ]
order = chisel2.auth_and_issue(domains, client=client)
global caa_recheck_setup_data
caa_recheck_setup_data = {
'client': client,
'authzs': order.authorizations,
}
def test_recheck_caa():
"""Request issuance for a domain where we have a old cached authz from when CAA
was good. We'll set a new CAA record forbidding issuance; the CAA should
recheck CAA and reject the request.
"""
if 'authzs' not in caa_recheck_setup_data:
raise(Exception("CAA authzs not prepared for test_caa"))
domains = []
for a in caa_recheck_setup_data['authzs']:
response = caa_recheck_setup_data['client']._post(a.uri, None)
if response.status_code != 200:
raise(Exception("Unexpected response for CAA authz: ",
response.status_code))
domain = a.body.identifier.value
domains.append(domain)
# Set a forbidding CAA record on just one domain
challSrv.add_caa_issue(domains[3], ";")
# Request issuance for the previously-issued domain name, which should
# now be denied due to CAA.
chisel2.expect_problem("urn:ietf:params:acme:error:caa",
lambda: chisel2.auth_and_issue(domains, client=caa_recheck_setup_data['client']))
def test_caa_good():
domain = random_domain()
challSrv.add_caa_issue(domain, "happy-hacker-ca.invalid")