Skip to content

Commit

Permalink
Implementing tests
Browse files Browse the repository at this point in the history
Implements tests and documents.
  • Loading branch information
mys721tx committed Dec 28, 2024
1 parent 0e681ee commit 73f6734
Show file tree
Hide file tree
Showing 47 changed files with 20,272 additions and 3 deletions.
30 changes: 27 additions & 3 deletions cdh.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,41 @@ import (
"google.golang.org/api/option"
)

// config holds the configuration values for the application, including
// the domains to be renewed and the path to the renewed certificate.
type config struct {
Domains []string `env:"RENEWED_DOMAINS, delimiter= "`
Cert string `env:"RENEWED_LINEAGE"`
}

// tlsa represents the DANE (DNS-based Authentication of Named Entities)
// information for a certificate, including the trust anchor, end entity,
// and associated DNS names.
type tlsa struct {
TrustAnchor string
EndEntity string
DNSNames []string
}

// NewTLSA creates a new instance of tlsa struct.
// NewTLSA creates a new instance of the tlsa struct with initialized DNSNames slice.
// It returns a pointer to the newly created tlsa instance.
func NewTLSA() *tlsa {
var t tlsa
t.DNSNames = make([]string, 0)
return &t
}

// ReadCert processes an x509.Certificate and populates the tlsa struct with
// the appropriate DANE (DNS-based Authentication of Named Entities) information.
// If the certificate is a CA (Certificate Authority), it sets the TrustAnchor field.
// Otherwise, it sets the EndEntity field and processes the DNS names associated
// with the certificate, ensuring each DNS name ends with a dot.
//
// Parameters:
// - c: A pointer to an x509.Certificate to be processed.
//
// Returns:
// - error: An error if the conversion to DANE fails, otherwise nil.
func (t *tlsa) ReadCert(c *x509.Certificate) error {
if dane, err := dns.CertificateToDANE(1, 1, c); err != nil {
return err
Expand All @@ -71,6 +88,8 @@ func (t *tlsa) ReadCert(c *x509.Certificate) error {
return nil
}

// MakeRRData generates the resource record data for the TLSA record.
// It returns a slice of strings containing the TLSA record data.
func (t tlsa) MakeRRData() []string {
r := []string{
fmt.Sprintf(
Expand All @@ -90,6 +109,9 @@ var (
keyPath, zone string
)

// readCert reads the certificate from the specified file path and returns
// a tlsa struct populated with the DANE information. It returns an error
// if the certificate cannot be read or processed.
func readCert(f string) (*tlsa, error) {
t := NewTLSA()

Expand All @@ -112,8 +134,8 @@ func readCert(f string) (*tlsa, error) {
return t, nil
}

// newDNSClient reads a JSON key file and return a DNS client, the project ID,
// and any error occurred.
// newDNSClient reads a JSON key file and returns a DNS client, the project ID,
// and any error that occurred.
func newDNSClient(f string) (*gcdns.Service, string, error) {
var projectID string
var err error
Expand Down Expand Up @@ -144,6 +166,8 @@ func newDNSClient(f string) (*gcdns.Service, string, error) {
return dnsSer, projectID, nil
}

// newChange creates a new DNS change set based on the provided resource record sets
// and the tlsa struct. It returns a pointer to the created gcdns.Change struct.
func newChange(rR []*gcdns.ResourceRecordSet, t *tlsa) *gcdns.Change {
cset := gcdns.Change{}

Expand Down
174 changes: 174 additions & 0 deletions cdh_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package main

import (
"crypto/tls"
"testing"

"github.com/stretchr/testify/assert"
)

func TestNewTLSA(t *testing.T) {
tlsa := NewTLSA()

assert.NotNil(t, tlsa, "Expected non-nil tlsa")
assert.Empty(t, tlsa.DNSNames, "Expected DNSNames to be empty")
assert.Equal(t, "", tlsa.TrustAnchor, "Expected TrustAnchor to be empty")
assert.Equal(t, "", tlsa.EndEntity, "Expected EndEntity to be empty")
}

const caPem = `-----BEGIN CERTIFICATE-----
MIICSDCCAamgAwIBAgIBKjAKBggqhkjOPQQDBDA4MTYwNAYDVQQKEy1OZXZlciBV
c2UgdGhpcyBDZXJ0aWZpY2F0ZSBpbiBQcm9kdWN0aW9uIEluYy4wHhcNMjQxMjI4
MDQzNDA5WhcNMjQxMjI4MDczNDA5WjA4MTYwNAYDVQQKEy1OZXZlciBVc2UgdGhp
cyBDZXJ0aWZpY2F0ZSBpbiBQcm9kdWN0aW9uIEluYy4wgZswEAYHKoZIzj0CAQYF
K4EEACMDgYYABAAqJjE+C/WparEFO+ZY1TTErxNrtt9ncLNjNAjl2HFG/q7/ufFP
h6Fh13TsCjVUpzvFfeUbkRKpyxxACGXN9BboKQB/VPjyzIEhBarS3uigswd52Mnh
kP0mohCNVF7qS2Sk5aj0Fl9tzyslfU2T6hlJ46JgwcFv+5ueitFhbMqDn3TF9aNh
MF8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD
ATAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSr1f5+mEVb9yPGB0mdaUBUdgIc
6TAKBggqhkjOPQQDBAOBjAAwgYgCQgEVeNrF24pn6UbvyX9M3O1D/1/MFDQhF46M
qPXNEv12Z8BegYpxmifP1YlhcY17zTQUUi8/Waw3LDjbvZxo/oyASwJCAdkLsyoh
SGTIzJ4dE1Ha53rZ1jrYOCDUxjwWIfpXNdp4rsgrz/mL/wNKX0ouq8ZWbfdbbEtk
0Mh8tcsZZuHPSiGo
-----END CERTIFICATE-----`

const caKey = `-----BEGIN PRIVATE KEY-----
MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAHIa3SBvNEdli+wXJ
m/IHWEXHg4dSWZOToYoZrnWifok/rtrZesaNmEeGf1bhQBZhs9vkffRPvmnnWphq
9HGJW1GhgYkDgYYABAAqJjE+C/WparEFO+ZY1TTErxNrtt9ncLNjNAjl2HFG/q7/
ufFPh6Fh13TsCjVUpzvFfeUbkRKpyxxACGXN9BboKQB/VPjyzIEhBarS3uigswd5
2MnhkP0mohCNVF7qS2Sk5aj0Fl9tzyslfU2T6hlJ46JgwcFv+5ueitFhbMqDn3TF
9Q==
-----END PRIVATE KEY-----`

const certPem = `-----BEGIN CERTIFICATE-----
MIICLzCCAZGgAwIBAgIBKjAKBggqhkjOPQQDBDA4MTYwNAYDVQQKEy1OZXZlciBV
c2UgdGhpcyBDZXJ0aWZpY2F0ZSBpbiBQcm9kdWN0aW9uIEluYy4wHhcNMjQxMjI4
MDQzNDA5WhcNMjQxMjI4MDczNDA5WjA4MTYwNAYDVQQKEy1OZXZlciBVc2UgdGhp
cyBDZXJ0aWZpY2F0ZSBpbiBQcm9kdWN0aW9uIEluYy4wgZswEAYHKoZIzj0CAQYF
K4EEACMDgYYABAHwqDKeeel1RkjjkkHV8ng5UzWABCqBUVPJUfdmUdukM97P14y9
T9IgyrLpu6gd+ch3aIQgHzSyp0aUOW3RDaSyywAoMiJllGpT47t2DwccF7cpNOHV
+S5IEze3NeedblRWRDT+H63y2hv9FoGYrNeGEvQcIAXxFrAbqLjUO5SafW27R6NJ
MEcwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD
ATAWBgNVHREEDzANggtleGFtcGxlLmNvbTAKBggqhkjOPQQDBAOBiwAwgYcCQSxa
29YLZolE9fCpbwri8cDNAAL/W07pNBfVOiL8wTxnEtLsM9AgnCfiyAysBTc7iAj+
9lPy0Nl/nPlTRlOhyWkYAkIBxJHpVO2pZPn1BRqGfqOGp21gZX3n/IKV+ZIr+fuB
NKyUNZ657ejPpd6ERfHN/f5kXNfxFZd7Tbxy3h8X+kJq3cU=
-----END CERTIFICATE-----`

const certKey = `-----BEGIN PRIVATE KEY-----
MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIA9beqnjUgpvkvAsr8
i+0P7Xb3YtJCcslVkkyd8wkQshIZvS1EC0cZuIl80ByWqzlh2pI8PUlhY4dr5mw2
R82Bnd+hgYkDgYYABAHwqDKeeel1RkjjkkHV8ng5UzWABCqBUVPJUfdmUdukM97P
14y9T9IgyrLpu6gd+ch3aIQgHzSyp0aUOW3RDaSyywAoMiJllGpT47t2DwccF7cp
NOHV+S5IEze3NeedblRWRDT+H63y2hv9FoGYrNeGEvQcIAXxFrAbqLjUO5SafW27
Rw==
-----END PRIVATE KEY-----`

func TestReadCerts(t *testing.T) {
tests := []struct {
name string
certPem string
keyPem string
trustAnchor bool
endEntity bool
dnsNames bool
}{
{
name: "CACert",
certPem: caPem,
keyPem: caKey,
trustAnchor: true,
endEntity: false,
dnsNames: false,
},
{
name: "LeafCert",
certPem: certPem,
keyPem: certKey,
trustAnchor: false,
endEntity: true,
dnsNames: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tlsa := NewTLSA()
cert, _ := tls.X509KeyPair([]byte(tt.certPem), []byte(tt.keyPem))

err := tlsa.ReadCert(*&cert.Leaf)

assert.NoError(t, err, "Expected no error")
if tt.trustAnchor {
assert.NotEmpty(t, tlsa.TrustAnchor, "Expected TrustAnchor to be non-nil")
} else {
assert.Empty(t, tlsa.TrustAnchor, "Expected TrustAnchor to be empty")
}
if tt.endEntity {
assert.NotEmpty(t, tlsa.EndEntity, "Expected EndEntity to be non-nil")
} else {
assert.Empty(t, tlsa.EndEntity, "Expected EndEntity to be empty")
}
if tt.dnsNames {
assert.NotEmpty(t, tlsa.DNSNames, "Expected DNSNames to be non-nil")
} else {
assert.Empty(t, tlsa.DNSNames, "Expected DNSNames to be empty")
}
})
}
}
func TestMakeRRData(t *testing.T) {
tests := []struct {
name string
tlsa tlsa
expectedRRs []string
}{
{
name: "EmptyTLSA",
tlsa: tlsa{},
expectedRRs: []string{
"3 1 1 ",
"2 1 1 ",
},
},
{
name: "EndEntityOnly",
tlsa: tlsa{
EndEntity: "abcdef123456",
},
expectedRRs: []string{
"3 1 1 abcdef123456",
"2 1 1 ",
},
},
{
name: "TrustAnchorOnly",
tlsa: tlsa{
TrustAnchor: "123456abcdef",
},
expectedRRs: []string{
"3 1 1 ",
"2 1 1 123456abcdef",
},
},
{
name: "BothEndEntityAndTrustAnchor",
tlsa: tlsa{
EndEntity: "abcdef123456",
TrustAnchor: "123456abcdef",
},
expectedRRs: []string{
"3 1 1 abcdef123456",
"2 1 1 123456abcdef",
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
rrs := tt.tlsa.MakeRRData()
assert.Equal(t, tt.expectedRRs, rrs, "Expected RR data to match")
})
}
}
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,23 @@ go 1.23
require (
github.com/miekg/dns v1.1.62
github.com/sethvargo/go-envconfig v1.1.0
github.com/stretchr/testify v1.10.0
google.golang.org/api v0.214.0
)

require (
cloud.google.com/go/auth v0.13.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect
cloud.google.com/go/compute/metadata v0.6.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/google/s2a-go v0.1.8 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect
go.opentelemetry.io/otel v1.33.0 // indirect
Expand All @@ -36,4 +39,5 @@ require (
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect
google.golang.org/grpc v1.69.2 // indirect
google.golang.org/protobuf v1.36.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
9 changes: 9 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,16 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gT
github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q=
github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/sethvargo/go-envconfig v1.1.0 h1:cWZiJxeTm7AlCvzGXrEXaSTCNgip5oJepekh/BOQuog=
github.com/sethvargo/go-envconfig v1.1.0/go.mod h1:JLd0KFWQYzyENqnEPWWZ49i4vzZo/6nRidxI8YvGiHw=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
Expand Down Expand Up @@ -73,5 +79,8 @@ google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU=
google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
15 changes: 15 additions & 0 deletions vendor/github.com/davecgh/go-spew/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 73f6734

Please sign in to comment.