boulder/test/integration/crl_test.go

93 lines
3.2 KiB
Go

//go:build integration
package integration
import (
"database/sql"
"io"
"net/http"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"testing"
"time"
"github.com/jmhodges/clock"
"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/test"
"github.com/letsencrypt/boulder/test/vars"
)
// runUpdater executes the crl-updater binary with the -runOnce flag, and
// returns when it completes.
func runUpdater(t *testing.T, configFile string) {
t.Helper()
binPath, err := filepath.Abs("bin/boulder")
test.AssertNotError(t, err, "computing boulder binary path")
c := exec.Command(binPath, "crl-updater", "-config", configFile, "-debug-addr", ":8022", "-runOnce")
out, err := c.CombinedOutput()
for _, line := range strings.Split(string(out), "\n") {
// Print the updater's stdout for debugging, but only if the test fails.
t.Log(line)
}
test.AssertNotError(t, err, "crl-updater failed")
}
// TestCRLPipeline runs an end-to-end test of the crl issuance process, ensuring
// that the correct number of properly-formed and validly-signed CRLs are sent
// to our fake S3 service.
func TestCRLPipeline(t *testing.T) {
// Basic setup.
fc := clock.NewFake()
configDir, ok := os.LookupEnv("BOULDER_CONFIG_DIR")
test.Assert(t, ok, "failed to look up test config directory")
configFile := path.Join(configDir, "crl-updater.json")
// Reset the "leasedUntil" column so that this test isn't dependent on state
// like priors runs of this test.
db, err := sql.Open("mysql", vars.DBConnSAIntegrationFullPerms)
test.AssertNotError(t, err, "opening database connection")
_, err = db.Exec(`UPDATE crlShards SET leasedUntil = ?`, fc.Now().Add(-time.Minute))
test.AssertNotError(t, err, "resetting leasedUntil column")
// Issue a test certificate and save its serial number.
client, err := makeClient()
test.AssertNotError(t, err, "creating acme client")
res, err := authAndIssue(client, nil, []string{random_domain()}, true)
test.AssertNotError(t, err, "failed to create test certificate")
cert := res.certs[0]
serial := core.SerialToString(cert.SerialNumber)
// Confirm that the cert does not yet show up as revoked in the CRLs.
runUpdater(t, configFile)
resp, err := http.Get("http://localhost:4501/query?serial=" + serial)
test.AssertNotError(t, err, "s3-test-srv GET /query failed")
test.AssertEquals(t, resp.StatusCode, 404)
resp.Body.Close()
// Revoke the certificate.
err = client.RevokeCertificate(client.Account, cert, client.PrivateKey, 5)
test.AssertNotError(t, err, "failed to revoke test certificate")
// Reset the "leasedUntil" column to prepare for another round of CRLs.
_, err = db.Exec(`UPDATE crlShards SET leasedUntil = ?`, fc.Now().Add(-time.Minute))
test.AssertNotError(t, err, "resetting leasedUntil column")
// Confirm that the cert now *does* show up in the CRLs.
runUpdater(t, configFile)
resp, err = http.Get("http://localhost:4501/query?serial=" + serial)
test.AssertNotError(t, err, "s3-test-srv GET /query failed")
test.AssertEquals(t, resp.StatusCode, 200)
// Confirm that the revoked certificate entry has the correct reason.
reason, err := io.ReadAll(resp.Body)
test.AssertNotError(t, err, "reading revocation reason")
test.AssertEquals(t, string(reason), "5")
resp.Body.Close()
}