mirror of
https://github.com/aquasecurity/kube-bench.git
synced 2024-12-11 17:28:08 +00:00
Merge branch 'main' into 918
This commit is contained in:
commit
0baeb0a292
35
.github/workflows/build.yml
vendored
35
.github/workflows/build.yml
vendored
@ -19,8 +19,8 @@ env:
|
|||||||
KIND_IMAGE: "kindest/node:v1.21.1@sha256:69860bda5563ac81e3c0057d654b5253219618a22ec3a346306239bba8cfa1a6"
|
KIND_IMAGE: "kindest/node:v1.21.1@sha256:69860bda5563ac81e3c0057d654b5253219618a22ec3a346306239bba8cfa1a6"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
lint:
|
||||||
name: Build
|
name: Lint
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-18.04
|
||||||
steps:
|
steps:
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
@ -31,12 +31,32 @@ jobs:
|
|||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: yaml-lint
|
- name: yaml-lint
|
||||||
uses: ibiqlik/action-yamllint@v3
|
uses: ibiqlik/action-yamllint@v3
|
||||||
|
unit:
|
||||||
|
name: Unit tests
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
steps:
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: 1.16
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
- name: Run unit tests
|
- name: Run unit tests
|
||||||
run: make tests
|
run: make tests
|
||||||
- name: Upload code coverage
|
- name: Upload code coverage
|
||||||
uses: codecov/codecov-action@v2
|
uses: codecov/codecov-action@v2
|
||||||
with:
|
with:
|
||||||
file: ./coverage.txt
|
file: ./coverage.txt
|
||||||
|
e2e:
|
||||||
|
name: E2e tests
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
steps:
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: 1.16
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
- name: Setup Kubernetes cluster (KIND)
|
- name: Setup Kubernetes cluster (KIND)
|
||||||
uses: engineerd/setup-kind@v0.5.0
|
uses: engineerd/setup-kind@v0.5.0
|
||||||
with:
|
with:
|
||||||
@ -56,6 +76,17 @@ jobs:
|
|||||||
first_file_path: ./test.data
|
first_file_path: ./test.data
|
||||||
second_file_path: integration/testdata/Expected_output.data
|
second_file_path: integration/testdata/Expected_output.data
|
||||||
expected_result: PASSED
|
expected_result: PASSED
|
||||||
|
release:
|
||||||
|
name: Release snapshot
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
needs: [e2e, unit]
|
||||||
|
steps:
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: 1.16
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
- name: Dry-run release snapshot
|
- name: Dry-run release snapshot
|
||||||
uses: goreleaser/goreleaser-action@v2
|
uses: goreleaser/goreleaser-action@v2
|
||||||
with:
|
with:
|
||||||
|
@ -591,11 +591,16 @@ groups:
|
|||||||
|
|
||||||
audit_config: "grep -A1 experimental-encryption-provider-config /etc/origin/master/master-config.yaml | sed -n '2p' | awk '{ print $2 }' | xargs cat"
|
audit_config: "grep -A1 experimental-encryption-provider-config /etc/origin/master/master-config.yaml | sed -n '2p' | awk '{ print $2 }' | xargs cat"
|
||||||
tests:
|
tests:
|
||||||
|
bin_op: and
|
||||||
test_items:
|
test_items:
|
||||||
- path: "{.providers.aescbc.experimental-encryption-provider-config}"
|
- path: "{.resources[*].providers[*].aescbc.keys[*]}}"
|
||||||
compare:
|
compare:
|
||||||
op: has
|
op: has
|
||||||
value: "aescbc"
|
value: "secret"
|
||||||
|
- path: "{.resources[*].providers[*].aescbc.keys[*]}}"
|
||||||
|
compare:
|
||||||
|
op: has
|
||||||
|
value: "name"
|
||||||
remediation: |
|
remediation: |
|
||||||
Edit the Openshift master config file /etc/origin/master/master-config.yaml and set aescbc as the first provider in encryption provider config.
|
Edit the Openshift master config file /etc/origin/master/master-config.yaml and set aescbc as the first provider in encryption provider config.
|
||||||
See https://docs.openshift.com/container-platform/3.10/admin_guide/encrypting_data.html.
|
See https://docs.openshift.com/container-platform/3.10/admin_guide/encrypting_data.html.
|
||||||
|
@ -427,7 +427,7 @@ func TestExecuteJSONPath(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"JSONPath parse works, results don't match",
|
"JSONPath parse works, results don't match",
|
||||||
"{.Kind}",
|
"{.resourcesproviders.aescbc}",
|
||||||
kubeletConfig{
|
kubeletConfig{
|
||||||
Kind: "KubeletConfiguration",
|
Kind: "KubeletConfiguration",
|
||||||
ApiVersion: "kubelet.config.k8s.io/v1beta1",
|
ApiVersion: "kubelet.config.k8s.io/v1beta1",
|
||||||
@ -1134,3 +1134,129 @@ func TestToNumeric(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestExecuteJSONPathOnEncryptionConfig(t *testing.T) {
|
||||||
|
|
||||||
|
type Resources struct {
|
||||||
|
Resources []string `json:"resources"`
|
||||||
|
Providers []map[string]interface{} `json:"providers"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type EncryptionConfig struct {
|
||||||
|
Kind string `json:"kind"`
|
||||||
|
ApiVersion string `json:"apiVersion"`
|
||||||
|
Resources []Resources `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Key struct {
|
||||||
|
Secret string `json:"secret"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Aescbc struct {
|
||||||
|
Keys []Key `json:"keys"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecretBox struct {
|
||||||
|
Keys []Key `json:"keys"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Aesgcm struct {
|
||||||
|
Keys []Key `json:"keys"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// identity disable encryption when set as the first parameter
|
||||||
|
type Identity struct {}
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
jsonPath string
|
||||||
|
jsonInterface EncryptionConfig
|
||||||
|
expectedResult string
|
||||||
|
expectedToFail bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"JSONPath parse works, results match",
|
||||||
|
"{.resources[*].providers[*].aescbc.keys[*].secret}",
|
||||||
|
EncryptionConfig{
|
||||||
|
Kind: "EncryptionConfig",
|
||||||
|
ApiVersion: "v1",
|
||||||
|
Resources: []Resources{{Resources: []string{"secrets"}, Providers: []map[string]interface{}{
|
||||||
|
{"aescbc": Aescbc{Keys: []Key{Key{Secret: "secret1", Name: "name1"}}}},
|
||||||
|
}}}},
|
||||||
|
"secret1",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"JSONPath parse works, results match",
|
||||||
|
"{.resources[*].providers[*].aescbc.keys[*].name}",
|
||||||
|
EncryptionConfig{
|
||||||
|
Kind: "EncryptionConfig",
|
||||||
|
ApiVersion: "v1",
|
||||||
|
Resources: []Resources{{Resources: []string{"secrets"}, Providers: []map[string]interface{}{
|
||||||
|
{"aescbc": Aescbc{Keys: []Key{Key{Secret: "secret1", Name: "name1"}}}},
|
||||||
|
}}}},
|
||||||
|
"name1",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"JSONPath parse works, results don't match",
|
||||||
|
"{.resources[*].providers[*].aescbc.keys[*].secret}",
|
||||||
|
EncryptionConfig{
|
||||||
|
Kind: "EncryptionConfig",
|
||||||
|
ApiVersion: "v1",
|
||||||
|
Resources: []Resources{{Resources: []string{"secrets"}, Providers: []map[string]interface{}{
|
||||||
|
{"aesgcm": Aesgcm{Keys: []Key{Key{Secret: "secret1", Name: "name1"}}}},
|
||||||
|
}}}},
|
||||||
|
"secret1",
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"JSONPath parse works, results match",
|
||||||
|
"{.resources[*].providers[*].aesgcm.keys[*].secret}",
|
||||||
|
EncryptionConfig{
|
||||||
|
Kind: "EncryptionConfig",
|
||||||
|
ApiVersion: "v1",
|
||||||
|
Resources: []Resources{{Resources: []string{"secrets"}, Providers: []map[string]interface{}{
|
||||||
|
{"aesgcm": Aesgcm{Keys: []Key{Key{Secret: "secret1", Name: "name1"}}}},
|
||||||
|
}}}},
|
||||||
|
"secret1",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"JSONPath parse works, results match",
|
||||||
|
"{.resources[*].providers[*].secretbox.keys[*].secret}",
|
||||||
|
EncryptionConfig{
|
||||||
|
Kind: "EncryptionConfig",
|
||||||
|
ApiVersion: "v1",
|
||||||
|
Resources: []Resources{{Resources: []string{"secrets"}, Providers: []map[string]interface{}{
|
||||||
|
{"secretbox": SecretBox{Keys: []Key{Key{Secret: "secret1", Name: "name1"}}}},
|
||||||
|
}}}},
|
||||||
|
"secret1",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"JSONPath parse works, results match",
|
||||||
|
"{.resources[*].providers[*].aescbc.keys[*].secret}",
|
||||||
|
EncryptionConfig{
|
||||||
|
Kind: "EncryptionConfig",
|
||||||
|
ApiVersion: "v1",
|
||||||
|
Resources: []Resources{{Resources: []string{"secrets"}, Providers: []map[string]interface{}{
|
||||||
|
{"aescbc": Aescbc{Keys: []Key{Key{Secret: "secret1", Name: "name1"}, Key{Secret: "secret2", Name: "name2"}}}},
|
||||||
|
}}}},
|
||||||
|
"secret1 secret2",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
t.Run(c.name, func(t *testing.T) {
|
||||||
|
result, err := executeJSONPath(c.jsonPath, c.jsonInterface)
|
||||||
|
if err != nil && !c.expectedToFail {
|
||||||
|
t.Fatalf("jsonPath:%q, expectedResult:%q got:%v", c.jsonPath, c.expectedResult, err)
|
||||||
|
}
|
||||||
|
if c.expectedResult != result && !c.expectedToFail {
|
||||||
|
t.Errorf("jsonPath:%q, expectedResult:%q got:%q", c.jsonPath, c.expectedResult, result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
107
cmd/database.go
107
cmd/database.go
@ -11,36 +11,98 @@ import (
|
|||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func savePgsql(jsonInfo string) {
|
type PsqlConnInfo struct {
|
||||||
envVars := map[string]string{
|
Host string
|
||||||
"PGSQL_HOST": viper.GetString("PGSQL_HOST"),
|
User string
|
||||||
"PGSQL_USER": viper.GetString("PGSQL_USER"),
|
DbName string
|
||||||
"PGSQL_DBNAME": viper.GetString("PGSQL_DBNAME"),
|
SslMode string
|
||||||
"PGSQL_SSLMODE": viper.GetString("PGSQL_SSLMODE"),
|
Password string
|
||||||
"PGSQL_PASSWORD": viper.GetString("PGSQL_PASSWORD"),
|
}
|
||||||
|
|
||||||
|
func getPsqlConnInfo() (PsqlConnInfo, error) {
|
||||||
|
var host string
|
||||||
|
if value := viper.GetString("PGSQL_HOST"); value != "" {
|
||||||
|
host = value
|
||||||
|
} else {
|
||||||
|
return PsqlConnInfo{}, fmt.Errorf("%s_PGSQL_HOST env var is required", envVarsPrefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range envVars {
|
var user string
|
||||||
if v == "" {
|
if value := viper.GetString("PGSQL_USER"); value != "" {
|
||||||
exitWithError(fmt.Errorf("environment variable %s is missing", envVarsPrefix+"_"+k))
|
user = value
|
||||||
}
|
} else {
|
||||||
|
return PsqlConnInfo{}, fmt.Errorf("%s_PGSQL_USER env var is required", envVarsPrefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
connInfo := fmt.Sprintf("host=%s user=%s dbname=%s sslmode=%s password=%s",
|
var dbName string
|
||||||
envVars["PGSQL_HOST"],
|
if value := viper.GetString("PGSQL_DBNAME"); value != "" {
|
||||||
envVars["PGSQL_USER"],
|
dbName = value
|
||||||
envVars["PGSQL_DBNAME"],
|
} else {
|
||||||
envVars["PGSQL_SSLMODE"],
|
return PsqlConnInfo{}, fmt.Errorf("%s_PGSQL_USER env var is required", envVarsPrefix)
|
||||||
envVars["PGSQL_PASSWORD"],
|
}
|
||||||
|
|
||||||
|
var sslMode string
|
||||||
|
if value := viper.GetString("PGSQL_SSLMODE"); value != "" {
|
||||||
|
sslMode = value
|
||||||
|
} else {
|
||||||
|
return PsqlConnInfo{}, fmt.Errorf("%s_PGSQL_SSLMODE env var is required", envVarsPrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
var password string
|
||||||
|
if value := viper.GetString("PGSQL_PASSWORD"); value != "" {
|
||||||
|
password = value
|
||||||
|
} else {
|
||||||
|
return PsqlConnInfo{}, fmt.Errorf("%s_PGSQL_PASSWORD env var is required", envVarsPrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
return PsqlConnInfo{
|
||||||
|
Host: host,
|
||||||
|
User: user,
|
||||||
|
DbName: dbName,
|
||||||
|
SslMode: sslMode,
|
||||||
|
Password: password,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PsqlConnInfo) toString() string {
|
||||||
|
return fmt.Sprintf("host=%s user=%s dbname=%s sslmode=%s password=%s",
|
||||||
|
c.Host,
|
||||||
|
c.User,
|
||||||
|
c.DbName,
|
||||||
|
c.SslMode,
|
||||||
|
c.Password,
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
hostname, err := os.Hostname()
|
func savePgsql(jsonInfo string) {
|
||||||
|
var hostname string
|
||||||
|
if value := viper.GetString("K8S_HOST"); value != "" {
|
||||||
|
// Adhere to the ScanHost column definition below
|
||||||
|
if len(value) > 63 {
|
||||||
|
exitWithError(fmt.Errorf("%s_K8S_HOST value's length must be less than 63 chars", envVarsPrefix))
|
||||||
|
}
|
||||||
|
|
||||||
|
hostname = value
|
||||||
|
} else {
|
||||||
|
host, err := os.Hostname()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exitWithError(fmt.Errorf("received error looking up hostname: %s", err))
|
exitWithError(fmt.Errorf("received error looking up hostname: %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
timestamp := time.Now()
|
hostname = host
|
||||||
|
}
|
||||||
|
|
||||||
|
PsqlConnInfo, err := getPsqlConnInfo()
|
||||||
|
if err != nil {
|
||||||
|
exitWithError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := gorm.Open(postgres.Open(PsqlConnInfo.toString()), &gorm.Config{})
|
||||||
|
if err != nil {
|
||||||
|
exitWithError(fmt.Errorf("received error connecting to database: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
timestamp := time.Now()
|
||||||
type ScanResult struct {
|
type ScanResult struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
ScanHost string `gorm:"type:varchar(63) not null"` // https://www.ietf.org/rfc/rfc1035.txt
|
ScanHost string `gorm:"type:varchar(63) not null"` // https://www.ietf.org/rfc/rfc1035.txt
|
||||||
@ -48,12 +110,7 @@ func savePgsql(jsonInfo string) {
|
|||||||
ScanInfo string `gorm:"type:jsonb not null"`
|
ScanInfo string `gorm:"type:jsonb not null"`
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := gorm.Open(postgres.Open(connInfo), &gorm.Config{})
|
|
||||||
if err != nil {
|
|
||||||
exitWithError(fmt.Errorf("received error connecting to database: %s", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
db.Debug().AutoMigrate(&ScanResult{})
|
db.Debug().AutoMigrate(&ScanResult{})
|
||||||
db.Save(&ScanResult{ScanHost: hostname, ScanTime: timestamp, ScanInfo: jsonInfo})
|
db.Save(&ScanResult{ScanHost: hostname, ScanTime: timestamp, ScanInfo: jsonInfo})
|
||||||
glog.V(2).Info(fmt.Sprintf("successfully stored result to: %s", envVars["PGSQL_HOST"]))
|
glog.V(2).Info(fmt.Sprintf("successfully stored result to: %s", PsqlConnInfo.Host))
|
||||||
}
|
}
|
||||||
|
4
go.mod
4
go.mod
@ -3,7 +3,7 @@ module github.com/aquasecurity/kube-bench
|
|||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/aws/aws-sdk-go v1.41.0
|
github.com/aws/aws-sdk-go v1.41.11
|
||||||
github.com/fatih/color v1.13.0
|
github.com/fatih/color v1.13.0
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
|
||||||
github.com/magiconair/properties v1.8.5
|
github.com/magiconair/properties v1.8.5
|
||||||
@ -13,7 +13,7 @@ require (
|
|||||||
github.com/spf13/viper v1.9.0
|
github.com/spf13/viper v1.9.0
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
gorm.io/driver/postgres v1.1.2
|
gorm.io/driver/postgres v1.2.0
|
||||||
gorm.io/gorm v1.21.16
|
gorm.io/gorm v1.21.16
|
||||||
k8s.io/client-go v0.22.2
|
k8s.io/client-go v0.22.2
|
||||||
)
|
)
|
||||||
|
9
go.sum
9
go.sum
@ -64,8 +64,8 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
|
|||||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||||
github.com/aws/aws-sdk-go v1.41.0 h1:XUzHLFWQVhmFtmKTodnAo5QdooPQfpVfilCxIV3aLoE=
|
github.com/aws/aws-sdk-go v1.41.11 h1:QLouWsiYQ8i22kD8k58Dpdhio1A0MpT7bg9ZNXqEjuI=
|
||||||
github.com/aws/aws-sdk-go v1.41.0/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
|
github.com/aws/aws-sdk-go v1.41.11/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
|
||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
@ -899,9 +899,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
|||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gorm.io/driver/postgres v1.1.2 h1:Amy3hCvLqM+/ICzjCnQr8wKFLVJTeOTdlMT7kCP+J1Q=
|
gorm.io/driver/postgres v1.2.0 h1:2k0EYyqii7sfWVM7yomw6a82Jt5wjuQUpWmD6fI9fGI=
|
||||||
gorm.io/driver/postgres v1.1.2/go.mod h1:/AGV0zvqF3mt9ZtzLzQmXWQ/5vr+1V1TyHZGZVjzmwI=
|
gorm.io/driver/postgres v1.2.0/go.mod h1:c/8rVZUl30/ZyaQtAobsLRbBTubskhCrkWZDwZe1KfI=
|
||||||
gorm.io/gorm v1.21.15/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
|
|
||||||
gorm.io/gorm v1.21.16 h1:YBIQLtP5PLfZQz59qfrq7xbrK7KWQ+JsXXCH/THlMqs=
|
gorm.io/gorm v1.21.16 h1:YBIQLtP5PLfZQz59qfrq7xbrK7KWQ+JsXXCH/THlMqs=
|
||||||
gorm.io/gorm v1.21.16/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
|
gorm.io/gorm v1.21.16/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
Loading…
Reference in New Issue
Block a user