-
Notifications
You must be signed in to change notification settings - Fork 76
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[skunkworks] Auditing contract testing
Signed-off-by: jose.vazquez <jose.vazquez@mongodb.com>
- Loading branch information
Showing
19 changed files
with
711 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
name: Contract Tests | ||
|
||
on: | ||
workflow_call: | ||
workflow_dispatch: | ||
|
||
jobs: | ||
contract: | ||
name: Contract Tests | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Check out code | ||
uses: actions/checkout@v4 | ||
with: | ||
ref: ${{github.event.pull_request.head.sha}} | ||
|
||
- name: Setup Go | ||
uses: actions/setup-go@v5 | ||
with: | ||
go-version-file: "${{ github.workspace }}/go.mod" | ||
cache: false | ||
|
||
- name: Create k8s Kind Cluster | ||
uses: helm/kind-action@v1.10.0 | ||
with: | ||
version: v0.22.0 | ||
config: test/helper/e2e/config/kind.yaml | ||
node_image: kindest/node:v1.29.2 | ||
|
||
- name: Run Contract Testing | ||
env: | ||
AKO_CONTRACT_TEST: 1 | ||
MCLI_OPS_MANAGER_URL: https://cloud-qa.mongodb.com | ||
MCLI_ORG_ID: ${{ secrets.ATLAS_ORG_ID }} | ||
MCLI_PUBLIC_API_KEY: ${{ secrets.ATLAS_PUBLIC_KEY }} | ||
MCLI_PRIVATE_API_KEY: ${{ secrets.ATLAS_PRIVATE_KEY }} | ||
run: make contract-tests |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package auditing | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"go.mongodb.org/atlas-sdk/v20231115008/admin" | ||
"go.uber.org/zap" | ||
"k8s.io/apimachinery/pkg/types" | ||
|
||
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translayer" | ||
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/atlas" | ||
) | ||
|
||
type Service interface { | ||
Get(ctx context.Context, projectID string) (*Auditing, error) | ||
Set(ctx context.Context, projectID string, auditing *Auditing) error | ||
} | ||
|
||
type service struct { | ||
admin.AuditingApi | ||
} | ||
|
||
func NewService(ctx context.Context, provider atlas.Provider, secretRef *types.NamespacedName, log *zap.SugaredLogger) (Service, error) { | ||
client, err := translayer.NewVersionedClient(ctx, provider, secretRef, log) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return NewFromAuditingAPI(client.AuditingApi), nil | ||
} | ||
|
||
func NewFromAuditingAPI(api admin.AuditingApi) *service { | ||
return &service{AuditingApi: api} | ||
} | ||
|
||
func (s *service) Get(ctx context.Context, projectID string) (*Auditing, error) { | ||
auditLog, _, err := s.AuditingApi.GetAuditingConfiguration(ctx, projectID).Execute() | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to get audit log from Atlas: %w", err) | ||
} | ||
return fromAtlas(auditLog) | ||
} | ||
|
||
func (s *service) Set(ctx context.Context, projectID string, auditing *Auditing) error { | ||
_, _, err := s.AuditingApi.UpdateAuditingConfiguration(ctx, projectID, toAtlas(auditing)).Execute() | ||
return err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package auditing | ||
|
||
import ( | ||
"fmt" | ||
|
||
"go.mongodb.org/atlas-sdk/v20231115008/admin" | ||
|
||
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/pointer" | ||
) | ||
|
||
type AuditingConfigType string | ||
|
||
const ( | ||
None AuditingConfigType = "NONE" | ||
FilterBuilder AuditingConfigType = "FILTER_BUILDER" | ||
FilterJSON AuditingConfigType = "FILTER_JSON" | ||
) | ||
|
||
type Auditing struct { | ||
Enabled bool | ||
AuditAuthorizationSuccess bool | ||
ConfigurationType AuditingConfigType | ||
AuditFilter string | ||
} | ||
|
||
func toAtlas(auditing *Auditing) *admin.AuditLog { | ||
return &admin.AuditLog{ | ||
Enabled: pointer.MakePtr(auditing.Enabled), | ||
AuditAuthorizationSuccess: pointer.MakePtr(auditing.AuditAuthorizationSuccess), | ||
AuditFilter: pointer.MakePtr(auditing.AuditFilter), | ||
// ConfigurationType is not set on the PATCH operation to Atlas | ||
} | ||
} | ||
|
||
func fromAtlas(auditLog *admin.AuditLog) (*Auditing, error) { | ||
cfgType, err := configTypeFromAtlas(auditLog.ConfigurationType) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &Auditing{ | ||
Enabled: pointer.GetOrDefault(auditLog.Enabled, false), | ||
AuditAuthorizationSuccess: pointer.GetOrDefault(auditLog.AuditAuthorizationSuccess, false), | ||
ConfigurationType: cfgType, | ||
AuditFilter: pointer.GetOrDefault(auditLog.AuditFilter, ""), | ||
}, nil | ||
} | ||
|
||
func configTypeFromAtlas(configType *string) (AuditingConfigType, error) { | ||
ct := pointer.GetOrDefault(configType, string(None)) | ||
switch ct { | ||
case string(None), string(FilterBuilder), string(FilterJSON): | ||
return AuditingConfigType(ct), nil | ||
default: | ||
return AuditingConfigType(ct), fmt.Errorf("unsupported Auditing Config type %q", ct) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package translayer | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"go.mongodb.org/atlas-sdk/v20231115008/admin" | ||
"go.uber.org/zap" | ||
"k8s.io/apimachinery/pkg/types" | ||
|
||
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/atlas" | ||
) | ||
|
||
func NewVersionedClient(ctx context.Context, provider atlas.Provider, secretRef *types.NamespacedName, log *zap.SugaredLogger) (*admin.APIClient, error) { | ||
apiClient, _, err := provider.SdkClient(ctx, secretRef, log) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to instantiate Versioned Atlas client: %w", err) | ||
} | ||
return apiClient, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
package auditing | ||
|
||
import ( | ||
"context" | ||
_ "embed" | ||
"log" | ||
"testing" | ||
"time" | ||
|
||
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translayer/auditing" | ||
"github.com/mongodb/mongodb-atlas-kubernetes/v2/test/helper/control" | ||
"github.com/mongodb/mongodb-atlas-kubernetes/v2/test/helper/launcher" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/mongodb/mongodb-atlas-kubernetes/v2/test/contract" | ||
) | ||
|
||
//go:embed test.yml | ||
var testYml string | ||
|
||
const ( | ||
testVersion = "2.1.0" | ||
) | ||
|
||
func TestMain(m *testing.M) { | ||
if !control.Enabled("AKO_CONTRACT_TEST") { | ||
log.Printf("Skipping contract test as AKO_CONTRACT_TEST is unset") | ||
return | ||
} | ||
l := launcher.NewFromEnv(testVersion) | ||
l.Launch( | ||
testYml, | ||
launcher.WaitReady("atlasprojects/my-project", 30*time.Second)) | ||
if !control.Enabled("SKIP_CLEANUP") { // allow to reuse Atlas resources for local tests | ||
defer l.Cleanup() | ||
} | ||
m.Run() | ||
} | ||
|
||
func TestDefaultAuditingGet(t *testing.T) { | ||
testProjectID := mustReadProjectID() | ||
ctx := context.Background() | ||
as := auditing.NewFromAuditingAPI(contract.MustVersionedClient(t, ctx).AuditingApi) | ||
|
||
result, err := as.Get(ctx, testProjectID) | ||
|
||
require.NoError(t, err) | ||
result.ConfigurationType = "" // Do not expect the returned cfg type to match | ||
if result.AuditFilter == "{}" { | ||
// Support re-runs, as we cannot get the filter back to empty | ||
result.AuditFilter = "" | ||
} | ||
assert.Equal(t, defaultAtlasAuditing(), result) | ||
} | ||
|
||
func defaultAtlasAuditing() *auditing.Auditing { | ||
return &auditing.Auditing{ | ||
Enabled: false, | ||
AuditAuthorizationSuccess: false, | ||
AuditFilter: "", | ||
} | ||
} | ||
|
||
func TestSyncs(t *testing.T) { | ||
testCases := []struct { | ||
title string | ||
auditing *auditing.Auditing | ||
}{ | ||
{ | ||
title: "Just enabled", | ||
auditing: &auditing.Auditing{ | ||
Enabled: true, | ||
AuditAuthorizationSuccess: false, | ||
AuditFilter: "{}", // must sent empty JSON to overwrite previous state | ||
}, | ||
}, | ||
{ | ||
title: "Auth success logs as well", | ||
auditing: &auditing.Auditing{ | ||
Enabled: true, | ||
AuditAuthorizationSuccess: true, | ||
AuditFilter: "{}", | ||
}, | ||
}, | ||
{ | ||
title: "With a filter", | ||
auditing: &auditing.Auditing{ | ||
Enabled: true, | ||
AuditAuthorizationSuccess: false, | ||
AuditFilter: `{"atype":"authenticate"}`, | ||
}, | ||
}, | ||
{ | ||
title: "With a filter and success logs", | ||
auditing: &auditing.Auditing{ | ||
Enabled: true, | ||
AuditAuthorizationSuccess: true, | ||
AuditFilter: `{"atype":"authenticate"}`, | ||
}, | ||
}, | ||
{ | ||
title: "All set but disabled", | ||
auditing: &auditing.Auditing{ | ||
Enabled: false, | ||
AuditAuthorizationSuccess: true, | ||
AuditFilter: `{"atype":"authenticate"}`, | ||
}, | ||
}, | ||
{ | ||
title: "Default (disabled) case", | ||
auditing: &auditing.Auditing{ | ||
Enabled: false, | ||
AuditAuthorizationSuccess: false, | ||
AuditFilter: "{}", | ||
}, | ||
}, | ||
} | ||
testProjectID := mustReadProjectID() | ||
ctx := context.Background() | ||
as := auditing.NewFromAuditingAPI(contract.MustVersionedClient(t, ctx).AuditingApi) | ||
|
||
for _, tc := range testCases { | ||
t.Run(tc.title, func(t *testing.T) { | ||
err := as.Set(ctx, testProjectID, tc.auditing) | ||
require.NoError(t, err) | ||
|
||
result, err := as.Get(ctx, testProjectID) | ||
require.NoError(t, err) | ||
result.ConfigurationType = "" // Do not expect the returned cfg type to match | ||
assert.Equal(t, tc.auditing, result) | ||
}) | ||
} | ||
} | ||
|
||
func mustReadProjectID() string { | ||
l := launcher.NewFromEnv(testVersion) | ||
output, err := l.Kubectl("get", "atlasprojects/my-project", "-o=jsonpath={.status.id}") | ||
if err != nil { | ||
log.Fatalf("Failed to get test project id: %v", err) | ||
} | ||
return output | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
apiVersion: atlas.mongodb.com/v1 | ||
kind: AtlasProject | ||
metadata: | ||
name: my-project | ||
spec: | ||
name: Test Atlas Operator Project |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package contract | ||
|
||
import ( | ||
"context" | ||
"os" | ||
"testing" | ||
|
||
"go.mongodb.org/atlas-sdk/v20231115008/admin" | ||
|
||
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/atlas" | ||
) | ||
|
||
func NewVersionedClient(ctx context.Context) (*admin.APIClient, error) { | ||
domain := os.Getenv("MCLI_OPS_MANAGER_URL") | ||
pubKey := os.Getenv("MCLI_PUBLIC_API_KEY") | ||
prvKey := os.Getenv("MCLI_PRIVATE_API_KEY") | ||
return atlas.NewClient(domain, pubKey, prvKey) | ||
} | ||
|
||
func MustVersionedClient(t *testing.T, ctx context.Context) *admin.APIClient { | ||
client, err := NewVersionedClient(ctx) | ||
if err != nil { | ||
t.Fatalf("Failed to get Atlas versioned client: %v", err) | ||
} | ||
return client | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.