chore: update to go1.20 (#1993)

This commit is contained in:
Ludovic Fernandez 2023-08-19 18:05:33 +02:00 committed by GitHub
parent c365d7efc8
commit b37d60c033
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 144 additions and 92 deletions

View file

@ -11,7 +11,7 @@ jobs:
name: Build and deploy documentation name: Build and deploy documentation
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
GO_VERSION: '1.20' GO_VERSION: stable
HUGO_VERSION: '0.117.0' HUGO_VERSION: '0.117.0'
CGO_ENABLED: 0 CGO_ENABLED: 0

View file

@ -16,37 +16,19 @@ jobs:
strategy: strategy:
matrix: matrix:
go-version: [ '1.19', '1.20', 1.x ] go-version: [ stable, oldstable ]
os: [ubuntu-latest, macos-latest, windows-latest] os: [ubuntu-latest, macos-latest, windows-latest]
steps: steps:
# https://github.com/marketplace/actions/setup-go-environment
- name: Set up Go ${{ matrix.go-version }}
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go-version }}
# https://github.com/marketplace/actions/checkout # https://github.com/marketplace/actions/checkout
- name: Checkout code - name: Checkout code
uses: actions/checkout@v3 uses: actions/checkout@v3
# https://github.com/marketplace/actions/cache # https://github.com/marketplace/actions/setup-go-environment
- name: Cache Go modules - name: Set up Go ${{ matrix.go-version }}
uses: actions/cache@v3 uses: actions/setup-go@v4
with: with:
# In order: go-version: ${{ matrix.go-version }}
# * Module download cache
# * Build cache (Linux)
# * Build cache (Mac)
# * Build cache (Windows)
path: |
~/go/pkg/mod
~/.cache/go-build
~/Library/Caches/go-build
%LocalAppData%\go-build
key: ${{ runner.os }}-${{ matrix.go-version }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-${{ matrix.go-version }}-go-
- name: Test - name: Test
run: go test -v -cover ./... run: go test -v -cover ./...

View file

@ -12,8 +12,8 @@ jobs:
name: Main Process name: Main Process
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
GO_VERSION: '1.20' GO_VERSION: stable
GOLANGCI_LINT_VERSION: v1.53.1 GOLANGCI_LINT_VERSION: v1.54.1
HUGO_VERSION: '0.117.0' HUGO_VERSION: '0.117.0'
CGO_ENABLED: 0 CGO_ENABLED: 0
LEGO_E2E_TESTS: CI LEGO_E2E_TESTS: CI
@ -21,26 +21,17 @@ jobs:
steps: steps:
# https://github.com/marketplace/actions/setup-go-environment
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v3
with:
go-version: ${{ env.GO_VERSION }}
# https://github.com/marketplace/actions/checkout # https://github.com/marketplace/actions/checkout
- name: Check out code - name: Check out code
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
# https://github.com/marketplace/actions/cache # https://github.com/marketplace/actions/setup-go-environment
- name: Cache Go modules - name: Set up Go ${{ env.GO_VERSION }}
uses: actions/cache@v3 uses: actions/setup-go@v4
with: with:
path: ~/go/pkg/mod go-version: ${{ env.GO_VERSION }}
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Check and get dependencies - name: Check and get dependencies
run: | run: |

View file

@ -11,7 +11,7 @@ jobs:
name: Release version name: Release version
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
GO_VERSION: '1.20' GO_VERSION: stable
CGO_ENABLED: 0 CGO_ENABLED: 0
steps: steps:

View file

@ -35,13 +35,14 @@ func (c *Certifier) getAuthorizations(order acme.ExtendedOrder) ([]acme.Authoriz
} }
var responses []acme.Authorization var responses []acme.Authorization
failures := make(obtainError)
failures := newObtainError()
for i := 0; i < len(order.Authorizations); i++ { for i := 0; i < len(order.Authorizations); i++ {
select { select {
case res := <-resc: case res := <-resc:
responses = append(responses, res) responses = append(responses, res)
case err := <-errc: case err := <-errc:
failures[err.Domain] = err.Error failures.Add(err.Domain, err.Error)
} }
} }
@ -52,12 +53,7 @@ func (c *Certifier) getAuthorizations(order acme.ExtendedOrder) ([]acme.Authoriz
close(resc) close(resc)
close(errc) close(errc)
// be careful to not return an empty failures map; return responses, failures.Join()
// even if empty, they become non-nil error values
if len(failures) > 0 {
return responses, failures
}
return responses, nil
} }
func (c *Certifier) deactivateAuthorizations(order acme.ExtendedOrder, force bool) { func (c *Certifier) deactivateAuthorizations(order acme.ExtendedOrder, force bool) {

View file

@ -149,11 +149,11 @@ func (c *Certifier) Obtain(request ObtainRequest) (*Resource, error) {
log.Infof("[%s] acme: Validations succeeded; requesting certificates", strings.Join(domains, ", ")) log.Infof("[%s] acme: Validations succeeded; requesting certificates", strings.Join(domains, ", "))
failures := make(obtainError) failures := newObtainError()
cert, err := c.getForOrder(domains, order, request.Bundle, request.PrivateKey, request.MustStaple, request.PreferredChain) cert, err := c.getForOrder(domains, order, request.Bundle, request.PrivateKey, request.MustStaple, request.PreferredChain)
if err != nil { if err != nil {
for _, auth := range authz { for _, auth := range authz {
failures[challenge.GetTargetedDomain(auth)] = err failures.Add(challenge.GetTargetedDomain(auth), err)
} }
} }
@ -161,12 +161,7 @@ func (c *Certifier) Obtain(request ObtainRequest) (*Resource, error) {
c.deactivateAuthorizations(order, true) c.deactivateAuthorizations(order, true)
} }
// Do not return an empty failures map, because return cert, failures.Join()
// it would still be a non-nil error value
if len(failures) > 0 {
return cert, failures
}
return cert, nil
} }
// ObtainForCSR tries to obtain a certificate matching the CSR passed into it. // ObtainForCSR tries to obtain a certificate matching the CSR passed into it.
@ -219,11 +214,11 @@ func (c *Certifier) ObtainForCSR(request ObtainForCSRRequest) (*Resource, error)
log.Infof("[%s] acme: Validations succeeded; requesting certificates", strings.Join(domains, ", ")) log.Infof("[%s] acme: Validations succeeded; requesting certificates", strings.Join(domains, ", "))
failures := make(obtainError) failures := newObtainError()
cert, err := c.getForCSR(domains, order, request.Bundle, request.CSR.Raw, nil, request.PreferredChain) cert, err := c.getForCSR(domains, order, request.Bundle, request.CSR.Raw, nil, request.PreferredChain)
if err != nil { if err != nil {
for _, auth := range authz { for _, auth := range authz {
failures[challenge.GetTargetedDomain(auth)] = err failures.Add(challenge.GetTargetedDomain(auth), err)
} }
} }
@ -236,12 +231,7 @@ func (c *Certifier) ObtainForCSR(request ObtainForCSRRequest) (*Resource, error)
cert.CSR = certcrypto.PEMEncode(request.CSR) cert.CSR = certcrypto.PEMEncode(request.CSR)
} }
// Do not return an empty failures map, return cert, failures.Join()
// because it would still be a non-nil error value
if len(failures) > 0 {
return cert, failures
}
return cert, nil
} }
func (c *Certifier) getForOrder(domains []string, order acme.ExtendedOrder, bundle bool, privateKey crypto.PrivateKey, mustStaple bool, preferredChain string) (*Resource, error) { func (c *Certifier) getForOrder(domains []string, order acme.ExtendedOrder, bundle bool, privateKey crypto.PrivateKey, mustStaple bool, preferredChain string) (*Resource, error) {

View file

@ -1,27 +1,37 @@
package certificate package certificate
import ( import (
"bytes" "errors"
"fmt" "fmt"
"sort"
) )
// obtainError is returned when there are specific errors available per domain. type obtainError struct {
type obtainError map[string]error data map[string]error
}
func (e obtainError) Error() string { func newObtainError() *obtainError {
buffer := bytes.NewBufferString("error: one or more domains had a problem:\n") return &obtainError{data: make(map[string]error)}
}
var domains []string func (e *obtainError) Add(domain string, err error) {
for domain := range e { e.data[domain] = err
domains = append(domains, domain) }
func (e *obtainError) Join() error {
if e == nil {
return nil
} }
sort.Strings(domains)
for _, domain := range domains { if len(e.data) == 0 {
_, _ = fmt.Fprintf(buffer, "[%s] %s\n", domain, e[domain]) return nil
} }
return buffer.String()
var err error
for d, e := range e.data {
err = errors.Join(err, fmt.Errorf("%s: %w", d, e))
}
return fmt.Errorf("error: one or more domains had a problem:\n%w", err)
} }
type domainError struct { type domainError struct {

View file

@ -0,0 +1,70 @@
package certificate
import (
"errors"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type TomatoError struct{}
func (t TomatoError) Error() string {
return "tomato"
}
type CarrotError struct{}
func (t CarrotError) Error() string {
return "carrot"
}
func Test_obtainError_Join(t *testing.T) {
failures := newObtainError()
failures.Add("example.com", &TomatoError{})
err := failures.Join()
to := &TomatoError{}
assert.ErrorAs(t, err, &to)
}
func Test_obtainError_Join_multiple_domains(t *testing.T) {
failures := newObtainError()
failures.Add("example.com", &TomatoError{})
failures.Add("example.org", &CarrotError{})
err := failures.Join()
to := &TomatoError{}
assert.ErrorAs(t, err, &to)
ca := &CarrotError{}
assert.ErrorAs(t, err, &ca)
}
func Test_obtainError_Join_no_error(t *testing.T) {
failures := newObtainError()
assert.NoError(t, failures.Join())
}
func Test_obtainError_Join_same_domain(t *testing.T) {
failures := newObtainError()
failures.Add("example.com", &TomatoError{})
failures.Add("example.com", &CarrotError{})
err := failures.Join()
to := &TomatoError{}
if errors.As(err, &to) {
require.Fail(t, "TomatoError should be overridden by CarrotError")
}
ca := &CarrotError{}
assert.ErrorAs(t, err, &ca)
}

2
go.mod
View file

@ -1,6 +1,6 @@
module github.com/go-acme/lego/v4 module github.com/go-acme/lego/v4
go 1.19 go 1.20
require ( require (
cloud.google.com/go/compute/metadata v0.2.3 cloud.google.com/go/compute/metadata v0.2.3

View file

@ -54,7 +54,7 @@ type DNSRequest struct {
// --- // ---
type GetDNSSettingsAPIResponse struct { type GetDNSSettingsAPIResponse struct {
Response GetDNSSettingsResponse `json:"Response" mapstructure:"Response"` Response GetDNSSettingsResponse `json:"Response" mapstructure:"Response"`
} }
type GetDNSSettingsResponse struct { type GetDNSSettingsResponse struct {

View file

@ -11,26 +11,26 @@ import (
"time" "time"
"github.com/go-acme/lego/v4/providers/dns/internal/errutils" "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
"golang.org/x/oauth2"
) )
const defaultBaseURL = "https://ipv64.net" const defaultBaseURL = "https://ipv64.net"
const authorizationHeader = "Authorization"
type Client struct { type Client struct {
apiKey string
baseURL *url.URL baseURL *url.URL
HTTPClient *http.Client HTTPClient *http.Client
} }
func NewClient(apiKey string) *Client { func NewClient(hc *http.Client) *Client {
baseURL, _ := url.Parse(defaultBaseURL) baseURL, _ := url.Parse(defaultBaseURL)
if hc == nil {
hc = &http.Client{Timeout: 15 * time.Second}
}
return &Client{ return &Client{
apiKey: apiKey,
baseURL: baseURL, baseURL: baseURL,
HTTPClient: &http.Client{Timeout: 15 * time.Second}, HTTPClient: hc,
} }
} }
@ -91,8 +91,6 @@ func (c Client) DeleteRecord(ctx context.Context, domain, prefix, recordType, co
} }
func (c Client) do(req *http.Request, result any) error { func (c Client) do(req *http.Request, result any) error {
req.Header.Set(authorizationHeader, fmt.Sprintf("Bearer %s", c.apiKey))
if req.Method != http.MethodGet { if req.Method != http.MethodGet {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
} }
@ -140,3 +138,16 @@ func parseError(req *http.Request, resp *http.Response) error {
return errAPI return errAPI
} }
func OAuthStaticAccessToken(client *http.Client, accessToken string) *http.Client {
if client == nil {
client = &http.Client{Timeout: 15 * time.Second}
}
client.Transport = &oauth2.Transport{
Source: oauth2.StaticTokenSource(&oauth2.Token{AccessToken: accessToken}),
Base: client.Transport,
}
return client
}

View file

@ -15,12 +15,14 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
const testAPIKey = "secret"
func setupTest(t *testing.T, handler http.HandlerFunc) *Client { func setupTest(t *testing.T, handler http.HandlerFunc) *Client {
t.Helper() t.Helper()
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
client := NewClient("secret") client := NewClient(OAuthStaticAccessToken(server.Client(), testAPIKey))
client.HTTPClient = server.Client() client.HTTPClient = server.Client()
client.baseURL, _ = url.Parse(server.URL) client.baseURL, _ = url.Parse(server.URL)
@ -34,8 +36,8 @@ func testHandler(method, filename string, statusCode int) http.HandlerFunc {
return return
} }
auth := req.Header.Get(authorizationHeader) auth := req.Header.Get("Authorization")
if auth != "Bearer secret" { if auth != "Bearer "+testAPIKey {
http.Error(rw, fmt.Sprintf("invalid API key: %s", auth), http.StatusUnauthorized) http.Error(rw, fmt.Sprintf("invalid API key: %s", auth), http.StatusUnauthorized)
return return
} }

View file

@ -78,7 +78,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("ipv64: credentials missing") return nil, errors.New("ipv64: credentials missing")
} }
client := internal.NewClient(config.APIKey) client := internal.NewClient(internal.OAuthStaticAccessToken(config.HTTPClient, config.APIKey))
if config.HTTPClient != nil { if config.HTTPClient != nil {
client.HTTPClient = config.HTTPClient client.HTTPClient = config.HTTPClient