build: bump golang: 1.17 -> 1.18

No change to go.mod's `go` stanza, so no changes in code compatibility.

However, it's used for building our docker images and release
binaries, and for fuzz testing in our nightly workflow.

Some test-related changes with the dns lookup built-in function's
error handling; and the hardcoded signature. Running

    go test ./topdown -run TestTopdownJWTEncodeSignECWithSeedReturnsSameSignature -count 10000

makes me believe that for whatever reason the signature changed,
it's at least stable.

topdown/http_test: Test-only change to accomodate this change in Go (https://go.dev/doc/go1.18):

    Certificate.Verify now uses platform APIs to verify certificate
    validity on macOS and iOS when it is called with a nil
    VerifyOpts.Roots or when using the root pool returned from
    SystemCertPool.

We're keeping the old message for go <= 1.17; in a silly-simple way.

Also:

* ci: build and test two old golang version on macos|linux

  We'll drop golang 1.15, keep one unsupported version (1.16).

Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
This commit is contained in:
Stephan Renatus
2022-03-18 10:14:01 +01:00
committed by Stephan Renatus
parent 3dd50d87f0
commit d2914c0d54
11 changed files with 168 additions and 105 deletions
+16 -11
View File
@@ -280,20 +280,25 @@ jobs:
working-directory: npm-opa-wasm
go-version-build:
name: Go compat builds
runs-on: ubuntu-latest
name: Go compat build/test
needs: generate
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- version: "1.16"
- version: "1.15"
os: [ubuntu-18.04, macos-latest]
version: ["1.17", "1.16"]
steps:
- name: Check out code
uses: actions/checkout@v3
- name: Build
run: make ci-go-ci-build-linux GOVERSION=${{ matrix.version }}
timeout-minutes: 30
- uses: actions/checkout@v3
- name: Download generated artifacts
uses: actions/download-artifact@v2
with:
name: generated
- uses: actions/setup-go@v2
with:
go-version: ${{ matrix.version }}
- run: make build
- run: make go-test
# Run PR metadata against Rego policies
rego-check-pr:
+1 -1
View File
@@ -1 +1 @@
1.17
1.18
+5
View File
@@ -2,6 +2,11 @@
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
// NOTE(sr): Different go runtime metrics on 1.16.
// This can be removed when we drop support for go 1.16.
//go:build !go1.16
// +build !go1.16
package prometheus
import (
+107
View File
@@ -0,0 +1,107 @@
// Copyright 2018 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
//go:build go1.17
// +build go1.17
// NOTE(sr): Split off of plugin_test.go, because time.UnixMilli doesn't
// exist before go 1.17. Can be merged with the other file once we drop
// support for go 1.16.
package status
import (
"context"
"testing"
"time"
"github.com/open-policy-agent/opa/plugins/bundle"
"github.com/prometheus/client_golang/prometheus/testutil"
)
func TestPluginPrometheus(t *testing.T) {
fixture := newTestFixture(t, nil, func(c *Config) {
c.Prometheus = true
})
fixture.server.ch = make(chan UpdateRequestV1)
defer fixture.server.stop()
ctx := context.Background()
err := fixture.plugin.Start(ctx)
if err != nil {
t.Fatal(err)
}
defer fixture.plugin.Stop(ctx)
<-fixture.server.ch
status := testStatus()
fixture.plugin.BulkUpdateBundleStatus(map[string]*bundle.Status{"bundle": status})
<-fixture.server.ch
registerMock := fixture.manager.PrometheusRegister().(*prometheusRegisterMock)
if registerMock.Collectors[pluginStatus] != true {
t.Fatalf("Plugin status metric was not registered on prometheus")
}
if registerMock.Collectors[loaded] != true {
t.Fatalf("Loaded metric was not registered on prometheus")
}
if registerMock.Collectors[failLoad] != true {
t.Fatalf("FailLoad metric was not registered on prometheus")
}
if registerMock.Collectors[lastRequest] != true {
t.Fatalf("Last request metric was not registered on prometheus")
}
if registerMock.Collectors[lastSuccessfulActivation] != true {
t.Fatalf("Last Successful Activation metric was not registered on prometheus")
}
if registerMock.Collectors[lastSuccessfulDownload] != true {
t.Fatalf("Last Successful Download metric was not registered on prometheus")
}
if registerMock.Collectors[lastSuccessfulRequest] != true {
t.Fatalf("Last Successful Request metric was not registered on prometheus")
}
if registerMock.Collectors[bundleLoadDuration] != true {
t.Fatalf("Bundle Load Duration metric was not registered on prometheus")
}
if len(registerMock.Collectors) != 8 {
t.Fatalf("Number of collectors expected (%v), got %v", 8, len(registerMock.Collectors))
}
lastRequestMetricResult := time.UnixMilli(int64(testutil.ToFloat64(lastRequest) / 1e6))
if !lastRequestMetricResult.Equal(status.LastRequest) {
t.Fatalf("Last request expected (%v), got %v", status.LastRequest.UTC(), lastRequestMetricResult.UTC())
}
lastSuccessfulRequestMetricResult := time.UnixMilli(int64(testutil.ToFloat64(lastSuccessfulRequest) / 1e6))
if !lastSuccessfulRequestMetricResult.Equal(status.LastSuccessfulRequest) {
t.Fatalf("Last request expected (%v), got %v", status.LastSuccessfulRequest.UTC(), lastSuccessfulRequestMetricResult.UTC())
}
lastSuccessfulDownloadMetricResult := time.UnixMilli(int64(testutil.ToFloat64(lastSuccessfulDownload) / 1e6))
if !lastSuccessfulDownloadMetricResult.Equal(status.LastSuccessfulDownload) {
t.Fatalf("Last request expected (%v), got %v", status.LastSuccessfulDownload.UTC(), lastSuccessfulDownloadMetricResult.UTC())
}
lastSuccessfulActivationMetricResult := time.UnixMilli(int64(testutil.ToFloat64(lastSuccessfulActivation) / 1e6))
if !lastSuccessfulActivationMetricResult.Equal(status.LastSuccessfulActivation) {
t.Fatalf("Last request expected (%v), got %v", status.LastSuccessfulActivation.UTC(), lastSuccessfulActivationMetricResult.UTC())
}
bundlesLoaded := testutil.CollectAndCount(loaded)
if bundlesLoaded != 1 {
t.Fatalf("Unexpected number of bundle loads (%v), got %v", 1, bundlesLoaded)
}
bundlesFailedToLoad := testutil.CollectAndCount(failLoad)
if bundlesFailedToLoad != 0 {
t.Fatalf("Unexpected number of bundle fails load (%v), got %v", 0, bundlesFailedToLoad)
}
pluginsStatus := testutil.CollectAndCount(pluginStatus)
if pluginsStatus != 1 {
t.Fatalf("Unexpected number of plugins (%v), got %v", 1, pluginsStatus)
}
}
-87
View File
@@ -23,7 +23,6 @@ import (
"github.com/open-policy-agent/opa/storage/inmem"
"github.com/open-policy-agent/opa/util"
"github.com/open-policy-agent/opa/version"
"github.com/prometheus/client_golang/prometheus/testutil"
)
func TestMain(m *testing.M) {
@@ -812,92 +811,6 @@ func TestPluginCustomBackend(t *testing.T) {
}
}
func TestPluginPrometheus(t *testing.T) {
fixture := newTestFixture(t, nil, func(c *Config) {
c.Prometheus = true
})
fixture.server.ch = make(chan UpdateRequestV1)
defer fixture.server.stop()
ctx := context.Background()
err := fixture.plugin.Start(ctx)
if err != nil {
t.Fatal(err)
}
defer fixture.plugin.Stop(ctx)
<-fixture.server.ch
status := testStatus()
fixture.plugin.BulkUpdateBundleStatus(map[string]*bundle.Status{"bundle": status})
<-fixture.server.ch
registerMock := fixture.manager.PrometheusRegister().(*prometheusRegisterMock)
if registerMock.Collectors[pluginStatus] != true {
t.Fatalf("Plugin status metric was not registered on prometheus")
}
if registerMock.Collectors[loaded] != true {
t.Fatalf("Loaded metric was not registered on prometheus")
}
if registerMock.Collectors[failLoad] != true {
t.Fatalf("FailLoad metric was not registered on prometheus")
}
if registerMock.Collectors[lastRequest] != true {
t.Fatalf("Last request metric was not registered on prometheus")
}
if registerMock.Collectors[lastSuccessfulActivation] != true {
t.Fatalf("Last Successful Activation metric was not registered on prometheus")
}
if registerMock.Collectors[lastSuccessfulDownload] != true {
t.Fatalf("Last Successful Download metric was not registered on prometheus")
}
if registerMock.Collectors[lastSuccessfulRequest] != true {
t.Fatalf("Last Successful Request metric was not registered on prometheus")
}
if registerMock.Collectors[bundleLoadDuration] != true {
t.Fatalf("Bundle Load Duration metric was not registered on prometheus")
}
if len(registerMock.Collectors) != 8 {
t.Fatalf("Number of collectors expected (%v), got %v", 8, len(registerMock.Collectors))
}
lastRequestMetricResult := time.UnixMilli(int64(testutil.ToFloat64(lastRequest) / 1e6))
if !lastRequestMetricResult.Equal(status.LastRequest) {
t.Fatalf("Last request expected (%v), got %v", status.LastRequest.UTC(), lastRequestMetricResult.UTC())
}
lastSuccessfulRequestMetricResult := time.UnixMilli(int64(testutil.ToFloat64(lastSuccessfulRequest) / 1e6))
if !lastSuccessfulRequestMetricResult.Equal(status.LastSuccessfulRequest) {
t.Fatalf("Last request expected (%v), got %v", status.LastSuccessfulRequest.UTC(), lastSuccessfulRequestMetricResult.UTC())
}
lastSuccessfulDownloadMetricResult := time.UnixMilli(int64(testutil.ToFloat64(lastSuccessfulDownload) / 1e6))
if !lastSuccessfulDownloadMetricResult.Equal(status.LastSuccessfulDownload) {
t.Fatalf("Last request expected (%v), got %v", status.LastSuccessfulDownload.UTC(), lastSuccessfulDownloadMetricResult.UTC())
}
lastSuccessfulActivationMetricResult := time.UnixMilli(int64(testutil.ToFloat64(lastSuccessfulActivation) / 1e6))
if !lastSuccessfulActivationMetricResult.Equal(status.LastSuccessfulActivation) {
t.Fatalf("Last request expected (%v), got %v", status.LastSuccessfulActivation.UTC(), lastSuccessfulActivationMetricResult.UTC())
}
bundlesLoaded := testutil.CollectAndCount(loaded)
if bundlesLoaded != 1 {
t.Fatalf("Unexpected number of bundle loads (%v), got %v", 1, bundlesLoaded)
}
bundlesFailedToLoad := testutil.CollectAndCount(failLoad)
if bundlesFailedToLoad != 0 {
t.Fatalf("Unexpected number of bundle fails load (%v), got %v", 0, bundlesFailedToLoad)
}
pluginsStatus := testutil.CollectAndCount(pluginStatus)
if pluginsStatus != 1 {
t.Fatalf("Unexpected number of plugins (%v), got %v", 1, pluginsStatus)
}
}
type prometheusRegisterMock struct {
Collectors map[prom.Collector]bool
}
+7
View File
@@ -2,6 +2,13 @@
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
// NOTE(sr): x509-related errors that we assert in the exported tests looked different
// before go1.17. Since they are still (non-strict) errors in both cases, we'll skip
// running the exported tests on go1.16.
// This can be removed when we drop support for go 1.16.
//go:build !go1.16
// +build !go1.16
package topdown
import (
+8
View File
@@ -0,0 +1,8 @@
//go:build !go1.18 || !darwin
// +build !go1.18 !darwin
package topdown
func fixupDarwinGo118(x string, _ string) string {
return x
}
+13
View File
@@ -0,0 +1,13 @@
//go:build go1.18
// +build go1.18
package topdown
func fixupDarwinGo118(x, y string) string {
switch x {
case "x509: certificate signed by unknown authority":
return y
default:
return x
}
}
+4 -4
View File
@@ -137,7 +137,7 @@ func TestHTTPGetRequestTlsInsecureSkipVerify(t *testing.T) {
expectedError error
}{
{note: "http.send", rules: []string{fmt.Sprintf(
`p = x { http.send({"method": "get", "url": "%s", "force_json_decode": true}, x) }`, ts.URL)}, expected: &Error{Message: "x509: certificate signed by unknown authority"}},
`p = x { http.send({"method": "get", "url": "%s", "force_json_decode": true}, x) }`, ts.URL)}, expected: &Error{Message: fixupDarwinGo118("x509: certificate signed by unknown authority", `x509: “Acme Co” certificate is not trusted`)}},
{note: "http.send", rules: []string{fmt.Sprintf(
`p = x { http.send({"method": "get", "url": "%s", "force_json_decode": true, "tls_insecure_skip_verify": true}, resp); x := clean_headers(resp) }`, ts.URL)}, expected: resultObj.String()},
// This case verifies that `tls_insecure_skip_verify`
@@ -2041,7 +2041,7 @@ func TestHTTPSClient(t *testing.T) {
t.Run("Negative Test: No Root Ca", func(t *testing.T) {
expectedResult := &Error{Code: BuiltinErr, Message: "x509: certificate signed by unknown authority", Location: nil}
expectedResult := &Error{Code: BuiltinErr, Message: fixupDarwinGo118("x509: certificate signed by unknown authority", `“my-server” certificate is not standards compliant`), Location: nil}
data := loadSmallTestData()
rule := []string{fmt.Sprintf(
`p = x { http.send({"method": "get", "url": "%s", "tls_client_cert_file": "%s", "tls_client_key_file": "%s"}, x) }`, s.URL, localClientCertFile, localClientKeyFile)}
@@ -2063,7 +2063,7 @@ func TestHTTPSClient(t *testing.T) {
t.Run("Negative Test: System Certs do not include local rootCA", func(t *testing.T) {
expectedResult := &Error{Code: BuiltinErr, Message: "x509: certificate signed by unknown authority", Location: nil}
expectedResult := &Error{Code: BuiltinErr, Message: fixupDarwinGo118("x509: certificate signed by unknown authority", `“my-server” certificate is not standards compliant`), Location: nil}
data := loadSmallTestData()
rule := []string{fmt.Sprintf(
`p = x { http.send({"method": "get", "url": "%s", "tls_client_cert_file": "%s", "tls_client_key_file": "%s", "tls_use_system_certs": true}, x) }`, s.URL, localClientCertFile, localClientKeyFile)}
@@ -2307,7 +2307,7 @@ func TestHTTPSNoClientCerts(t *testing.T) {
t.Run("Negative Test: System Certs do not include local rootCA", func(t *testing.T) {
expectedResult := &Error{Code: BuiltinErr, Message: "x509: certificate signed by unknown authority", Location: nil}
expectedResult := &Error{Code: BuiltinErr, Message: fixupDarwinGo118("x509: certificate signed by unknown authority", `“my-server” certificate is not standards compliant`), Location: nil}
data := loadSmallTestData()
rule := []string{fmt.Sprintf(
`p = x { http.send({"method": "get", "url": "%s", "tls_use_system_certs": true}, x) }`, s.URL)}
+2 -1
View File
@@ -6,6 +6,7 @@ package topdown
import (
"net"
"strings"
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/topdown/builtins"
@@ -36,7 +37,7 @@ func builtinLookupIPAddr(bctx BuiltinContext, operands []*ast.Term, iter func(*a
addrs, err := resolv.LookupIPAddr(bctx.Context, name)
if err != nil {
// NOTE(sr): We can't do better than this right now, see https://github.com/golang/go/issues/36208
if err.Error() == "operation was canceled" || err.Error() == "i/o timeout" {
if strings.Contains(err.Error(), "operation was canceled") || strings.Contains(err.Error(), "i/o timeout") {
return Halt{
Err: &Error{
Code: CancelErr,
+5 -1
View File
@@ -9,6 +9,7 @@ import (
"encoding/json"
"fmt"
"os"
"runtime"
"strings"
"testing"
"time"
@@ -469,7 +470,10 @@ func TestTopdownJWTEncodeSignECWithSeedReturnsSameSignature(t *testing.T) {
"y":"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0",
"d":"jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI"
}, x)`
encodedSigned := "eyJhbGciOiAiRVMyNTYifQ.eyJwYXkiOiAibG9hZCJ9.-LoHxtbT8t_TnqlLyONI4BtjvfkySO8TcoCFENqTTH2AKxvn29nAjxOdlbY-0EKVM2nJ4ukCx4IGtZtuwXr0VQ"
encodedSigned := "eyJhbGciOiAiRVMyNTYifQ.eyJwYXkiOiAibG9hZCJ9.05wmHY3NomU1jr7yvusBvKwhthRklPuJhUPOkoeIn5e5n_GXvE25EfRs9AJK2wOy6NoY2ljhj07M9BMtV0dfyA"
if runtime.Version() != "go1.18" {
encodedSigned = "eyJhbGciOiAiRVMyNTYifQ.eyJwYXkiOiAibG9hZCJ9.-LoHxtbT8t_TnqlLyONI4BtjvfkySO8TcoCFENqTTH2AKxvn29nAjxOdlbY-0EKVM2nJ4ukCx4IGtZtuwXr0VQ"
}
for i := 0; i < 10; i++ {
q := NewQuery(ast.MustParseBody(query)).