mirror of
https://dev.azure.com/schwarzit/schwarzit.stackit-public/_git/audit-go
synced 2026-02-08 00:57:24 +00:00
Compare commits
18 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80326d88a6 | ||
|
|
b10f6797ff | ||
|
|
84c49f2690 | ||
|
|
4c7c36c8f1 | ||
|
|
a706af62a4 | ||
|
|
f2715624e9 | ||
|
|
40eacfe4ad | ||
|
|
cdea0ac81a | ||
|
|
85aae1c2e7 | ||
|
|
56b04b94cb | ||
|
|
6af0e83a95 | ||
|
|
6b5bc6dfe2 | ||
|
|
e8567c19ff | ||
|
|
618be58a26 | ||
|
|
68cec628e0 | ||
|
|
3eb803ae1c | ||
|
|
ddee3db2fe | ||
|
|
720a1a6d72 |
65 changed files with 3436 additions and 2775 deletions
|
|
@ -1,17 +1,22 @@
|
||||||
pool:
|
pool:
|
||||||
vmImage: 'ubuntu-latest'
|
vmImage: 'ubuntu-24.04'
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
- name: bufVersion
|
- name: bufVersion
|
||||||
value: v1.50.0
|
# go install github.com/bufbuild/buf/cmd/buf@
|
||||||
|
value: v1.63.0
|
||||||
- name: golangCiLintVersion
|
- name: golangCiLintVersion
|
||||||
value: v1.63.4
|
# github.com/golangci/golangci-lint
|
||||||
|
value: v2.8.0
|
||||||
- name: goVersion
|
- name: goVersion
|
||||||
value: 1.22.7
|
# github.com/golang/go
|
||||||
|
value: 1.24.0
|
||||||
- name: protobufValidateVersion
|
- name: protobufValidateVersion
|
||||||
value: v1.2.1
|
# go install github.com/envoyproxy/protoc-gen-validate@
|
||||||
|
value: v1.3.0
|
||||||
- name: protobufVersion
|
- name: protobufVersion
|
||||||
value: v1.36.4
|
# go install google.golang.org/protobuf/cmd/protoc-gen-go@
|
||||||
|
value: v1.36.11
|
||||||
- name: GOPATH
|
- name: GOPATH
|
||||||
value: '$(system.defaultWorkingDirectory)/gopath'
|
value: '$(system.defaultWorkingDirectory)/gopath'
|
||||||
|
|
||||||
|
|
@ -21,6 +26,7 @@ stages:
|
||||||
- job: GoBuildTest
|
- job: GoBuildTest
|
||||||
displayName: Run build and tests
|
displayName: Run build and tests
|
||||||
variables:
|
variables:
|
||||||
|
- group: artifactory-xx-sit-odj-sec-ident
|
||||||
- name: isCiBuild
|
- name: isCiBuild
|
||||||
value: $[eq(variables['Build.SourceBranch'], 'refs/heads/main')]
|
value: $[eq(variables['Build.SourceBranch'], 'refs/heads/main')]
|
||||||
steps:
|
steps:
|
||||||
|
|
@ -80,6 +86,10 @@ stages:
|
||||||
condition: succeeded()
|
condition: succeeded()
|
||||||
displayName: Check local changes after code generation and formatting
|
displayName: Check local changes after code generation and formatting
|
||||||
|
|
||||||
|
- script: echo "$(ARTIFACTORY_PASSWORD)" | docker login schwarzit-docker.jfrog.io --username $(ARTIFACTORY_USER) --password-stdin
|
||||||
|
displayName: 'Docker login'
|
||||||
|
condition: succeeded()
|
||||||
|
|
||||||
- bash: go build ./...
|
- bash: go build ./...
|
||||||
condition: succeeded()
|
condition: succeeded()
|
||||||
displayName: Build
|
displayName: Build
|
||||||
|
|
|
||||||
46
.azuredevops/main-code-analyze.yml
Normal file
46
.azuredevops/main-code-analyze.yml
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
---
|
||||||
|
name: audit_go_main_code_analyze_$(Date:yyyy-MM-dd)_$(SourceBranchName)_$(Rev:r)
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
- main
|
||||||
|
|
||||||
|
resources:
|
||||||
|
repositories:
|
||||||
|
- repository: tools
|
||||||
|
type: git
|
||||||
|
name: schwarzit.stackit-core-platform/core-platform-tools
|
||||||
|
ref: refs/tags/v1.15.0
|
||||||
|
|
||||||
|
pool:
|
||||||
|
vmImage: ubuntu-24.04
|
||||||
|
|
||||||
|
variables:
|
||||||
|
- name: reportDir
|
||||||
|
value: '$(System.DefaultWorkingDirectory)/out'
|
||||||
|
- name: goVersion
|
||||||
|
value: 1.25.5
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- stage: CodeQualityScans
|
||||||
|
displayName: "Code Quality Scans"
|
||||||
|
jobs:
|
||||||
|
- template: ./.azuredevops/templates/jobs/code/code-format.yml@tools
|
||||||
|
parameters:
|
||||||
|
lintReports: true
|
||||||
|
lintReportDir: $(reportDir)
|
||||||
|
|
||||||
|
- template: ./.azuredevops/templates/jobs/code/code-test.yml@tools
|
||||||
|
parameters:
|
||||||
|
testReports: true
|
||||||
|
testReportDir: $(reportDir)
|
||||||
|
|
||||||
|
- template: ./.azuredevops/templates/jobs/code/code-quality-scans.yml@tools
|
||||||
|
parameters:
|
||||||
|
dependsOn:
|
||||||
|
- Tests
|
||||||
|
- Linter
|
||||||
|
organization: 'xx-sit-odj-stackit-public'
|
||||||
|
serviceConnection: 'xx-sit-odj-stackit-public-snyk'
|
||||||
|
sonar: true
|
||||||
|
sonarReportSourceDir: $(reportDir)
|
||||||
|
sonarServiceConnection: sonarqube-audit-go
|
||||||
|
|
@ -6,6 +6,6 @@
|
||||||
|
|
||||||
[Describe how the change was tested if it needs explanation]
|
[Describe how the change was tested if it needs explanation]
|
||||||
|
|
||||||
Security-concept-update-needed: true/false.
|
Security-concept-update-needed: false.
|
||||||
|
|
||||||
JIRA Work Item: STACKITALO-xxx
|
JIRA Work Item: [STACKITRMA-XXX](https://jira.schwarz/browse/STACKITRMA-XXX)
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
trigger: none
|
trigger: none
|
||||||
|
|
||||||
pool:
|
pool:
|
||||||
vmImage: 'ubuntu-latest'
|
vmImage: 'ubuntu-24.04'
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
- name: releaseType
|
- name: releaseType
|
||||||
|
|
|
||||||
287
.golangci.yml
Normal file
287
.golangci.yml
Normal file
|
|
@ -0,0 +1,287 @@
|
||||||
|
version: "2"
|
||||||
|
run:
|
||||||
|
issues-exit-code: 1
|
||||||
|
tests: true
|
||||||
|
linters:
|
||||||
|
default: none
|
||||||
|
enable:
|
||||||
|
- asciicheck
|
||||||
|
- bodyclose
|
||||||
|
- copyloopvar
|
||||||
|
- cyclop
|
||||||
|
- dogsled
|
||||||
|
- dupl
|
||||||
|
- durationcheck
|
||||||
|
- errcheck
|
||||||
|
- errorlint
|
||||||
|
- exhaustive
|
||||||
|
- forbidigo
|
||||||
|
- forcetypeassert
|
||||||
|
- gochecknoglobals
|
||||||
|
- gochecknoinits
|
||||||
|
- gocognit
|
||||||
|
- goconst
|
||||||
|
- gocritic
|
||||||
|
- gocyclo
|
||||||
|
- gomoddirectives
|
||||||
|
- gomodguard
|
||||||
|
- goprintffuncname
|
||||||
|
- gosec
|
||||||
|
- govet
|
||||||
|
- importas
|
||||||
|
- ineffassign
|
||||||
|
- lll
|
||||||
|
- makezero
|
||||||
|
- misspell
|
||||||
|
- nakedret
|
||||||
|
- nestif
|
||||||
|
- nilerr
|
||||||
|
- noctx
|
||||||
|
- nolintlint
|
||||||
|
- prealloc
|
||||||
|
- predeclared
|
||||||
|
- promlinter
|
||||||
|
- revive
|
||||||
|
- rowserrcheck
|
||||||
|
- sqlclosecheck
|
||||||
|
- staticcheck
|
||||||
|
- tparallel
|
||||||
|
- unconvert
|
||||||
|
- unparam
|
||||||
|
- unused
|
||||||
|
- wastedassign
|
||||||
|
settings:
|
||||||
|
cyclop:
|
||||||
|
max-complexity: 45
|
||||||
|
package-average: 0
|
||||||
|
dogsled:
|
||||||
|
max-blank-identifiers: 2
|
||||||
|
dupl:
|
||||||
|
threshold: 150
|
||||||
|
errcheck:
|
||||||
|
check-type-assertions: true
|
||||||
|
check-blank: true
|
||||||
|
exhaustive:
|
||||||
|
default-signifies-exhaustive: true
|
||||||
|
funlen:
|
||||||
|
lines: 100
|
||||||
|
statements: 50
|
||||||
|
gocognit:
|
||||||
|
min-complexity: 45
|
||||||
|
goconst:
|
||||||
|
min-len: 3
|
||||||
|
min-occurrences: 5
|
||||||
|
gocritic:
|
||||||
|
disabled-checks:
|
||||||
|
- dupImport
|
||||||
|
- octalLiteral
|
||||||
|
- unnamedResult
|
||||||
|
enabled-tags:
|
||||||
|
- diagnostic
|
||||||
|
- experimental
|
||||||
|
- opinionated
|
||||||
|
- performance
|
||||||
|
- style
|
||||||
|
settings:
|
||||||
|
hugeParam:
|
||||||
|
sizeThreshold: 121
|
||||||
|
gocyclo:
|
||||||
|
min-complexity: 45
|
||||||
|
govet:
|
||||||
|
disable:
|
||||||
|
- fieldalignment
|
||||||
|
enable-all: true
|
||||||
|
lll:
|
||||||
|
line-length: 180
|
||||||
|
tab-width: 1
|
||||||
|
nakedret:
|
||||||
|
max-func-lines: 5
|
||||||
|
nestif:
|
||||||
|
min-complexity: 10
|
||||||
|
nlreturn:
|
||||||
|
block-size: 5
|
||||||
|
nolintlint:
|
||||||
|
require-explanation: true
|
||||||
|
require-specific: true
|
||||||
|
allow-unused: false
|
||||||
|
prealloc:
|
||||||
|
simple: true
|
||||||
|
range-loops: true
|
||||||
|
for-loops: true
|
||||||
|
revive:
|
||||||
|
rules:
|
||||||
|
- name: context-keys-type
|
||||||
|
disabled: false
|
||||||
|
- name: time-naming
|
||||||
|
disabled: false
|
||||||
|
- name: var-declaration
|
||||||
|
disabled: false
|
||||||
|
- name: unexported-return
|
||||||
|
disabled: false
|
||||||
|
- name: errorf
|
||||||
|
disabled: false
|
||||||
|
- name: blank-imports
|
||||||
|
disabled: false
|
||||||
|
- name: context-as-argument
|
||||||
|
disabled: false
|
||||||
|
- name: dot-imports
|
||||||
|
disabled: false
|
||||||
|
- name: error-return
|
||||||
|
disabled: false
|
||||||
|
- name: error-strings
|
||||||
|
disabled: false
|
||||||
|
- name: error-naming
|
||||||
|
disabled: false
|
||||||
|
- name: exported
|
||||||
|
disabled: false
|
||||||
|
- name: increment-decrement
|
||||||
|
disabled: false
|
||||||
|
- name: var-naming
|
||||||
|
disabled: true
|
||||||
|
- name: package-comments
|
||||||
|
disabled: false
|
||||||
|
- name: range
|
||||||
|
disabled: false
|
||||||
|
- name: receiver-naming
|
||||||
|
disabled: false
|
||||||
|
- name: indent-error-flow
|
||||||
|
disabled: false
|
||||||
|
staticcheck:
|
||||||
|
initialisms:
|
||||||
|
- ACL
|
||||||
|
- API
|
||||||
|
- ASCII
|
||||||
|
- CPU
|
||||||
|
- CSS
|
||||||
|
- DNS
|
||||||
|
- EOF
|
||||||
|
- GUID
|
||||||
|
- HTML
|
||||||
|
- HTTP
|
||||||
|
- HTTPS
|
||||||
|
- ID
|
||||||
|
- IP
|
||||||
|
- JSON
|
||||||
|
- QPS
|
||||||
|
- RAM
|
||||||
|
- RPC
|
||||||
|
- SLA
|
||||||
|
- SMTP
|
||||||
|
- SQL
|
||||||
|
- SSH
|
||||||
|
- TCP
|
||||||
|
- TLS
|
||||||
|
- TTL
|
||||||
|
- UDP
|
||||||
|
- UI
|
||||||
|
- GID
|
||||||
|
- UID
|
||||||
|
- UUID
|
||||||
|
- URI
|
||||||
|
- URL
|
||||||
|
- UTF8
|
||||||
|
- VM
|
||||||
|
- XML
|
||||||
|
- XMPP
|
||||||
|
- XSRF
|
||||||
|
- XSS
|
||||||
|
- SIP
|
||||||
|
- RTP
|
||||||
|
- AMQP
|
||||||
|
- DB
|
||||||
|
- TS
|
||||||
|
unparam:
|
||||||
|
check-exported: false
|
||||||
|
unused:
|
||||||
|
exported-fields-are-used: false
|
||||||
|
whitespace:
|
||||||
|
multi-if: false
|
||||||
|
multi-func: false
|
||||||
|
exclusions:
|
||||||
|
generated: lax
|
||||||
|
presets:
|
||||||
|
- comments
|
||||||
|
- common-false-positives
|
||||||
|
- legacy
|
||||||
|
- std-error-handling
|
||||||
|
rules:
|
||||||
|
- path: internal/audit/api/api_common.go
|
||||||
|
text: context-as-argument
|
||||||
|
- linters:
|
||||||
|
- gochecknoglobals
|
||||||
|
path: pkg/audit/common/api.go|pkg/log/log.go|internal/telemetry/telemetry.go
|
||||||
|
- linters:
|
||||||
|
- dupl
|
||||||
|
path: pkg/audit/api/api_.*.go
|
||||||
|
- path: internal/audit/api/model_test.go|internal/audit/api/model.go
|
||||||
|
text: G115
|
||||||
|
- linters:
|
||||||
|
- gosec
|
||||||
|
path: internal/audit/api/test_data.go
|
||||||
|
- linters:
|
||||||
|
- dogsled
|
||||||
|
- dupl
|
||||||
|
- errcheck
|
||||||
|
- forbidigo
|
||||||
|
- forcetypeassert
|
||||||
|
- gochecknoglobals
|
||||||
|
- gocognit
|
||||||
|
- goconst
|
||||||
|
- gocritic
|
||||||
|
- ineffassign
|
||||||
|
- lll
|
||||||
|
- nakedret
|
||||||
|
- nestif
|
||||||
|
- nlreturn
|
||||||
|
- noctx
|
||||||
|
- revive
|
||||||
|
- staticcheck
|
||||||
|
- unconvert
|
||||||
|
- unparam
|
||||||
|
- wastedassign
|
||||||
|
- wsl
|
||||||
|
path: _test\.go
|
||||||
|
- linters:
|
||||||
|
- govet
|
||||||
|
text: declaration of "err" shadows declaration
|
||||||
|
- linters:
|
||||||
|
- dogsled
|
||||||
|
- dupl
|
||||||
|
- errcheck
|
||||||
|
- forbidigo
|
||||||
|
- forcetypeassert
|
||||||
|
- gochecknoglobals
|
||||||
|
- gocognit
|
||||||
|
- goconst
|
||||||
|
- gocritic
|
||||||
|
- ineffassign
|
||||||
|
- lll
|
||||||
|
- nakedret
|
||||||
|
- nestif
|
||||||
|
- nlreturn
|
||||||
|
- noctx
|
||||||
|
- revive
|
||||||
|
- staticcheck
|
||||||
|
- unconvert
|
||||||
|
- unparam
|
||||||
|
- wastedassign
|
||||||
|
- wsl
|
||||||
|
path: test_.*\.go|pkg/messaging/test/solace.go
|
||||||
|
- linters:
|
||||||
|
- prealloc
|
||||||
|
path: internal/messaging/amqp_connection_pool_test.go
|
||||||
|
text: Consider preallocating connections with capacity 5
|
||||||
|
paths:
|
||||||
|
- third_party$
|
||||||
|
- builtin$
|
||||||
|
- examples$
|
||||||
|
issues:
|
||||||
|
max-issues-per-linter: 0
|
||||||
|
max-same-issues: 0
|
||||||
|
formatters:
|
||||||
|
exclusions:
|
||||||
|
generated: lax
|
||||||
|
paths:
|
||||||
|
- third_party$
|
||||||
|
- builtin$
|
||||||
|
- examples$
|
||||||
82
Makefile
Normal file
82
Makefile
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
SHELL = /bin/bash -euo pipefail
|
||||||
|
PWD = $(shell pwd)
|
||||||
|
export PATH := $(PWD)/bin:$(PATH)
|
||||||
|
|
||||||
|
# constants
|
||||||
|
GOLANGCI_VERSION = 2.8.0
|
||||||
|
|
||||||
|
all: download build ## Initializes all tools and files
|
||||||
|
all/ci: ado-git-setup all
|
||||||
|
|
||||||
|
out:
|
||||||
|
@mkdir -pv "$(@)"
|
||||||
|
|
||||||
|
build: out ## do nothing
|
||||||
|
|
||||||
|
.PHONY: build/%
|
||||||
|
build/%: out ## do nothing
|
||||||
|
|
||||||
|
download:
|
||||||
|
@go mod download
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
@go fmt ./...
|
||||||
|
|
||||||
|
GOLANGCI_LINT = bin/golangci-lint-$(GOLANGCI_VERSION)
|
||||||
|
$(GOLANGCI_LINT):
|
||||||
|
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | bash -s -- -b bin v$(GOLANGCI_VERSION)
|
||||||
|
@mv bin/golangci-lint "$(@)"
|
||||||
|
|
||||||
|
lint: fmt $(GOLANGCI_LINT) download ## Lints all code with golangci-lint
|
||||||
|
@$(GOLANGCI_LINT) run
|
||||||
|
|
||||||
|
lint/fix: fmt $(GOLANGCI_LINT) download ## Fixes automatically fixable things like imports for the defined lint rules
|
||||||
|
@$(GOLANGCI_LINT) run --fix
|
||||||
|
|
||||||
|
lint/reports: fmt $(GOLANGCI_LINT) download ## Fixes automatically fixable things like imports for the defined lint rules
|
||||||
|
@$(GOLANGCI_LINT) run ./... --output.checkstyle.path stdout | awk '!/0 issues./' > out/lint.xml
|
||||||
|
|
||||||
|
test-clean:
|
||||||
|
@go clean -testcache
|
||||||
|
|
||||||
|
tidy:
|
||||||
|
@go mod tidy
|
||||||
|
|
||||||
|
test:
|
||||||
|
@go test ./...
|
||||||
|
|
||||||
|
coverage: out/report.json ## Displays coverage per func on cli
|
||||||
|
go tool cover -func=out/cover.out
|
||||||
|
|
||||||
|
html-coverage: out/report.json ## Displays the coverage results in the browser
|
||||||
|
go tool cover -html=out/cover.out
|
||||||
|
|
||||||
|
test-reports: out/report.json
|
||||||
|
|
||||||
|
.PHONY: out/report.json
|
||||||
|
out/report.json: out
|
||||||
|
go test -v $$(go list ./... | grep -v '/tests') -tags=unit -coverprofile=out/cover.out -json | tee "$(@)"
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -rf bin out
|
||||||
|
|
||||||
|
.PHONY: ado-git-setup
|
||||||
|
ado-git-setup:
|
||||||
|
# Add "dev.azure.com/schwarzit" to GOPRIVATE if not present
|
||||||
|
@priv="$$(go env GOPRIVATE)"; \
|
||||||
|
[[ "$$priv" =~ '(^|,)dev\.azure\.com(/|,|$)' ]] || go env -w "GOPRIVATE=$${priv:+$$priv,}dev.azure.com/schwarzit"
|
||||||
|
# Configure HTTPS (with PAT) or SSH access to Go import paths
|
||||||
|
@if [[ -n "$${ADO_PAT:+x}" ]]; then \
|
||||||
|
git config --global "url.https://schwarzit:$${ADO_PAT}@dev.azure.com/schwarzit/.insteadof" 'https://dev.azure.com/schwarzit/'; \
|
||||||
|
else \
|
||||||
|
git config --global 'url.git@ssh.dev.azure.com:v3/schwarzit.insteadOf' 'https://dev.azure.com/schwarzit'; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo 'Usage: make <OPTIONS> ... <TARGETS>'
|
||||||
|
@echo ''
|
||||||
|
@echo 'Available targets are:'
|
||||||
|
@echo ''
|
||||||
|
@grep -E '^[ a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
|
||||||
|
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||||
|
@echo ''
|
||||||
48
README.md
48
README.md
|
|
@ -1,3 +1,35 @@
|
||||||
|
> ## DEPRECATION NOTICE
|
||||||
|
>
|
||||||
|
> ### Discontinuation of the current audit log system
|
||||||
|
>
|
||||||
|
> The audit log system provided to date will be discontinued in its current form.
|
||||||
|
> This decision was made to pave the way for a new, more powerful audit log system that
|
||||||
|
> will be provided in the future. The new system offers extended functionalities and
|
||||||
|
> improved integration options, particularly with regard to the use and analysis of
|
||||||
|
> audit data by our customers.
|
||||||
|
>
|
||||||
|
> ### What does it mean?
|
||||||
|
> The existing audit log system will be supported until the new system is generally
|
||||||
|
> available to customers on Mai 1, 2026.
|
||||||
|
> **Services that are already sending audit log events to the existing audit log
|
||||||
|
> system must continue to do so until the new system is GA** and further information
|
||||||
|
> about the shutdown process is provided.
|
||||||
|
> **Large volumes of new audit event types must not be sent to the existing audit log
|
||||||
|
> system.**
|
||||||
|
>
|
||||||
|
> STACKIT services should start migrating to the new system now by sending data to
|
||||||
|
> the new system (**in parallel**).
|
||||||
|
> **The new audit log system may drop and does not guarantee to store events until
|
||||||
|
> it will be GA**.
|
||||||
|
> Further information on the changeover and how to use the new system can be found in the
|
||||||
|
> [developer docs](https://developers.stackit.schwarz/domains/central-services/telemetry-router/integration/).
|
||||||
|
>
|
||||||
|
> We are confident that the new audit log system will make an important contribution to
|
||||||
|
> improving the transparency, traceability, and integration for our customers.
|
||||||
|
> If you have any questions or need assistance, the
|
||||||
|
> [STACKIT Telemetry Hub](https://chat.google.com/room/AAQAf9NsX6M?cls=7) team will be
|
||||||
|
> happy to help.
|
||||||
|
|
||||||
## audit-go
|
## audit-go
|
||||||
|
|
||||||
The audit-go library is the core library for validation and sending of audit events.
|
The audit-go library is the core library for validation and sending of audit events.
|
||||||
|
|
@ -32,13 +64,7 @@ The code can be found in the [api_routable.go](./api_routable.go) and
|
||||||
### Development
|
### Development
|
||||||
|
|
||||||
#### Go
|
#### Go
|
||||||
The current minimum toolchain version is **go1.22**.
|
The current minimum Go version is **go1.24.0**.
|
||||||
The toolchain version can be set as environment variable (either manually in the terminal
|
|
||||||
or in the ~/.basrc or ~/.zshrc):
|
|
||||||
|
|
||||||
```shell
|
|
||||||
export GOTOOLCHAIN=go1.22.7
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Linter
|
#### Linter
|
||||||
|
|
||||||
|
|
@ -46,7 +72,7 @@ The linter *golangci-lint* can either be installed via package manager (e.g. bre
|
||||||
by running the following command in the terminal:
|
by running the following command in the terminal:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.63.4
|
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.8.0
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Schema Generation
|
#### Schema Generation
|
||||||
|
|
@ -61,9 +87,9 @@ Buf and the required plugins can either be installed via package manager (e.g. b
|
||||||
or manually by running:
|
or manually by running:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
go install github.com/bufbuild/buf/cmd/buf@v1.50.0 #Pipeline: bufVersion
|
go install github.com/bufbuild/buf/cmd/buf@v1.63.0 #Pipeline: bufVersion
|
||||||
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.36.4 #Pipeline: protobufVersion, go.mod: buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go
|
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.36.11 #Pipeline: protobufVersion, go.mod: buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go
|
||||||
go install github.com/envoyproxy/protoc-gen-validate@v1.2.1 #Pipeline: protobufValidateVersion, go.mod: google.golang.org/protobuf
|
go install github.com/envoyproxy/protoc-gen-validate@v1.3.0 #Pipeline: protobufValidateVersion, go.mod: google.golang.org/protobuf
|
||||||
```
|
```
|
||||||
|
|
||||||
Please check that the versions above match the versions in the *go.mod* file
|
Please check that the versions above match the versions in the *go.mod* file
|
||||||
|
|
|
||||||
|
|
@ -1,423 +0,0 @@
|
||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/audit/messaging"
|
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
|
||||||
|
|
||||||
"github.com/bufbuild/protovalidate-go"
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/mock"
|
|
||||||
"google.golang.org/protobuf/proto"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MessagingApiMock struct {
|
|
||||||
mock.Mock
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MessagingApiMock) Send(
|
|
||||||
ctx context.Context,
|
|
||||||
topic string,
|
|
||||||
data []byte,
|
|
||||||
contentType string,
|
|
||||||
applicationProperties map[string]any,
|
|
||||||
) error {
|
|
||||||
|
|
||||||
args := m.Called(ctx, topic, data, contentType, applicationProperties)
|
|
||||||
return args.Error(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MessagingApiMock) Close(_ context.Context) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProtobufValidatorMock struct {
|
|
||||||
mock.Mock
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *ProtobufValidatorMock) Validate(msg proto.Message) error {
|
|
||||||
args := m.Called(msg)
|
|
||||||
return args.Error(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
type TopicNameResolverMock struct {
|
|
||||||
mock.Mock
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TopicNameResolverMock) Resolve(routableIdentifier *RoutableIdentifier) (string, error) {
|
|
||||||
args := m.Called(routableIdentifier)
|
|
||||||
return args.String(0), args.Error(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewValidator(t *testing.T) ProtobufValidator {
|
|
||||||
validator, err := protovalidate.New()
|
|
||||||
var protoValidator ProtobufValidator = validator
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
return protoValidator
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_ValidateAndSerializePartially_EventNil(t *testing.T) {
|
|
||||||
validator := NewValidator(t)
|
|
||||||
|
|
||||||
_, err := validateAndSerializePartially(
|
|
||||||
validator, nil, auditV1.Visibility_VISIBILITY_PUBLIC, nil)
|
|
||||||
|
|
||||||
assert.ErrorIs(t, err, ErrEventNil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_ValidateAndSerializePartially_AuditEventValidationFailed(t *testing.T) {
|
|
||||||
validator := NewValidator(t)
|
|
||||||
|
|
||||||
event, objectIdentifier := newOrganizationAuditEvent(nil)
|
|
||||||
event.LogName = ""
|
|
||||||
|
|
||||||
_, err := validateAndSerializePartially(
|
|
||||||
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, NewRoutableIdentifier(objectIdentifier))
|
|
||||||
|
|
||||||
assert.EqualError(t, err, "validation error:\n - log_name: value is required [required]")
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_ValidateAndSerializePartially_RoutableEventValidationFailed(t *testing.T) {
|
|
||||||
validator := NewValidator(t)
|
|
||||||
|
|
||||||
event, objectIdentifier := newOrganizationAuditEvent(nil)
|
|
||||||
_, err := validateAndSerializePartially(validator, event, 3, NewRoutableIdentifier(objectIdentifier))
|
|
||||||
|
|
||||||
assert.EqualError(t, err, "validation error:\n - visibility: value must be one of the defined enum values [enum.defined_only]")
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_ValidateAndSerializePartially_CheckVisibility_Event(t *testing.T) {
|
|
||||||
validator := NewValidator(t)
|
|
||||||
|
|
||||||
event, objectIdentifier := newOrganizationAuditEvent(nil)
|
|
||||||
|
|
||||||
t.Run("Visibility public - object identifier nil", func(t *testing.T) {
|
|
||||||
_, err := validateAndSerializePartially(
|
|
||||||
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, nil)
|
|
||||||
|
|
||||||
assert.ErrorIs(t, err, ErrObjectIdentifierNil)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Visibility private - object identifier nil", func(t *testing.T) {
|
|
||||||
_, err := validateAndSerializePartially(
|
|
||||||
validator, event, auditV1.Visibility_VISIBILITY_PRIVATE, nil)
|
|
||||||
|
|
||||||
assert.ErrorIs(t, err, ErrObjectIdentifierNil)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Visibility public - object identifier system", func(t *testing.T) {
|
|
||||||
_, err := validateAndSerializePartially(
|
|
||||||
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, RoutableSystemIdentifier)
|
|
||||||
|
|
||||||
assert.ErrorIs(t, err, ErrObjectIdentifierVisibilityMismatch)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Visibility public - object identifier set", func(t *testing.T) {
|
|
||||||
routableEvent, err := validateAndSerializePartially(
|
|
||||||
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, NewRoutableIdentifier(objectIdentifier))
|
|
||||||
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.NotNil(t, routableEvent)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Visibility private - object identifier system", func(t *testing.T) {
|
|
||||||
_, err := validateAndSerializePartially(
|
|
||||||
validator, event, auditV1.Visibility_VISIBILITY_PRIVATE, RoutableSystemIdentifier)
|
|
||||||
|
|
||||||
assert.ErrorIs(t, err, ErrAttributeIdentifierInvalid)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Visibility private - object identifier set", func(t *testing.T) {
|
|
||||||
routableEvent, err := validateAndSerializePartially(
|
|
||||||
validator, event, auditV1.Visibility_VISIBILITY_PRIVATE, NewRoutableIdentifier(objectIdentifier))
|
|
||||||
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.NotNil(t, routableEvent)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_ValidateAndSerializePartially_CheckVisibility_SystemEvent(t *testing.T) {
|
|
||||||
validator := NewValidator(t)
|
|
||||||
|
|
||||||
event := newSystemAuditEvent(nil)
|
|
||||||
|
|
||||||
t.Run("Visibility public - object identifier nil", func(t *testing.T) {
|
|
||||||
_, err := validateAndSerializePartially(
|
|
||||||
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, nil)
|
|
||||||
|
|
||||||
assert.ErrorIs(t, err, ErrObjectIdentifierNil)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Visibility private - object identifier nil", func(t *testing.T) {
|
|
||||||
_, err := validateAndSerializePartially(
|
|
||||||
validator, event, auditV1.Visibility_VISIBILITY_PRIVATE, nil)
|
|
||||||
|
|
||||||
assert.ErrorIs(t, err, ErrObjectIdentifierNil)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Visibility public - object identifier system", func(t *testing.T) {
|
|
||||||
_, err := validateAndSerializePartially(
|
|
||||||
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, RoutableSystemIdentifier)
|
|
||||||
|
|
||||||
assert.ErrorIs(t, err, ErrObjectIdentifierVisibilityMismatch)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Visibility public - object identifier set", func(t *testing.T) {
|
|
||||||
_, err := validateAndSerializePartially(
|
|
||||||
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, NewRoutableIdentifier(
|
|
||||||
&auditV1.ObjectIdentifier{Identifier: uuid.NewString(), Type: string(ObjectTypeOrganization)}))
|
|
||||||
|
|
||||||
assert.ErrorIs(t, err, ErrInvalidRoutableIdentifierForSystemEvent)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Visibility private - object identifier system", func(t *testing.T) {
|
|
||||||
routableEvent, err := validateAndSerializePartially(
|
|
||||||
validator, event, auditV1.Visibility_VISIBILITY_PRIVATE, RoutableSystemIdentifier)
|
|
||||||
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.NotNil(t, routableEvent)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Visibility private - object identifier set", func(t *testing.T) {
|
|
||||||
_, err := validateAndSerializePartially(
|
|
||||||
validator, event, auditV1.Visibility_VISIBILITY_PRIVATE, NewRoutableIdentifier(
|
|
||||||
&auditV1.ObjectIdentifier{Identifier: uuid.NewString(), Type: string(ObjectTypeOrganization)}))
|
|
||||||
|
|
||||||
assert.ErrorIs(t, err, ErrInvalidRoutableIdentifierForSystemEvent)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_ValidateAndSerializePartially_UnsupportedIdentifierType(t *testing.T) {
|
|
||||||
validator := NewValidator(t)
|
|
||||||
|
|
||||||
event, objectIdentifier := newFolderAuditEvent(nil)
|
|
||||||
objectIdentifier.Type = "invalid"
|
|
||||||
|
|
||||||
_, err := validateAndSerializePartially(
|
|
||||||
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, NewRoutableIdentifier(objectIdentifier))
|
|
||||||
|
|
||||||
assert.ErrorIs(t, err, ErrUnsupportedRoutableType)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_ValidateAndSerializePartially_LogNameIdentifierMismatch(t *testing.T) {
|
|
||||||
validator := NewValidator(t)
|
|
||||||
|
|
||||||
event, objectIdentifier := newFolderAuditEvent(nil)
|
|
||||||
parts := strings.Split(event.LogName, "/")
|
|
||||||
identifier := parts[1]
|
|
||||||
|
|
||||||
t.Run("LogName type mismatch", func(t *testing.T) {
|
|
||||||
event.LogName = fmt.Sprintf("projects/%s/logs/admin-activity", identifier)
|
|
||||||
_, err := validateAndSerializePartially(
|
|
||||||
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, NewRoutableIdentifier(objectIdentifier))
|
|
||||||
|
|
||||||
assert.ErrorIs(t, err, ErrAttributeTypeInvalid)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("LogName identifier mismatch", func(t *testing.T) {
|
|
||||||
event.LogName = fmt.Sprintf("folders/%s/logs/admin-activity", uuid.NewString())
|
|
||||||
_, err := validateAndSerializePartially(
|
|
||||||
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, NewRoutableIdentifier(objectIdentifier))
|
|
||||||
|
|
||||||
assert.ErrorIs(t, err, ErrAttributeIdentifierInvalid)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_ValidateAndSerializePartially_ResourceNameIdentifierMismatch(t *testing.T) {
|
|
||||||
validator := NewValidator(t)
|
|
||||||
|
|
||||||
event, objectIdentifier := newFolderAuditEvent(nil)
|
|
||||||
parts := strings.Split(event.ProtoPayload.ResourceName, "/")
|
|
||||||
identifier := parts[1]
|
|
||||||
|
|
||||||
t.Run("ResourceName type mismatch", func(t *testing.T) {
|
|
||||||
event.ProtoPayload.ResourceName = fmt.Sprintf("projects/%s", identifier)
|
|
||||||
_, err := validateAndSerializePartially(
|
|
||||||
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, NewRoutableIdentifier(objectIdentifier))
|
|
||||||
|
|
||||||
assert.ErrorIs(t, err, ErrAttributeTypeInvalid)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("ResourceName identifier mismatch", func(t *testing.T) {
|
|
||||||
event.ProtoPayload.ResourceName = fmt.Sprintf("folders/%s", uuid.NewString())
|
|
||||||
_, err := validateAndSerializePartially(
|
|
||||||
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, NewRoutableIdentifier(objectIdentifier))
|
|
||||||
|
|
||||||
assert.ErrorIs(t, err, ErrAttributeIdentifierInvalid)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_ValidateAndSerializePartially_SystemEvent(t *testing.T) {
|
|
||||||
validator := NewValidator(t)
|
|
||||||
|
|
||||||
event := newSystemAuditEvent(nil)
|
|
||||||
|
|
||||||
routableEvent, err := validateAndSerializePartially(
|
|
||||||
validator, event, auditV1.Visibility_VISIBILITY_PRIVATE, RoutableSystemIdentifier)
|
|
||||||
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, event.LogName, fmt.Sprintf("system/%s/logs/%s", SystemIdentifier.Identifier, EventTypeSystemEvent))
|
|
||||||
assert.True(t, proto.Equal(routableEvent.ObjectIdentifier, SystemIdentifier))
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Send_TopicNameResolverNil(t *testing.T) {
|
|
||||||
err := send(nil, nil, context.Background(), nil, nil)
|
|
||||||
assert.ErrorIs(t, err, ErrTopicNameResolverNil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Send_TopicNameResolutionError(t *testing.T) {
|
|
||||||
expectedError := errors.New("expected error")
|
|
||||||
|
|
||||||
topicNameResolverMock := TopicNameResolverMock{}
|
|
||||||
topicNameResolverMock.On("Resolve", mock.Anything).Return("topic", expectedError)
|
|
||||||
var topicNameResolver TopicNameResolver = &topicNameResolverMock
|
|
||||||
|
|
||||||
var cloudEvent = CloudEvent{}
|
|
||||||
|
|
||||||
var messagingApi messaging.Api = &messaging.AmqpApi{}
|
|
||||||
err := send(topicNameResolver, messagingApi, context.Background(), RoutableSystemIdentifier, &cloudEvent)
|
|
||||||
assert.ErrorIs(t, err, expectedError)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Send_MessagingApiNil(t *testing.T) {
|
|
||||||
var topicNameResolver TopicNameResolver = &LegacyTopicNameResolver{topicName: "test"}
|
|
||||||
err := send(topicNameResolver, nil, context.Background(), nil, nil)
|
|
||||||
assert.ErrorIs(t, err, ErrMessagingApiNil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Send_CloudEventNil(t *testing.T) {
|
|
||||||
var topicNameResolver TopicNameResolver = &LegacyTopicNameResolver{topicName: "test"}
|
|
||||||
var messagingApi messaging.Api = &messaging.AmqpApi{}
|
|
||||||
|
|
||||||
err := send(topicNameResolver, messagingApi, context.Background(), nil, nil)
|
|
||||||
assert.ErrorIs(t, err, ErrCloudEventNil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Send_ObjectIdentifierNil(t *testing.T) {
|
|
||||||
var topicNameResolver TopicNameResolver = &LegacyTopicNameResolver{topicName: "test"}
|
|
||||||
var messagingApi messaging.Api = &messaging.AmqpApi{}
|
|
||||||
var cloudEvent = CloudEvent{}
|
|
||||||
|
|
||||||
err := send(topicNameResolver, messagingApi, context.Background(), nil, &cloudEvent)
|
|
||||||
assert.ErrorIs(t, err, ErrObjectIdentifierNil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Send_UnsupportedObjectIdentifierType(t *testing.T) {
|
|
||||||
var topicNameResolver TopicNameResolver = &LegacyTopicNameResolver{topicName: "test"}
|
|
||||||
var messagingApi messaging.Api = &messaging.AmqpApi{}
|
|
||||||
var cloudEvent = CloudEvent{}
|
|
||||||
var objectIdentifier = auditV1.ObjectIdentifier{Identifier: uuid.NewString(), Type: "unsupported"}
|
|
||||||
|
|
||||||
err := send(topicNameResolver, messagingApi, context.Background(), NewRoutableIdentifier(&objectIdentifier), &cloudEvent)
|
|
||||||
assert.ErrorIs(t, err, ErrUnsupportedRoutableType)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Send(t *testing.T) {
|
|
||||||
topicNameResolverMock := TopicNameResolverMock{}
|
|
||||||
topicNameResolverMock.On("Resolve", mock.Anything).Return("topic", nil)
|
|
||||||
var topicNameResolver TopicNameResolver = &topicNameResolverMock
|
|
||||||
|
|
||||||
messagingApiMock := MessagingApiMock{}
|
|
||||||
messagingApiMock.On("Send", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
|
||||||
var messagingApi messaging.Api = &messagingApiMock
|
|
||||||
|
|
||||||
var cloudEvent = CloudEvent{}
|
|
||||||
assert.NoError(t, send(topicNameResolver, messagingApi, context.Background(), RoutableSystemIdentifier, &cloudEvent))
|
|
||||||
assert.True(t, messagingApiMock.AssertNumberOfCalls(t, "Send", 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_SendAllHeadersSet(t *testing.T) {
|
|
||||||
topicNameResolverMock := TopicNameResolverMock{}
|
|
||||||
topicNameResolverMock.On("Resolve", mock.Anything).Return("topic", nil)
|
|
||||||
var topicNameResolver TopicNameResolver = &topicNameResolverMock
|
|
||||||
|
|
||||||
messagingApiMock := MessagingApiMock{}
|
|
||||||
messagingApiMock.On("Send", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
|
||||||
var messagingApi messaging.Api = &messagingApiMock
|
|
||||||
|
|
||||||
traceState := "rojo=00f067aa0ba902b7,congo=t61rcWkgMzE"
|
|
||||||
traceParent := "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
|
|
||||||
expectedTime := time.Now()
|
|
||||||
var cloudEvent = CloudEvent{
|
|
||||||
SpecVersion: "1.0",
|
|
||||||
Source: "resourcemanager",
|
|
||||||
Id: "id",
|
|
||||||
Time: expectedTime,
|
|
||||||
DataContentType: ContentTypeCloudEventsProtobuf,
|
|
||||||
DataType: "type",
|
|
||||||
Subject: "subject",
|
|
||||||
TraceParent: &traceParent,
|
|
||||||
TraceState: &traceState,
|
|
||||||
}
|
|
||||||
assert.NoError(t, send(topicNameResolver, messagingApi, context.Background(), RoutableSystemIdentifier, &cloudEvent))
|
|
||||||
assert.True(t, messagingApiMock.AssertNumberOfCalls(t, "Send", 1))
|
|
||||||
|
|
||||||
arguments := messagingApiMock.Calls[0].Arguments
|
|
||||||
topic := arguments.Get(1).(string)
|
|
||||||
assert.Equal(t, "topic", topic)
|
|
||||||
|
|
||||||
contentType := arguments.Get(3).(string)
|
|
||||||
assert.Equal(t, ContentTypeCloudEventsProtobuf, contentType)
|
|
||||||
|
|
||||||
applicationProperties := arguments.Get(4).(map[string]any)
|
|
||||||
assert.Equal(t, "1.0", applicationProperties["cloudEvents:specversion"])
|
|
||||||
assert.Equal(t, "resourcemanager", applicationProperties["cloudEvents:source"])
|
|
||||||
assert.Equal(t, "id", applicationProperties["cloudEvents:id"])
|
|
||||||
assert.Equal(t, expectedTime.UnixMilli(), applicationProperties["cloudEvents:time"])
|
|
||||||
assert.Equal(t, ContentTypeCloudEventsProtobuf, applicationProperties["cloudEvents:datacontenttype"])
|
|
||||||
assert.Equal(t, "type", applicationProperties["cloudEvents:type"])
|
|
||||||
assert.Equal(t, "subject", applicationProperties["cloudEvents:subject"])
|
|
||||||
assert.Equal(t, traceParent, applicationProperties["cloudEvents:traceparent"])
|
|
||||||
assert.Equal(t, traceState, applicationProperties["cloudEvents:tracestate"])
|
|
||||||
messagingApiMock.AssertExpectations(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_SendWithoutOptionalHeadersSet(t *testing.T) {
|
|
||||||
topicNameResolverMock := TopicNameResolverMock{}
|
|
||||||
topicNameResolverMock.On("Resolve", mock.Anything).Return("topic", nil)
|
|
||||||
var topicNameResolver TopicNameResolver = &topicNameResolverMock
|
|
||||||
|
|
||||||
messagingApiMock := MessagingApiMock{}
|
|
||||||
messagingApiMock.On("Send", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
|
||||||
var messagingApi messaging.Api = &messagingApiMock
|
|
||||||
|
|
||||||
expectedTime := time.Now()
|
|
||||||
var cloudEvent = CloudEvent{
|
|
||||||
SpecVersion: "1.0",
|
|
||||||
Source: "resourcemanager",
|
|
||||||
Id: "id",
|
|
||||||
Time: expectedTime,
|
|
||||||
DataContentType: ContentTypeCloudEventsProtobuf,
|
|
||||||
DataType: "type",
|
|
||||||
Subject: "subject",
|
|
||||||
}
|
|
||||||
assert.NoError(t, send(topicNameResolver, messagingApi, context.Background(), RoutableSystemIdentifier, &cloudEvent))
|
|
||||||
assert.True(t, messagingApiMock.AssertNumberOfCalls(t, "Send", 1))
|
|
||||||
|
|
||||||
arguments := messagingApiMock.Calls[0].Arguments
|
|
||||||
topic := arguments.Get(1).(string)
|
|
||||||
assert.Equal(t, "topic", topic)
|
|
||||||
|
|
||||||
contentType := arguments.Get(3).(string)
|
|
||||||
assert.Equal(t, ContentTypeCloudEventsProtobuf, contentType)
|
|
||||||
|
|
||||||
applicationProperties := arguments.Get(4).(map[string]any)
|
|
||||||
assert.Equal(t, "1.0", applicationProperties["cloudEvents:specversion"])
|
|
||||||
assert.Equal(t, "resourcemanager", applicationProperties["cloudEvents:source"])
|
|
||||||
assert.Equal(t, "id", applicationProperties["cloudEvents:id"])
|
|
||||||
assert.Equal(t, expectedTime.UnixMilli(), applicationProperties["cloudEvents:time"])
|
|
||||||
assert.Equal(t, ContentTypeCloudEventsProtobuf, applicationProperties["cloudEvents:datacontenttype"])
|
|
||||||
assert.Equal(t, "type", applicationProperties["cloudEvents:type"])
|
|
||||||
assert.Equal(t, "subject", applicationProperties["cloudEvents:subject"])
|
|
||||||
assert.Equal(t, nil, applicationProperties["cloudEvents:traceparent"])
|
|
||||||
assert.Equal(t, nil, applicationProperties["cloudEvents:tracestate"])
|
|
||||||
messagingApiMock.AssertExpectations(t)
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.36.4
|
// protoc-gen-go v1.36.11
|
||||||
// protoc (unknown)
|
// protoc (unknown)
|
||||||
// source: audit/v1/audit_event.proto
|
// source: audit/v1/audit_event.proto
|
||||||
|
|
||||||
|
|
@ -521,8 +521,8 @@ type AuthenticationInfo struct {
|
||||||
// The email address of the authenticated user.
|
// The email address of the authenticated user.
|
||||||
// Service accounts have email addresses that can be used.
|
// Service accounts have email addresses that can be used.
|
||||||
//
|
//
|
||||||
// Required: true
|
// Required: false
|
||||||
PrincipalEmail string `protobuf:"bytes,2,opt,name=principal_email,json=principalEmail,proto3" json:"principal_email,omitempty"`
|
PrincipalEmail *string `protobuf:"bytes,2,opt,name=principal_email,json=principalEmail,proto3,oneof" json:"principal_email,omitempty"`
|
||||||
// The name of the service account used to create or exchange
|
// The name of the service account used to create or exchange
|
||||||
// credentials for authenticating the service account making the request.
|
// credentials for authenticating the service account making the request.
|
||||||
//
|
//
|
||||||
|
|
@ -584,8 +584,8 @@ func (x *AuthenticationInfo) GetPrincipalId() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AuthenticationInfo) GetPrincipalEmail() string {
|
func (x *AuthenticationInfo) GetPrincipalEmail() string {
|
||||||
if x != nil {
|
if x != nil && x.PrincipalEmail != nil {
|
||||||
return x.PrincipalEmail
|
return *x.PrincipalEmail
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
@ -1465,326 +1465,143 @@ func (x *ServiceAccountDelegationInfo_IdpPrincipal) GetServiceMetadata() *struct
|
||||||
|
|
||||||
var File_audit_v1_audit_event_proto protoreflect.FileDescriptor
|
var File_audit_v1_audit_event_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_audit_v1_audit_event_proto_rawDesc = string([]byte{
|
const file_audit_v1_audit_event_proto_rawDesc = "" +
|
||||||
0x0a, 0x1a, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x64, 0x69, 0x74,
|
"\n" +
|
||||||
0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x61, 0x75,
|
"\x1aaudit/v1/audit_event.proto\x12\baudit.v1\x1a\x1bbuf/validate/validate.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\xe2\x04\n" +
|
||||||
0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x1a, 0x1b, 0x62, 0x75, 0x66, 0x2f, 0x76, 0x61, 0x6c, 0x69,
|
"\rAuditLogEntry\x12x\n" +
|
||||||
0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72,
|
"\blog_name\x18\x01 \x01(\tB]\xbaHZ\xc8\x01\x01rU2S^[a-z-]+/[a-z0-9-]+/logs/(?:admin-activity|system-event|policy-denied|data-access)$R\alogName\x12?\n" +
|
||||||
0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74,
|
"\rproto_payload\x18\x02 \x01(\v2\x12.audit.v1.AuditLogB\x06\xbaH\x03\xc8\x01\x01R\fprotoPayload\x12L\n" +
|
||||||
0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
"\tinsert_id\x18\x03 \x01(\tB/\xbaH,\xc8\x01\x01r'2%^[0-9]+/[a-z0-9-]+/[a-z0-9-]+/[0-9]+$R\binsertId\x12;\n" +
|
||||||
0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
"\x06labels\x18\x04 \x03(\v2#.audit.v1.AuditLogEntry.LabelsEntryR\x06labels\x126\n" +
|
||||||
0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f,
|
"\x0ecorrelation_id\x18\x05 \x01(\tB\n" +
|
||||||
0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
"\xbaH\ar\x05\x10\x01\x18\xff\x01H\x00R\rcorrelationId\x88\x01\x01\x12E\n" +
|
||||||
0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f,
|
"\ttimestamp\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampB\v\xbaH\b\xc8\x01\x01\xb2\x01\x028\x01R\ttimestamp\x12>\n" +
|
||||||
0x74, 0x6f, 0x22, 0xe2, 0x04, 0x0a, 0x0d, 0x41, 0x75, 0x64, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x45,
|
"\bseverity\x18\a \x01(\x0e2\x15.audit.v1.LogSeverityB\v\xbaH\b\xc8\x01\x01\x82\x01\x02\x10\x01R\bseverity\x1a9\n" +
|
||||||
0x6e, 0x74, 0x72, 0x79, 0x12, 0x78, 0x0a, 0x08, 0x6c, 0x6f, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
|
"\vLabelsEntry\x12\x10\n" +
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x5d, 0xba, 0x48, 0x5a, 0xc8, 0x01, 0x01, 0x72, 0x55,
|
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||||
0x32, 0x53, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x2d, 0x5d, 0x2b, 0x2f, 0x5b, 0x61, 0x2d, 0x7a, 0x30,
|
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01B\x11\n" +
|
||||||
0x2d, 0x39, 0x2d, 0x5d, 0x2b, 0x2f, 0x6c, 0x6f, 0x67, 0x73, 0x2f, 0x28, 0x3f, 0x3a, 0x61, 0x64,
|
"\x0f_correlation_id\"\xb3\x06\n" +
|
||||||
0x6d, 0x69, 0x6e, 0x2d, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x7c, 0x73, 0x79, 0x73,
|
"\bAuditLog\x125\n" +
|
||||||
0x74, 0x65, 0x6d, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x7c, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79,
|
"\fservice_name\x18\x01 \x01(\tB\x12\xbaH\x0f\xc8\x01\x01r\n" +
|
||||||
0x2d, 0x64, 0x65, 0x6e, 0x69, 0x65, 0x64, 0x7c, 0x64, 0x61, 0x74, 0x61, 0x2d, 0x61, 0x63, 0x63,
|
"\x10\x012\x06.*\\S.*R\vserviceName\x12w\n" +
|
||||||
0x65, 0x73, 0x73, 0x29, 0x24, 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3f,
|
"\x0eoperation_name\x18\x02 \x01(\tBP\xbaHM\xc8\x01\x01rH\x10\x01\x18\xff\x012A^stackit\\.[a-z0-9-]+\\.(?:v[0-9]+\\.)?(?:[a-z0-9-.]+\\.)?[a-z0-9-]+$R\roperationName\x12c\n" +
|
||||||
0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18,
|
"\rresource_name\x18\x03 \x01(\tB>\xbaH;\xc8\x01\x01r6\x10\x01\x18\xff\x012/^[a-z]+/[a-z0-9-]+(?:/[a-z0-9-]+/[a-z0-9-_]+)*$R\fresourceName\x12U\n" +
|
||||||
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31,
|
"\x13authentication_info\x18\x04 \x01(\v2\x1c.audit.v1.AuthenticationInfoB\x06\xbaH\x03\xc8\x01\x01R\x12authenticationInfo\x12J\n" +
|
||||||
0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01,
|
"\x12authorization_info\x18\x05 \x03(\v2\x1b.audit.v1.AuthorizationInfoR\x11authorizationInfo\x12L\n" +
|
||||||
0x01, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12,
|
"\x10request_metadata\x18\x06 \x01(\v2\x19.audit.v1.RequestMetadataB\x06\xbaH\x03\xc8\x01\x01R\x0frequestMetadata\x126\n" +
|
||||||
0x4c, 0x0a, 0x09, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01,
|
"\arequest\x18\a \x01(\v2\x17.google.protobuf.StructH\x00R\arequest\x88\x01\x01\x12O\n" +
|
||||||
0x28, 0x09, 0x42, 0x2f, 0xba, 0x48, 0x2c, 0xc8, 0x01, 0x01, 0x72, 0x27, 0x32, 0x25, 0x5e, 0x5b,
|
"\x11response_metadata\x18\b \x01(\v2\x1a.audit.v1.ResponseMetadataB\x06\xbaH\x03\xc8\x01\x01R\x10responseMetadata\x128\n" +
|
||||||
0x30, 0x2d, 0x39, 0x5d, 0x2b, 0x2f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x2d, 0x5d, 0x2b,
|
"\bresponse\x18\t \x01(\v2\x17.google.protobuf.StructH\x01R\bresponse\x88\x01\x01\x128\n" +
|
||||||
0x2f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x2d, 0x5d, 0x2b, 0x2f, 0x5b, 0x30, 0x2d, 0x39,
|
"\bmetadata\x18\n" +
|
||||||
0x5d, 0x2b, 0x24, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x49, 0x64, 0x12, 0x3b, 0x0a,
|
" \x01(\v2\x17.google.protobuf.StructH\x02R\bmetadata\x88\x01\x01B\n" +
|
||||||
0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e,
|
"\n" +
|
||||||
0x61, 0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x4c, 0x6f,
|
"\b_requestB\v\n" +
|
||||||
0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74,
|
"\t_responseB\v\n" +
|
||||||
0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x36, 0x0a, 0x0e, 0x63, 0x6f,
|
"\t_metadata\"\x93\x03\n" +
|
||||||
0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01,
|
"\x12AuthenticationInfo\x125\n" +
|
||||||
0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xff, 0x01, 0x48, 0x00,
|
"\fprincipal_id\x18\x01 \x01(\tB\x12\xbaH\x0f\xc8\x01\x01r\n" +
|
||||||
0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x88,
|
"\x10\x012\x06.*\\S.*R\vprincipalId\x12:\n" +
|
||||||
0x01, 0x01, 0x12, 0x45, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18,
|
"\x0fprincipal_email\x18\x02 \x01(\tB\f\xbaH\tr\a\x10\x05\x18\xff\x01`\x01H\x00R\x0eprincipalEmail\x88\x01\x01\x12n\n" +
|
||||||
0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
|
"\x14service_account_name\x18\x03 \x01(\tB7\xbaH4r220^[a-z-]+/[a-z0-9-]+/service-accounts/[a-z0-9-]+$H\x01R\x12serviceAccountName\x88\x01\x01\x12m\n" +
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
|
"\x1fservice_account_delegation_info\x18\x04 \x03(\v2&.audit.v1.ServiceAccountDelegationInfoR\x1cserviceAccountDelegationInfoB\x12\n" +
|
||||||
0x70, 0x42, 0x0b, 0xba, 0x48, 0x08, 0xc8, 0x01, 0x01, 0xb2, 0x01, 0x02, 0x38, 0x01, 0x52, 0x09,
|
"\x10_principal_emailB\x17\n" +
|
||||||
0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3e, 0x0a, 0x08, 0x73, 0x65, 0x76,
|
"\x15_service_account_name\"\xf2\x01\n" +
|
||||||
0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x61, 0x75,
|
"\x11AuthorizationInfo\x12U\n" +
|
||||||
0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69,
|
"\bresource\x18\x01 \x01(\tB9\xbaH6\xc8\x01\x01r12/^[a-z]+/[a-z0-9-]+(?:/[a-z0-9-]+/[a-z0-9-_]+)*$R\bresource\x12L\n" +
|
||||||
0x74, 0x79, 0x42, 0x0b, 0xba, 0x48, 0x08, 0xc8, 0x01, 0x01, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52,
|
"\n" +
|
||||||
0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62,
|
"permission\x18\x02 \x01(\tB'\xbaH$r\"2 ^[a-z-]+(?:\\.[a-z-]+)*\\.[a-z-]+$H\x00R\n" +
|
||||||
0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
|
"permission\x88\x01\x01\x12\x1d\n" +
|
||||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
|
"\agranted\x18\x03 \x01(\bH\x01R\agranted\x88\x01\x01B\r\n" +
|
||||||
0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
"\v_permissionB\n" +
|
||||||
0x3a, 0x02, 0x38, 0x01, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61,
|
"\n" +
|
||||||
0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x22, 0xab, 0x06, 0x0a, 0x08, 0x41, 0x75, 0x64, 0x69,
|
"\b_granted\"\xaa\v\n" +
|
||||||
0x74, 0x4c, 0x6f, 0x67, 0x12, 0x2d, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f,
|
"\x10AttributeContext\x1a\xa9\x01\n" +
|
||||||
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8,
|
"\x04Auth\x12J\n" +
|
||||||
0x01, 0x01, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e,
|
"\tprincipal\x18\x01 \x01(\tB,\xbaH)\xc8\x01\x01r$2\"^[a-zA-Z0-9-%._]+/[a-zA-Z0-9-%.]+$R\tprincipal\x12\x1c\n" +
|
||||||
0x61, 0x6d, 0x65, 0x12, 0x77, 0x0a, 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
"\taudiences\x18\x02 \x03(\tR\taudiences\x127\n" +
|
||||||
0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x50, 0xba, 0x48, 0x4d,
|
"\x06claims\x18\x03 \x01(\v2\x17.google.protobuf.StructB\x06\xbaH\x03\xc8\x01\x01R\x06claims\x1a\xce\x04\n" +
|
||||||
0xc8, 0x01, 0x01, 0x72, 0x48, 0x10, 0x01, 0x18, 0xff, 0x01, 0x32, 0x41, 0x5e, 0x73, 0x74, 0x61,
|
"\aRequest\x12\x13\n" +
|
||||||
0x63, 0x6b, 0x69, 0x74, 0x5c, 0x2e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x2d, 0x5d, 0x2b,
|
"\x02id\x18\x01 \x01(\tH\x00R\x02id\x88\x01\x01\x12J\n" +
|
||||||
0x5c, 0x2e, 0x28, 0x3f, 0x3a, 0x76, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0x5c, 0x2e, 0x29, 0x3f,
|
"\x06method\x18\x02 \x01(\x0e2%.audit.v1.AttributeContext.HttpMethodB\v\xbaH\b\xc8\x01\x01\x82\x01\x02\x10\x01R\x06method\x12Q\n" +
|
||||||
0x28, 0x3f, 0x3a, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x2d, 0x2e, 0x5d, 0x2b, 0x5c, 0x2e,
|
"\aheaders\x18\x03 \x03(\v2/.audit.v1.AttributeContext.Request.HeadersEntryB\x06\xbaH\x03\xc8\x01\x01R\aheaders\x12)\n" +
|
||||||
0x29, 0x3f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x2d, 0x5d, 0x2b, 0x24, 0x52, 0x0d, 0x6f,
|
"\x04path\x18\x04 \x01(\tB\x15\xbaH\x12\xc8\x01\x01r\r\x10\x01\x18\xff\x012\x06.*\\S.*R\x04path\x12&\n" +
|
||||||
0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x63, 0x0a, 0x0d,
|
"\x04host\x18\x05 \x01(\tB\x12\xbaH\x0f\xc8\x01\x01r\n" +
|
||||||
0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20,
|
"\x10\x012\x06.*\\S.*R\x04host\x12*\n" +
|
||||||
0x01, 0x28, 0x09, 0x42, 0x3e, 0xba, 0x48, 0x3b, 0xc8, 0x01, 0x01, 0x72, 0x36, 0x10, 0x01, 0x18,
|
"\x06scheme\x18\x06 \x01(\tB\x12\xbaH\x0f\xc8\x01\x01r\n" +
|
||||||
0xff, 0x01, 0x32, 0x2f, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x5d, 0x2b, 0x2f, 0x5b, 0x61, 0x2d, 0x7a,
|
"\x10\x012\x06.*\\S.*R\x06scheme\x12\x19\n" +
|
||||||
0x30, 0x2d, 0x39, 0x2d, 0x5d, 0x2b, 0x28, 0x3f, 0x3a, 0x2f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d,
|
"\x05query\x18\a \x01(\tH\x01R\x05query\x88\x01\x01\x12;\n" +
|
||||||
0x39, 0x2d, 0x5d, 0x2b, 0x2f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x2d, 0x5f, 0x5d, 0x2b,
|
"\x04time\x18\b \x01(\v2\x1a.google.protobuf.TimestampB\v\xbaH\b\xc8\x01\x01\xb2\x01\x028\x01R\x04time\x12.\n" +
|
||||||
0x29, 0x2a, 0x24, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d,
|
"\bprotocol\x18\t \x01(\tB\x12\xbaH\x0f\xc8\x01\x01r\n" +
|
||||||
0x65, 0x12, 0x55, 0x0a, 0x13, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74,
|
"\x10\x012\x06.*\\S.*R\bprotocol\x12;\n" +
|
||||||
0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c,
|
"\x04auth\x18\n" +
|
||||||
0x2e, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e,
|
" \x01(\v2\x1f.audit.v1.AttributeContext.AuthB\x06\xbaH\x03\xc8\x01\x01R\x04auth\x1a:\n" +
|
||||||
0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x06, 0xba, 0x48,
|
"\fHeadersEntry\x12\x10\n" +
|
||||||
0x03, 0xc8, 0x01, 0x01, 0x52, 0x12, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61,
|
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||||
0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x4a, 0x0a, 0x12, 0x61, 0x75, 0x74, 0x68,
|
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01B\x05\n" +
|
||||||
0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x05,
|
"\x03_idB\b\n" +
|
||||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e,
|
"\x06_query\x1a\x87\x03\n" +
|
||||||
0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66,
|
"\bResponse\x12W\n" +
|
||||||
0x6f, 0x52, 0x11, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
"\x12num_response_items\x18\x01 \x01(\v2\x1b.google.protobuf.Int64ValueB\a\xbaH\x04\"\x02(\x00H\x00R\x10numResponseItems\x88\x01\x01\x12=\n" +
|
||||||
0x49, 0x6e, 0x66, 0x6f, 0x12, 0x4c, 0x0a, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f,
|
"\x04size\x18\x02 \x01(\v2\x1b.google.protobuf.Int64ValueB\a\xbaH\x04\"\x02(\x00H\x01R\x04size\x88\x01\x01\x12J\n" +
|
||||||
0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19,
|
"\aheaders\x18\x03 \x03(\v20.audit.v1.AttributeContext.Response.HeadersEntryR\aheaders\x12;\n" +
|
||||||
0x2e, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
"\x04time\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampB\v\xbaH\b\xc8\x01\x01\xb2\x01\x028\x01R\x04time\x1a:\n" +
|
||||||
0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01,
|
"\fHeadersEntry\x12\x10\n" +
|
||||||
0x01, 0x52, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
|
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||||
0x74, 0x61, 0x12, 0x36, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x07, 0x20,
|
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01B\x15\n" +
|
||||||
0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
"\x13_num_response_itemsB\a\n" +
|
||||||
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x48, 0x00, 0x52, 0x07,
|
"\x05_size\"\x8e\x02\n" +
|
||||||
0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x88, 0x01, 0x01, 0x12, 0x4f, 0x0a, 0x11, 0x72, 0x65,
|
"\n" +
|
||||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18,
|
"HttpMethod\x12\x1b\n" +
|
||||||
0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31,
|
"\x17HTTP_METHOD_UNSPECIFIED\x10\x00\x12\x15\n" +
|
||||||
0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
|
"\x11HTTP_METHOD_OTHER\x10\x01\x12\x13\n" +
|
||||||
0x61, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x10, 0x72, 0x65, 0x73, 0x70, 0x6f,
|
"\x0fHTTP_METHOD_GET\x10\x02\x12\x14\n" +
|
||||||
0x6e, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x38, 0x0a, 0x08, 0x72,
|
"\x10HTTP_METHOD_HEAD\x10\x03\x12\x14\n" +
|
||||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
|
"\x10HTTP_METHOD_POST\x10\x04\x12\x13\n" +
|
||||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
|
"\x0fHTTP_METHOD_PUT\x10\x05\x12\x16\n" +
|
||||||
0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x48, 0x01, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
"\x12HTTP_METHOD_DELETE\x10\x06\x12\x17\n" +
|
||||||
0x73, 0x65, 0x88, 0x01, 0x01, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
|
"\x13HTTP_METHOD_CONNECT\x10\a\x12\x17\n" +
|
||||||
0x61, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
"\x13HTTP_METHOD_OPTIONS\x10\b\x12\x15\n" +
|
||||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74,
|
"\x11HTTP_METHOD_TRACE\x10\t\x12\x15\n" +
|
||||||
0x48, 0x02, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x88, 0x01, 0x01, 0x42,
|
"\x11HTTP_METHOD_PATCH\x10\n" +
|
||||||
0x0a, 0x0a, 0x08, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x0b, 0x0a, 0x09, 0x5f,
|
"\"\xe9\x01\n" +
|
||||||
0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6d, 0x65, 0x74,
|
"\x0fRequestMetadata\x12'\n" +
|
||||||
0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0xf3, 0x02, 0x0a, 0x12, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e,
|
"\tcaller_ip\x18\x01 \x01(\tB\n" +
|
||||||
0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2d, 0x0a, 0x0c,
|
"\xbaH\a\xc8\x01\x01r\x02p\x01R\bcallerIp\x12R\n" +
|
||||||
0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
"\x1acaller_supplied_user_agent\x18\x02 \x01(\tB\x15\xbaH\x12\xc8\x01\x01r\r\x10\x01\x18\xff\x012\x06.*\\S.*R\x17callerSuppliedUserAgent\x12Y\n" +
|
||||||
0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0b,
|
"\x12request_attributes\x18\x03 \x01(\v2\".audit.v1.AttributeContext.RequestB\x06\xbaH\x03\xc8\x01\x01R\x11requestAttributes\"\xb4\x02\n" +
|
||||||
0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x36, 0x0a, 0x0f, 0x70,
|
"\x10ResponseMetadata\x12H\n" +
|
||||||
0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02,
|
"\vstatus_code\x18\x01 \x01(\v2\x1b.google.protobuf.Int32ValueB\n" +
|
||||||
0x20, 0x01, 0x28, 0x09, 0x42, 0x0d, 0xba, 0x48, 0x0a, 0xc8, 0x01, 0x01, 0x72, 0x05, 0x10, 0x01,
|
"\xbaH\a\xc8\x01\x01\x1a\x02(\x00R\n" +
|
||||||
0x18, 0xff, 0x01, 0x52, 0x0e, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x45, 0x6d,
|
"statusCode\x12(\n" +
|
||||||
0x61, 0x69, 0x6c, 0x12, 0x6e, 0x0a, 0x14, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61,
|
"\rerror_message\x18\x02 \x01(\tH\x00R\ferrorMessage\x88\x01\x01\x12<\n" +
|
||||||
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
|
"\rerror_details\x18\x03 \x03(\v2\x17.google.protobuf.StructR\ferrorDetails\x12\\\n" +
|
||||||
0x09, 0x42, 0x37, 0xba, 0x48, 0x34, 0x72, 0x32, 0x32, 0x30, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x2d,
|
"\x13response_attributes\x18\x04 \x01(\v2#.audit.v1.AttributeContext.ResponseB\x06\xbaH\x03\xc8\x01\x01R\x12responseAttributesB\x10\n" +
|
||||||
0x5d, 0x2b, 0x2f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x2d, 0x5d, 0x2b, 0x2f, 0x73, 0x65,
|
"\x0e_error_message\"\xca\x04\n" +
|
||||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x2d, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x5b,
|
"\x1cServiceAccountDelegationInfo\x12c\n" +
|
||||||
0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x2d, 0x5d, 0x2b, 0x24, 0x48, 0x00, 0x52, 0x12, 0x73, 0x65,
|
"\x10system_principal\x18\x01 \x01(\v26.audit.v1.ServiceAccountDelegationInfo.SystemPrincipalH\x00R\x0fsystemPrincipal\x12Z\n" +
|
||||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65,
|
"\ridp_principal\x18\x02 \x01(\v23.audit.v1.ServiceAccountDelegationInfo.IdpPrincipalH\x00R\fidpPrincipal\x1ao\n" +
|
||||||
0x88, 0x01, 0x01, 0x12, 0x6d, 0x0a, 0x1f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61,
|
"\x0fSystemPrincipal\x12G\n" +
|
||||||
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f,
|
"\x10service_metadata\x18\x01 \x01(\v2\x17.google.protobuf.StructH\x00R\x0fserviceMetadata\x88\x01\x01B\x13\n" +
|
||||||
0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61,
|
"\x11_service_metadata\x1a\xe3\x01\n" +
|
||||||
0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41,
|
"\fIdpPrincipal\x125\n" +
|
||||||
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
"\fprincipal_id\x18\x01 \x01(\tB\x12\xbaH\x0f\xc8\x01\x01r\n" +
|
||||||
0x49, 0x6e, 0x66, 0x6f, 0x52, 0x1c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63,
|
"\x10\x012\x06.*\\S.*R\vprincipalId\x12>\n" +
|
||||||
0x6f, 0x75, 0x6e, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e,
|
"\x0fprincipal_email\x18\x02 \x01(\tB\x15\xbaH\x12\xc8\x01\x01r\r\x10\x01\x18\xff\x012\x06.*\\S.*R\x0eprincipalEmail\x12G\n" +
|
||||||
0x66, 0x6f, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61,
|
"\x10service_metadata\x18\x03 \x01(\v2\x17.google.protobuf.StructH\x00R\x0fserviceMetadata\x88\x01\x01B\x13\n" +
|
||||||
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xf2, 0x01, 0x0a, 0x11,
|
"\x11_service_metadataB\x12\n" +
|
||||||
0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66,
|
"\tauthority\x12\x05\xbaH\x02\b\x01*\x96\x02\n" +
|
||||||
0x6f, 0x12, 0x55, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20,
|
"\vLogSeverity\x12\x1c\n" +
|
||||||
0x01, 0x28, 0x09, 0x42, 0x39, 0xba, 0x48, 0x36, 0xc8, 0x01, 0x01, 0x72, 0x31, 0x32, 0x2f, 0x5e,
|
"\x18LOG_SEVERITY_UNSPECIFIED\x10\x00\x12\x18\n" +
|
||||||
0x5b, 0x61, 0x2d, 0x7a, 0x5d, 0x2b, 0x2f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x2d, 0x5d,
|
"\x14LOG_SEVERITY_DEFAULT\x10d\x12\x17\n" +
|
||||||
0x2b, 0x28, 0x3f, 0x3a, 0x2f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x2d, 0x5d, 0x2b, 0x2f,
|
"\x12LOG_SEVERITY_DEBUG\x10\xc8\x01\x12\x16\n" +
|
||||||
0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x2d, 0x5f, 0x5d, 0x2b, 0x29, 0x2a, 0x24, 0x52, 0x08,
|
"\x11LOG_SEVERITY_INFO\x10\xac\x02\x12\x18\n" +
|
||||||
0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x6d,
|
"\x13LOG_SEVERITY_NOTICE\x10\x90\x03\x12\x19\n" +
|
||||||
0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x27, 0xba, 0x48,
|
"\x14LOG_SEVERITY_WARNING\x10\xf4\x03\x12\x17\n" +
|
||||||
0x24, 0x72, 0x22, 0x32, 0x20, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x2d, 0x5d, 0x2b, 0x28, 0x3f, 0x3a,
|
"\x12LOG_SEVERITY_ERROR\x10\xd8\x04\x12\x1a\n" +
|
||||||
0x5c, 0x2e, 0x5b, 0x61, 0x2d, 0x7a, 0x2d, 0x5d, 0x2b, 0x29, 0x2a, 0x5c, 0x2e, 0x5b, 0x61, 0x2d,
|
"\x15LOG_SEVERITY_CRITICAL\x10\xbc\x05\x12\x17\n" +
|
||||||
0x7a, 0x2d, 0x5d, 0x2b, 0x24, 0x48, 0x00, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73,
|
"\x12LOG_SEVERITY_ALERT\x10\xa0\x06\x12\x1b\n" +
|
||||||
0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x65,
|
"\x16LOG_SEVERITY_EMERGENCY\x10\x84\aB1\n" +
|
||||||
0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x48, 0x01, 0x52, 0x07, 0x67, 0x72, 0x61, 0x6e, 0x74,
|
"\x1ccom.schwarz.stackit.audit.v1P\x01Z\x0f./audit;auditV1b\x06proto3"
|
||||||
0x65, 0x64, 0x88, 0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73,
|
|
||||||
0x73, 0x69, 0x6f, 0x6e, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x64,
|
|
||||||
0x22, 0x89, 0x0b, 0x0a, 0x10, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x43, 0x6f,
|
|
||||||
0x6e, 0x74, 0x65, 0x78, 0x74, 0x1a, 0xa8, 0x01, 0x0a, 0x04, 0x41, 0x75, 0x74, 0x68, 0x12, 0x49,
|
|
||||||
0x0a, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28,
|
|
||||||
0x09, 0x42, 0x2b, 0xba, 0x48, 0x28, 0xc8, 0x01, 0x01, 0x72, 0x23, 0x32, 0x21, 0x5e, 0x5b, 0x61,
|
|
||||||
0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x2d, 0x25, 0x2e, 0x5d, 0x2b, 0x2f, 0x5b, 0x61,
|
|
||||||
0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x2d, 0x25, 0x2e, 0x5d, 0x2b, 0x24, 0x52, 0x09,
|
|
||||||
0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x75, 0x64,
|
|
||||||
0x69, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x75,
|
|
||||||
0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x06, 0x63, 0x6c, 0x61, 0x69, 0x6d,
|
|
||||||
0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
|
||||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74,
|
|
||||||
0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x06, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x73,
|
|
||||||
0x1a, 0xae, 0x04, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x13, 0x0a, 0x02,
|
|
||||||
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x02, 0x69, 0x64, 0x88, 0x01,
|
|
||||||
0x01, 0x12, 0x4a, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
|
|
||||||
0x0e, 0x32, 0x25, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74,
|
|
||||||
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x48, 0x74,
|
|
||||||
0x74, 0x70, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x42, 0x0b, 0xba, 0x48, 0x08, 0xc8, 0x01, 0x01,
|
|
||||||
0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x51, 0x0a,
|
|
||||||
0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f,
|
|
||||||
0x2e, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62,
|
|
||||||
0x75, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65,
|
|
||||||
0x73, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42,
|
|
||||||
0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73,
|
|
||||||
0x12, 0x21, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0d,
|
|
||||||
0xba, 0x48, 0x0a, 0xc8, 0x01, 0x01, 0x72, 0x05, 0x10, 0x01, 0x18, 0xff, 0x01, 0x52, 0x04, 0x70,
|
|
||||||
0x61, 0x74, 0x68, 0x12, 0x1e, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28,
|
|
||||||
0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x68,
|
|
||||||
0x6f, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x06, 0x20,
|
|
||||||
0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02, 0x10, 0x01, 0x52,
|
|
||||||
0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79,
|
|
||||||
0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x88,
|
|
||||||
0x01, 0x01, 0x12, 0x3b, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b,
|
|
||||||
0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
|
||||||
0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x0b, 0xba, 0x48,
|
|
||||||
0x08, 0xc8, 0x01, 0x01, 0xb2, 0x01, 0x02, 0x38, 0x01, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12,
|
|
||||||
0x26, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28,
|
|
||||||
0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02, 0x10, 0x01, 0x52, 0x08, 0x70,
|
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x3b, 0x0a, 0x04, 0x61, 0x75, 0x74, 0x68, 0x18,
|
|
||||||
0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31,
|
|
||||||
0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78,
|
|
||||||
0x74, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x04,
|
|
||||||
0x61, 0x75, 0x74, 0x68, 0x1a, 0x3a, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45,
|
|
||||||
0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
|
|
||||||
0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
|
|
||||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
|
|
||||||
0x42, 0x05, 0x0a, 0x03, 0x5f, 0x69, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x71, 0x75, 0x65, 0x72,
|
|
||||||
0x79, 0x1a, 0x87, 0x03, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57,
|
|
||||||
0x0a, 0x12, 0x6e, 0x75, 0x6d, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x69,
|
|
||||||
0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f,
|
|
||||||
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74,
|
|
||||||
0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x07, 0xba, 0x48, 0x04, 0x22, 0x02, 0x28, 0x00,
|
|
||||||
0x48, 0x00, 0x52, 0x10, 0x6e, 0x75, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x49,
|
|
||||||
0x74, 0x65, 0x6d, 0x73, 0x88, 0x01, 0x01, 0x12, 0x3d, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18,
|
|
||||||
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
|
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c,
|
|
||||||
0x75, 0x65, 0x42, 0x07, 0xba, 0x48, 0x04, 0x22, 0x02, 0x28, 0x00, 0x48, 0x01, 0x52, 0x04, 0x73,
|
|
||||||
0x69, 0x7a, 0x65, 0x88, 0x01, 0x01, 0x12, 0x4a, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
|
|
||||||
0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2e,
|
|
||||||
0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74,
|
|
||||||
0x65, 0x78, 0x74, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x48, 0x65, 0x61,
|
|
||||||
0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65,
|
|
||||||
0x72, 0x73, 0x12, 0x3b, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
|
|
||||||
0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
|
||||||
0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x0b, 0xba, 0x48,
|
|
||||||
0x08, 0xc8, 0x01, 0x01, 0xb2, 0x01, 0x02, 0x38, 0x01, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x1a,
|
|
||||||
0x3a, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
|
|
||||||
0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
|
|
||||||
0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
|
||||||
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x15, 0x0a, 0x13, 0x5f,
|
|
||||||
0x6e, 0x75, 0x6d, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x69, 0x74, 0x65,
|
|
||||||
0x6d, 0x73, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x22, 0x8e, 0x02, 0x0a, 0x0a,
|
|
||||||
0x48, 0x74, 0x74, 0x70, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1b, 0x0a, 0x17, 0x48, 0x54,
|
|
||||||
0x54, 0x50, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43,
|
|
||||||
0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x48, 0x54, 0x54, 0x50, 0x5f,
|
|
||||||
0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x4f, 0x54, 0x48, 0x45, 0x52, 0x10, 0x01, 0x12, 0x13,
|
|
||||||
0x0a, 0x0f, 0x48, 0x54, 0x54, 0x50, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x47, 0x45,
|
|
||||||
0x54, 0x10, 0x02, 0x12, 0x14, 0x0a, 0x10, 0x48, 0x54, 0x54, 0x50, 0x5f, 0x4d, 0x45, 0x54, 0x48,
|
|
||||||
0x4f, 0x44, 0x5f, 0x48, 0x45, 0x41, 0x44, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x48, 0x54, 0x54,
|
|
||||||
0x50, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x50, 0x4f, 0x53, 0x54, 0x10, 0x04, 0x12,
|
|
||||||
0x13, 0x0a, 0x0f, 0x48, 0x54, 0x54, 0x50, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x50,
|
|
||||||
0x55, 0x54, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x48, 0x54, 0x54, 0x50, 0x5f, 0x4d, 0x45, 0x54,
|
|
||||||
0x48, 0x4f, 0x44, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x06, 0x12, 0x17, 0x0a, 0x13,
|
|
||||||
0x48, 0x54, 0x54, 0x50, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x43, 0x4f, 0x4e, 0x4e,
|
|
||||||
0x45, 0x43, 0x54, 0x10, 0x07, 0x12, 0x17, 0x0a, 0x13, 0x48, 0x54, 0x54, 0x50, 0x5f, 0x4d, 0x45,
|
|
||||||
0x54, 0x48, 0x4f, 0x44, 0x5f, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x10, 0x08, 0x12, 0x15,
|
|
||||||
0x0a, 0x11, 0x48, 0x54, 0x54, 0x50, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x54, 0x52,
|
|
||||||
0x41, 0x43, 0x45, 0x10, 0x09, 0x12, 0x15, 0x0a, 0x11, 0x48, 0x54, 0x54, 0x50, 0x5f, 0x4d, 0x45,
|
|
||||||
0x54, 0x48, 0x4f, 0x44, 0x5f, 0x50, 0x41, 0x54, 0x43, 0x48, 0x10, 0x0a, 0x22, 0xe1, 0x01, 0x0a,
|
|
||||||
0x0f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
|
|
||||||
0x12, 0x27, 0x0a, 0x09, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x69, 0x70, 0x18, 0x01, 0x20,
|
|
||||||
0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02, 0x70, 0x01, 0x52,
|
|
||||||
0x08, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x70, 0x12, 0x4a, 0x0a, 0x1a, 0x63, 0x61, 0x6c,
|
|
||||||
0x6c, 0x65, 0x72, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x5f, 0x75, 0x73, 0x65,
|
|
||||||
0x72, 0x5f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0d, 0xba,
|
|
||||||
0x48, 0x0a, 0xc8, 0x01, 0x01, 0x72, 0x05, 0x10, 0x01, 0x18, 0xff, 0x01, 0x52, 0x17, 0x63, 0x61,
|
|
||||||
0x6c, 0x6c, 0x65, 0x72, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72,
|
|
||||||
0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x59, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
|
||||||
0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
|
|
||||||
0x0b, 0x32, 0x22, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74,
|
|
||||||
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x52, 0x65,
|
|
||||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x11, 0x72,
|
|
||||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
|
|
||||||
0x22, 0xb4, 0x02, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x74,
|
|
||||||
0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x48, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f,
|
|
||||||
0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f,
|
|
||||||
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74,
|
|
||||||
0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x1a,
|
|
||||||
0x02, 0x28, 0x00, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12,
|
|
||||||
0x28, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
|
||||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d,
|
|
||||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x88, 0x01, 0x01, 0x12, 0x3c, 0x0a, 0x0d, 0x65, 0x72, 0x72,
|
|
||||||
0x6f, 0x72, 0x5f, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
|
|
||||||
0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
|
||||||
0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72,
|
|
||||||
0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x5c, 0x0a, 0x13, 0x72, 0x65, 0x73, 0x70, 0x6f,
|
|
||||||
0x6e, 0x73, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x04,
|
|
||||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e,
|
|
||||||
0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
|
|
||||||
0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01,
|
|
||||||
0x01, 0x52, 0x12, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69,
|
|
||||||
0x62, 0x75, 0x74, 0x65, 0x73, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f,
|
|
||||||
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xba, 0x04, 0x0a, 0x1c, 0x53, 0x65, 0x72, 0x76,
|
|
||||||
0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61,
|
|
||||||
0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x63, 0x0a, 0x10, 0x73, 0x79, 0x73, 0x74,
|
|
||||||
0x65, 0x6d, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01,
|
|
||||||
0x28, 0x0b, 0x32, 0x36, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65,
|
|
||||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x44, 0x65, 0x6c, 0x65,
|
|
||||||
0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65,
|
|
||||||
0x6d, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x48, 0x00, 0x52, 0x0f, 0x73, 0x79,
|
|
||||||
0x73, 0x74, 0x65, 0x6d, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x12, 0x5a, 0x0a,
|
|
||||||
0x0d, 0x69, 0x64, 0x70, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x18, 0x02,
|
|
||||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e,
|
|
||||||
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x44, 0x65,
|
|
||||||
0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x49, 0x64, 0x70,
|
|
||||||
0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x48, 0x00, 0x52, 0x0c, 0x69, 0x64, 0x70,
|
|
||||||
0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x1a, 0x6f, 0x0a, 0x0f, 0x53, 0x79, 0x73,
|
|
||||||
0x74, 0x65, 0x6d, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x12, 0x47, 0x0a, 0x10,
|
|
||||||
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
|
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x48,
|
|
||||||
0x00, 0x52, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
|
|
||||||
0x74, 0x61, 0x88, 0x01, 0x01, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
|
|
||||||
0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0xd3, 0x01, 0x0a, 0x0c, 0x49,
|
|
||||||
0x64, 0x70, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x12, 0x2d, 0x0a, 0x0c, 0x70,
|
|
||||||
0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
|
||||||
0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0b, 0x70,
|
|
||||||
0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x36, 0x0a, 0x0f, 0x70, 0x72,
|
|
||||||
0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20,
|
|
||||||
0x01, 0x28, 0x09, 0x42, 0x0d, 0xba, 0x48, 0x0a, 0xc8, 0x01, 0x01, 0x72, 0x05, 0x10, 0x01, 0x18,
|
|
||||||
0xff, 0x01, 0x52, 0x0e, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x45, 0x6d, 0x61,
|
|
||||||
0x69, 0x6c, 0x12, 0x47, 0x0a, 0x10, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x65,
|
|
||||||
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67,
|
|
||||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53,
|
|
||||||
0x74, 0x72, 0x75, 0x63, 0x74, 0x48, 0x00, 0x52, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
|
||||||
0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x88, 0x01, 0x01, 0x42, 0x13, 0x0a, 0x11, 0x5f,
|
|
||||||
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
|
|
||||||
0x42, 0x12, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x05, 0xba,
|
|
||||||
0x48, 0x02, 0x08, 0x01, 0x2a, 0x96, 0x02, 0x0a, 0x0b, 0x4c, 0x6f, 0x67, 0x53, 0x65, 0x76, 0x65,
|
|
||||||
0x72, 0x69, 0x74, 0x79, 0x12, 0x1c, 0x0a, 0x18, 0x4c, 0x4f, 0x47, 0x5f, 0x53, 0x45, 0x56, 0x45,
|
|
||||||
0x52, 0x49, 0x54, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44,
|
|
||||||
0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x4c, 0x4f, 0x47, 0x5f, 0x53, 0x45, 0x56, 0x45, 0x52, 0x49,
|
|
||||||
0x54, 0x59, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x64, 0x12, 0x17, 0x0a, 0x12,
|
|
||||||
0x4c, 0x4f, 0x47, 0x5f, 0x53, 0x45, 0x56, 0x45, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x44, 0x45, 0x42,
|
|
||||||
0x55, 0x47, 0x10, 0xc8, 0x01, 0x12, 0x16, 0x0a, 0x11, 0x4c, 0x4f, 0x47, 0x5f, 0x53, 0x45, 0x56,
|
|
||||||
0x45, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0xac, 0x02, 0x12, 0x18, 0x0a,
|
|
||||||
0x13, 0x4c, 0x4f, 0x47, 0x5f, 0x53, 0x45, 0x56, 0x45, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x4e, 0x4f,
|
|
||||||
0x54, 0x49, 0x43, 0x45, 0x10, 0x90, 0x03, 0x12, 0x19, 0x0a, 0x14, 0x4c, 0x4f, 0x47, 0x5f, 0x53,
|
|
||||||
0x45, 0x56, 0x45, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x57, 0x41, 0x52, 0x4e, 0x49, 0x4e, 0x47, 0x10,
|
|
||||||
0xf4, 0x03, 0x12, 0x17, 0x0a, 0x12, 0x4c, 0x4f, 0x47, 0x5f, 0x53, 0x45, 0x56, 0x45, 0x52, 0x49,
|
|
||||||
0x54, 0x59, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0xd8, 0x04, 0x12, 0x1a, 0x0a, 0x15, 0x4c,
|
|
||||||
0x4f, 0x47, 0x5f, 0x53, 0x45, 0x56, 0x45, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x43, 0x52, 0x49, 0x54,
|
|
||||||
0x49, 0x43, 0x41, 0x4c, 0x10, 0xbc, 0x05, 0x12, 0x17, 0x0a, 0x12, 0x4c, 0x4f, 0x47, 0x5f, 0x53,
|
|
||||||
0x45, 0x56, 0x45, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x41, 0x4c, 0x45, 0x52, 0x54, 0x10, 0xa0, 0x06,
|
|
||||||
0x12, 0x1b, 0x0a, 0x16, 0x4c, 0x4f, 0x47, 0x5f, 0x53, 0x45, 0x56, 0x45, 0x52, 0x49, 0x54, 0x59,
|
|
||||||
0x5f, 0x45, 0x4d, 0x45, 0x52, 0x47, 0x45, 0x4e, 0x43, 0x59, 0x10, 0x84, 0x07, 0x42, 0x31, 0x0a,
|
|
||||||
0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x63, 0x68, 0x77, 0x61, 0x72, 0x7a, 0x2e, 0x73, 0x74, 0x61,
|
|
||||||
0x63, 0x6b, 0x69, 0x74, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x50, 0x01, 0x5a,
|
|
||||||
0x0f, 0x2e, 0x2f, 0x61, 0x75, 0x64, 0x69, 0x74, 0x3b, 0x61, 0x75, 0x64, 0x69, 0x74, 0x56, 0x31,
|
|
||||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
})
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_audit_v1_audit_event_proto_rawDescOnce sync.Once
|
file_audit_v1_audit_event_proto_rawDescOnce sync.Once
|
||||||
|
|
|
||||||
|
|
@ -554,8 +554,6 @@ func (m *AuthenticationInfo) validate(all bool) error {
|
||||||
|
|
||||||
// no validation rules for PrincipalId
|
// no validation rules for PrincipalId
|
||||||
|
|
||||||
// no validation rules for PrincipalEmail
|
|
||||||
|
|
||||||
for idx, item := range m.GetServiceAccountDelegationInfo() {
|
for idx, item := range m.GetServiceAccountDelegationInfo() {
|
||||||
_, _ = idx, item
|
_, _ = idx, item
|
||||||
|
|
||||||
|
|
@ -590,6 +588,10 @@ func (m *AuthenticationInfo) validate(all bool) error {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if m.PrincipalEmail != nil {
|
||||||
|
// no validation rules for PrincipalEmail
|
||||||
|
}
|
||||||
|
|
||||||
if m.ServiceAccountName != nil {
|
if m.ServiceAccountName != nil {
|
||||||
// no validation rules for ServiceAccountName
|
// no validation rules for ServiceAccountName
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.36.4
|
// protoc-gen-go v1.36.11
|
||||||
// protoc (unknown)
|
// protoc (unknown)
|
||||||
// source: audit/v1/routable_event.proto
|
// source: audit/v1/routable_event.proto
|
||||||
|
|
||||||
|
|
@ -411,74 +411,44 @@ func (*RoutableAuditEvent_EncryptedData) isRoutableAuditEvent_Data() {}
|
||||||
|
|
||||||
var File_audit_v1_routable_event_proto protoreflect.FileDescriptor
|
var File_audit_v1_routable_event_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_audit_v1_routable_event_proto_rawDesc = string([]byte{
|
const file_audit_v1_routable_event_proto_rawDesc = "" +
|
||||||
0x0a, 0x1d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x61,
|
"\n" +
|
||||||
0x62, 0x6c, 0x65, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
|
"\x1daudit/v1/routable_event.proto\x12\baudit.v1\x1a\x1bbuf/validate/validate.proto\"_\n" +
|
||||||
0x08, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x1a, 0x1b, 0x62, 0x75, 0x66, 0x2f, 0x76,
|
"\x10ObjectIdentifier\x12+\n" +
|
||||||
0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65,
|
"\n" +
|
||||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x5f, 0x0a, 0x10, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74,
|
"identifier\x18\x01 \x01(\tB\v\xbaH\b\xc8\x01\x01r\x03\xb0\x01\x01R\n" +
|
||||||
0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x2b, 0x0a, 0x0a, 0x69, 0x64,
|
"identifier\x12\x1e\n" +
|
||||||
0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0b,
|
"\x04type\x18\x02 \x01(\tB\n" +
|
||||||
0xba, 0x48, 0x08, 0xc8, 0x01, 0x01, 0x72, 0x03, 0xb0, 0x01, 0x01, 0x52, 0x0a, 0x69, 0x64, 0x65,
|
"\xbaH\a\xc8\x01\x01r\x02\x10\x01R\x04type\"\xc5\x01\n" +
|
||||||
0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
|
"\rEncryptedData\x12\x1e\n" +
|
||||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02, 0x10,
|
"\x04data\x18\x01 \x01(\fB\n" +
|
||||||
0x01, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xc5, 0x01, 0x0a, 0x0d, 0x45, 0x6e, 0x63, 0x72,
|
"\xbaH\a\xc8\x01\x01z\x02\x10\x01R\x04data\x12/\n" +
|
||||||
0x79, 0x70, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x04, 0x64, 0x61, 0x74,
|
"\rprotobuf_type\x18\x02 \x01(\tB\n" +
|
||||||
0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x7a,
|
"\xbaH\a\xc8\x01\x01r\x02\x10\x01R\fprotobufType\x129\n" +
|
||||||
0x02, 0x10, 0x01, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2f, 0x0a, 0x0d, 0x70, 0x72, 0x6f,
|
"\x12encrypted_password\x18\x03 \x01(\tB\n" +
|
||||||
0x74, 0x6f, 0x62, 0x75, 0x66, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
"\xbaH\a\xc8\x01\x01r\x02\x10\x01R\x11encryptedPassword\x12(\n" +
|
||||||
0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x70, 0x72,
|
"\vkey_version\x18\x04 \x01(\x05B\a\xbaH\x04\x1a\x02(\x01R\n" +
|
||||||
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x54, 0x79, 0x70, 0x65, 0x12, 0x39, 0x0a, 0x12, 0x65, 0x6e,
|
"keyVersion\"b\n" +
|
||||||
0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
|
"\x0fUnencryptedData\x12\x1e\n" +
|
||||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02,
|
"\x04data\x18\x01 \x01(\fB\n" +
|
||||||
0x10, 0x01, 0x52, 0x11, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x50, 0x61, 0x73,
|
"\xbaH\a\xc8\x01\x01z\x02\x10\x01R\x04data\x12/\n" +
|
||||||
0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x28, 0x0a, 0x0b, 0x6b, 0x65, 0x79, 0x5f, 0x76, 0x65, 0x72,
|
"\rprotobuf_type\x18\x02 \x01(\tB\n" +
|
||||||
0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x42, 0x07, 0xba, 0x48, 0x04, 0x1a,
|
"\xbaH\a\xc8\x01\x01r\x02\x10\x01R\fprotobufType\"\xb5\x03\n" +
|
||||||
0x02, 0x28, 0x01, 0x52, 0x0a, 0x6b, 0x65, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22,
|
"\x12RoutableAuditEvent\x12r\n" +
|
||||||
0x62, 0x0a, 0x0f, 0x55, 0x6e, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x44, 0x61,
|
"\x0eoperation_name\x18\x01 \x01(\tBK\xbaHH\xc8\x01\x01rC2A^stackit\\.[a-z0-9-]+\\.(?:v[0-9]+\\.)?(?:[a-z0-9-.]+\\.)?[a-z0-9-]+$R\roperationName\x12A\n" +
|
||||||
0x74, 0x61, 0x12, 0x1e, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
|
"\n" +
|
||||||
0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x7a, 0x02, 0x10, 0x01, 0x52, 0x04, 0x64, 0x61,
|
"visibility\x18\x02 \x01(\x0e2\x14.audit.v1.VisibilityB\v\xbaH\b\xc8\x01\x01\x82\x01\x02\x10\x01R\n" +
|
||||||
0x74, 0x61, 0x12, 0x2f, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x5f, 0x74,
|
"visibility\x12O\n" +
|
||||||
0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01,
|
"\x11object_identifier\x18\x03 \x01(\v2\x1a.audit.v1.ObjectIdentifierB\x06\xbaH\x03\xc8\x01\x01R\x10objectIdentifier\x12F\n" +
|
||||||
0x01, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x54,
|
"\x10unencrypted_data\x18\x04 \x01(\v2\x19.audit.v1.UnencryptedDataH\x00R\x0funencryptedData\x12@\n" +
|
||||||
0x79, 0x70, 0x65, 0x22, 0xb5, 0x03, 0x0a, 0x12, 0x52, 0x6f, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65,
|
"\x0eencrypted_data\x18\x05 \x01(\v2\x17.audit.v1.EncryptedDataH\x00R\rencryptedDataB\r\n" +
|
||||||
0x41, 0x75, 0x64, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x72, 0x0a, 0x0e, 0x6f, 0x70,
|
"\x04data\x12\x05\xbaH\x02\b\x01*W\n" +
|
||||||
0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
|
"\n" +
|
||||||
0x28, 0x09, 0x42, 0x4b, 0xba, 0x48, 0x48, 0xc8, 0x01, 0x01, 0x72, 0x43, 0x32, 0x41, 0x5e, 0x73,
|
"Visibility\x12\x1a\n" +
|
||||||
0x74, 0x61, 0x63, 0x6b, 0x69, 0x74, 0x5c, 0x2e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x2d,
|
"\x16VISIBILITY_UNSPECIFIED\x10\x00\x12\x15\n" +
|
||||||
0x5d, 0x2b, 0x5c, 0x2e, 0x28, 0x3f, 0x3a, 0x76, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0x5c, 0x2e,
|
"\x11VISIBILITY_PUBLIC\x10\x01\x12\x16\n" +
|
||||||
0x29, 0x3f, 0x28, 0x3f, 0x3a, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x2d, 0x2e, 0x5d, 0x2b,
|
"\x12VISIBILITY_PRIVATE\x10\x02B1\n" +
|
||||||
0x5c, 0x2e, 0x29, 0x3f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x2d, 0x5d, 0x2b, 0x24, 0x52,
|
"\x1ccom.schwarz.stackit.audit.v1P\x01Z\x0f./audit;auditV1b\x06proto3"
|
||||||
0x0d, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x41,
|
|
||||||
0x0a, 0x0a, 0x76, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01,
|
|
||||||
0x28, 0x0e, 0x32, 0x14, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x69,
|
|
||||||
0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x42, 0x0b, 0xba, 0x48, 0x08, 0xc8, 0x01, 0x01,
|
|
||||||
0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x76, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74,
|
|
||||||
0x79, 0x12, 0x4f, 0x0a, 0x11, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x65, 0x6e,
|
|
||||||
0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61,
|
|
||||||
0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64,
|
|
||||||
0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01,
|
|
||||||
0x52, 0x10, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69,
|
|
||||||
0x65, 0x72, 0x12, 0x46, 0x0a, 0x10, 0x75, 0x6e, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65,
|
|
||||||
0x64, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61,
|
|
||||||
0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70,
|
|
||||||
0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x65, 0x6e, 0x63,
|
|
||||||
0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x12, 0x40, 0x0a, 0x0e, 0x65, 0x6e,
|
|
||||||
0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01,
|
|
||||||
0x28, 0x0b, 0x32, 0x17, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e,
|
|
||||||
0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0d, 0x65,
|
|
||||||
0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x42, 0x0d, 0x0a, 0x04,
|
|
||||||
0x64, 0x61, 0x74, 0x61, 0x12, 0x05, 0xba, 0x48, 0x02, 0x08, 0x01, 0x2a, 0x57, 0x0a, 0x0a, 0x56,
|
|
||||||
0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x1a, 0x0a, 0x16, 0x56, 0x49, 0x53,
|
|
||||||
0x49, 0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46,
|
|
||||||
0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x56, 0x49, 0x53, 0x49, 0x42, 0x49, 0x4c,
|
|
||||||
0x49, 0x54, 0x59, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12,
|
|
||||||
0x56, 0x49, 0x53, 0x49, 0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x5f, 0x50, 0x52, 0x49, 0x56, 0x41,
|
|
||||||
0x54, 0x45, 0x10, 0x02, 0x42, 0x31, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x63, 0x68, 0x77,
|
|
||||||
0x61, 0x72, 0x7a, 0x2e, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x69, 0x74, 0x2e, 0x61, 0x75, 0x64, 0x69,
|
|
||||||
0x74, 0x2e, 0x76, 0x31, 0x50, 0x01, 0x5a, 0x0f, 0x2e, 0x2f, 0x61, 0x75, 0x64, 0x69, 0x74, 0x3b,
|
|
||||||
0x61, 0x75, 0x64, 0x69, 0x74, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
})
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_audit_v1_routable_event_proto_rawDescOnce sync.Once
|
file_audit_v1_routable_event_proto_rawDescOnce sync.Once
|
||||||
|
|
|
||||||
95
go.mod
95
go.mod
|
|
@ -1,87 +1,88 @@
|
||||||
module dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git
|
module dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git
|
||||||
|
|
||||||
go 1.22.7
|
go 1.24.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.4-20241127180247-a33202765966.1
|
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20251209175733-2a1774d88802.1
|
||||||
github.com/Azure/go-amqp v1.3.0
|
buf.build/go/protovalidate v1.1.0
|
||||||
github.com/bufbuild/protovalidate-go v0.8.2
|
github.com/Azure/go-amqp v1.5.1
|
||||||
|
github.com/docker/docker v28.5.2+incompatible
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/lestrrat-go/jwx/v2 v2.1.3
|
github.com/lestrrat-go/jwx/v2 v2.1.6
|
||||||
github.com/rs/zerolog v1.33.0
|
github.com/rs/zerolog v1.34.0
|
||||||
github.com/stretchr/testify v1.10.0
|
github.com/stretchr/testify v1.11.1
|
||||||
github.com/testcontainers/testcontainers-go v0.35.0
|
github.com/testcontainers/testcontainers-go v0.40.0
|
||||||
go.opentelemetry.io/otel v1.34.0
|
go.opentelemetry.io/otel v1.39.0
|
||||||
go.opentelemetry.io/otel/trace v1.34.0
|
go.opentelemetry.io/otel/trace v1.39.0
|
||||||
google.golang.org/protobuf v1.36.4
|
google.golang.org/protobuf v1.36.11
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cel.dev/expr v0.19.2 // indirect
|
cel.dev/expr v0.25.1 // indirect
|
||||||
dario.cat/mergo v1.0.1 // indirect
|
dario.cat/mergo v1.0.2 // indirect
|
||||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 // indirect
|
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
|
github.com/containerd/errdefs v1.0.0 // indirect
|
||||||
|
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||||
github.com/containerd/log v0.1.0 // indirect
|
github.com/containerd/log v0.1.0 // indirect
|
||||||
github.com/containerd/platforms v0.2.1 // indirect
|
github.com/containerd/platforms v0.2.1 // indirect
|
||||||
github.com/cpuguy83/dockercfg v0.3.2 // indirect
|
github.com/cpuguy83/dockercfg v0.3.2 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
|
||||||
github.com/distribution/reference v0.6.0 // indirect
|
github.com/distribution/reference v0.6.0 // indirect
|
||||||
github.com/docker/docker v27.5.1+incompatible // indirect
|
github.com/docker/go-connections v0.6.0 // indirect
|
||||||
github.com/docker/go-connections v0.5.0 // indirect
|
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
|
github.com/ebitengine/purego v0.9.1 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/go-logr/logr v1.4.2 // indirect
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.4 // indirect
|
github.com/goccy/go-json v0.10.5 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/google/cel-go v0.26.1 // indirect
|
||||||
github.com/google/cel-go v0.23.0 // indirect
|
github.com/klauspost/compress v1.18.2 // indirect
|
||||||
github.com/klauspost/compress v1.17.11 // indirect
|
github.com/lestrrat-go/blackmagic v1.0.4 // indirect
|
||||||
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
|
|
||||||
github.com/lestrrat-go/httpcc v1.0.1 // indirect
|
github.com/lestrrat-go/httpcc v1.0.1 // indirect
|
||||||
github.com/lestrrat-go/httprc v1.0.6 // indirect
|
github.com/lestrrat-go/httprc v1.0.6 // indirect
|
||||||
github.com/lestrrat-go/iter v1.0.2 // indirect
|
github.com/lestrrat-go/iter v1.0.2 // indirect
|
||||||
github.com/lestrrat-go/option v1.0.1 // indirect
|
github.com/lestrrat-go/option v1.0.1 // indirect
|
||||||
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect
|
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect
|
||||||
github.com/magiconair/properties v1.8.9 // indirect
|
github.com/magiconair/properties v1.8.10 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||||
|
github.com/moby/go-archive v0.2.0 // indirect
|
||||||
github.com/moby/patternmatcher v0.6.0 // indirect
|
github.com/moby/patternmatcher v0.6.0 // indirect
|
||||||
github.com/moby/sys/sequential v0.6.0 // indirect
|
github.com/moby/sys/sequential v0.6.0 // indirect
|
||||||
github.com/moby/sys/user v0.3.0 // indirect
|
github.com/moby/sys/user v0.4.0 // indirect
|
||||||
github.com/moby/sys/userns v0.1.0 // indirect
|
github.com/moby/sys/userns v0.1.0 // indirect
|
||||||
github.com/moby/term v0.5.2 // indirect
|
github.com/moby/term v0.5.2 // indirect
|
||||||
github.com/morikuni/aec v1.0.0 // indirect
|
github.com/morikuni/aec v1.1.0 // indirect
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||||
github.com/segmentio/asm v1.2.0 // indirect
|
github.com/segmentio/asm v1.2.1 // indirect
|
||||||
github.com/shirou/gopsutil/v3 v3.24.5 // indirect
|
github.com/shirou/gopsutil/v4 v4.25.12 // indirect
|
||||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
|
||||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
github.com/stoewer/go-strcase v1.3.0 // indirect
|
github.com/stoewer/go-strcase v1.3.1 // indirect
|
||||||
github.com/stretchr/objx v0.5.2 // indirect
|
github.com/stretchr/objx v0.5.3 // indirect
|
||||||
github.com/tklauser/go-sysconf v0.3.14 // indirect
|
github.com/tklauser/go-sysconf v0.3.16 // indirect
|
||||||
github.com/tklauser/numcpus v0.9.0 // indirect
|
github.com/tklauser/numcpus v0.11.0 // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.34.0 // indirect
|
go.opentelemetry.io/otel/metric v1.39.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk v1.34.0 // indirect
|
golang.org/x/crypto v0.46.0 // indirect
|
||||||
golang.org/x/crypto v0.32.0 // indirect
|
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect
|
||||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect
|
golang.org/x/sys v0.40.0 // indirect
|
||||||
golang.org/x/sys v0.29.0 // indirect
|
golang.org/x/text v0.33.0 // indirect
|
||||||
golang.org/x/text v0.21.0 // indirect
|
golang.org/x/time v0.14.0 // indirect
|
||||||
golang.org/x/time v0.9.0 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250124145028-65684f501c47 // indirect
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
||||||
267
go.sum
267
go.sum
|
|
@ -1,23 +1,33 @@
|
||||||
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.4-20241127180247-a33202765966.1 h1:yeaeyw0RQUe009ebxBQ3TsqBPptiNEGsiS10t+8Htuo=
|
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20251209175733-2a1774d88802.1 h1:j9yeqTWEFrtimt8Nng2MIeRrpoCvQzM9/g25XTvqUGg=
|
||||||
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.4-20241127180247-a33202765966.1/go.mod h1:novQBstnxcGpfKf8qGRATqn1anQKwMJIbH5Q581jibU=
|
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20251209175733-2a1774d88802.1/go.mod h1:tvtbpgaVXZX4g6Pn+AnzFycuRK3MOz5HJfEGeEllXYM=
|
||||||
cel.dev/expr v0.19.2 h1:V354PbqIXr9IQdwy4SYA4xa0HXaWq1BUPAGzugBY5V4=
|
buf.build/go/protovalidate v1.1.0 h1:pQqEQRpOo4SqS60qkvmhLTTQU9JwzEvdyiqAtXa5SeY=
|
||||||
cel.dev/expr v0.19.2/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
|
buf.build/go/protovalidate v1.1.0/go.mod h1:bGZcPiAQDC3ErCHK3t74jSoJDFOs2JH3d7LWuTEIdss=
|
||||||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4=
|
||||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
|
||||||
|
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
|
||||||
|
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
|
||||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
|
||||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||||
github.com/Azure/go-amqp v1.3.0 h1://1rikYhoIQNXJFXyoO/Rlb4+4EkHYfJceNtLlys2/4=
|
github.com/Azure/go-amqp v1.5.1 h1:WyiPTz2C3zVvDL7RLAqwWdeoYhMtX62MZzQoP09fzsU=
|
||||||
github.com/Azure/go-amqp v1.3.0/go.mod h1:vZAogwdrkbyK3Mla8m/CxSc/aKdnTZ4IbPxl51Y5WZE=
|
github.com/Azure/go-amqp v1.5.1/go.mod h1:vZAogwdrkbyK3Mla8m/CxSc/aKdnTZ4IbPxl51Y5WZE=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
|
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
|
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
|
||||||
github.com/bufbuild/protovalidate-go v0.8.2 h1:sgzXHkHYP6HnAsL2Rd3I1JxkYUyEQUv9awU1PduMxbM=
|
github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4=
|
||||||
github.com/bufbuild/protovalidate-go v0.8.2/go.mod h1:K6w8iPNAXBoIivVueSELbUeUl+MmeTQfCDSug85pn3M=
|
github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs=
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
|
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
||||||
|
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
|
||||||
|
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
|
||||||
|
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
|
||||||
|
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
|
||||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
|
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
|
||||||
|
|
@ -30,67 +40,63 @@ github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
|
||||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||||
github.com/docker/docker v27.5.1+incompatible h1:4PYU5dnBYqRQi0294d1FBECqT9ECWeQAIfE8q4YnPY8=
|
github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=
|
||||||
github.com/docker/docker v27.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
|
||||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
|
||||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM=
|
github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A=
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4=
|
github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
||||||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||||
github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM=
|
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||||
github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/google/cel-go v0.26.1 h1:iPbVVEdkhTX++hpe3lzSk7D3G3QSYqLGoHOcEio+UXQ=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/google/cel-go v0.26.1/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM=
|
||||||
github.com/google/cel-go v0.23.0 h1:knsnzeUOcREUFo0ZFJqZI8Rk6uEVyobAlir7GEbf5v0=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/google/cel-go v0.23.0/go.mod h1:52Pb6QsDbC5kvgxvZhiL9QX1oZEkcUF/ZqaPx1J5Wwo=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
|
||||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
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 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k=
|
github.com/lestrrat-go/blackmagic v1.0.4 h1:IwQibdnf8l2KoO+qC3uT4OaTWsW7tuRQXy9TRN9QanA=
|
||||||
github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
|
github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw=
|
||||||
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
|
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
|
||||||
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
|
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
|
||||||
github.com/lestrrat-go/httprc v1.0.6 h1:qgmgIRhpvBqexMJjA/PmwSvhNk679oqD1RbovdCGW8k=
|
github.com/lestrrat-go/httprc v1.0.6 h1:qgmgIRhpvBqexMJjA/PmwSvhNk679oqD1RbovdCGW8k=
|
||||||
github.com/lestrrat-go/httprc v1.0.6/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
|
github.com/lestrrat-go/httprc v1.0.6/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
|
||||||
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
|
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
|
||||||
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
|
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
|
||||||
github.com/lestrrat-go/jwx/v2 v2.1.3 h1:Ud4lb2QuxRClYAmRleF50KrbKIoM1TddXgBrneT5/Jo=
|
github.com/lestrrat-go/jwx/v2 v2.1.6 h1:hxM1gfDILk/l5ylers6BX/Eq1m/pnxe9NBwW6lVfecA=
|
||||||
github.com/lestrrat-go/jwx/v2 v2.1.3/go.mod h1:q6uFgbgZfEmQrfJfrCo90QcQOcXFMfbI/fO0NqRtvZo=
|
github.com/lestrrat-go/jwx/v2 v2.1.6/go.mod h1:Y722kU5r/8mV7fYDifjug0r8FK8mZdw0K0GpJw/l8pU=
|
||||||
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
|
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
|
||||||
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||||
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 h1:7UMa6KCCMjZEMDtTVdcGu0B1GmmC7QJKiCCjyTAWQy0=
|
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 h1:PwQumkgq4/acIiZhtifTV5OUqqiP82UAl0h87xj/l9k=
|
||||||
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
|
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
|
||||||
github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
|
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
|
||||||
github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||||
|
|
@ -100,107 +106,94 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||||
|
github.com/moby/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8=
|
||||||
|
github.com/moby/go-archive v0.2.0/go.mod h1:mNeivT14o8xU+5q1YnNrkQVpK+dnNe/K6fHqnTg4qPU=
|
||||||
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
||||||
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||||
|
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
|
||||||
|
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
|
||||||
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
|
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
|
||||||
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
|
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
|
||||||
github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
|
github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
|
||||||
github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
|
github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
|
||||||
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
|
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
|
||||||
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
|
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
|
||||||
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
|
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
|
||||||
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
|
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
|
||||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
github.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ=
|
||||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
github.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw=
|
||||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
github.com/rodaine/protogofakeit v0.1.1 h1:ZKouljuRM3A+TArppfBqnH8tGZHOwM/pjvtXe9DaXH8=
|
||||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
github.com/rodaine/protogofakeit v0.1.1/go.mod h1:pXn/AstBYMaSfc1/RqH3N82pBuxtWgejz1AlYpY1mI0=
|
||||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||||
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
|
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
|
||||||
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
|
||||||
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
|
github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=
|
||||||
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
|
github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
||||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
github.com/shirou/gopsutil/v4 v4.25.12 h1:e7PvW/0RmJ8p8vPGJH4jvNkOyLmbkXgXW4m6ZPic6CY=
|
||||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
github.com/shirou/gopsutil/v4 v4.25.12/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU=
|
||||||
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
|
||||||
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
|
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
|
github.com/stoewer/go-strcase v1.3.1 h1:iS0MdW+kVTxgMoE1LAZyMiYJFKlOzLooE4MxjirtkAs=
|
||||||
github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
|
github.com/stoewer/go-strcase v1.3.1/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=
|
||||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
github.com/testcontainers/testcontainers-go v0.35.0 h1:uADsZpTKFAtp8SLK+hMwSaa+X+JiERHtd4sQAFmXeMo=
|
github.com/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+aMnb6JfVz1mxk7OeMU=
|
||||||
github.com/testcontainers/testcontainers-go v0.35.0/go.mod h1:oEVBj5zrfJTrgjwONs1SsRbnBtH9OKl+IGl3UMcr2B4=
|
github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY=
|
||||||
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
|
github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA=
|
||||||
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
|
github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=
|
||||||
github.com/tklauser/numcpus v0.9.0 h1:lmyCHtANi8aRUgkckBgoDk1nHCux3n2cgkJLXdQGPDo=
|
github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw=
|
||||||
github.com/tklauser/numcpus v0.9.0/go.mod h1:SN6Nq1O3VychhC1npsWostA+oW+VOQTxZrS604NSRyI=
|
github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ=
|
||||||
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||||
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
|
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 h1:BEj3SPM81McUZHYjRS5pEgNgnmzGJ5tRpU5krWnV8Bs=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0/go.mod h1:9cKLGBDzI/F3NoHLQGm4ZrYdIHsvGt6ej6hUowxY0J4=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU=
|
||||||
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
|
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||||
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
|
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||||
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
|
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||||
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
|
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||||
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
|
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||||
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
|
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||||
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
|
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||||
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
|
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
||||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
||||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0=
|
||||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA=
|
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU=
|
||||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
|
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
|
||||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
|
@ -208,37 +201,27 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
|
||||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
|
||||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
|
||||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||||
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
|
google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b h1:uA40e2M6fYRBf0+8uN5mLlqUtV192iiksiICIBkYJ1E=
|
||||||
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:Xa7le7qx2vmqB/SzWUBa7KdMjpdpAHlh5QCSnjessQk=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b h1:Mv8VFug0MP9e5vUxfBcE3vUkV6CImK3cMNMIDFjmzxU=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 h1:5iw9XJTD4thFidQmFVvx0wi4g5yOHk76rNRUxz1ZG5g=
|
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47/go.mod h1:AfA77qWLcidQWywD0YgqfpJzf50w2VjzBml3TybHeJU=
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250124145028-65684f501c47 h1:91mG8dNTpkC0uChJUQ9zCiRqx3GEEFOWaRZ0mI6Oj2I=
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250124145028-65684f501c47/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50=
|
|
||||||
google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A=
|
|
||||||
google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
|
|
||||||
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
|
|
||||||
google.golang.org/protobuf v1.36.4/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 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 h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
||||||
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
||||||
|
|
|
||||||
|
|
@ -2,72 +2,27 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/telemetry"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
|
||||||
"dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/audit/messaging"
|
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
|
||||||
|
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
internalTelemetry "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/internal/telemetry"
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
|
pkgMessagingApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContentTypeCloudEventsProtobuf the cloudevents protobuf content-type sent in metadata of messages
|
var TopicNamePattern = regexp.MustCompile(`^topic://stackit-platform/t/swz/audit-log/(?:conway|eu01|eu02|sx-stoi01)/[Vv][1-9](?:\.\d)?/[A-Za-z0-9-]+/[A-Za-z0-9-/]+`)
|
||||||
const ContentTypeCloudEventsProtobuf = "application/cloudevents+protobuf"
|
|
||||||
const ContentTypeCloudEventsJson = "application/cloudevents+json; charset=UTF-8"
|
|
||||||
|
|
||||||
// ErrAttributeIdentifierInvalid indicates that the object identifier
|
func ValidateAndSerializePartially(
|
||||||
// and the identifier in the checked attribute do not match
|
validator pkgAuditCommon.ProtobufValidator,
|
||||||
var ErrAttributeIdentifierInvalid = errors.New("attribute identifier invalid")
|
|
||||||
|
|
||||||
// ErrAttributeTypeInvalid indicates that an invalid type has been provided.
|
|
||||||
var ErrAttributeTypeInvalid = errors.New("attribute type invalid")
|
|
||||||
|
|
||||||
// ErrCloudEventNil states that the given cloud event is nil
|
|
||||||
var ErrCloudEventNil = errors.New("cloud event nil")
|
|
||||||
|
|
||||||
// ErrEventNil indicates that the event was nil
|
|
||||||
var ErrEventNil = errors.New("event is nil")
|
|
||||||
|
|
||||||
// ErrInvalidRoutableIdentifierForSystemEvent states that the routable identifier is not valid for a system event
|
|
||||||
var ErrInvalidRoutableIdentifierForSystemEvent = errors.New("invalid identifier for system event")
|
|
||||||
|
|
||||||
// ErrMessagingApiNil states that the messaging api is nil
|
|
||||||
var ErrMessagingApiNil = errors.New("messaging api nil")
|
|
||||||
|
|
||||||
// ErrObjectIdentifierNil indicates that the object identifier was nil
|
|
||||||
var ErrObjectIdentifierNil = errors.New("object identifier is nil")
|
|
||||||
|
|
||||||
// ErrObjectIdentifierVisibilityMismatch indicates that a reference mismatch was detected.
|
|
||||||
//
|
|
||||||
// Valid combinations are:
|
|
||||||
// * Visibility: Public, ObjectIdentifier: <type>
|
|
||||||
// * Visibility: Private, ObjectIdentifier: <type | system>
|
|
||||||
var ErrObjectIdentifierVisibilityMismatch = errors.New("object reference visibility mismatch")
|
|
||||||
|
|
||||||
// ErrTopicNameResolverNil states that the topic name resolve is nil
|
|
||||||
var ErrTopicNameResolverNil = errors.New("topic name resolver nil")
|
|
||||||
|
|
||||||
// ErrUnknownObjectType indicates that the given input is an unknown object type
|
|
||||||
var ErrUnknownObjectType = errors.New("unknown object type")
|
|
||||||
|
|
||||||
// ErrUnsupportedEventTypeDataAccess states that the event type "data-access" is currently not supported
|
|
||||||
var ErrUnsupportedEventTypeDataAccess = errors.New("unsupported event type data access")
|
|
||||||
|
|
||||||
// ErrUnsupportedObjectIdentifierType indicates that an unsupported object identifier type has been provided
|
|
||||||
var ErrUnsupportedObjectIdentifierType = errors.New("unsupported object identifier type")
|
|
||||||
|
|
||||||
// ErrUnsupportedRoutableType indicates that the given input is an unsupported routable type
|
|
||||||
var ErrUnsupportedRoutableType = errors.New("unsupported routable type")
|
|
||||||
|
|
||||||
func validateAndSerializePartially(
|
|
||||||
validator ProtobufValidator,
|
|
||||||
event *auditV1.AuditLogEntry,
|
event *auditV1.AuditLogEntry,
|
||||||
visibility auditV1.Visibility,
|
visibility auditV1.Visibility,
|
||||||
routableIdentifier *RoutableIdentifier,
|
routableIdentifier *pkgAuditCommon.RoutableIdentifier,
|
||||||
) (*auditV1.RoutableAuditEvent, error) {
|
) (*auditV1.RoutableAuditEvent, error) {
|
||||||
|
|
||||||
// Check preconditions
|
// Check preconditions
|
||||||
|
|
@ -86,10 +41,10 @@ func validateAndSerializePartially(
|
||||||
}
|
}
|
||||||
|
|
||||||
func newValidatedRoutableAuditEvent(
|
func newValidatedRoutableAuditEvent(
|
||||||
validator ProtobufValidator,
|
validator pkgAuditCommon.ProtobufValidator,
|
||||||
event *auditV1.AuditLogEntry,
|
event *auditV1.AuditLogEntry,
|
||||||
visibility auditV1.Visibility,
|
visibility auditV1.Visibility,
|
||||||
routableIdentifier *RoutableIdentifier) (*auditV1.RoutableAuditEvent, error) {
|
routableIdentifier *pkgAuditCommon.RoutableIdentifier) (*auditV1.RoutableAuditEvent, error) {
|
||||||
|
|
||||||
// Test serialization even if the data is dropped later when logging to the legacy solution
|
// Test serialization even if the data is dropped later when logging to the legacy solution
|
||||||
auditEventBytes, err := proto.Marshal(event)
|
auditEventBytes, err := proto.Marshal(event)
|
||||||
|
|
@ -117,18 +72,18 @@ func newValidatedRoutableAuditEvent(
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateAuditLogEntry(
|
func validateAuditLogEntry(
|
||||||
validator ProtobufValidator,
|
validator pkgAuditCommon.ProtobufValidator,
|
||||||
event *auditV1.AuditLogEntry,
|
event *auditV1.AuditLogEntry,
|
||||||
visibility auditV1.Visibility,
|
visibility auditV1.Visibility,
|
||||||
routableIdentifier *RoutableIdentifier,
|
routableIdentifier *pkgAuditCommon.RoutableIdentifier,
|
||||||
) error {
|
) error {
|
||||||
|
|
||||||
// Return error if the given event or object identifier is nil
|
// Return error if the given event or object identifier is nil
|
||||||
if event == nil {
|
if event == nil {
|
||||||
return ErrEventNil
|
return pkgAuditCommon.ErrEventNil
|
||||||
}
|
}
|
||||||
if routableIdentifier == nil {
|
if routableIdentifier == nil {
|
||||||
return ErrObjectIdentifierNil
|
return pkgAuditCommon.ErrObjectIdentifierNil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the actual event
|
// Validate the actual event
|
||||||
|
|
@ -139,21 +94,21 @@ func validateAuditLogEntry(
|
||||||
|
|
||||||
// Ensure that a valid object identifier is set if the event is public
|
// Ensure that a valid object identifier is set if the event is public
|
||||||
if isSystemIdentifier(routableIdentifier) && visibility == auditV1.Visibility_VISIBILITY_PUBLIC {
|
if isSystemIdentifier(routableIdentifier) && visibility == auditV1.Visibility_VISIBILITY_PUBLIC {
|
||||||
return ErrObjectIdentifierVisibilityMismatch
|
return pkgAuditCommon.ErrObjectIdentifierVisibilityMismatch
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that provided identifier type is supported
|
// Check that provided identifier type is supported
|
||||||
if err := routableIdentifier.Type.IsSupportedType(); err != nil {
|
if err := routableIdentifier.Type.IsSupportedType(); err != nil {
|
||||||
if errors.Is(err, ErrUnknownObjectType) {
|
if errors.Is(err, pkgAuditCommon.ErrUnknownObjectType) {
|
||||||
return ErrUnsupportedRoutableType
|
return pkgAuditCommon.ErrUnsupportedRoutableType
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check identifier consistency across event attributes
|
// Check identifier consistency across event attributes
|
||||||
if strings.HasSuffix(event.LogName, string(EventTypeSystemEvent)) {
|
if strings.HasSuffix(event.LogName, string(pkgAuditCommon.EventTypeSystemEvent)) {
|
||||||
if !(routableIdentifier.Identifier == SystemIdentifier.Identifier && routableIdentifier.Type == ObjectTypeSystem) {
|
if routableIdentifier.Identifier != pkgAuditCommon.SystemIdentifier.Identifier || routableIdentifier.Type != pkgAuditCommon.ObjectTypeSystem {
|
||||||
return ErrInvalidRoutableIdentifierForSystemEvent
|
return pkgAuditCommon.ErrInvalidRoutableIdentifierForSystemEvent
|
||||||
}
|
}
|
||||||
// The resource name can either contain the system identifier or another resource identifier
|
// The resource name can either contain the system identifier or another resource identifier
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -168,32 +123,32 @@ func validateAuditLogEntry(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send implements AuditApi.Send
|
// Send implements AuditApi.Send
|
||||||
func send(
|
func Send(
|
||||||
topicNameResolver TopicNameResolver,
|
topicNameResolver pkgAuditCommon.TopicNameResolver,
|
||||||
messagingApi messaging.Api,
|
messagingApi pkgMessagingApi.Api,
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
routableIdentifier *RoutableIdentifier,
|
routableIdentifier *pkgAuditCommon.RoutableIdentifier,
|
||||||
cloudEvent *CloudEvent,
|
cloudEvent *pkgAuditCommon.CloudEvent,
|
||||||
) error {
|
) error {
|
||||||
|
|
||||||
// Check that given objects are not nil
|
// Check that given objects are not nil
|
||||||
if topicNameResolver == nil {
|
if topicNameResolver == nil {
|
||||||
return ErrTopicNameResolverNil
|
return pkgAuditCommon.ErrTopicNameResolverNil
|
||||||
}
|
}
|
||||||
if messagingApi == nil {
|
if messagingApi == nil {
|
||||||
return ErrMessagingApiNil
|
return pkgAuditCommon.ErrMessagingApiNil
|
||||||
}
|
}
|
||||||
if cloudEvent == nil {
|
if cloudEvent == nil {
|
||||||
return ErrCloudEventNil
|
return pkgAuditCommon.ErrCloudEventNil
|
||||||
}
|
}
|
||||||
if routableIdentifier == nil {
|
if routableIdentifier == nil {
|
||||||
return ErrObjectIdentifierNil
|
return pkgAuditCommon.ErrObjectIdentifierNil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that provided identifier type is supported
|
// Check that provided identifier type is supported
|
||||||
if err := routableIdentifier.Type.IsSupportedType(); err != nil {
|
if err := routableIdentifier.Type.IsSupportedType(); err != nil {
|
||||||
if errors.Is(err, ErrUnknownObjectType) {
|
if errors.Is(err, pkgAuditCommon.ErrUnknownObjectType) {
|
||||||
return ErrUnsupportedRoutableType
|
return pkgAuditCommon.ErrUnsupportedRoutableType
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -222,15 +177,15 @@ func send(
|
||||||
|
|
||||||
// Telemetry
|
// Telemetry
|
||||||
applicationAttributes["cloudEvents:sdklanguage"] = "go"
|
applicationAttributes["cloudEvents:sdklanguage"] = "go"
|
||||||
auditGoVersion := telemetry.AuditGoVersion
|
auditGoVersion := internalTelemetry.AuditGoVersion
|
||||||
if auditGoVersion != "" {
|
if auditGoVersion != "" {
|
||||||
applicationAttributes["cloudEvents:sdkversion"] = auditGoVersion
|
applicationAttributes["cloudEvents:sdkversion"] = auditGoVersion
|
||||||
}
|
}
|
||||||
auditGoGrpcVersion := telemetry.AuditGoGrpcVersion
|
auditGoGrpcVersion := internalTelemetry.AuditGoGrpcVersion
|
||||||
if auditGoGrpcVersion != "" {
|
if auditGoGrpcVersion != "" {
|
||||||
applicationAttributes["cloudEvents:sdkgrpcversion"] = auditGoGrpcVersion
|
applicationAttributes["cloudEvents:sdkgrpcversion"] = auditGoGrpcVersion
|
||||||
}
|
}
|
||||||
auditGoHttpVersion := telemetry.AuditGoHttpVersion
|
auditGoHttpVersion := internalTelemetry.AuditGoHttpVersion
|
||||||
if auditGoHttpVersion != "" {
|
if auditGoHttpVersion != "" {
|
||||||
applicationAttributes["cloudEvents:sdkhttpversion"] = auditGoHttpVersion
|
applicationAttributes["cloudEvents:sdkhttpversion"] = auditGoHttpVersion
|
||||||
}
|
}
|
||||||
|
|
@ -243,16 +198,16 @@ func send(
|
||||||
applicationAttributes)
|
applicationAttributes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isSystemIdentifier(identifier *RoutableIdentifier) bool {
|
func isSystemIdentifier(identifier *pkgAuditCommon.RoutableIdentifier) bool {
|
||||||
if identifier.Identifier == uuid.Nil.String() && identifier.Type == ObjectTypeSystem {
|
if identifier.Identifier == uuid.Nil.String() && identifier.Type == pkgAuditCommon.ObjectTypeSystem {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func areIdentifiersIdentical(routableIdentifier *RoutableIdentifier, logName string) error {
|
func areIdentifiersIdentical(routableIdentifier *pkgAuditCommon.RoutableIdentifier, logName string) error {
|
||||||
dataType, identifier := getTypeAndIdentifierFromString(logName)
|
dataType, identifier := getTypeAndIdentifierFromString(logName)
|
||||||
objectType := ObjectTypeFromPluralString(dataType)
|
objectType := pkgAuditCommon.ObjectTypeFromPluralString(dataType)
|
||||||
err := objectType.IsSupportedType()
|
err := objectType.IsSupportedType()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -260,12 +215,12 @@ func areIdentifiersIdentical(routableIdentifier *RoutableIdentifier, logName str
|
||||||
return areTypeAndIdentifierIdentical(routableIdentifier, objectType, identifier)
|
return areTypeAndIdentifierIdentical(routableIdentifier, objectType, identifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
func areTypeAndIdentifierIdentical(routableIdentifier *RoutableIdentifier, dataType ObjectType, identifier string) error {
|
func areTypeAndIdentifierIdentical(routableIdentifier *pkgAuditCommon.RoutableIdentifier, dataType pkgAuditCommon.ObjectType, identifier string) error {
|
||||||
if routableIdentifier.Identifier != identifier {
|
if routableIdentifier.Identifier != identifier {
|
||||||
return ErrAttributeIdentifierInvalid
|
return pkgAuditCommon.ErrAttributeIdentifierInvalid
|
||||||
}
|
}
|
||||||
if routableIdentifier.Type != dataType {
|
if routableIdentifier.Type != dataType {
|
||||||
return ErrAttributeTypeInvalid
|
return pkgAuditCommon.ErrAttributeTypeInvalid
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
477
internal/audit/api/api_common_test.go
Normal file
477
internal/audit/api/api_common_test.go
Normal file
|
|
@ -0,0 +1,477 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"buf.build/go/protovalidate"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
|
pkgMessagingApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MessagingApiMock struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MessagingApiMock) Send(
|
||||||
|
ctx context.Context,
|
||||||
|
topic string,
|
||||||
|
data []byte,
|
||||||
|
contentType string,
|
||||||
|
applicationProperties map[string]any,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
args := m.Called(ctx, topic, data, contentType, applicationProperties)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MessagingApiMock) Close(_ context.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type TopicNameResolverMock struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *TopicNameResolverMock) Resolve(routableIdentifier *pkgAuditCommon.RoutableIdentifier) (string, error) {
|
||||||
|
args := m.Called(routableIdentifier)
|
||||||
|
return args.String(0), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewValidator(t *testing.T) pkgAuditCommon.ProtobufValidator {
|
||||||
|
validator, err := protovalidate.New()
|
||||||
|
var protoValidator pkgAuditCommon.ProtobufValidator = validator
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
return protoValidator
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_ValidateAndSerializePartially_EventNil(t *testing.T) {
|
||||||
|
validator := NewValidator(t)
|
||||||
|
|
||||||
|
_, err := ValidateAndSerializePartially(
|
||||||
|
validator, nil, auditV1.Visibility_VISIBILITY_PUBLIC, nil)
|
||||||
|
|
||||||
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrEventNil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_ValidateAndSerializePartially_AuditEventValidationFailed(t *testing.T) {
|
||||||
|
validator := NewValidator(t)
|
||||||
|
|
||||||
|
event, objectIdentifier := NewOrganizationAuditEvent(nil)
|
||||||
|
event.LogName = ""
|
||||||
|
|
||||||
|
_, err := ValidateAndSerializePartially(
|
||||||
|
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.NewRoutableIdentifier(objectIdentifier))
|
||||||
|
|
||||||
|
assert.EqualError(t, err, "validation error: log_name: value is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_ValidateAndSerializePartially_RoutableEventValidationFailed(t *testing.T) {
|
||||||
|
validator := NewValidator(t)
|
||||||
|
|
||||||
|
event, objectIdentifier := NewOrganizationAuditEvent(nil)
|
||||||
|
_, err := ValidateAndSerializePartially(validator, event, 3, pkgAuditCommon.NewRoutableIdentifier(objectIdentifier))
|
||||||
|
|
||||||
|
assert.EqualError(t, err, "validation error: visibility: value must be one of the defined enum values")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_ValidateAndSerializePartially_CheckVisibility_Event(t *testing.T) {
|
||||||
|
validator := NewValidator(t)
|
||||||
|
|
||||||
|
event, objectIdentifier := NewOrganizationAuditEvent(nil)
|
||||||
|
|
||||||
|
t.Run("Visibility public - object identifier nil", func(t *testing.T) {
|
||||||
|
_, err := ValidateAndSerializePartially(
|
||||||
|
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, nil)
|
||||||
|
|
||||||
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrObjectIdentifierNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Visibility private - object identifier nil", func(t *testing.T) {
|
||||||
|
_, err := ValidateAndSerializePartially(
|
||||||
|
validator, event, auditV1.Visibility_VISIBILITY_PRIVATE, nil)
|
||||||
|
|
||||||
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrObjectIdentifierNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Visibility public - object identifier system", func(t *testing.T) {
|
||||||
|
_, err := ValidateAndSerializePartially(
|
||||||
|
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.RoutableSystemIdentifier)
|
||||||
|
|
||||||
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrObjectIdentifierVisibilityMismatch)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Visibility public - object identifier set", func(t *testing.T) {
|
||||||
|
routableEvent, err := ValidateAndSerializePartially(
|
||||||
|
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.NewRoutableIdentifier(objectIdentifier))
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, routableEvent)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Visibility private - object identifier system", func(t *testing.T) {
|
||||||
|
_, err := ValidateAndSerializePartially(
|
||||||
|
validator, event, auditV1.Visibility_VISIBILITY_PRIVATE, pkgAuditCommon.RoutableSystemIdentifier)
|
||||||
|
|
||||||
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrAttributeIdentifierInvalid)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Visibility private - object identifier set", func(t *testing.T) {
|
||||||
|
routableEvent, err := ValidateAndSerializePartially(
|
||||||
|
validator, event, auditV1.Visibility_VISIBILITY_PRIVATE, pkgAuditCommon.NewRoutableIdentifier(objectIdentifier))
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, routableEvent)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_ValidateAndSerializePartially_CheckVisibility_SystemEvent(t *testing.T) {
|
||||||
|
validator := NewValidator(t)
|
||||||
|
|
||||||
|
event := NewSystemAuditEvent(nil)
|
||||||
|
|
||||||
|
t.Run("Visibility public - object identifier nil", func(t *testing.T) {
|
||||||
|
_, err := ValidateAndSerializePartially(
|
||||||
|
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, nil)
|
||||||
|
|
||||||
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrObjectIdentifierNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Visibility private - object identifier nil", func(t *testing.T) {
|
||||||
|
_, err := ValidateAndSerializePartially(
|
||||||
|
validator, event, auditV1.Visibility_VISIBILITY_PRIVATE, nil)
|
||||||
|
|
||||||
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrObjectIdentifierNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Visibility public - object identifier system", func(t *testing.T) {
|
||||||
|
_, err := ValidateAndSerializePartially(
|
||||||
|
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.RoutableSystemIdentifier)
|
||||||
|
|
||||||
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrObjectIdentifierVisibilityMismatch)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Visibility public - object identifier set", func(t *testing.T) {
|
||||||
|
_, err := ValidateAndSerializePartially(
|
||||||
|
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.NewRoutableIdentifier(
|
||||||
|
&auditV1.ObjectIdentifier{Identifier: uuid.NewString(), Type: string(pkgAuditCommon.ObjectTypeOrganization)}))
|
||||||
|
|
||||||
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrInvalidRoutableIdentifierForSystemEvent)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Visibility private - object identifier system", func(t *testing.T) {
|
||||||
|
routableEvent, err := ValidateAndSerializePartially(
|
||||||
|
validator, event, auditV1.Visibility_VISIBILITY_PRIVATE, pkgAuditCommon.RoutableSystemIdentifier)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, routableEvent)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Visibility private - object identifier set", func(t *testing.T) {
|
||||||
|
_, err := ValidateAndSerializePartially(
|
||||||
|
validator, event, auditV1.Visibility_VISIBILITY_PRIVATE, pkgAuditCommon.NewRoutableIdentifier(
|
||||||
|
&auditV1.ObjectIdentifier{Identifier: uuid.NewString(), Type: string(pkgAuditCommon.ObjectTypeOrganization)}))
|
||||||
|
|
||||||
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrInvalidRoutableIdentifierForSystemEvent)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_ValidateAndSerializePartially_UnsupportedIdentifierType(t *testing.T) {
|
||||||
|
validator := NewValidator(t)
|
||||||
|
|
||||||
|
event, objectIdentifier := NewFolderAuditEvent(nil)
|
||||||
|
objectIdentifier.Type = "invalid"
|
||||||
|
|
||||||
|
_, err := ValidateAndSerializePartially(
|
||||||
|
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.NewRoutableIdentifier(objectIdentifier))
|
||||||
|
|
||||||
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrUnsupportedRoutableType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_ValidateAndSerializePartially_LogNameIdentifierMismatch(t *testing.T) {
|
||||||
|
validator := NewValidator(t)
|
||||||
|
|
||||||
|
event, objectIdentifier := NewFolderAuditEvent(nil)
|
||||||
|
parts := strings.Split(event.LogName, "/")
|
||||||
|
identifier := parts[1]
|
||||||
|
|
||||||
|
t.Run("LogName type mismatch", func(t *testing.T) {
|
||||||
|
event.LogName = fmt.Sprintf("projects/%s/logs/admin-activity", identifier)
|
||||||
|
_, err := ValidateAndSerializePartially(
|
||||||
|
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.NewRoutableIdentifier(objectIdentifier))
|
||||||
|
|
||||||
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrAttributeTypeInvalid)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("LogName identifier mismatch", func(t *testing.T) {
|
||||||
|
event.LogName = fmt.Sprintf("folders/%s/logs/admin-activity", uuid.NewString())
|
||||||
|
_, err := ValidateAndSerializePartially(
|
||||||
|
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.NewRoutableIdentifier(objectIdentifier))
|
||||||
|
|
||||||
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrAttributeIdentifierInvalid)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_ValidateAndSerializePartially_ResourceNameIdentifierMismatch(t *testing.T) {
|
||||||
|
validator := NewValidator(t)
|
||||||
|
|
||||||
|
event, objectIdentifier := NewFolderAuditEvent(nil)
|
||||||
|
parts := strings.Split(event.ProtoPayload.ResourceName, "/")
|
||||||
|
identifier := parts[1]
|
||||||
|
|
||||||
|
t.Run("ResourceName type mismatch", func(t *testing.T) {
|
||||||
|
event.ProtoPayload.ResourceName = fmt.Sprintf("projects/%s", identifier)
|
||||||
|
_, err := ValidateAndSerializePartially(
|
||||||
|
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.NewRoutableIdentifier(objectIdentifier))
|
||||||
|
|
||||||
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrAttributeTypeInvalid)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ResourceName identifier mismatch", func(t *testing.T) {
|
||||||
|
event.ProtoPayload.ResourceName = fmt.Sprintf("folders/%s", uuid.NewString())
|
||||||
|
_, err := ValidateAndSerializePartially(
|
||||||
|
validator, event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.NewRoutableIdentifier(objectIdentifier))
|
||||||
|
|
||||||
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrAttributeIdentifierInvalid)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_ValidateAndSerializePartially_SystemEvent(t *testing.T) {
|
||||||
|
validator := NewValidator(t)
|
||||||
|
|
||||||
|
event := NewSystemAuditEvent(nil)
|
||||||
|
|
||||||
|
routableEvent, err := ValidateAndSerializePartially(
|
||||||
|
validator, event, auditV1.Visibility_VISIBILITY_PRIVATE, pkgAuditCommon.RoutableSystemIdentifier)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, event.LogName, fmt.Sprintf("system/%s/logs/%s", pkgAuditCommon.SystemIdentifier.Identifier, pkgAuditCommon.EventTypeSystemEvent))
|
||||||
|
assert.True(t, proto.Equal(routableEvent.ObjectIdentifier, pkgAuditCommon.SystemIdentifier))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Send_TopicNameResolverNil(t *testing.T) {
|
||||||
|
err := Send(nil, nil, context.Background(), nil, nil)
|
||||||
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrTopicNameResolverNil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Send_TopicNameResolutionError(t *testing.T) {
|
||||||
|
expectedError := errors.New("expected error")
|
||||||
|
|
||||||
|
topicNameResolverMock := TopicNameResolverMock{}
|
||||||
|
topicNameResolverMock.On("Resolve", mock.Anything).Return("topic", expectedError)
|
||||||
|
var topicNameResolver pkgAuditCommon.TopicNameResolver = &topicNameResolverMock
|
||||||
|
|
||||||
|
var cloudEvent = pkgAuditCommon.CloudEvent{}
|
||||||
|
|
||||||
|
var messagingApi pkgMessagingApi.Api = &pkgMessagingApi.AmqpApi{}
|
||||||
|
err := Send(topicNameResolver, messagingApi, context.Background(), pkgAuditCommon.RoutableSystemIdentifier, &cloudEvent)
|
||||||
|
assert.ErrorIs(t, err, expectedError)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Send_MessagingApiNil(t *testing.T) {
|
||||||
|
var topicNameResolver pkgAuditCommon.TopicNameResolver = &pkgAuditCommon.StaticTopicNameTestResolver{TopicName: "test"}
|
||||||
|
err := Send(topicNameResolver, nil, context.Background(), nil, nil)
|
||||||
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrMessagingApiNil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Send_CloudEventNil(t *testing.T) {
|
||||||
|
var topicNameResolver pkgAuditCommon.TopicNameResolver = &pkgAuditCommon.StaticTopicNameTestResolver{TopicName: "test"}
|
||||||
|
var messagingApi pkgMessagingApi.Api = &pkgMessagingApi.AmqpApi{}
|
||||||
|
|
||||||
|
err := Send(topicNameResolver, messagingApi, context.Background(), nil, nil)
|
||||||
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrCloudEventNil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Send_ObjectIdentifierNil(t *testing.T) {
|
||||||
|
var topicNameResolver pkgAuditCommon.TopicNameResolver = &pkgAuditCommon.StaticTopicNameTestResolver{TopicName: "test"}
|
||||||
|
var messagingApi pkgMessagingApi.Api = &pkgMessagingApi.AmqpApi{}
|
||||||
|
var cloudEvent = pkgAuditCommon.CloudEvent{}
|
||||||
|
|
||||||
|
err := Send(topicNameResolver, messagingApi, context.Background(), nil, &cloudEvent)
|
||||||
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrObjectIdentifierNil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Send_UnsupportedObjectIdentifierType(t *testing.T) {
|
||||||
|
var topicNameResolver pkgAuditCommon.TopicNameResolver = &pkgAuditCommon.StaticTopicNameTestResolver{TopicName: "test"}
|
||||||
|
var messagingApi pkgMessagingApi.Api = &pkgMessagingApi.AmqpApi{}
|
||||||
|
var cloudEvent = pkgAuditCommon.CloudEvent{}
|
||||||
|
var objectIdentifier = auditV1.ObjectIdentifier{Identifier: uuid.NewString(), Type: "unsupported"}
|
||||||
|
|
||||||
|
err := Send(topicNameResolver, messagingApi, context.Background(), pkgAuditCommon.NewRoutableIdentifier(&objectIdentifier), &cloudEvent)
|
||||||
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrUnsupportedRoutableType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Send(t *testing.T) {
|
||||||
|
topicNameResolverMock := TopicNameResolverMock{}
|
||||||
|
topicNameResolverMock.On("Resolve", mock.Anything).Return("topic", nil)
|
||||||
|
var topicNameResolver pkgAuditCommon.TopicNameResolver = &topicNameResolverMock
|
||||||
|
|
||||||
|
messagingApiMock := MessagingApiMock{}
|
||||||
|
messagingApiMock.On("Send", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
||||||
|
var messagingApi pkgMessagingApi.Api = &messagingApiMock
|
||||||
|
|
||||||
|
var cloudEvent = pkgAuditCommon.CloudEvent{}
|
||||||
|
assert.NoError(t, Send(topicNameResolver, messagingApi, context.Background(), pkgAuditCommon.RoutableSystemIdentifier, &cloudEvent))
|
||||||
|
assert.True(t, messagingApiMock.AssertNumberOfCalls(t, "Send", 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_SendAllHeadersSet(t *testing.T) {
|
||||||
|
topicNameResolverMock := TopicNameResolverMock{}
|
||||||
|
topicNameResolverMock.On("Resolve", mock.Anything).Return("topic", nil)
|
||||||
|
var topicNameResolver pkgAuditCommon.TopicNameResolver = &topicNameResolverMock
|
||||||
|
|
||||||
|
messagingApiMock := MessagingApiMock{}
|
||||||
|
messagingApiMock.On("Send", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
||||||
|
var messagingApi pkgMessagingApi.Api = &messagingApiMock
|
||||||
|
|
||||||
|
traceState := "rojo=00f067aa0ba902b7,congo=t61rcWkgMzE"
|
||||||
|
traceParent := "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
|
||||||
|
expectedTime := time.Now()
|
||||||
|
var cloudEvent = pkgAuditCommon.CloudEvent{
|
||||||
|
SpecVersion: "1.0",
|
||||||
|
Source: "resourcemanager",
|
||||||
|
Id: "id",
|
||||||
|
Time: expectedTime,
|
||||||
|
DataContentType: pkgAuditCommon.ContentTypeCloudEventsProtobuf,
|
||||||
|
DataType: "type",
|
||||||
|
Subject: "subject",
|
||||||
|
TraceParent: &traceParent,
|
||||||
|
TraceState: &traceState,
|
||||||
|
}
|
||||||
|
assert.NoError(t, Send(topicNameResolver, messagingApi, context.Background(), pkgAuditCommon.RoutableSystemIdentifier, &cloudEvent))
|
||||||
|
assert.True(t, messagingApiMock.AssertNumberOfCalls(t, "Send", 1))
|
||||||
|
|
||||||
|
arguments := messagingApiMock.Calls[0].Arguments
|
||||||
|
topic := arguments.Get(1).(string)
|
||||||
|
assert.Equal(t, "topic", topic)
|
||||||
|
|
||||||
|
contentType := arguments.Get(3).(string)
|
||||||
|
assert.Equal(t, pkgAuditCommon.ContentTypeCloudEventsProtobuf, contentType)
|
||||||
|
|
||||||
|
applicationProperties := arguments.Get(4).(map[string]any)
|
||||||
|
assert.Equal(t, "1.0", applicationProperties["cloudEvents:specversion"])
|
||||||
|
assert.Equal(t, "resourcemanager", applicationProperties["cloudEvents:source"])
|
||||||
|
assert.Equal(t, "id", applicationProperties["cloudEvents:id"])
|
||||||
|
assert.Equal(t, expectedTime.UnixMilli(), applicationProperties["cloudEvents:time"])
|
||||||
|
assert.Equal(t, pkgAuditCommon.ContentTypeCloudEventsProtobuf, applicationProperties["cloudEvents:datacontenttype"])
|
||||||
|
assert.Equal(t, "type", applicationProperties["cloudEvents:type"])
|
||||||
|
assert.Equal(t, "subject", applicationProperties["cloudEvents:subject"])
|
||||||
|
assert.Equal(t, traceParent, applicationProperties["cloudEvents:traceparent"])
|
||||||
|
assert.Equal(t, traceState, applicationProperties["cloudEvents:tracestate"])
|
||||||
|
messagingApiMock.AssertExpectations(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_SendWithoutOptionalHeadersSet(t *testing.T) {
|
||||||
|
topicNameResolverMock := TopicNameResolverMock{}
|
||||||
|
topicNameResolverMock.On("Resolve", mock.Anything).Return("topic", nil)
|
||||||
|
var topicNameResolver pkgAuditCommon.TopicNameResolver = &topicNameResolverMock
|
||||||
|
|
||||||
|
messagingApiMock := MessagingApiMock{}
|
||||||
|
messagingApiMock.On("Send", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
||||||
|
var messagingApi pkgMessagingApi.Api = &messagingApiMock
|
||||||
|
|
||||||
|
expectedTime := time.Now()
|
||||||
|
var cloudEvent = pkgAuditCommon.CloudEvent{
|
||||||
|
SpecVersion: "1.0",
|
||||||
|
Source: "resourcemanager",
|
||||||
|
Id: "id",
|
||||||
|
Time: expectedTime,
|
||||||
|
DataContentType: pkgAuditCommon.ContentTypeCloudEventsProtobuf,
|
||||||
|
DataType: "type",
|
||||||
|
Subject: "subject",
|
||||||
|
}
|
||||||
|
assert.NoError(t, Send(topicNameResolver, messagingApi, context.Background(), pkgAuditCommon.RoutableSystemIdentifier, &cloudEvent))
|
||||||
|
assert.True(t, messagingApiMock.AssertNumberOfCalls(t, "Send", 1))
|
||||||
|
|
||||||
|
arguments := messagingApiMock.Calls[0].Arguments
|
||||||
|
topic := arguments.Get(1).(string)
|
||||||
|
assert.Equal(t, "topic", topic)
|
||||||
|
|
||||||
|
contentType := arguments.Get(3).(string)
|
||||||
|
assert.Equal(t, pkgAuditCommon.ContentTypeCloudEventsProtobuf, contentType)
|
||||||
|
|
||||||
|
applicationProperties := arguments.Get(4).(map[string]any)
|
||||||
|
assert.Equal(t, "1.0", applicationProperties["cloudEvents:specversion"])
|
||||||
|
assert.Equal(t, "resourcemanager", applicationProperties["cloudEvents:source"])
|
||||||
|
assert.Equal(t, "id", applicationProperties["cloudEvents:id"])
|
||||||
|
assert.Equal(t, expectedTime.UnixMilli(), applicationProperties["cloudEvents:time"])
|
||||||
|
assert.Equal(t, pkgAuditCommon.ContentTypeCloudEventsProtobuf, applicationProperties["cloudEvents:datacontenttype"])
|
||||||
|
assert.Equal(t, "type", applicationProperties["cloudEvents:type"])
|
||||||
|
assert.Equal(t, "subject", applicationProperties["cloudEvents:subject"])
|
||||||
|
assert.Equal(t, nil, applicationProperties["cloudEvents:traceparent"])
|
||||||
|
assert.Equal(t, nil, applicationProperties["cloudEvents:tracestate"])
|
||||||
|
messagingApiMock.AssertExpectations(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_ValidateTopicNames(t *testing.T) {
|
||||||
|
t.Run("conway", func(t *testing.T) {
|
||||||
|
topicName := "topic://stackit-platform/t/swz/audit-log/conway/v1.0/service-name/events"
|
||||||
|
assert.True(t, TopicNamePattern.MatchString(topicName))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("eu01", func(t *testing.T) {
|
||||||
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1.0/service-name/events"
|
||||||
|
assert.True(t, TopicNamePattern.MatchString(topicName))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("eu02", func(t *testing.T) {
|
||||||
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu02/v1.0/service-name/events"
|
||||||
|
assert.True(t, TopicNamePattern.MatchString(topicName))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("sx-stoi01", func(t *testing.T) {
|
||||||
|
topicName := "topic://stackit-platform/t/swz/audit-log/sx-stoi01/v1.0/service-name/events"
|
||||||
|
assert.True(t, TopicNamePattern.MatchString(topicName))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("version without decimals", func(t *testing.T) {
|
||||||
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/service-name/events"
|
||||||
|
assert.True(t, TopicNamePattern.MatchString(topicName))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("version as uppercase", func(t *testing.T) {
|
||||||
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/V1.0/service-name/events"
|
||||||
|
assert.True(t, TopicNamePattern.MatchString(topicName))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("service name without dash", func(t *testing.T) {
|
||||||
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1.0/service/events"
|
||||||
|
assert.True(t, TopicNamePattern.MatchString(topicName))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("multiple additional parts", func(t *testing.T) {
|
||||||
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1.0/service-name/multiple/additional/parts"
|
||||||
|
assert.True(t, TopicNamePattern.MatchString(topicName))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("additional parts with dash", func(t *testing.T) {
|
||||||
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1.0/service-name/multiple-additional/parts"
|
||||||
|
assert.True(t, TopicNamePattern.MatchString(topicName))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("topic prefix missing", func(t *testing.T) {
|
||||||
|
topicName := "stackit-platform/t/swz/audit-log/eu01/v1.0/service-name/events"
|
||||||
|
assert.False(t, TopicNamePattern.MatchString(topicName))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid region", func(t *testing.T) {
|
||||||
|
topicName := "topic://stackit-platform/t/swz/audit-log/invalid/v1.0/service-name/events"
|
||||||
|
assert.False(t, TopicNamePattern.MatchString(topicName))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("additional parts missing", func(t *testing.T) {
|
||||||
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1.0/service-name"
|
||||||
|
assert.False(t, TopicNamePattern.MatchString(topicName))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -8,29 +8,32 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
|
||||||
"google.golang.org/protobuf/encoding/protojson"
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
|
|
||||||
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrUnsupportedSeverity = errors.New("unsupported severity level")
|
var ErrUnsupportedSeverity = errors.New("unsupported severity level")
|
||||||
|
|
||||||
// convertAndSerializeIntoLegacyFormat converts the protobuf events into the json serialized legacy audit log format
|
// ConvertAndSerializeIntoLegacyFormat converts the protobuf events into the json serialized legacy audit log format
|
||||||
func convertAndSerializeIntoLegacyFormat(
|
func ConvertAndSerializeIntoLegacyFormat(
|
||||||
event *auditV1.AuditLogEntry,
|
event *auditV1.AuditLogEntry,
|
||||||
routableEvent *auditV1.RoutableAuditEvent,
|
routableEvent *auditV1.RoutableAuditEvent,
|
||||||
) ([]byte, error) {
|
) ([]byte, error) {
|
||||||
|
|
||||||
// Event type
|
// Event type
|
||||||
var eventType string
|
var eventType string
|
||||||
if strings.HasSuffix(event.LogName, string(EventTypeAdminActivity)) {
|
switch {
|
||||||
|
case strings.HasSuffix(event.LogName, string(pkgAuditCommon.EventTypeAdminActivity)):
|
||||||
eventType = "ADMIN_ACTIVITY"
|
eventType = "ADMIN_ACTIVITY"
|
||||||
} else if strings.HasSuffix(event.LogName, string(EventTypeSystemEvent)) {
|
case strings.HasSuffix(event.LogName, string(pkgAuditCommon.EventTypeSystemEvent)):
|
||||||
eventType = "SYSTEM_EVENT"
|
eventType = "SYSTEM_EVENT"
|
||||||
} else if strings.HasSuffix(event.LogName, string(EventTypePolicyDenied)) {
|
case strings.HasSuffix(event.LogName, string(pkgAuditCommon.EventTypePolicyDenied)):
|
||||||
eventType = "POLICY_DENIED"
|
eventType = "POLICY_DENIED"
|
||||||
} else if strings.HasSuffix(event.LogName, string(EventTypeDataAccess)) {
|
case strings.HasSuffix(event.LogName, string(pkgAuditCommon.EventTypeDataAccess)):
|
||||||
return nil, ErrUnsupportedEventTypeDataAccess
|
return nil, pkgAuditCommon.ErrUnsupportedEventTypeDataAccess
|
||||||
} else {
|
default:
|
||||||
return nil, errors.New("unsupported event type")
|
return nil, errors.New("unsupported event type")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -46,7 +49,7 @@ func convertAndSerializeIntoLegacyFormat(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Principals
|
// Principals
|
||||||
var serviceAccountDelegationInfo *LegacyAuditEventServiceAccountDelegationInfo = nil
|
var serviceAccountDelegationInfo *LegacyAuditEventServiceAccountDelegationInfo
|
||||||
if len(event.ProtoPayload.AuthenticationInfo.ServiceAccountDelegationInfo) > 0 {
|
if len(event.ProtoPayload.AuthenticationInfo.ServiceAccountDelegationInfo) > 0 {
|
||||||
var principals []LegacyAuditEventPrincipal
|
var principals []LegacyAuditEventPrincipal
|
||||||
for _, principal := range event.ProtoPayload.AuthenticationInfo.ServiceAccountDelegationInfo {
|
for _, principal := range event.ProtoPayload.AuthenticationInfo.ServiceAccountDelegationInfo {
|
||||||
|
|
@ -73,7 +76,7 @@ func convertAndSerializeIntoLegacyFormat(
|
||||||
Endpoint: "none",
|
Endpoint: "none",
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var parameters map[string]interface{} = nil
|
var parameters map[string]interface{}
|
||||||
if event.ProtoPayload.RequestMetadata.RequestAttributes.Path != "" &&
|
if event.ProtoPayload.RequestMetadata.RequestAttributes.Path != "" &&
|
||||||
event.ProtoPayload.RequestMetadata.RequestAttributes.Query != nil &&
|
event.ProtoPayload.RequestMetadata.RequestAttributes.Query != nil &&
|
||||||
*event.ProtoPayload.RequestMetadata.RequestAttributes.Query != "" {
|
*event.ProtoPayload.RequestMetadata.RequestAttributes.Query != "" {
|
||||||
|
|
@ -95,11 +98,11 @@ func convertAndSerializeIntoLegacyFormat(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var body map[string]interface{} = nil
|
var body map[string]interface{}
|
||||||
if event.ProtoPayload.Request != nil {
|
if event.ProtoPayload.Request != nil {
|
||||||
body = event.ProtoPayload.Request.AsMap()
|
body = event.ProtoPayload.Request.AsMap()
|
||||||
}
|
}
|
||||||
var headers map[string]interface{} = nil
|
var headers map[string]interface{}
|
||||||
if event.ProtoPayload.RequestMetadata.RequestAttributes.Headers != nil {
|
if event.ProtoPayload.RequestMetadata.RequestAttributes.Headers != nil {
|
||||||
headers = map[string]interface{}{}
|
headers = map[string]interface{}{}
|
||||||
for key, value := range event.ProtoPayload.RequestMetadata.RequestAttributes.Headers {
|
for key, value := range event.ProtoPayload.RequestMetadata.RequestAttributes.Headers {
|
||||||
|
|
@ -116,34 +119,34 @@ func convertAndSerializeIntoLegacyFormat(
|
||||||
}
|
}
|
||||||
|
|
||||||
if routableEvent.ObjectIdentifier == nil {
|
if routableEvent.ObjectIdentifier == nil {
|
||||||
return nil, ErrObjectIdentifierNil
|
return nil, pkgAuditCommon.ErrObjectIdentifierNil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context and event type
|
// Context and event type
|
||||||
var messageContext *LegacyAuditEventContext
|
var messageContext *LegacyAuditEventContext
|
||||||
switch routableEvent.ObjectIdentifier.Type {
|
switch routableEvent.ObjectIdentifier.Type {
|
||||||
case string(ObjectTypeProject):
|
case string(pkgAuditCommon.ObjectTypeProject):
|
||||||
messageContext = &LegacyAuditEventContext{
|
messageContext = &LegacyAuditEventContext{
|
||||||
OrganizationId: nil,
|
OrganizationId: nil,
|
||||||
FolderId: nil,
|
FolderId: nil,
|
||||||
ProjectId: &routableEvent.ObjectIdentifier.Identifier,
|
ProjectId: &routableEvent.ObjectIdentifier.Identifier,
|
||||||
}
|
}
|
||||||
case string(ObjectTypeFolder):
|
case string(pkgAuditCommon.ObjectTypeFolder):
|
||||||
messageContext = &LegacyAuditEventContext{
|
messageContext = &LegacyAuditEventContext{
|
||||||
OrganizationId: nil,
|
OrganizationId: nil,
|
||||||
FolderId: &routableEvent.ObjectIdentifier.Identifier,
|
FolderId: &routableEvent.ObjectIdentifier.Identifier,
|
||||||
ProjectId: nil,
|
ProjectId: nil,
|
||||||
}
|
}
|
||||||
case string(ObjectTypeOrganization):
|
case string(pkgAuditCommon.ObjectTypeOrganization):
|
||||||
messageContext = &LegacyAuditEventContext{
|
messageContext = &LegacyAuditEventContext{
|
||||||
OrganizationId: &routableEvent.ObjectIdentifier.Identifier,
|
OrganizationId: &routableEvent.ObjectIdentifier.Identifier,
|
||||||
FolderId: nil,
|
FolderId: nil,
|
||||||
ProjectId: nil,
|
ProjectId: nil,
|
||||||
}
|
}
|
||||||
case string(ObjectTypeSystem):
|
case string(pkgAuditCommon.ObjectTypeSystem):
|
||||||
messageContext = nil
|
messageContext = nil
|
||||||
default:
|
default:
|
||||||
return nil, ErrUnsupportedObjectIdentifierType
|
return nil, pkgAuditCommon.ErrUnsupportedObjectIdentifierType
|
||||||
}
|
}
|
||||||
|
|
||||||
var visibility string
|
var visibility string
|
||||||
|
|
@ -152,6 +155,8 @@ func convertAndSerializeIntoLegacyFormat(
|
||||||
visibility = "PUBLIC"
|
visibility = "PUBLIC"
|
||||||
case auditV1.Visibility_VISIBILITY_PRIVATE:
|
case auditV1.Visibility_VISIBILITY_PRIVATE:
|
||||||
visibility = "PRIVATE"
|
visibility = "PRIVATE"
|
||||||
|
case auditV1.Visibility_VISIBILITY_UNSPECIFIED:
|
||||||
|
visibility = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Details
|
// Details
|
||||||
|
|
@ -171,23 +176,16 @@ func convertAndSerializeIntoLegacyFormat(
|
||||||
// Severity
|
// Severity
|
||||||
var severity string
|
var severity string
|
||||||
switch event.Severity {
|
switch event.Severity {
|
||||||
case auditV1.LogSeverity_LOG_SEVERITY_DEFAULT:
|
case auditV1.LogSeverity_LOG_SEVERITY_DEFAULT,
|
||||||
fallthrough
|
auditV1.LogSeverity_LOG_SEVERITY_DEBUG,
|
||||||
case auditV1.LogSeverity_LOG_SEVERITY_DEBUG:
|
auditV1.LogSeverity_LOG_SEVERITY_INFO,
|
||||||
fallthrough
|
auditV1.LogSeverity_LOG_SEVERITY_NOTICE,
|
||||||
case auditV1.LogSeverity_LOG_SEVERITY_INFO:
|
auditV1.LogSeverity_LOG_SEVERITY_WARNING:
|
||||||
fallthrough
|
|
||||||
case auditV1.LogSeverity_LOG_SEVERITY_NOTICE:
|
|
||||||
fallthrough
|
|
||||||
case auditV1.LogSeverity_LOG_SEVERITY_WARNING:
|
|
||||||
severity = "INFO"
|
severity = "INFO"
|
||||||
case auditV1.LogSeverity_LOG_SEVERITY_ERROR:
|
case auditV1.LogSeverity_LOG_SEVERITY_ERROR,
|
||||||
fallthrough
|
auditV1.LogSeverity_LOG_SEVERITY_CRITICAL,
|
||||||
case auditV1.LogSeverity_LOG_SEVERITY_CRITICAL:
|
auditV1.LogSeverity_LOG_SEVERITY_ALERT,
|
||||||
fallthrough
|
auditV1.LogSeverity_LOG_SEVERITY_EMERGENCY:
|
||||||
case auditV1.LogSeverity_LOG_SEVERITY_ALERT:
|
|
||||||
fallthrough
|
|
||||||
case auditV1.LogSeverity_LOG_SEVERITY_EMERGENCY:
|
|
||||||
severity = "ERROR"
|
severity = "ERROR"
|
||||||
default:
|
default:
|
||||||
return nil, ErrUnsupportedSeverity
|
return nil, ErrUnsupportedSeverity
|
||||||
|
|
@ -204,7 +202,7 @@ func convertAndSerializeIntoLegacyFormat(
|
||||||
UserAgent: userAgent,
|
UserAgent: userAgent,
|
||||||
Initiator: LegacyAuditEventPrincipal{
|
Initiator: LegacyAuditEventPrincipal{
|
||||||
Id: event.ProtoPayload.AuthenticationInfo.PrincipalId,
|
Id: event.ProtoPayload.AuthenticationInfo.PrincipalId,
|
||||||
Email: &event.ProtoPayload.AuthenticationInfo.PrincipalEmail,
|
Email: event.ProtoPayload.AuthenticationInfo.PrincipalEmail,
|
||||||
},
|
},
|
||||||
ServiceAccountDelegationInfo: serviceAccountDelegationInfo,
|
ServiceAccountDelegationInfo: serviceAccountDelegationInfo,
|
||||||
Request: request,
|
Request: request,
|
||||||
|
|
@ -3,12 +3,14 @@ package api
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_ConvertAndSerializeIntoLegacyFormat_NoObjectIdentifier(t *testing.T) {
|
func Test_ConvertAndSerializeIntoLegacyFormat_NoObjectIdentifier(t *testing.T) {
|
||||||
event, _ := newProjectAuditEvent(nil)
|
event, _ := NewProjectAuditEvent(nil)
|
||||||
routableEvent := auditV1.RoutableAuditEvent{
|
routableEvent := auditV1.RoutableAuditEvent{
|
||||||
OperationName: event.ProtoPayload.OperationName,
|
OperationName: event.ProtoPayload.OperationName,
|
||||||
Visibility: auditV1.Visibility_VISIBILITY_PUBLIC,
|
Visibility: auditV1.Visibility_VISIBILITY_PUBLIC,
|
||||||
|
|
@ -16,6 +18,6 @@ func Test_ConvertAndSerializeIntoLegacyFormat_NoObjectIdentifier(t *testing.T) {
|
||||||
Data: nil,
|
Data: nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := convertAndSerializeIntoLegacyFormat(event, &routableEvent)
|
_, err := ConvertAndSerializeIntoLegacyFormat(event, &routableEvent)
|
||||||
assert.ErrorIs(t, err, ErrObjectIdentifierNil)
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrObjectIdentifierNil)
|
||||||
}
|
}
|
||||||
|
|
@ -2,23 +2,21 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/lestrrat-go/jwx/v2/jwt"
|
|
||||||
"google.golang.org/protobuf/encoding/protojson"
|
|
||||||
"google.golang.org/protobuf/proto"
|
|
||||||
"google.golang.org/protobuf/types/known/structpb"
|
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
|
||||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
|
||||||
"net"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/lestrrat-go/jwx/v2/jwt"
|
||||||
|
"google.golang.org/protobuf/types/known/structpb"
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||||
|
|
||||||
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
const EmailAddressDoNotReplyAtStackItDotCloud = "do-not-reply@stackit.cloud"
|
const EmailAddressDoNotReplyAtStackItDotCloud = "do-not-reply@stackit.cloud"
|
||||||
|
|
@ -31,66 +29,6 @@ var ErrInvalidAuthorizationHeaderValue = errors.New("invalid authorization heade
|
||||||
var ErrInvalidBearerToken = errors.New("invalid bearer token")
|
var ErrInvalidBearerToken = errors.New("invalid bearer token")
|
||||||
var ErrTokenIsNotBearerToken = errors.New("token is not a bearer token")
|
var ErrTokenIsNotBearerToken = errors.New("token is not a bearer token")
|
||||||
|
|
||||||
var objectTypeIdPattern, _ = regexp.Compile(".*/(projects|folders|organizations)/([0-9a-fA-F-]{36})(?:/.*)?")
|
|
||||||
|
|
||||||
type ApiRequest struct {
|
|
||||||
|
|
||||||
// Body
|
|
||||||
//
|
|
||||||
// Required: false
|
|
||||||
Body *[]byte
|
|
||||||
|
|
||||||
// The (HTTP) request headers / gRPC metadata.
|
|
||||||
//
|
|
||||||
// Internal IP-Addresses have to be removed (e.g. in x-forwarded-xxx headers).
|
|
||||||
//
|
|
||||||
// Required: true
|
|
||||||
Header map[string][]string
|
|
||||||
|
|
||||||
// The HTTP request `Host` header value.
|
|
||||||
//
|
|
||||||
// Required: true
|
|
||||||
Host string
|
|
||||||
|
|
||||||
// Method
|
|
||||||
//
|
|
||||||
// Required: true
|
|
||||||
Method string
|
|
||||||
|
|
||||||
// The URL scheme, such as `http`, `https` or `gRPC`.
|
|
||||||
//
|
|
||||||
// Required: true
|
|
||||||
Scheme string
|
|
||||||
|
|
||||||
// The network protocol used with the request, such as "http/1.1",
|
|
||||||
// "spdy/3", "h2", "h2c", "webrtc", "tcp", "udp", "quic". See
|
|
||||||
// https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
|
|
||||||
// for details.
|
|
||||||
//
|
|
||||||
// Required: true
|
|
||||||
Proto string
|
|
||||||
|
|
||||||
// The url
|
|
||||||
//
|
|
||||||
// Required: true
|
|
||||||
URL RequestUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
type RequestUrl struct {
|
|
||||||
|
|
||||||
// The gRPC / HTTP URL path.
|
|
||||||
//
|
|
||||||
// Required: true
|
|
||||||
Path string
|
|
||||||
|
|
||||||
// The HTTP URL query in the format of "name1=value1&name2=value2", as it
|
|
||||||
// appears in the first line of the HTTP request.
|
|
||||||
// The input should be escaped to not contain any special characters.
|
|
||||||
//
|
|
||||||
// Required: false
|
|
||||||
RawQuery *string
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuditRequest bundles request related parameters
|
// AuditRequest bundles request related parameters
|
||||||
type AuditRequest struct {
|
type AuditRequest struct {
|
||||||
|
|
||||||
|
|
@ -100,7 +38,7 @@ type AuditRequest struct {
|
||||||
// It should never include user-generated data, such as file contents.
|
// It should never include user-generated data, such as file contents.
|
||||||
//
|
//
|
||||||
// Required: true
|
// Required: true
|
||||||
Request *ApiRequest
|
Request *pkgAuditCommon.ApiRequest
|
||||||
|
|
||||||
// The IP address of the caller.
|
// The IP address of the caller.
|
||||||
// For caller from internet, this will be public IPv4 or IPv6 address.
|
// For caller from internet, this will be public IPv4 or IPv6 address.
|
||||||
|
|
@ -145,7 +83,7 @@ type AuditResponse struct {
|
||||||
// elsewhere in the log record.
|
// elsewhere in the log record.
|
||||||
//
|
//
|
||||||
// Required: false
|
// Required: false
|
||||||
ResponseBodyBytes *[]byte
|
ResponseBodyBytes []byte
|
||||||
|
|
||||||
// The http or gRPC status code.
|
// The http or gRPC status code.
|
||||||
//
|
//
|
||||||
|
|
@ -294,7 +232,7 @@ func NewAuditLogEntry(
|
||||||
auditResponse AuditResponse,
|
auditResponse AuditResponse,
|
||||||
|
|
||||||
// Optional map that is added as "details" to the message
|
// Optional map that is added as "details" to the message
|
||||||
eventMetadata *map[string]interface{},
|
eventMetadata map[string]interface{},
|
||||||
|
|
||||||
// Required metadata
|
// Required metadata
|
||||||
auditMetadata AuditMetadata,
|
auditMetadata AuditMetadata,
|
||||||
|
|
@ -309,9 +247,9 @@ func NewAuditLogEntry(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Join(err, ErrInvalidResponse)
|
return nil, errors.Join(err, ErrInvalidResponse)
|
||||||
}
|
}
|
||||||
var responseLength *int64 = nil
|
var responseLength *int64
|
||||||
if responseBody != nil {
|
if responseBody != nil {
|
||||||
length := int64(len(*auditResponse.ResponseBodyBytes))
|
length := int64(len(auditResponse.ResponseBodyBytes))
|
||||||
responseLength = &length
|
responseLength = &length
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -332,7 +270,7 @@ func NewAuditLogEntry(
|
||||||
scheme := auditRequest.Request.Scheme
|
scheme := auditRequest.Request.Scheme
|
||||||
|
|
||||||
// Initialize authorization info if available
|
// Initialize authorization info if available
|
||||||
var authorizationInfo []*auditV1.AuthorizationInfo = nil
|
var authorizationInfo []*auditV1.AuthorizationInfo
|
||||||
if auditMetadata.AuditPermission != nil && auditMetadata.AuditPermissionGranted != nil {
|
if auditMetadata.AuditPermission != nil && auditMetadata.AuditPermissionGranted != nil {
|
||||||
authorizationInfo = []*auditV1.AuthorizationInfo{
|
authorizationInfo = []*auditV1.AuthorizationInfo{
|
||||||
NewAuthorizationInfo(
|
NewAuthorizationInfo(
|
||||||
|
|
@ -342,15 +280,15 @@ func NewAuditLogEntry(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize labels if available
|
// Initialize labels if available
|
||||||
var labels map[string]string = nil
|
var labels map[string]string
|
||||||
if auditMetadata.AuditLabels != nil {
|
if auditMetadata.AuditLabels != nil {
|
||||||
labels = *auditMetadata.AuditLabels
|
labels = *auditMetadata.AuditLabels
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize metadata/details
|
// Initialize metadata/details
|
||||||
var metadata *structpb.Struct = nil
|
var metadata *structpb.Struct
|
||||||
if eventMetadata != nil {
|
if eventMetadata != nil {
|
||||||
metadataStruct, err := structpb.NewStruct(*eventMetadata)
|
metadataStruct, err := structpb.NewStruct(eventMetadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -409,24 +347,6 @@ func NewAuditLogEntry(
|
||||||
return &event, nil
|
return &event, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCalledServiceNameFromRequest extracts the called service name from subdomain name
|
|
||||||
func GetCalledServiceNameFromRequest(request *ApiRequest, fallbackName string) string {
|
|
||||||
if request == nil {
|
|
||||||
return fallbackName
|
|
||||||
}
|
|
||||||
|
|
||||||
var calledServiceName = fallbackName
|
|
||||||
host := request.Host
|
|
||||||
ip := net.ParseIP(host)
|
|
||||||
if ip == nil && !strings.Contains(host, "localhost") {
|
|
||||||
dotIdx := strings.Index(host, ".")
|
|
||||||
if dotIdx != -1 {
|
|
||||||
calledServiceName = host[0:dotIdx]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return calledServiceName
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPbInt64Value returns protobuf int64 wrapper if value is not nil.
|
// NewPbInt64Value returns protobuf int64 wrapper if value is not nil.
|
||||||
func NewPbInt64Value(value *int64) *wrapperspb.Int64Value {
|
func NewPbInt64Value(value *int64) *wrapperspb.Int64Value {
|
||||||
if value != nil {
|
if value != nil {
|
||||||
|
|
@ -437,7 +357,7 @@ func NewPbInt64Value(value *int64) *wrapperspb.Int64Value {
|
||||||
|
|
||||||
// NewRequestMetadata returns initialized protobuf RequestMetadata object.
|
// NewRequestMetadata returns initialized protobuf RequestMetadata object.
|
||||||
func NewRequestMetadata(
|
func NewRequestMetadata(
|
||||||
request *ApiRequest,
|
request *pkgAuditCommon.ApiRequest,
|
||||||
requestHeaders map[string]string,
|
requestHeaders map[string]string,
|
||||||
requestId *string,
|
requestId *string,
|
||||||
requestScheme string,
|
requestScheme string,
|
||||||
|
|
@ -469,7 +389,7 @@ func NewRequestMetadata(
|
||||||
|
|
||||||
// NewRequestAttributes returns initialized protobuf AttributeContext_Request object.
|
// NewRequestAttributes returns initialized protobuf AttributeContext_Request object.
|
||||||
func NewRequestAttributes(
|
func NewRequestAttributes(
|
||||||
request *ApiRequest,
|
request *pkgAuditCommon.ApiRequest,
|
||||||
requestHeaders map[string]string,
|
requestHeaders map[string]string,
|
||||||
requestId *string,
|
requestId *string,
|
||||||
requestScheme string,
|
requestScheme string,
|
||||||
|
|
@ -480,7 +400,7 @@ func NewRequestAttributes(
|
||||||
) *auditV1.AttributeContext_Request {
|
) *auditV1.AttributeContext_Request {
|
||||||
|
|
||||||
rawQuery := request.URL.RawQuery
|
rawQuery := request.URL.RawQuery
|
||||||
var query *string = nil
|
var query *string
|
||||||
if rawQuery != nil && *rawQuery != "" {
|
if rawQuery != nil && *rawQuery != "" {
|
||||||
escapedQuery := url.QueryEscape(*rawQuery)
|
escapedQuery := url.QueryEscape(*rawQuery)
|
||||||
query = &escapedQuery
|
query = &escapedQuery
|
||||||
|
|
@ -488,7 +408,7 @@ func NewRequestAttributes(
|
||||||
|
|
||||||
return &auditV1.AttributeContext_Request{
|
return &auditV1.AttributeContext_Request{
|
||||||
Id: requestId,
|
Id: requestId,
|
||||||
Method: StringToHttpMethod(request.Method),
|
Method: pkgAuditCommon.StringToHttpMethod(request.Method),
|
||||||
Headers: requestHeaders,
|
Headers: requestHeaders,
|
||||||
Path: request.URL.Path,
|
Path: request.URL.Path,
|
||||||
Host: request.Host,
|
Host: request.Host,
|
||||||
|
|
@ -505,7 +425,7 @@ func NewRequestAttributes(
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAuthorizationInfo returns protobuf AuthorizationInfo for the given parameters.
|
// NewAuthorizationInfo returns protobuf AuthorizationInfo for the given parameters.
|
||||||
func NewAuthorizationInfo(resourceName string, permission string, granted bool) *auditV1.AuthorizationInfo {
|
func NewAuthorizationInfo(resourceName, permission string, granted bool) *auditV1.AuthorizationInfo {
|
||||||
return &auditV1.AuthorizationInfo{
|
return &auditV1.AuthorizationInfo{
|
||||||
Resource: resourceName,
|
Resource: resourceName,
|
||||||
Permission: &permission,
|
Permission: &permission,
|
||||||
|
|
@ -514,14 +434,14 @@ func NewAuthorizationInfo(resourceName string, permission string, granted bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInsertId returns a correctly formatted insert id.
|
// NewInsertId returns a correctly formatted insert id.
|
||||||
func NewInsertId(insertTime time.Time, location string, workerId string, eventSequenceNumber uint64) string {
|
func NewInsertId(insertTime time.Time, location, workerId string, eventSequenceNumber uint64) string {
|
||||||
return fmt.Sprintf("%d/%s/%s/%d", insertTime.UnixNano(), location, workerId, eventSequenceNumber)
|
return fmt.Sprintf("%d/%s/%s/%d", insertTime.UnixNano(), location, workerId, eventSequenceNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewResponseMetadata returns protobuf response status with status code and short message.
|
// NewResponseMetadata returns protobuf response status with status code and short message.
|
||||||
func NewResponseMetadata(statusCode int, numResponseItems *int64, responseSize *int64, headers map[string]string, responseTime time.Time) *auditV1.ResponseMetadata {
|
func NewResponseMetadata(statusCode int, numResponseItems, responseSize *int64, headers map[string]string, responseTime time.Time) *auditV1.ResponseMetadata {
|
||||||
|
|
||||||
var message *string = nil
|
var message *string
|
||||||
if statusCode >= 400 && statusCode < 500 {
|
if statusCode >= 400 && statusCode < 500 {
|
||||||
text := "Client error"
|
text := "Client error"
|
||||||
message = &text
|
message = &text
|
||||||
|
|
@ -530,7 +450,7 @@ func NewResponseMetadata(statusCode int, numResponseItems *int64, responseSize *
|
||||||
message = &text
|
message = &text
|
||||||
}
|
}
|
||||||
|
|
||||||
var size *wrapperspb.Int64Value = nil
|
var size *wrapperspb.Int64Value
|
||||||
if responseSize != nil {
|
if responseSize != nil {
|
||||||
size = wrapperspb.Int64(*responseSize)
|
size = wrapperspb.Int64(*responseSize)
|
||||||
}
|
}
|
||||||
|
|
@ -548,26 +468,26 @@ func NewResponseMetadata(statusCode int, numResponseItems *int64, responseSize *
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewResponseBody converts the JSON byte response into a protobuf struct.
|
// NewResponseBody converts the JSON byte response into a protobuf struct.
|
||||||
func NewResponseBody(response *[]byte) (*structpb.Struct, error) {
|
func NewResponseBody(response []byte) (*structpb.Struct, error) {
|
||||||
|
|
||||||
// Return if nil
|
// Return if nil
|
||||||
if response == nil || len(*response) == 0 {
|
if len(response) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to protobuf struct
|
// Convert to protobuf struct
|
||||||
return byteArrayToPbStruct(*response)
|
return byteArrayToPbStruct(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRequestBody converts the request body into a protobuf struct.
|
// NewRequestBody converts the request body into a protobuf struct.
|
||||||
func NewRequestBody(request *ApiRequest) (*structpb.Struct, error) {
|
func NewRequestBody(request *pkgAuditCommon.ApiRequest) (*structpb.Struct, error) {
|
||||||
|
|
||||||
if request.Body == nil || len(*request.Body) == 0 {
|
if len(request.Body) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to protobuf struct
|
// Convert to protobuf struct
|
||||||
return byteArrayToPbStruct(*request.Body)
|
return byteArrayToPbStruct(request.Body)
|
||||||
}
|
}
|
||||||
|
|
||||||
// byteArrayToPbStruct converts a given json byte array into a protobuf struct.
|
// byteArrayToPbStruct converts a given json byte array into a protobuf struct.
|
||||||
|
|
@ -582,12 +502,12 @@ func byteArrayToPbStruct(bytes []byte) (*structpb.Struct, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterAndMergeHeaders filters ":authority", "Authorization", "B3" and "Host" headers as well as
|
// FilterAndMergeHeaders filters ":authority", "Authorization", "B3" and "Host" headers as well as
|
||||||
// all headers starting with the prefixes "X-" and "STACKIT-".
|
// all headers starting with the prefixes "X-", "STACKIT-" and "grpcgateway-".
|
||||||
// Headers are merged if there is more than one value for a given name.
|
// Headers are merged if there is more than one value for a given name.
|
||||||
func FilterAndMergeHeaders(headers map[string][]string) map[string]string {
|
func FilterAndMergeHeaders(headers map[string][]string) map[string]string {
|
||||||
var resultMap = make(map[string]string)
|
var resultMap = make(map[string]string)
|
||||||
skipHeaders := []string{":authority", "authorization", "b3", "host"}
|
skipHeaders := []string{":authority", "authorization", "b3", "host"}
|
||||||
skipPrefixHeaders := []string{"x-", "stackit-"}
|
skipPrefixHeaders := []string{"x-", "stackit-", "grpcgateway-"}
|
||||||
|
|
||||||
if len(headers) == 0 {
|
if len(headers) == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -616,8 +536,8 @@ func FilterAndMergeHeaders(headers map[string][]string) map[string]string {
|
||||||
|
|
||||||
// NewAuditRoutingIdentifier instantiates a new auditApi.RoutableIdentifier for
|
// NewAuditRoutingIdentifier instantiates a new auditApi.RoutableIdentifier for
|
||||||
// the given object ID and object type.
|
// the given object ID and object type.
|
||||||
func NewAuditRoutingIdentifier(objectId string, objectType ObjectType) *RoutableIdentifier {
|
func NewAuditRoutingIdentifier(objectId string, objectType pkgAuditCommon.ObjectType) *pkgAuditCommon.RoutableIdentifier {
|
||||||
return &RoutableIdentifier{
|
return &pkgAuditCommon.RoutableIdentifier{
|
||||||
Identifier: objectId,
|
Identifier: objectId,
|
||||||
Type: objectType,
|
Type: objectType,
|
||||||
}
|
}
|
||||||
|
|
@ -628,7 +548,7 @@ func NewAuditRoutingIdentifier(objectId string, objectType ObjectType) *Routable
|
||||||
// - authenticationPrincipal - principal identifier
|
// - authenticationPrincipal - principal identifier
|
||||||
// - audiences - list of audience claims
|
// - audiences - list of audience claims
|
||||||
// - authenticationInfo - information about the user or service-account authentication
|
// - authenticationInfo - information about the user or service-account authentication
|
||||||
func AuditAttributesFromAuthorizationHeader(request *ApiRequest) (
|
func AuditAttributesFromAuthorizationHeader(request *pkgAuditCommon.ApiRequest) (
|
||||||
*structpb.Struct,
|
*structpb.Struct,
|
||||||
string,
|
string,
|
||||||
[]string,
|
[]string,
|
||||||
|
|
@ -636,14 +556,17 @@ func AuditAttributesFromAuthorizationHeader(request *ApiRequest) (
|
||||||
error,
|
error,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
var principalId = "none"
|
|
||||||
var principalEmail = EmailAddressDoNotReplyAtStackItDotCloud
|
|
||||||
emptyClaims, _ := structpb.NewStruct(make(map[string]interface{}))
|
|
||||||
var auditClaims = emptyClaims
|
|
||||||
var authenticationPrincipal = "none/none"
|
var authenticationPrincipal = "none/none"
|
||||||
var serviceAccountName *string = nil
|
var principalId = "none"
|
||||||
|
var principalEmail *string
|
||||||
|
emptyClaims, err := structpb.NewStruct(make(map[string]interface{}))
|
||||||
|
if err != nil {
|
||||||
|
return nil, authenticationPrincipal, nil, nil, err
|
||||||
|
}
|
||||||
|
var auditClaims = emptyClaims
|
||||||
|
var serviceAccountName *string
|
||||||
audiences := make([]string, 0)
|
audiences := make([]string, 0)
|
||||||
var delegationInfo []*auditV1.ServiceAccountDelegationInfo = nil
|
var delegationInfo []*auditV1.ServiceAccountDelegationInfo
|
||||||
|
|
||||||
authorizationHeaders := request.Header["Authorization"]
|
authorizationHeaders := request.Header["Authorization"]
|
||||||
if len(authorizationHeaders) == 0 {
|
if len(authorizationHeaders) == 0 {
|
||||||
|
|
@ -652,7 +575,7 @@ func AuditAttributesFromAuthorizationHeader(request *ApiRequest) (
|
||||||
}
|
}
|
||||||
authorizationHeader := strings.Join(authorizationHeaders, ",")
|
authorizationHeader := strings.Join(authorizationHeaders, ",")
|
||||||
trimmedAuthorizationHeader := strings.TrimSpace(authorizationHeader)
|
trimmedAuthorizationHeader := strings.TrimSpace(authorizationHeader)
|
||||||
if len(trimmedAuthorizationHeader) > 0 {
|
if trimmedAuthorizationHeader != "" {
|
||||||
|
|
||||||
// Parse claims
|
// Parse claims
|
||||||
token, err := parseToken(trimmedAuthorizationHeader)
|
token, err := parseToken(trimmedAuthorizationHeader)
|
||||||
|
|
@ -712,9 +635,8 @@ func getTokenClaim(token jwt.Token, claimName string) *string {
|
||||||
if claimExists {
|
if claimExists {
|
||||||
claimString := fmt.Sprintf("%s", claim)
|
claimString := fmt.Sprintf("%s", claim)
|
||||||
return &claimString
|
return &claimString
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractAuthenticationPrincipal(token jwt.Token) string {
|
func extractAuthenticationPrincipal(token jwt.Token) string {
|
||||||
|
|
@ -792,9 +714,8 @@ func extractServiceAccountDelegationInfoDetails(actClaims map[string]interface{}
|
||||||
nestedDelegations := extractServiceAccountDelegationInfo(actClaims)
|
nestedDelegations := extractServiceAccountDelegationInfo(actClaims)
|
||||||
if len(nestedDelegations) > 0 {
|
if len(nestedDelegations) > 0 {
|
||||||
return append(delegations, nestedDelegations...)
|
return append(delegations, nestedDelegations...)
|
||||||
} else {
|
|
||||||
return delegations
|
|
||||||
}
|
}
|
||||||
|
return delegations
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractServiceAccountDelegationInfo(claims map[string]interface{}) []*auditV1.ServiceAccountDelegationInfo {
|
func extractServiceAccountDelegationInfo(claims map[string]interface{}) []*auditV1.ServiceAccountDelegationInfo {
|
||||||
|
|
@ -820,144 +741,15 @@ func extractSubjectAndEmailFromActClaims(actClaim map[string]interface{}) (strin
|
||||||
return principalId, principalEmail
|
return principalId, principalEmail
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractSubjectAndEmail(token jwt.Token) (string, string) {
|
func extractSubjectAndEmail(token jwt.Token) (string, *string) {
|
||||||
var principalEmail string
|
var principalEmail *string
|
||||||
principalId := token.Subject()
|
principalId := token.Subject()
|
||||||
emailClaim, hasEmail := token.Get("email")
|
emailClaim, hasEmail := token.Get("email")
|
||||||
if !hasEmail {
|
if hasEmail {
|
||||||
principalEmail = EmailAddressDoNotReplyAtStackItDotCloud
|
trimmedEmail := strings.TrimSpace(fmt.Sprintf("%s", emailClaim))
|
||||||
} else {
|
if trimmedEmail != "" {
|
||||||
principalEmail = fmt.Sprintf("%s", emailClaim)
|
principalEmail = &trimmedEmail
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return principalId, principalEmail
|
return principalId, principalEmail
|
||||||
}
|
}
|
||||||
|
|
||||||
// OperationNameFromUrlPath converts the request url path into an operation name.
|
|
||||||
// UUIDs and query parameters are filtered out, slashes replaced by dots.
|
|
||||||
// HTTP methods are added as suffix as follows:
|
|
||||||
// - POST - create
|
|
||||||
// - PUT - update
|
|
||||||
// - PATCH - update
|
|
||||||
// - DELETE - delete
|
|
||||||
// - others - read
|
|
||||||
func OperationNameFromUrlPath(path string, requestMethod string) string {
|
|
||||||
queryIdx := strings.Index(path, "?")
|
|
||||||
if queryIdx != -1 {
|
|
||||||
path = path[:queryIdx]
|
|
||||||
}
|
|
||||||
path = strings.TrimPrefix(path, "/")
|
|
||||||
path = strings.TrimSuffix(path, "/")
|
|
||||||
split := strings.Split(path, "/")
|
|
||||||
|
|
||||||
operation := ""
|
|
||||||
for _, part := range split {
|
|
||||||
// skip uuids in path
|
|
||||||
_, err := uuid.Parse(part)
|
|
||||||
if err == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
operation = fmt.Sprintf("%s/%s", operation, part)
|
|
||||||
}
|
|
||||||
|
|
||||||
operation = strings.ReplaceAll(operation, "/", ".")
|
|
||||||
operation = strings.TrimPrefix(operation, ".")
|
|
||||||
operation = strings.ToLower(operation)
|
|
||||||
if len(operation) > 0 {
|
|
||||||
method := StringToHttpMethod(requestMethod)
|
|
||||||
var action string
|
|
||||||
switch method {
|
|
||||||
case auditV1.AttributeContext_HTTP_METHOD_PUT:
|
|
||||||
fallthrough
|
|
||||||
case auditV1.AttributeContext_HTTP_METHOD_PATCH:
|
|
||||||
action = "update"
|
|
||||||
case auditV1.AttributeContext_HTTP_METHOD_POST:
|
|
||||||
action = "create"
|
|
||||||
case auditV1.AttributeContext_HTTP_METHOD_DELETE:
|
|
||||||
action = "delete"
|
|
||||||
default:
|
|
||||||
action = "read"
|
|
||||||
}
|
|
||||||
operation = fmt.Sprintf("%s.%s", operation, action)
|
|
||||||
}
|
|
||||||
|
|
||||||
return operation
|
|
||||||
}
|
|
||||||
|
|
||||||
// OperationNameFromGrpcMethod converts the grpc path into an operation name.
|
|
||||||
func OperationNameFromGrpcMethod(path string) string {
|
|
||||||
operation := strings.TrimPrefix(path, "/")
|
|
||||||
operation = strings.TrimSuffix(operation, "/")
|
|
||||||
|
|
||||||
operation = strings.ReplaceAll(operation, "/", ".")
|
|
||||||
operation = strings.TrimPrefix(operation, ".")
|
|
||||||
operation = strings.ToLower(operation)
|
|
||||||
|
|
||||||
return operation
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetObjectIdAndTypeFromUrlPath(path string) (
|
|
||||||
string,
|
|
||||||
*ObjectType,
|
|
||||||
error,
|
|
||||||
) {
|
|
||||||
|
|
||||||
// Extract object id and type from request url
|
|
||||||
objectTypeIdMatches := objectTypeIdPattern.FindStringSubmatch(path)
|
|
||||||
if len(objectTypeIdMatches) > 0 {
|
|
||||||
objectType := ObjectTypeFromPluralString(objectTypeIdMatches[1])
|
|
||||||
err := objectType.IsSupportedType()
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
objectId := objectTypeIdMatches[2]
|
|
||||||
|
|
||||||
return objectId, &objectType, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ToArrayMap(input map[string]string) map[string][]string {
|
|
||||||
output := map[string][]string{}
|
|
||||||
for key, value := range input {
|
|
||||||
output[key] = []string{value}
|
|
||||||
}
|
|
||||||
return output
|
|
||||||
}
|
|
||||||
|
|
||||||
func StringAttributeFromMetadata(metadata map[string][]string, name string) string {
|
|
||||||
var value = ""
|
|
||||||
rawValue, hasAttribute := metadata[name]
|
|
||||||
if hasAttribute && len(rawValue) > 0 {
|
|
||||||
value = rawValue[0]
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResponseBodyToBytes converts a JSON or Protobuf response into a byte array
|
|
||||||
func ResponseBodyToBytes(response any) (*[]byte, error) {
|
|
||||||
if response == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
responseBytes, isBytes := response.([]byte)
|
|
||||||
if isBytes {
|
|
||||||
return &responseBytes, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
responseProtoMessage, isProtoMessage := response.(proto.Message)
|
|
||||||
if isProtoMessage {
|
|
||||||
responseJson, err := protojson.Marshal(responseProtoMessage)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &responseJson, nil
|
|
||||||
} else {
|
|
||||||
responseJson, err := json.Marshal(response)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &responseJson, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,61 +1,23 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"google.golang.org/protobuf/encoding/protojson"
|
|
||||||
"google.golang.org/protobuf/types/known/structpb"
|
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
|
||||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"google.golang.org/protobuf/types/known/structpb"
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||||
|
|
||||||
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_GetCalledServiceNameFromRequest(t *testing.T) {
|
|
||||||
|
|
||||||
t.Run("request is nil", func(t *testing.T) {
|
|
||||||
serviceName := GetCalledServiceNameFromRequest(nil, "resource-manager")
|
|
||||||
assert.Equal(t, "resource-manager", serviceName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("localhost", func(t *testing.T) {
|
|
||||||
request := ApiRequest{Host: "localhost:8080"}
|
|
||||||
serviceName := GetCalledServiceNameFromRequest(&request, "resource-manager")
|
|
||||||
assert.Equal(t, "resource-manager", serviceName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("cf", func(t *testing.T) {
|
|
||||||
request := ApiRequest{Host: "stackit-resource-manager-go-dev.apps.01.cf.eu01.stackit.cloud"}
|
|
||||||
serviceName := GetCalledServiceNameFromRequest(&request, "resource-manager")
|
|
||||||
assert.Equal(t, "stackit-resource-manager-go-dev", serviceName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("cf invalid host", func(t *testing.T) {
|
|
||||||
request := ApiRequest{Host: ""}
|
|
||||||
serviceName := GetCalledServiceNameFromRequest(&request, "resource-manager")
|
|
||||||
assert.Equal(t, "resource-manager", serviceName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("ip", func(t *testing.T) {
|
|
||||||
request := ApiRequest{Host: "127.0.0.1"}
|
|
||||||
serviceName := GetCalledServiceNameFromRequest(&request, "resource-manager")
|
|
||||||
assert.Equal(t, "resource-manager", serviceName)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
t.Run("ip short", func(t *testing.T) {
|
|
||||||
request := ApiRequest{Host: "::1"}
|
|
||||||
serviceName := GetCalledServiceNameFromRequest(&request, "resource-manager")
|
|
||||||
assert.Equal(t, "resource-manager", serviceName)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_NewPbInt64Value(t *testing.T) {
|
func Test_NewPbInt64Value(t *testing.T) {
|
||||||
|
|
||||||
t.Run("nil", func(t *testing.T) {
|
t.Run("nil", func(t *testing.T) {
|
||||||
|
|
@ -123,9 +85,9 @@ func Test_NewRequestMetadata(t *testing.T) {
|
||||||
requestHeaders["Custom"] = []string{"customHeader"}
|
requestHeaders["Custom"] = []string{"customHeader"}
|
||||||
|
|
||||||
queryString := "topic=project"
|
queryString := "topic=project"
|
||||||
request := ApiRequest{
|
request := pkgAuditCommon.ApiRequest{
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
URL: RequestUrl{Path: "/audit/new", RawQuery: &queryString},
|
URL: pkgAuditCommon.RequestUrl{Path: "/audit/new", RawQuery: &queryString},
|
||||||
Host: "localhost:8080",
|
Host: "localhost:8080",
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
Scheme: "http",
|
Scheme: "http",
|
||||||
|
|
@ -187,9 +149,9 @@ func Test_NewRequestMetadata(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("without query parameters", func(t *testing.T) {
|
t.Run("without query parameters", func(t *testing.T) {
|
||||||
request := ApiRequest{
|
request := pkgAuditCommon.ApiRequest{
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
URL: RequestUrl{Path: "/audit/new"},
|
URL: pkgAuditCommon.RequestUrl{Path: "/audit/new"},
|
||||||
Host: "localhost:8080",
|
Host: "localhost:8080",
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
Header: requestHeaders,
|
Header: requestHeaders,
|
||||||
|
|
@ -213,9 +175,9 @@ func Test_NewRequestMetadata(t *testing.T) {
|
||||||
|
|
||||||
t.Run("with empty query parameters", func(t *testing.T) {
|
t.Run("with empty query parameters", func(t *testing.T) {
|
||||||
emptyQuery := ""
|
emptyQuery := ""
|
||||||
request := ApiRequest{
|
request := pkgAuditCommon.ApiRequest{
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
URL: RequestUrl{Path: "/audit/new", RawQuery: &emptyQuery},
|
URL: pkgAuditCommon.RequestUrl{Path: "/audit/new", RawQuery: &emptyQuery},
|
||||||
Host: "localhost:8080",
|
Host: "localhost:8080",
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
Header: requestHeaders,
|
Header: requestHeaders,
|
||||||
|
|
@ -238,9 +200,9 @@ func Test_NewRequestMetadata(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("without request id", func(t *testing.T) {
|
t.Run("without request id", func(t *testing.T) {
|
||||||
request := ApiRequest{
|
request := pkgAuditCommon.ApiRequest{
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
URL: RequestUrl{Path: "/audit/new", RawQuery: &queryString},
|
URL: pkgAuditCommon.RequestUrl{Path: "/audit/new", RawQuery: &queryString},
|
||||||
Host: "localhost:8080",
|
Host: "localhost:8080",
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
Header: requestHeaders,
|
Header: requestHeaders,
|
||||||
|
|
@ -262,9 +224,9 @@ func Test_NewRequestMetadata(t *testing.T) {
|
||||||
t.Run("various default http methods", func(t *testing.T) {
|
t.Run("various default http methods", func(t *testing.T) {
|
||||||
httpMethods := []string{"GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE", "PATCH"}
|
httpMethods := []string{"GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE", "PATCH"}
|
||||||
for _, httpMethod := range httpMethods {
|
for _, httpMethod := range httpMethods {
|
||||||
request := ApiRequest{
|
request := pkgAuditCommon.ApiRequest{
|
||||||
Method: httpMethod,
|
Method: httpMethod,
|
||||||
URL: RequestUrl{Path: "/audit/new", RawQuery: &queryString},
|
URL: pkgAuditCommon.RequestUrl{Path: "/audit/new", RawQuery: &queryString},
|
||||||
Host: "localhost:8080",
|
Host: "localhost:8080",
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
Header: requestHeaders,
|
Header: requestHeaders,
|
||||||
|
|
@ -286,9 +248,9 @@ func Test_NewRequestMetadata(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("unknown http method", func(t *testing.T) {
|
t.Run("unknown http method", func(t *testing.T) {
|
||||||
request := ApiRequest{
|
request := pkgAuditCommon.ApiRequest{
|
||||||
Method: "",
|
Method: "",
|
||||||
URL: RequestUrl{Path: "/audit/new", RawQuery: &queryString},
|
URL: pkgAuditCommon.RequestUrl{Path: "/audit/new", RawQuery: &queryString},
|
||||||
Host: "localhost:8080",
|
Host: "localhost:8080",
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
Header: requestHeaders,
|
Header: requestHeaders,
|
||||||
|
|
@ -331,6 +293,7 @@ func Test_FilterAndMergeRequestHeaders(t *testing.T) {
|
||||||
headers := make(map[string][]string)
|
headers := make(map[string][]string)
|
||||||
headers["X-Forwarded-Proto"] = []string{"https"}
|
headers["X-Forwarded-Proto"] = []string{"https"}
|
||||||
headers["Stackit-test"] = []string{"test"}
|
headers["Stackit-test"] = []string{"test"}
|
||||||
|
headers["grpcgateway-authorization"] = []string{userToken}
|
||||||
|
|
||||||
filteredHeaders := FilterAndMergeHeaders(headers)
|
filteredHeaders := FilterAndMergeHeaders(headers)
|
||||||
assert.Equal(t, 0, len(filteredHeaders))
|
assert.Equal(t, 0, len(filteredHeaders))
|
||||||
|
|
@ -376,7 +339,7 @@ func Test_AuditAttributesFromAuthorizationHeader(t *testing.T) {
|
||||||
headerValue := "Basic username:password"
|
headerValue := "Basic username:password"
|
||||||
headers := make(map[string][]string)
|
headers := make(map[string][]string)
|
||||||
headers["Authorization"] = []string{headerValue}
|
headers["Authorization"] = []string{headerValue}
|
||||||
request := ApiRequest{Header: headers}
|
request := pkgAuditCommon.ApiRequest{Header: headers}
|
||||||
|
|
||||||
_, _, _, _, err := AuditAttributesFromAuthorizationHeader(&request)
|
_, _, _, _, err := AuditAttributesFromAuthorizationHeader(&request)
|
||||||
assert.ErrorIs(t, err, ErrTokenIsNotBearerToken)
|
assert.ErrorIs(t, err, ErrTokenIsNotBearerToken)
|
||||||
|
|
@ -386,7 +349,7 @@ func Test_AuditAttributesFromAuthorizationHeader(t *testing.T) {
|
||||||
headerValue := "a b c"
|
headerValue := "a b c"
|
||||||
headers := make(map[string][]string)
|
headers := make(map[string][]string)
|
||||||
headers["Authorization"] = []string{headerValue}
|
headers["Authorization"] = []string{headerValue}
|
||||||
request := ApiRequest{Header: headers}
|
request := pkgAuditCommon.ApiRequest{Header: headers}
|
||||||
|
|
||||||
_, _, _, _, err := AuditAttributesFromAuthorizationHeader(&request)
|
_, _, _, _, err := AuditAttributesFromAuthorizationHeader(&request)
|
||||||
assert.ErrorIs(t, err, ErrInvalidAuthorizationHeaderValue)
|
assert.ErrorIs(t, err, ErrInvalidAuthorizationHeaderValue)
|
||||||
|
|
@ -396,7 +359,7 @@ func Test_AuditAttributesFromAuthorizationHeader(t *testing.T) {
|
||||||
headerValue := "Bearer a.b.c.d"
|
headerValue := "Bearer a.b.c.d"
|
||||||
headers := make(map[string][]string)
|
headers := make(map[string][]string)
|
||||||
headers["Authorization"] = []string{headerValue}
|
headers["Authorization"] = []string{headerValue}
|
||||||
request := ApiRequest{Header: headers}
|
request := pkgAuditCommon.ApiRequest{Header: headers}
|
||||||
|
|
||||||
_, _, _, _, err := AuditAttributesFromAuthorizationHeader(&request)
|
_, _, _, _, err := AuditAttributesFromAuthorizationHeader(&request)
|
||||||
assert.ErrorIs(t, err, ErrInvalidBearerToken)
|
assert.ErrorIs(t, err, ErrInvalidBearerToken)
|
||||||
|
|
@ -406,7 +369,7 @@ func Test_AuditAttributesFromAuthorizationHeader(t *testing.T) {
|
||||||
headerValue := "Bearer a.b.c"
|
headerValue := "Bearer a.b.c"
|
||||||
headers := make(map[string][]string)
|
headers := make(map[string][]string)
|
||||||
headers["Authorization"] = []string{headerValue}
|
headers["Authorization"] = []string{headerValue}
|
||||||
request := ApiRequest{Header: headers}
|
request := pkgAuditCommon.ApiRequest{Header: headers}
|
||||||
|
|
||||||
_, _, _, _, err := AuditAttributesFromAuthorizationHeader(&request)
|
_, _, _, _, err := AuditAttributesFromAuthorizationHeader(&request)
|
||||||
assert.ErrorIs(t, err, ErrInvalidBearerToken)
|
assert.ErrorIs(t, err, ErrInvalidBearerToken)
|
||||||
|
|
@ -415,7 +378,7 @@ func Test_AuditAttributesFromAuthorizationHeader(t *testing.T) {
|
||||||
t.Run("client credentials token", func(t *testing.T) {
|
t.Run("client credentials token", func(t *testing.T) {
|
||||||
headers := make(map[string][]string)
|
headers := make(map[string][]string)
|
||||||
headers["Authorization"] = []string{clientCredentialsToken}
|
headers["Authorization"] = []string{clientCredentialsToken}
|
||||||
request := ApiRequest{Header: headers}
|
request := pkgAuditCommon.ApiRequest{Header: headers}
|
||||||
|
|
||||||
auditClaims, authenticationPrincipal, audiences, authenticationInfo, err :=
|
auditClaims, authenticationPrincipal, audiences, authenticationInfo, err :=
|
||||||
AuditAttributesFromAuthorizationHeader(&request)
|
AuditAttributesFromAuthorizationHeader(&request)
|
||||||
|
|
@ -441,7 +404,7 @@ func Test_AuditAttributesFromAuthorizationHeader(t *testing.T) {
|
||||||
assert.Equal(t, []string{"stackit-resource-manager-dev"}, audiences)
|
assert.Equal(t, []string{"stackit-resource-manager-dev"}, audiences)
|
||||||
|
|
||||||
assert.Equal(t, "stackit-resource-manager-dev", authenticationInfo.PrincipalId)
|
assert.Equal(t, "stackit-resource-manager-dev", authenticationInfo.PrincipalId)
|
||||||
assert.Equal(t, "do-not-reply@stackit.cloud", authenticationInfo.PrincipalEmail)
|
assert.Nil(t, authenticationInfo.PrincipalEmail)
|
||||||
|
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
||||||
|
|
@ -450,7 +413,7 @@ func Test_AuditAttributesFromAuthorizationHeader(t *testing.T) {
|
||||||
t.Run("service account access token", func(t *testing.T) {
|
t.Run("service account access token", func(t *testing.T) {
|
||||||
headers := make(map[string][]string)
|
headers := make(map[string][]string)
|
||||||
headers["Authorization"] = []string{serviceAccountToken}
|
headers["Authorization"] = []string{serviceAccountToken}
|
||||||
request := ApiRequest{Header: headers}
|
request := pkgAuditCommon.ApiRequest{Header: headers}
|
||||||
|
|
||||||
auditClaims, authenticationPrincipal, audiences, authenticationInfo, err :=
|
auditClaims, authenticationPrincipal, audiences, authenticationInfo, err :=
|
||||||
AuditAttributesFromAuthorizationHeader(&request)
|
AuditAttributesFromAuthorizationHeader(&request)
|
||||||
|
|
@ -479,7 +442,47 @@ func Test_AuditAttributesFromAuthorizationHeader(t *testing.T) {
|
||||||
assert.Equal(t, []string{"stackit", "api"}, audiences)
|
assert.Equal(t, []string{"stackit", "api"}, audiences)
|
||||||
|
|
||||||
assert.Equal(t, "10f38b01-534b-47bb-a03a-e294ca2be4de", authenticationInfo.PrincipalId)
|
assert.Equal(t, "10f38b01-534b-47bb-a03a-e294ca2be4de", authenticationInfo.PrincipalId)
|
||||||
assert.Equal(t, "my-service-yifc9e1@sa.stackit.cloud", authenticationInfo.PrincipalEmail)
|
assert.Equal(t, "my-service-yifc9e1@sa.stackit.cloud", *authenticationInfo.PrincipalEmail)
|
||||||
|
|
||||||
|
assert.Equal(t,
|
||||||
|
"projects/dacc7830-843e-4c5e-86ff-aa0fb51d636f/service-accounts/10f38b01-534b-47bb-a03a-e294ca2be4de",
|
||||||
|
*authenticationInfo.ServiceAccountName)
|
||||||
|
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("service account access token with underscore in subject", func(t *testing.T) {
|
||||||
|
headers := make(map[string][]string)
|
||||||
|
headers["Authorization"] = []string{serviceAccountTokenUnderscoreSubject}
|
||||||
|
request := pkgAuditCommon.ApiRequest{Header: headers}
|
||||||
|
|
||||||
|
auditClaims, authenticationPrincipal, audiences, authenticationInfo, err :=
|
||||||
|
AuditAttributesFromAuthorizationHeader(&request)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
auditClaimsMap := auditClaims.AsMap()
|
||||||
|
assert.Len(t, auditClaimsMap, 12)
|
||||||
|
assert.Equal(t, []interface{}{"stackit", "api"}, auditClaimsMap["aud"])
|
||||||
|
assert.Equal(t, "cd94f01a-df2e-4456-902e-48f5e57f0b63", auditClaimsMap["azp"])
|
||||||
|
assert.Equal(t, "my-service-yifc9e1@sa.stackit.cloud", auditClaimsMap["email"])
|
||||||
|
assert.Equal(t, "2024-08-03 07:15:43 +0000 UTC", auditClaimsMap["exp"])
|
||||||
|
assert.Equal(t, "2024-08-02 07:15:43 +0000 UTC", auditClaimsMap["iat"])
|
||||||
|
assert.Equal(t, "stackit/serviceaccount", auditClaimsMap["iss"])
|
||||||
|
assert.Equal(t, "84c30a46-1001-436f-859f-89c0ba19be1e", auditClaimsMap["jti"])
|
||||||
|
assert.Equal(t, "api", auditClaimsMap["stackit/serviceaccount/namespace"])
|
||||||
|
assert.Equal(t, "10f38b01-534b-47bb-a03a-e294ca2be4de", auditClaimsMap[TokenClaimStackitServiceAccountId])
|
||||||
|
assert.Equal(t, "legacy", auditClaimsMap["stackit/serviceaccount/token.source"])
|
||||||
|
assert.Equal(t, "dacc7830-843e-4c5e-86ff-aa0fb51d636f", auditClaimsMap[TokenClaimStackitProjectId])
|
||||||
|
assert.Equal(t, "10f38b01_534b_47bb_a03a_e294ca2be4de", auditClaimsMap["sub"])
|
||||||
|
|
||||||
|
principal := fmt.Sprintf("%s/%s",
|
||||||
|
url.QueryEscape("10f38b01_534b_47bb_a03a_e294ca2be4de"),
|
||||||
|
url.QueryEscape("stackit/serviceaccount"))
|
||||||
|
assert.Equal(t, principal, authenticationPrincipal)
|
||||||
|
|
||||||
|
assert.Equal(t, []string{"stackit", "api"}, audiences)
|
||||||
|
|
||||||
|
assert.Equal(t, "10f38b01_534b_47bb_a03a_e294ca2be4de", authenticationInfo.PrincipalId)
|
||||||
|
assert.Equal(t, "my-service-yifc9e1@sa.stackit.cloud", *authenticationInfo.PrincipalEmail)
|
||||||
|
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
"projects/dacc7830-843e-4c5e-86ff-aa0fb51d636f/service-accounts/10f38b01-534b-47bb-a03a-e294ca2be4de",
|
"projects/dacc7830-843e-4c5e-86ff-aa0fb51d636f/service-accounts/10f38b01-534b-47bb-a03a-e294ca2be4de",
|
||||||
|
|
@ -490,7 +493,7 @@ func Test_AuditAttributesFromAuthorizationHeader(t *testing.T) {
|
||||||
t.Run("impersonated token of access token", func(t *testing.T) {
|
t.Run("impersonated token of access token", func(t *testing.T) {
|
||||||
headers := make(map[string][]string)
|
headers := make(map[string][]string)
|
||||||
headers["Authorization"] = []string{serviceAccountTokenImpersonated}
|
headers["Authorization"] = []string{serviceAccountTokenImpersonated}
|
||||||
request := ApiRequest{Header: headers}
|
request := pkgAuditCommon.ApiRequest{Header: headers}
|
||||||
|
|
||||||
auditClaims, authenticationPrincipal, audiences, authenticationInfo, err :=
|
auditClaims, authenticationPrincipal, audiences, authenticationInfo, err :=
|
||||||
AuditAttributesFromAuthorizationHeader(&request)
|
AuditAttributesFromAuthorizationHeader(&request)
|
||||||
|
|
@ -523,7 +526,7 @@ func Test_AuditAttributesFromAuthorizationHeader(t *testing.T) {
|
||||||
assert.Equal(t, []string{"stackit", "api"}, audiences)
|
assert.Equal(t, []string{"stackit", "api"}, audiences)
|
||||||
|
|
||||||
assert.Equal(t, "f45009b2-6433-43c1-b6c7-618c44359e71", authenticationInfo.PrincipalId)
|
assert.Equal(t, "f45009b2-6433-43c1-b6c7-618c44359e71", authenticationInfo.PrincipalId)
|
||||||
assert.Equal(t, "service-account-2-tj9srt1@sa.stackit.cloud", authenticationInfo.PrincipalEmail)
|
assert.Equal(t, "service-account-2-tj9srt1@sa.stackit.cloud", *authenticationInfo.PrincipalEmail)
|
||||||
|
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
"projects/dacc7830-843e-4c5e-86ff-aa0fb51d636f/service-accounts/f45009b2-6433-43c1-b6c7-618c44359e71",
|
"projects/dacc7830-843e-4c5e-86ff-aa0fb51d636f/service-accounts/f45009b2-6433-43c1-b6c7-618c44359e71",
|
||||||
|
|
@ -538,7 +541,7 @@ func Test_AuditAttributesFromAuthorizationHeader(t *testing.T) {
|
||||||
t.Run("impersonated token of impersonated access token", func(t *testing.T) {
|
t.Run("impersonated token of impersonated access token", func(t *testing.T) {
|
||||||
headers := make(map[string][]string)
|
headers := make(map[string][]string)
|
||||||
headers["Authorization"] = []string{serviceAccountTokenRepeatedlyImpersonated}
|
headers["Authorization"] = []string{serviceAccountTokenRepeatedlyImpersonated}
|
||||||
request := ApiRequest{Header: headers}
|
request := pkgAuditCommon.ApiRequest{Header: headers}
|
||||||
|
|
||||||
auditClaims, authenticationPrincipal, audiences, authenticationInfo, err :=
|
auditClaims, authenticationPrincipal, audiences, authenticationInfo, err :=
|
||||||
AuditAttributesFromAuthorizationHeader(&request)
|
AuditAttributesFromAuthorizationHeader(&request)
|
||||||
|
|
@ -574,7 +577,7 @@ func Test_AuditAttributesFromAuthorizationHeader(t *testing.T) {
|
||||||
assert.Equal(t, []string{"stackit", "api"}, audiences)
|
assert.Equal(t, []string{"stackit", "api"}, audiences)
|
||||||
|
|
||||||
assert.Equal(t, "1734b4b6-1d5e-4819-9b50-29917a1b9ad5", authenticationInfo.PrincipalId)
|
assert.Equal(t, "1734b4b6-1d5e-4819-9b50-29917a1b9ad5", authenticationInfo.PrincipalId)
|
||||||
assert.Equal(t, "service-account-3-fghsxw1@sa.stackit.cloud", authenticationInfo.PrincipalEmail)
|
assert.Equal(t, "service-account-3-fghsxw1@sa.stackit.cloud", *authenticationInfo.PrincipalEmail)
|
||||||
|
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
"projects/dacc7830-843e-4c5e-86ff-aa0fb51d636f/service-accounts/1734b4b6-1d5e-4819-9b50-29917a1b9ad5",
|
"projects/dacc7830-843e-4c5e-86ff-aa0fb51d636f/service-accounts/1734b4b6-1d5e-4819-9b50-29917a1b9ad5",
|
||||||
|
|
@ -591,7 +594,7 @@ func Test_AuditAttributesFromAuthorizationHeader(t *testing.T) {
|
||||||
t.Run("user token", func(t *testing.T) {
|
t.Run("user token", func(t *testing.T) {
|
||||||
headers := make(map[string][]string)
|
headers := make(map[string][]string)
|
||||||
headers["Authorization"] = []string{userToken}
|
headers["Authorization"] = []string{userToken}
|
||||||
request := ApiRequest{Header: headers}
|
request := pkgAuditCommon.ApiRequest{Header: headers}
|
||||||
|
|
||||||
auditClaims, authenticationPrincipal, audiences, authenticationInfo, err :=
|
auditClaims, authenticationPrincipal, audiences, authenticationInfo, err :=
|
||||||
AuditAttributesFromAuthorizationHeader(&request)
|
AuditAttributesFromAuthorizationHeader(&request)
|
||||||
|
|
@ -619,7 +622,7 @@ func Test_AuditAttributesFromAuthorizationHeader(t *testing.T) {
|
||||||
assert.Equal(t, []string{"stackit-portal-login-dev-client-id"}, audiences)
|
assert.Equal(t, []string{"stackit-portal-login-dev-client-id"}, audiences)
|
||||||
|
|
||||||
assert.Equal(t, "cd94f01a-df2e-4456-902e-48f5e57f0b63", authenticationInfo.PrincipalId)
|
assert.Equal(t, "cd94f01a-df2e-4456-902e-48f5e57f0b63", authenticationInfo.PrincipalId)
|
||||||
assert.Equal(t, "Christian.Schaible@novatec-gmbh.de", authenticationInfo.PrincipalEmail)
|
assert.Equal(t, "Christian.Schaible@novatec-gmbh.de", *authenticationInfo.PrincipalEmail)
|
||||||
|
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
||||||
|
|
@ -628,7 +631,7 @@ func Test_AuditAttributesFromAuthorizationHeader(t *testing.T) {
|
||||||
t.Run("user token with simple aud claim", func(t *testing.T) {
|
t.Run("user token with simple aud claim", func(t *testing.T) {
|
||||||
headers := make(map[string][]string)
|
headers := make(map[string][]string)
|
||||||
headers["Authorization"] = []string{userTokenWithSimpleAudience}
|
headers["Authorization"] = []string{userTokenWithSimpleAudience}
|
||||||
request := ApiRequest{Header: headers}
|
request := pkgAuditCommon.ApiRequest{Header: headers}
|
||||||
|
|
||||||
auditClaims, authenticationPrincipal, audiences, authenticationInfo, err :=
|
auditClaims, authenticationPrincipal, audiences, authenticationInfo, err :=
|
||||||
AuditAttributesFromAuthorizationHeader(&request)
|
AuditAttributesFromAuthorizationHeader(&request)
|
||||||
|
|
@ -654,7 +657,7 @@ func Test_AuditAttributesFromAuthorizationHeader(t *testing.T) {
|
||||||
assert.Equal(t, []string{"https://stackit-service-account-dev.apps.01.cf.eu01.stackit.cloud"}, audiences)
|
assert.Equal(t, []string{"https://stackit-service-account-dev.apps.01.cf.eu01.stackit.cloud"}, audiences)
|
||||||
|
|
||||||
assert.Equal(t, "5e426aed-c487-4c48-af25-87f69cf9cdd4", authenticationInfo.PrincipalId)
|
assert.Equal(t, "5e426aed-c487-4c48-af25-87f69cf9cdd4", authenticationInfo.PrincipalId)
|
||||||
assert.Equal(t, "Lukas.Schmitt@stackit.cloud", authenticationInfo.PrincipalEmail)
|
assert.Equal(t, "Lukas.Schmitt@stackit.cloud", *authenticationInfo.PrincipalEmail)
|
||||||
|
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
||||||
|
|
@ -670,9 +673,9 @@ func Test_NewAuditLogEntry(t *testing.T) {
|
||||||
requestHeaders["User-Agent"] = []string{userAgent}
|
requestHeaders["User-Agent"] = []string{userAgent}
|
||||||
requestHeaders["Custom"] = []string{"customHeader"}
|
requestHeaders["Custom"] = []string{"customHeader"}
|
||||||
|
|
||||||
request := ApiRequest{
|
request := pkgAuditCommon.ApiRequest{
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
URL: RequestUrl{Path: "/audit/new"},
|
URL: pkgAuditCommon.RequestUrl{Path: "/audit/new"},
|
||||||
Host: "localhost:8080",
|
Host: "localhost:8080",
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
Scheme: "http",
|
Scheme: "http",
|
||||||
|
|
@ -699,7 +702,7 @@ func Test_NewAuditLogEntry(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
objectId := uuid.NewString()
|
objectId := uuid.NewString()
|
||||||
logName := fmt.Sprintf("projects/%s/logs/%s", objectId, EventTypeAdminActivity)
|
logName := fmt.Sprintf("projects/%s/logs/%s", objectId, pkgAuditCommon.EventTypeAdminActivity)
|
||||||
serviceName := "resource-manager"
|
serviceName := "resource-manager"
|
||||||
operationName := fmt.Sprintf("stackit.%s.v2.projects.updated", serviceName)
|
operationName := fmt.Sprintf("stackit.%s.v2.projects.updated", serviceName)
|
||||||
resourceName := fmt.Sprintf("projects/%s", objectId)
|
resourceName := fmt.Sprintf("projects/%s", objectId)
|
||||||
|
|
@ -753,7 +756,7 @@ func Test_NewAuditLogEntry(t *testing.T) {
|
||||||
authenticationInfo := payload.AuthenticationInfo
|
authenticationInfo := payload.AuthenticationInfo
|
||||||
assert.NotNil(t, authenticationInfo)
|
assert.NotNil(t, authenticationInfo)
|
||||||
assert.Equal(t, "cd94f01a-df2e-4456-902e-48f5e57f0b63", authenticationInfo.PrincipalId)
|
assert.Equal(t, "cd94f01a-df2e-4456-902e-48f5e57f0b63", authenticationInfo.PrincipalId)
|
||||||
assert.Equal(t, "Christian.Schaible@novatec-gmbh.de", authenticationInfo.PrincipalEmail)
|
assert.Equal(t, "Christian.Schaible@novatec-gmbh.de", *authenticationInfo.PrincipalEmail)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
||||||
|
|
||||||
|
|
@ -779,14 +782,14 @@ func Test_NewAuditLogEntry(t *testing.T) {
|
||||||
requestBody["key"] = "request"
|
requestBody["key"] = "request"
|
||||||
requestBodyBytes, _ := json.Marshal(requestBody)
|
requestBodyBytes, _ := json.Marshal(requestBody)
|
||||||
query := "topic=project"
|
query := "topic=project"
|
||||||
request := ApiRequest{
|
request := pkgAuditCommon.ApiRequest{
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
URL: RequestUrl{Path: "/audit/new", RawQuery: &query},
|
URL: pkgAuditCommon.RequestUrl{Path: "/audit/new", RawQuery: &query},
|
||||||
Host: "localhost:8080",
|
Host: "localhost:8080",
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
Scheme: "http",
|
Scheme: "http",
|
||||||
Header: requestHeaders,
|
Header: requestHeaders,
|
||||||
Body: &requestBodyBytes,
|
Body: requestBodyBytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
clientIp := "127.0.0.1"
|
clientIp := "127.0.0.1"
|
||||||
|
|
@ -813,7 +816,7 @@ func Test_NewAuditLogEntry(t *testing.T) {
|
||||||
responseTime := time.Now().UTC()
|
responseTime := time.Now().UTC()
|
||||||
|
|
||||||
auditResponse := AuditResponse{
|
auditResponse := AuditResponse{
|
||||||
ResponseBodyBytes: &responseBody,
|
ResponseBodyBytes: responseBody,
|
||||||
ResponseStatusCode: responseStatusCode,
|
ResponseStatusCode: responseStatusCode,
|
||||||
ResponseHeaders: responseHeader,
|
ResponseHeaders: responseHeader,
|
||||||
ResponseNumItems: &responseNumItems,
|
ResponseNumItems: &responseNumItems,
|
||||||
|
|
@ -823,7 +826,7 @@ func Test_NewAuditLogEntry(t *testing.T) {
|
||||||
auditTime := time.Now().UTC()
|
auditTime := time.Now().UTC()
|
||||||
|
|
||||||
objectId := uuid.NewString()
|
objectId := uuid.NewString()
|
||||||
logName := fmt.Sprintf("projects/%s/logs/%s", objectId, EventTypeAdminActivity)
|
logName := fmt.Sprintf("projects/%s/logs/%s", objectId, pkgAuditCommon.EventTypeAdminActivity)
|
||||||
serviceName := "resource-manager"
|
serviceName := "resource-manager"
|
||||||
operationName := fmt.Sprintf("stackit.%s.v2.projects.updated", serviceName)
|
operationName := fmt.Sprintf("stackit.%s.v2.projects.updated", serviceName)
|
||||||
resourceName := fmt.Sprintf("projects/%s", objectId)
|
resourceName := fmt.Sprintf("projects/%s", objectId)
|
||||||
|
|
@ -852,7 +855,7 @@ func Test_NewAuditLogEntry(t *testing.T) {
|
||||||
logEntry, _ := NewAuditLogEntry(
|
logEntry, _ := NewAuditLogEntry(
|
||||||
auditRequest,
|
auditRequest,
|
||||||
auditResponse,
|
auditResponse,
|
||||||
&eventMetadata,
|
eventMetadata,
|
||||||
auditMetadata)
|
auditMetadata)
|
||||||
|
|
||||||
assert.Equal(t, logName, logEntry.LogName)
|
assert.Equal(t, logName, logEntry.LogName)
|
||||||
|
|
@ -886,7 +889,7 @@ func Test_NewAuditLogEntry(t *testing.T) {
|
||||||
authenticationInfo := payload.AuthenticationInfo
|
authenticationInfo := payload.AuthenticationInfo
|
||||||
assert.NotNil(t, authenticationInfo)
|
assert.NotNil(t, authenticationInfo)
|
||||||
assert.Equal(t, "cd94f01a-df2e-4456-902e-48f5e57f0b63", authenticationInfo.PrincipalId)
|
assert.Equal(t, "cd94f01a-df2e-4456-902e-48f5e57f0b63", authenticationInfo.PrincipalId)
|
||||||
assert.Equal(t, "Christian.Schaible@novatec-gmbh.de", authenticationInfo.PrincipalEmail)
|
assert.Equal(t, "Christian.Schaible@novatec-gmbh.de", *authenticationInfo.PrincipalEmail)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
||||||
|
|
||||||
|
|
@ -920,231 +923,9 @@ func Test_NewInsertId(t *testing.T) {
|
||||||
|
|
||||||
func Test_NewNewAuditRoutingIdentifier(t *testing.T) {
|
func Test_NewNewAuditRoutingIdentifier(t *testing.T) {
|
||||||
objectId := uuid.NewString()
|
objectId := uuid.NewString()
|
||||||
objectType := ObjectTypeProject
|
objectType := pkgAuditCommon.ObjectTypeProject
|
||||||
|
|
||||||
routingIdentifier := NewAuditRoutingIdentifier(objectId, objectType)
|
routingIdentifier := NewAuditRoutingIdentifier(objectId, objectType)
|
||||||
assert.Equal(t, objectId, routingIdentifier.Identifier)
|
assert.Equal(t, objectId, routingIdentifier.Identifier)
|
||||||
assert.Equal(t, objectType, routingIdentifier.Type)
|
assert.Equal(t, objectType, routingIdentifier.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_OperationNameFromUrlPath(t *testing.T) {
|
|
||||||
|
|
||||||
t.Run("empty path", func(t *testing.T) {
|
|
||||||
operationName := OperationNameFromUrlPath("", "GET")
|
|
||||||
assert.Equal(t, "", operationName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("root path", func(t *testing.T) {
|
|
||||||
operationName := OperationNameFromUrlPath("/", "GET")
|
|
||||||
assert.Equal(t, "", operationName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("path without version", func(t *testing.T) {
|
|
||||||
operationName := OperationNameFromUrlPath("/projects", "GET")
|
|
||||||
assert.Equal(t, "projects.read", operationName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("path with uuid without version", func(t *testing.T) {
|
|
||||||
operationName := OperationNameFromUrlPath("/projects/ac51bbd2-cb23-441b-a2ee-5393189695aa", "GET")
|
|
||||||
assert.Equal(t, "projects.read", operationName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("path with uuid and version", func(t *testing.T) {
|
|
||||||
operationName := OperationNameFromUrlPath("/v2/projects/ac51bbd2-cb23-441b-a2ee-5393189695aa", "GET")
|
|
||||||
assert.Equal(t, "v2.projects.read", operationName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("concatenated path", func(t *testing.T) {
|
|
||||||
operationName := OperationNameFromUrlPath("/v2/organizations/ac51bbd2-cb23-441b-a2ee-5393189695aa/folders/167fc176-9d8e-477b-a56c-b50d7b26adcf/projects/0a2a4f9b-4e67-4562-ad02-c2d200e05aa6/audit/policy", "GET")
|
|
||||||
assert.Equal(t, "v2.organizations.folders.projects.audit.policy.read", operationName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("path with query params", func(t *testing.T) {
|
|
||||||
operationName := OperationNameFromUrlPath("/v2/organizations/ac51bbd2-cb23-441b-a2ee-5393189695aa/audit/policy?since=2024-08-27", "GET")
|
|
||||||
assert.Equal(t, "v2.organizations.audit.policy.read", operationName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("path trailing slash", func(t *testing.T) {
|
|
||||||
operationName := OperationNameFromUrlPath("/projects/ac51bbd2-cb23-441b-a2ee-5393189695aa/", "GET")
|
|
||||||
assert.Equal(t, "projects.read", operationName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("path trailing slash and query params", func(t *testing.T) {
|
|
||||||
operationName := OperationNameFromUrlPath("/projects/ac51bbd2-cb23-441b-a2ee-5393189695aa/?changeDate=2024-10-13", "GET")
|
|
||||||
assert.Equal(t, "projects.read", operationName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("http method post", func(t *testing.T) {
|
|
||||||
operationName := OperationNameFromUrlPath("/projects", "POST")
|
|
||||||
assert.Equal(t, "projects.create", operationName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("http method put", func(t *testing.T) {
|
|
||||||
operationName := OperationNameFromUrlPath("/projects", "PUT")
|
|
||||||
assert.Equal(t, "projects.update", operationName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("http method patch", func(t *testing.T) {
|
|
||||||
operationName := OperationNameFromUrlPath("/projects", "PATCH")
|
|
||||||
assert.Equal(t, "projects.update", operationName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("http method delete", func(t *testing.T) {
|
|
||||||
operationName := OperationNameFromUrlPath("/projects", "DELETE")
|
|
||||||
assert.Equal(t, "projects.delete", operationName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("operation name fallback on options", func(t *testing.T) {
|
|
||||||
operationName := OperationNameFromUrlPath("/projects", "OPTIONS")
|
|
||||||
assert.Equal(t, "projects.read", operationName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("operation name fallback on unknown", func(t *testing.T) {
|
|
||||||
operationName := OperationNameFromUrlPath("/projects", "UNKNOWN")
|
|
||||||
assert.Equal(t, "projects.read", operationName)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_OperationNameFromGrpcMethod(t *testing.T) {
|
|
||||||
|
|
||||||
t.Run("empty path", func(t *testing.T) {
|
|
||||||
operationName := OperationNameFromGrpcMethod("")
|
|
||||||
assert.Equal(t, "", operationName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("root path", func(t *testing.T) {
|
|
||||||
operationName := OperationNameFromGrpcMethod("/")
|
|
||||||
assert.Equal(t, "", operationName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("path without version", func(t *testing.T) {
|
|
||||||
operationName := OperationNameFromGrpcMethod("/example.ExampleService/ManualAuditEvent")
|
|
||||||
assert.Equal(t, "example.exampleservice.manualauditevent", operationName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("path with version", func(t *testing.T) {
|
|
||||||
operationName := OperationNameFromGrpcMethod("/example.v1.ExampleService/ManualAuditEvent")
|
|
||||||
assert.Equal(t, "example.v1.exampleservice.manualauditevent", operationName)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("path trailing slash", func(t *testing.T) {
|
|
||||||
operationName := OperationNameFromGrpcMethod("/example.v1.ExampleService/ManualAuditEvent/")
|
|
||||||
assert.Equal(t, "example.v1.exampleservice.manualauditevent", operationName)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_GetObjectIdAndTypeFromUrlPath(t *testing.T) {
|
|
||||||
|
|
||||||
t.Run("object id and type not in url", func(t *testing.T) {
|
|
||||||
objectId, objectType, err := GetObjectIdAndTypeFromUrlPath("/v2/projects/audit")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, "", objectId)
|
|
||||||
assert.Nil(t, objectType)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("object id and type in url", func(t *testing.T) {
|
|
||||||
objectId, objectType, err := GetObjectIdAndTypeFromUrlPath("/v2/projects/f17d4064-9b65-4334-b6a7-8fed96340124")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, "f17d4064-9b65-4334-b6a7-8fed96340124", objectId)
|
|
||||||
assert.Equal(t, ObjectTypeProject, *objectType)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("multiple object ids and types in url", func(t *testing.T) {
|
|
||||||
objectId, objectType, err := GetObjectIdAndTypeFromUrlPath("/v2/organization/8ee58bec-d496-4bb9-af8d-72fda4d78b6b/projects/f17d4064-9b65-4334-b6a7-8fed96340124")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, "f17d4064-9b65-4334-b6a7-8fed96340124", objectId)
|
|
||||||
assert.Equal(t, ObjectTypeProject, *objectType)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_ToArrayMap(t *testing.T) {
|
|
||||||
|
|
||||||
t.Run("empty map", func(t *testing.T) {
|
|
||||||
result := ToArrayMap(map[string]string{})
|
|
||||||
assert.Equal(t, map[string][]string{}, result)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("empty map", func(t *testing.T) {
|
|
||||||
result := ToArrayMap(map[string]string{"key1": "value1", "key2": "value2"})
|
|
||||||
assert.Equal(t, map[string][]string{
|
|
||||||
"key1": {"value1"},
|
|
||||||
"key2": {"value2"},
|
|
||||||
}, result)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_StringAttributeFromMetadata(t *testing.T) {
|
|
||||||
|
|
||||||
metadata := map[string][]string{"key1": {"value1"}, "key2": {"value2"}}
|
|
||||||
|
|
||||||
t.Run("not found", func(t *testing.T) {
|
|
||||||
attribute := StringAttributeFromMetadata(metadata, "key3")
|
|
||||||
assert.Equal(t, "", attribute)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("found", func(t *testing.T) {
|
|
||||||
attribute := StringAttributeFromMetadata(metadata, "key2")
|
|
||||||
assert.Equal(t, "value2", attribute)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_ResponseBodyToBytes(t *testing.T) {
|
|
||||||
|
|
||||||
t.Run(
|
|
||||||
"nil response body", func(t *testing.T) {
|
|
||||||
bytes, err := ResponseBodyToBytes(nil)
|
|
||||||
assert.Nil(t, bytes)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
t.Run(
|
|
||||||
"bytes", func(t *testing.T) {
|
|
||||||
responseBody := []byte("data")
|
|
||||||
bytes, err := ResponseBodyToBytes(responseBody)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, &responseBody, bytes)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
t.Run(
|
|
||||||
"Protobuf message", func(t *testing.T) {
|
|
||||||
protobufMessage := auditV1.ObjectIdentifier{Identifier: uuid.NewString(), Type: string(ObjectTypeProject)}
|
|
||||||
bytes, err := ResponseBodyToBytes(&protobufMessage)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
expected, err := protojson.Marshal(&protobufMessage)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, &expected, bytes)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
t.Run(
|
|
||||||
"struct", func(t *testing.T) {
|
|
||||||
type CustomObject struct {
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
responseBody := CustomObject{Value: "data"}
|
|
||||||
bytes, err := ResponseBodyToBytes(responseBody)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
expected, err := json.Marshal(responseBody)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, &expected, bytes)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
t.Run(
|
|
||||||
"map", func(t *testing.T) {
|
|
||||||
|
|
||||||
responseBody := map[string]interface{}{"value": "data"}
|
|
||||||
bytes, err := ResponseBodyToBytes(responseBody)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
expected, err := json.Marshal(responseBody)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, &expected, bytes)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
|
||||||
"github.com/bufbuild/protovalidate-go"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"buf.build/go/protovalidate"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_RoutableAuditEvent(t *testing.T) {
|
func Test_RoutableAuditEvent(t *testing.T) {
|
||||||
|
|
@ -18,7 +21,7 @@ func Test_RoutableAuditEvent(t *testing.T) {
|
||||||
Visibility: auditV1.Visibility_VISIBILITY_PUBLIC,
|
Visibility: auditV1.Visibility_VISIBILITY_PUBLIC,
|
||||||
ObjectIdentifier: &auditV1.ObjectIdentifier{
|
ObjectIdentifier: &auditV1.ObjectIdentifier{
|
||||||
Identifier: "14f7aa86-77ba-4d77-a091-a2cf3395a221",
|
Identifier: "14f7aa86-77ba-4d77-a091-a2cf3395a221",
|
||||||
Type: string(ObjectTypeProject),
|
Type: string(pkgAuditCommon.ObjectTypeProject),
|
||||||
},
|
},
|
||||||
Data: &auditV1.RoutableAuditEvent_UnencryptedData{UnencryptedData: &auditV1.UnencryptedData{
|
Data: &auditV1.RoutableAuditEvent_UnencryptedData{UnencryptedData: &auditV1.UnencryptedData{
|
||||||
Data: []byte("data"),
|
Data: []byte("data"),
|
||||||
|
|
@ -37,7 +40,7 @@ func Test_RoutableAuditEvent(t *testing.T) {
|
||||||
event.OperationName = ""
|
event.OperationName = ""
|
||||||
|
|
||||||
err := validator.Validate(&event)
|
err := validator.Validate(&event)
|
||||||
assert.EqualError(t, err, "validation error:\n - operation_name: value is required [required]")
|
assert.EqualError(t, err, "validation error: operation_name: value is required")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("invalid operation name", func(t *testing.T) {
|
t.Run("invalid operation name", func(t *testing.T) {
|
||||||
|
|
@ -45,7 +48,7 @@ func Test_RoutableAuditEvent(t *testing.T) {
|
||||||
event.OperationName = "stackit.resource-manager.v1.INVALID.organizations.create"
|
event.OperationName = "stackit.resource-manager.v1.INVALID.organizations.create"
|
||||||
|
|
||||||
err := validator.Validate(&event)
|
err := validator.Validate(&event)
|
||||||
assert.EqualError(t, err, "validation error:\n - operation_name: value does not match regex pattern `^stackit\\.[a-z0-9-]+\\.(?:v[0-9]+\\.)?(?:[a-z0-9-.]+\\.)?[a-z0-9-]+$` [string.pattern]")
|
assert.EqualError(t, err, "validation error: operation_name: value does not match regex pattern `^stackit\\.[a-z0-9-]+\\.(?:v[0-9]+\\.)?(?:[a-z0-9-.]+\\.)?[a-z0-9-]+$`")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("visibility invalid", func(t *testing.T) {
|
t.Run("visibility invalid", func(t *testing.T) {
|
||||||
|
|
@ -53,7 +56,7 @@ func Test_RoutableAuditEvent(t *testing.T) {
|
||||||
event.Visibility = -1
|
event.Visibility = -1
|
||||||
|
|
||||||
err := validator.Validate(&event)
|
err := validator.Validate(&event)
|
||||||
assert.EqualError(t, err, "validation error:\n - visibility: value must be one of the defined enum values [enum.defined_only]")
|
assert.EqualError(t, err, "validation error: visibility: value must be one of the defined enum values")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("visibility unspecified", func(t *testing.T) {
|
t.Run("visibility unspecified", func(t *testing.T) {
|
||||||
|
|
@ -61,7 +64,7 @@ func Test_RoutableAuditEvent(t *testing.T) {
|
||||||
event.Visibility = auditV1.Visibility_VISIBILITY_UNSPECIFIED
|
event.Visibility = auditV1.Visibility_VISIBILITY_UNSPECIFIED
|
||||||
|
|
||||||
err := validator.Validate(&event)
|
err := validator.Validate(&event)
|
||||||
assert.EqualError(t, err, "validation error:\n - visibility: value is required [required]")
|
assert.EqualError(t, err, "validation error: visibility: value is required")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("object identifier nil", func(t *testing.T) {
|
t.Run("object identifier nil", func(t *testing.T) {
|
||||||
|
|
@ -69,7 +72,7 @@ func Test_RoutableAuditEvent(t *testing.T) {
|
||||||
event.ObjectIdentifier = nil
|
event.ObjectIdentifier = nil
|
||||||
|
|
||||||
err := validator.Validate(&event)
|
err := validator.Validate(&event)
|
||||||
assert.EqualError(t, err, "validation error:\n - object_identifier: value is required [required]")
|
assert.EqualError(t, err, "validation error: object_identifier: value is required")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("object identifier id empty", func(t *testing.T) {
|
t.Run("object identifier id empty", func(t *testing.T) {
|
||||||
|
|
@ -77,7 +80,7 @@ func Test_RoutableAuditEvent(t *testing.T) {
|
||||||
event.ObjectIdentifier.Identifier = ""
|
event.ObjectIdentifier.Identifier = ""
|
||||||
|
|
||||||
err := validator.Validate(&event)
|
err := validator.Validate(&event)
|
||||||
assert.EqualError(t, err, "validation error:\n - object_identifier.identifier: value is required [required]")
|
assert.EqualError(t, err, "validation error: object_identifier.identifier: value is required")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("object identifier id not uuid", func(t *testing.T) {
|
t.Run("object identifier id not uuid", func(t *testing.T) {
|
||||||
|
|
@ -85,7 +88,7 @@ func Test_RoutableAuditEvent(t *testing.T) {
|
||||||
event.ObjectIdentifier.Identifier = "invalid"
|
event.ObjectIdentifier.Identifier = "invalid"
|
||||||
|
|
||||||
err := validator.Validate(&event)
|
err := validator.Validate(&event)
|
||||||
assert.EqualError(t, err, "validation error:\n - object_identifier.identifier: value must be a valid UUID [string.uuid]")
|
assert.EqualError(t, err, "validation error: object_identifier.identifier: value must be a valid UUID")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("object identifier type empty", func(t *testing.T) {
|
t.Run("object identifier type empty", func(t *testing.T) {
|
||||||
|
|
@ -93,7 +96,7 @@ func Test_RoutableAuditEvent(t *testing.T) {
|
||||||
event.ObjectIdentifier.Type = ""
|
event.ObjectIdentifier.Type = ""
|
||||||
|
|
||||||
err := validator.Validate(&event)
|
err := validator.Validate(&event)
|
||||||
assert.EqualError(t, err, "validation error:\n - object_identifier.type: value is required [required]")
|
assert.EqualError(t, err, "validation error: object_identifier.type: value is required")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("data nil", func(t *testing.T) {
|
t.Run("data nil", func(t *testing.T) {
|
||||||
|
|
@ -101,7 +104,7 @@ func Test_RoutableAuditEvent(t *testing.T) {
|
||||||
event.Data = nil
|
event.Data = nil
|
||||||
|
|
||||||
err := validator.Validate(&event)
|
err := validator.Validate(&event)
|
||||||
assert.EqualError(t, err, "validation error:\n - data: exactly one field is required in oneof [required]")
|
assert.EqualError(t, err, "validation error: data: exactly one field is required in oneof")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("data empty", func(t *testing.T) {
|
t.Run("data empty", func(t *testing.T) {
|
||||||
|
|
@ -112,7 +115,7 @@ func Test_RoutableAuditEvent(t *testing.T) {
|
||||||
}}
|
}}
|
||||||
|
|
||||||
err := validator.Validate(&event)
|
err := validator.Validate(&event)
|
||||||
assert.EqualError(t, err, "validation error:\n - unencrypted_data.data: value is required [required]")
|
assert.EqualError(t, err, "validation error: unencrypted_data.data: value is required")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("data protobuf type empty", func(t *testing.T) {
|
t.Run("data protobuf type empty", func(t *testing.T) {
|
||||||
|
|
@ -123,6 +126,59 @@ func Test_RoutableAuditEvent(t *testing.T) {
|
||||||
}}
|
}}
|
||||||
|
|
||||||
err := validator.Validate(&event)
|
err := validator.Validate(&event)
|
||||||
assert.EqualError(t, err, "validation error:\n - unencrypted_data.protobuf_type: value is required [required]")
|
assert.EqualError(t, err, "validation error: unencrypted_data.protobuf_type: value is required")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_AuthenticationInfo(t *testing.T) {
|
||||||
|
|
||||||
|
validator, err := protovalidate.New()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
email := "x@x.x"
|
||||||
|
newEvent := func() auditV1.AuthenticationInfo {
|
||||||
|
return auditV1.AuthenticationInfo{
|
||||||
|
PrincipalId: "1234567890",
|
||||||
|
PrincipalEmail: &email,
|
||||||
|
ServiceAccountName: nil,
|
||||||
|
ServiceAccountDelegationInfo: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("valid event", func(t *testing.T) {
|
||||||
|
event := newEvent()
|
||||||
|
err := validator.Validate(&event)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("valid event without email", func(t *testing.T) {
|
||||||
|
event := newEvent()
|
||||||
|
event.PrincipalEmail = nil
|
||||||
|
err := validator.Validate(&event)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("principal id contains only whitespace", func(t *testing.T) {
|
||||||
|
event := newEvent()
|
||||||
|
event.PrincipalId = " "
|
||||||
|
err := validator.Validate(&event)
|
||||||
|
assert.EqualError(t, err, "validation error: principal_id: value does not match regex pattern `.*\\S.*`")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("principal email contains only whitespace", func(t *testing.T) {
|
||||||
|
event := newEvent()
|
||||||
|
whitespaceEmail := " "
|
||||||
|
event.PrincipalEmail = &whitespaceEmail
|
||||||
|
err := validator.Validate(&event)
|
||||||
|
assert.EqualError(t, err, "validation error: principal_email: value must be a valid email address")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("missing host in email", func(t *testing.T) {
|
||||||
|
event := newEvent()
|
||||||
|
invalidEmail := "@test.com"
|
||||||
|
event.PrincipalEmail = &invalidEmail
|
||||||
|
err := validator.Validate(&event)
|
||||||
|
assert.EqualError(t, err, "validation error: principal_email: value must be a valid email address")
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -4,16 +4,17 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
|
||||||
|
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"google.golang.org/protobuf/types/known/structpb"
|
"google.golang.org/protobuf/types/known/structpb"
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||||
|
|
||||||
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
const clientCredentialsToken = "Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOGJlZjc1LWRmY2QtNGE3My1hMzkxLTU0YTdhZjU3YTdkNiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsic3RhY2tpdC1yZXNvdXJjZS1tYW5hZ2VyLWRldiJdLCJjbGllbnRfaWQiOiJzdGFja2l0LXJlc291cmNlLW1hbmFnZXItZGV2IiwiZXhwIjoxNzI0NDA1MzI2LCJpYXQiOjE3MjQ0MDQ0MjYsImlzcyI6Imh0dHBzOi8vYWNjb3VudHMuZGV2LnN0YWNraXQuY2xvdWQiLCJqdGkiOiJlNDZlYmEzOC1kZWRiLTQ1NDEtOTRmMy00OWY5N2E5MzRkNTgiLCJuYmYiOjE3MjQ0MDQ0MjYsInNjb3BlIjoidWFhLm5vbmUiLCJzdWIiOiJzdGFja2l0LXJlc291cmNlLW1hbmFnZXItZGV2In0.JP5Uy7AMdK4ukzQ6aOYzbVwEmq0Tp2ppQGRqGOhuVQgbqs6yJ33GKXo7RPsJVLw3FR7XAxENIVqNvzGotbDXr0NjBGdzyxIHzrOaUqM4w1iLzD1KF51dXFwkoigqDdD7Ze9eI_Uo3tSn8FwGLTSoO-ONQYpnceCiGut2Gc6VIL8HOLdh8dzlRENGQtgYd-3Y5zqpoLrsR2Bd-0sv15sF-5aI0CqcC8gE70JPImKf2u_IYI-TYMDNk86YSCtaYO5-alOrHXXWwgzSoH-r2s5qoOhPbei9myV_P4fdcKXxMqfap9hImXPUooVhpdUr1AabZw3MtW7rION8tJAiauhMQA"
|
const clientCredentialsToken = "Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOGJlZjc1LWRmY2QtNGE3My1hMzkxLTU0YTdhZjU3YTdkNiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsic3RhY2tpdC1yZXNvdXJjZS1tYW5hZ2VyLWRldiJdLCJjbGllbnRfaWQiOiJzdGFja2l0LXJlc291cmNlLW1hbmFnZXItZGV2IiwiZXhwIjoxNzI0NDA1MzI2LCJpYXQiOjE3MjQ0MDQ0MjYsImlzcyI6Imh0dHBzOi8vYWNjb3VudHMuZGV2LnN0YWNraXQuY2xvdWQiLCJqdGkiOiJlNDZlYmEzOC1kZWRiLTQ1NDEtOTRmMy00OWY5N2E5MzRkNTgiLCJuYmYiOjE3MjQ0MDQ0MjYsInNjb3BlIjoidWFhLm5vbmUiLCJzdWIiOiJzdGFja2l0LXJlc291cmNlLW1hbmFnZXItZGV2In0.JP5Uy7AMdK4ukzQ6aOYzbVwEmq0Tp2ppQGRqGOhuVQgbqs6yJ33GKXo7RPsJVLw3FR7XAxENIVqNvzGotbDXr0NjBGdzyxIHzrOaUqM4w1iLzD1KF51dXFwkoigqDdD7Ze9eI_Uo3tSn8FwGLTSoO-ONQYpnceCiGut2Gc6VIL8HOLdh8dzlRENGQtgYd-3Y5zqpoLrsR2Bd-0sv15sF-5aI0CqcC8gE70JPImKf2u_IYI-TYMDNk86YSCtaYO5-alOrHXXWwgzSoH-r2s5qoOhPbei9myV_P4fdcKXxMqfap9hImXPUooVhpdUr1AabZw3MtW7rION8tJAiauhMQA"
|
||||||
|
const serviceAccountTokenUnderscoreSubject = "Bearer eyJraWQiOiJaVFJqWlRNek5tSmlNRGt3TldJMU5USTRZVGxpT1RjMllUWXlZVE16WldNIiwiYWxnIjoiUlM1MTIifQ.eyJzdWIiOiIxMGYzOGIwMV81MzRiXzQ3YmJfYTAzYV9lMjk0Y2EyYmU0ZGUiLCJhdWQiOlsic3RhY2tpdCIsImFwaSJdLCJzdGFja2l0L3NlcnZpY2VhY2NvdW50L3Rva2VuLnNvdXJjZSI6ImxlZ2FjeSIsInN0YWNraXQvc2VydmljZWFjY291bnQvbmFtZXNwYWNlIjoiYXBpIiwic3RhY2tpdC9wcm9qZWN0L3Byb2plY3QuaWQiOiJkYWNjNzgzMC04NDNlLTRjNWUtODZmZi1hYTBmYjUxZDYzNmYiLCJhenAiOiJjZDk0ZjAxYS1kZjJlLTQ0NTYtOTAyZS00OGY1ZTU3ZjBiNjMiLCJpc3MiOiJzdGFja2l0L3NlcnZpY2VhY2NvdW50Iiwic3RhY2tpdC9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiMTBmMzhiMDEtNTM0Yi00N2JiLWEwM2EtZTI5NGNhMmJlNGRlIiwiZXhwIjoxNzIyNjY5MzQzLCJpYXQiOjE3MjI1ODI5NDMsImVtYWlsIjoibXktc2VydmljZS15aWZjOWUxQHNhLnN0YWNraXQuY2xvdWQiLCJqdGkiOiI4NGMzMGE0Ni0xMDAxLTQzNmYtODU5Zi04OWMwYmExOWJlMWUifQ.bfD2TxfioqaKbqFJvnV_gq5zY_aoKVD2qzySMQjubaLQ5Vx_Tj95HU0q7gdNczNgcT0tBRyUp0pE4g4bwaPpB2MtYtUUunzpwG8sOX_OBchkorhcC4N50cdF5TR2pg0SMp3L6QBo3coHVbjHvaipshCj1NvyXYzARb4dSR0adrsIGnqy3IaScty1A2XQ7PN6SX_OVmxO5swpL0I-afKvCOffnChI3qmFAL5t6sFxm8PoaCWLIrkoxdtqxw5ZqsPPOJ0qDhssTuc3nE4JrQnzX8fZH5FiBVVHGT76KUNgPFd26UsVzbGqBXK20pn3pbIQHwbRiVOh6qanjr9kvHBXpQ"
|
||||||
const serviceAccountTokenRepeatedlyImpersonated = "Bearer eyJraWQiOiJaVFJqWlRNek5tSmlNRGt3TldJMU5USTRZVGxpT1RjMllUWXlZVE16WldNIiwiYWxnIjoiUlM1MTIifQ.eyJzdWIiOiIxNzM0YjRiNi0xZDVlLTQ4MTktOWI1MC0yOTkxN2ExYjlhZDUiLCJpc3MiOiJzdGFja2l0L3NlcnZpY2VhY2NvdW50IiwiYXVkIjpbInN0YWNraXQiLCJhcGkiXSwic3RhY2tpdC9zZXJ2aWNlYWNjb3VudC90b2tlbi5zb3VyY2UiOiJvYXV0aDIiLCJhY3QiOnsic3ViIjoiZjQ1MDA5YjItNjQzMy00M2MxLWI2YzctNjE4YzQ0MzU5ZTcxIiwiYWN0Ijp7InN1YiI6IjAyYWVmNTE2LTMxN2YtNGVjMS1hMWRmLTFhY2JkNGQ0OWZlMyJ9fSwic3RhY2tpdC9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJhcGkiLCJzdGFja2l0L3Byb2plY3QvcHJvamVjdC5pZCI6ImRhY2M3ODMwLTg0M2UtNGM1ZS04NmZmLWFhMGZiNTFkNjM2ZiIsImF6cCI6ImY0NTAwOWIyLTY0MzMtNDNjMS1iNmM3LTYxOGM0NDM1OWU3MSIsInN0YWNraXQvc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjE3MzRiNGI2LTFkNWUtNDgxOS05YjUwLTI5OTE3YTFiOWFkNSIsImV4cCI6MTcyNDA2Mjk2MywiaWF0IjoxNzI0MDU5MzYzLCJlbWFpbCI6InNlcnZpY2UtYWNjb3VudC0zLWZnaHN4dzFAc2Euc3RhY2tpdC5jbG91ZCIsImp0aSI6IjFmN2YxZWZjLTMzNDktNDExYS1hNWQ3LTIyNTVlMGE1YThhZSJ9.c1ae17bAtyOdmwXQbK37W-NTyOxo7iER5aHS_C0fU1qKl2BjOz708GLjH-_vxx9eKPeYznfI21_xlTaAvuG4Aco9f5YDK7fooTVHnDaOSSggqcEaDzDPrNXhhKEDxotJeq9zRMVCEStcbirjTounnLbuULRbO5GSY5jo-8n2UKxSZ2j5G_SjFHajdJwmzwvOttp08tdL8ck1uDdgVNBfcm0VIdb6WmgrCIUq5rmoa-cRPkdEurNtIEgEB_9U0Xh-SpmmsvFsWWeNIKz0e_5RCIyJonm_wMkGmblGegemkYL76ypeMNXTQsly1RozDIePfzHuZOWbySHSCd-vKQa2kw"
|
const serviceAccountTokenRepeatedlyImpersonated = "Bearer eyJraWQiOiJaVFJqWlRNek5tSmlNRGt3TldJMU5USTRZVGxpT1RjMllUWXlZVE16WldNIiwiYWxnIjoiUlM1MTIifQ.eyJzdWIiOiIxNzM0YjRiNi0xZDVlLTQ4MTktOWI1MC0yOTkxN2ExYjlhZDUiLCJpc3MiOiJzdGFja2l0L3NlcnZpY2VhY2NvdW50IiwiYXVkIjpbInN0YWNraXQiLCJhcGkiXSwic3RhY2tpdC9zZXJ2aWNlYWNjb3VudC90b2tlbi5zb3VyY2UiOiJvYXV0aDIiLCJhY3QiOnsic3ViIjoiZjQ1MDA5YjItNjQzMy00M2MxLWI2YzctNjE4YzQ0MzU5ZTcxIiwiYWN0Ijp7InN1YiI6IjAyYWVmNTE2LTMxN2YtNGVjMS1hMWRmLTFhY2JkNGQ0OWZlMyJ9fSwic3RhY2tpdC9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJhcGkiLCJzdGFja2l0L3Byb2plY3QvcHJvamVjdC5pZCI6ImRhY2M3ODMwLTg0M2UtNGM1ZS04NmZmLWFhMGZiNTFkNjM2ZiIsImF6cCI6ImY0NTAwOWIyLTY0MzMtNDNjMS1iNmM3LTYxOGM0NDM1OWU3MSIsInN0YWNraXQvc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjE3MzRiNGI2LTFkNWUtNDgxOS05YjUwLTI5OTE3YTFiOWFkNSIsImV4cCI6MTcyNDA2Mjk2MywiaWF0IjoxNzI0MDU5MzYzLCJlbWFpbCI6InNlcnZpY2UtYWNjb3VudC0zLWZnaHN4dzFAc2Euc3RhY2tpdC5jbG91ZCIsImp0aSI6IjFmN2YxZWZjLTMzNDktNDExYS1hNWQ3LTIyNTVlMGE1YThhZSJ9.c1ae17bAtyOdmwXQbK37W-NTyOxo7iER5aHS_C0fU1qKl2BjOz708GLjH-_vxx9eKPeYznfI21_xlTaAvuG4Aco9f5YDK7fooTVHnDaOSSggqcEaDzDPrNXhhKEDxotJeq9zRMVCEStcbirjTounnLbuULRbO5GSY5jo-8n2UKxSZ2j5G_SjFHajdJwmzwvOttp08tdL8ck1uDdgVNBfcm0VIdb6WmgrCIUq5rmoa-cRPkdEurNtIEgEB_9U0Xh-SpmmsvFsWWeNIKz0e_5RCIyJonm_wMkGmblGegemkYL76ypeMNXTQsly1RozDIePfzHuZOWbySHSCd-vKQa2kw"
|
||||||
const serviceAccountTokenImpersonated = "Bearer eyJraWQiOiJaVFJqWlRNek5tSmlNRGt3TldJMU5USTRZVGxpT1RjMllUWXlZVE16WldNIiwiYWxnIjoiUlM1MTIifQ.eyJzdWIiOiJmNDUwMDliMi02NDMzLTQzYzEtYjZjNy02MThjNDQzNTllNzEiLCJpc3MiOiJzdGFja2l0L3NlcnZpY2VhY2NvdW50IiwiYXVkIjpbInN0YWNraXQiLCJhcGkiXSwic3RhY2tpdC9zZXJ2aWNlYWNjb3VudC90b2tlbi5zb3VyY2UiOiJvYXV0aDIiLCJhY3QiOnsic3ViIjoiMDJhZWY1MTYtMzE3Zi00ZWMxLWExZGYtMWFjYmQ0ZDQ5ZmUzIn0sInN0YWNraXQvc2VydmljZWFjY291bnQvbmFtZXNwYWNlIjoiYXBpIiwic3RhY2tpdC9wcm9qZWN0L3Byb2plY3QuaWQiOiJkYWNjNzgzMC04NDNlLTRjNWUtODZmZi1hYTBmYjUxZDYzNmYiLCJhenAiOiIwMmFlZjUxNi0zMTdmLTRlYzEtYTFkZi0xYWNiZDRkNDlmZTMiLCJzdGFja2l0L3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJmNDUwMDliMi02NDMzLTQzYzEtYjZjNy02MThjNDQzNTllNzEiLCJleHAiOjE3MjQwNjI5MDcsImlhdCI6MTcyNDA1OTMwNywiZW1haWwiOiJzZXJ2aWNlLWFjY291bnQtMi10ajlzcnQxQHNhLnN0YWNraXQuY2xvdWQiLCJqdGkiOiIzNzU1NTE4My0wMWI5LTQyNzAtYmRjMS02OWI0ZmNmZDVlZTkifQ.auBvvsIesFMAlWOCPCPC77DrrHF7gSKZwKs_Zry5KFvu2bpZZC1BcSXOc8b9eh0SzANI9M9aGJBhOzOm39-ZZ5XOQ-6_y1aWuEenYQ6kT5D3GzCUTMDzSi1lcZ4IG5nFMa_AAlVEN_7AMv7LHGtz49bWLJnAgeTo1cvof-OgP4mCQ5O6E0iyAq-5u8V8NJL7HIZy7BDe4J1mjfYhwKagrN7QFWu4fhN4TNS7d922X_6V489BhjRFRYjLW_qDnv912JorbGRz_XwNy_dPA81EkdMyKE0BJUezguJUEKEG2_JEi9O64Flcoi6x8cFHYhaDuMMSLipzePaHdyk2lQtH7Q"
|
const serviceAccountTokenImpersonated = "Bearer eyJraWQiOiJaVFJqWlRNek5tSmlNRGt3TldJMU5USTRZVGxpT1RjMllUWXlZVE16WldNIiwiYWxnIjoiUlM1MTIifQ.eyJzdWIiOiJmNDUwMDliMi02NDMzLTQzYzEtYjZjNy02MThjNDQzNTllNzEiLCJpc3MiOiJzdGFja2l0L3NlcnZpY2VhY2NvdW50IiwiYXVkIjpbInN0YWNraXQiLCJhcGkiXSwic3RhY2tpdC9zZXJ2aWNlYWNjb3VudC90b2tlbi5zb3VyY2UiOiJvYXV0aDIiLCJhY3QiOnsic3ViIjoiMDJhZWY1MTYtMzE3Zi00ZWMxLWExZGYtMWFjYmQ0ZDQ5ZmUzIn0sInN0YWNraXQvc2VydmljZWFjY291bnQvbmFtZXNwYWNlIjoiYXBpIiwic3RhY2tpdC9wcm9qZWN0L3Byb2plY3QuaWQiOiJkYWNjNzgzMC04NDNlLTRjNWUtODZmZi1hYTBmYjUxZDYzNmYiLCJhenAiOiIwMmFlZjUxNi0zMTdmLTRlYzEtYTFkZi0xYWNiZDRkNDlmZTMiLCJzdGFja2l0L3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJmNDUwMDliMi02NDMzLTQzYzEtYjZjNy02MThjNDQzNTllNzEiLCJleHAiOjE3MjQwNjI5MDcsImlhdCI6MTcyNDA1OTMwNywiZW1haWwiOiJzZXJ2aWNlLWFjY291bnQtMi10ajlzcnQxQHNhLnN0YWNraXQuY2xvdWQiLCJqdGkiOiIzNzU1NTE4My0wMWI5LTQyNzAtYmRjMS02OWI0ZmNmZDVlZTkifQ.auBvvsIesFMAlWOCPCPC77DrrHF7gSKZwKs_Zry5KFvu2bpZZC1BcSXOc8b9eh0SzANI9M9aGJBhOzOm39-ZZ5XOQ-6_y1aWuEenYQ6kT5D3GzCUTMDzSi1lcZ4IG5nFMa_AAlVEN_7AMv7LHGtz49bWLJnAgeTo1cvof-OgP4mCQ5O6E0iyAq-5u8V8NJL7HIZy7BDe4J1mjfYhwKagrN7QFWu4fhN4TNS7d922X_6V489BhjRFRYjLW_qDnv912JorbGRz_XwNy_dPA81EkdMyKE0BJUezguJUEKEG2_JEi9O64Flcoi6x8cFHYhaDuMMSLipzePaHdyk2lQtH7Q"
|
||||||
const serviceAccountToken = "Bearer eyJraWQiOiJaVFJqWlRNek5tSmlNRGt3TldJMU5USTRZVGxpT1RjMllUWXlZVE16WldNIiwiYWxnIjoiUlM1MTIifQ.eyJzdWIiOiIxMGYzOGIwMS01MzRiLTQ3YmItYTAzYS1lMjk0Y2EyYmU0ZGUiLCJhdWQiOlsic3RhY2tpdCIsImFwaSJdLCJzdGFja2l0L3NlcnZpY2VhY2NvdW50L3Rva2VuLnNvdXJjZSI6ImxlZ2FjeSIsInN0YWNraXQvc2VydmljZWFjY291bnQvbmFtZXNwYWNlIjoiYXBpIiwic3RhY2tpdC9wcm9qZWN0L3Byb2plY3QuaWQiOiJkYWNjNzgzMC04NDNlLTRjNWUtODZmZi1hYTBmYjUxZDYzNmYiLCJhenAiOiJjZDk0ZjAxYS1kZjJlLTQ0NTYtOTAyZS00OGY1ZTU3ZjBiNjMiLCJpc3MiOiJzdGFja2l0L3NlcnZpY2VhY2NvdW50Iiwic3RhY2tpdC9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiMTBmMzhiMDEtNTM0Yi00N2JiLWEwM2EtZTI5NGNhMmJlNGRlIiwiZXhwIjoxNzIyNjY5MzQzLCJpYXQiOjE3MjI1ODI5NDMsImVtYWlsIjoibXktc2VydmljZS15aWZjOWUxQHNhLnN0YWNraXQuY2xvdWQiLCJqdGkiOiI4NGMzMGE0Ni0xMDAxLTQzNmYtODU5Zi04OWMwYmExOWJlMWUifQ.hb8X9VKc9xViHgNMyFHT9ePj_lyEwTV1D2es8E278WtoCJ9-4GPPQGjhcLGGrigjnvpRYV2LKzNqpQslerT5lFT_pHACsryaAE0ImYjmoe-nutA7BBpYuM_JN6pk5VIjVFLTqRKeIvFexPacqS2Vo3YoK1GvxPB8WPWBbGIsBtMl-PTm8OTwwzooBOoCRhhMR-E1lFbAymLsc1JI4yDQKLLomvhEopgmocCnQ-P1QkiKMqdkNxiD_YYLLYTOApg6d62BhqpH66ziqx493AStdZ8d5Kjvf3e1knDhaxVwNCghQj7lSo2kNAqZe__g2tiXpiZNTXBFJ_5HgQMLh67wng"
|
const serviceAccountToken = "Bearer eyJraWQiOiJaVFJqWlRNek5tSmlNRGt3TldJMU5USTRZVGxpT1RjMllUWXlZVE16WldNIiwiYWxnIjoiUlM1MTIifQ.eyJzdWIiOiIxMGYzOGIwMS01MzRiLTQ3YmItYTAzYS1lMjk0Y2EyYmU0ZGUiLCJhdWQiOlsic3RhY2tpdCIsImFwaSJdLCJzdGFja2l0L3NlcnZpY2VhY2NvdW50L3Rva2VuLnNvdXJjZSI6ImxlZ2FjeSIsInN0YWNraXQvc2VydmljZWFjY291bnQvbmFtZXNwYWNlIjoiYXBpIiwic3RhY2tpdC9wcm9qZWN0L3Byb2plY3QuaWQiOiJkYWNjNzgzMC04NDNlLTRjNWUtODZmZi1hYTBmYjUxZDYzNmYiLCJhenAiOiJjZDk0ZjAxYS1kZjJlLTQ0NTYtOTAyZS00OGY1ZTU3ZjBiNjMiLCJpc3MiOiJzdGFja2l0L3NlcnZpY2VhY2NvdW50Iiwic3RhY2tpdC9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiMTBmMzhiMDEtNTM0Yi00N2JiLWEwM2EtZTI5NGNhMmJlNGRlIiwiZXhwIjoxNzIyNjY5MzQzLCJpYXQiOjE3MjI1ODI5NDMsImVtYWlsIjoibXktc2VydmljZS15aWZjOWUxQHNhLnN0YWNraXQuY2xvdWQiLCJqdGkiOiI4NGMzMGE0Ni0xMDAxLTQzNmYtODU5Zi04OWMwYmExOWJlMWUifQ.hb8X9VKc9xViHgNMyFHT9ePj_lyEwTV1D2es8E278WtoCJ9-4GPPQGjhcLGGrigjnvpRYV2LKzNqpQslerT5lFT_pHACsryaAE0ImYjmoe-nutA7BBpYuM_JN6pk5VIjVFLTqRKeIvFexPacqS2Vo3YoK1GvxPB8WPWBbGIsBtMl-PTm8OTwwzooBOoCRhhMR-E1lFbAymLsc1JI4yDQKLLomvhEopgmocCnQ-P1QkiKMqdkNxiD_YYLLYTOApg6d62BhqpH66ziqx493AStdZ8d5Kjvf3e1knDhaxVwNCghQj7lSo2kNAqZe__g2tiXpiZNTXBFJ_5HgQMLh67wng"
|
||||||
|
|
@ -21,8 +22,9 @@ const userToken = "Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOGJlZjc1LWRmY2QtNGE3My
|
||||||
const userTokenWithSimpleAudience = "Bearer eyJhbGciOiJSUzUxMiIsImtpZCI6InNlcnZpY2UtYWNjb3VudC1mMDdiZjZhOC02MjA3LTRmOGItYjNlOS03M2VkMGJlYjg4ZjUiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJodHRwczovL3N0YWNraXQtc2VydmljZS1hY2NvdW50LWRldi5hcHBzLjAxLmNmLmV1MDEuc3RhY2tpdC5jbG91ZCIsImVtYWlsIjoiTHVrYXMuU2NobWl0dEBzdGFja2l0LmNsb3VkIiwiZXhwIjoxNzMyMTgyMDM1LCJpYXQiOjE3MzIxNzg0MzUsImlzcyI6Imh0dHBzOi8vYXBpLmRldi5zdGFja2l0LmNsb3VkIiwianRpIjoiYzJiZTE2NTEtMWU1NC00ZTZlLWJhYzMtZWYwNzJiM2YwMTQ5IiwibmJmIjoxNzMyMTc4NDE4LCJyb2xlcyI6bnVsbCwic2NvcGUiOiJvcGVuaWQgZW1haWwgcG9ydGFsLWJmZiIsInN1YiI6IjVlNDI2YWVkLWM0ODctNGM0OC1hZjI1LTg3ZjY5Y2Y5Y2RkNCIsInVzZXJfaWQiOiIiLCJ4X2NsaWVudF9pZCI6IiIsInppZCI6IiJ9.notavailable"
|
const userTokenWithSimpleAudience = "Bearer eyJhbGciOiJSUzUxMiIsImtpZCI6InNlcnZpY2UtYWNjb3VudC1mMDdiZjZhOC02MjA3LTRmOGItYjNlOS03M2VkMGJlYjg4ZjUiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJodHRwczovL3N0YWNraXQtc2VydmljZS1hY2NvdW50LWRldi5hcHBzLjAxLmNmLmV1MDEuc3RhY2tpdC5jbG91ZCIsImVtYWlsIjoiTHVrYXMuU2NobWl0dEBzdGFja2l0LmNsb3VkIiwiZXhwIjoxNzMyMTgyMDM1LCJpYXQiOjE3MzIxNzg0MzUsImlzcyI6Imh0dHBzOi8vYXBpLmRldi5zdGFja2l0LmNsb3VkIiwianRpIjoiYzJiZTE2NTEtMWU1NC00ZTZlLWJhYzMtZWYwNzJiM2YwMTQ5IiwibmJmIjoxNzMyMTc4NDE4LCJyb2xlcyI6bnVsbCwic2NvcGUiOiJvcGVuaWQgZW1haWwgcG9ydGFsLWJmZiIsInN1YiI6IjVlNDI2YWVkLWM0ODctNGM0OC1hZjI1LTg3ZjY5Y2Y5Y2RkNCIsInVzZXJfaWQiOiIiLCJ4X2NsaWVudF9pZCI6IiIsInppZCI6IiJ9.notavailable"
|
||||||
|
|
||||||
var TestHeaders = map[string][]string{"user-agent": {"custom"}, "authorization": {userToken}}
|
var TestHeaders = map[string][]string{"user-agent": {"custom"}, "authorization": {userToken}}
|
||||||
|
var TestHeadersSa = map[string][]string{"user-agent": {"custom"}, "authorization": {serviceAccountTokenUnderscoreSubject}}
|
||||||
|
|
||||||
func newOrganizationAuditEvent(
|
func NewOrganizationAuditEvent(
|
||||||
customization *func(
|
customization *func(
|
||||||
*auditV1.AuditLogEntry,
|
*auditV1.AuditLogEntry,
|
||||||
*auditV1.ObjectIdentifier,
|
*auditV1.ObjectIdentifier,
|
||||||
|
|
@ -41,20 +43,21 @@ func newOrganizationAuditEvent(
|
||||||
headers["Content-Type"] = "application/json"
|
headers["Content-Type"] = "application/json"
|
||||||
labels := make(map[string]string)
|
labels := make(map[string]string)
|
||||||
labels["label1"] = "value1"
|
labels["label1"] = "value1"
|
||||||
|
email := "user@example.com"
|
||||||
auditEvent := &auditV1.AuditLogEntry{
|
auditEvent := &auditV1.AuditLogEntry{
|
||||||
LogName: fmt.Sprintf("%s/%s/logs/%s", ObjectTypeOrganization.Plural(), identifier, EventTypeAdminActivity),
|
LogName: fmt.Sprintf("%s/%s/logs/%s", pkgAuditCommon.ObjectTypeOrganization.Plural(), identifier, pkgAuditCommon.EventTypeAdminActivity),
|
||||||
ProtoPayload: &auditV1.AuditLog{
|
ProtoPayload: &auditV1.AuditLog{
|
||||||
ServiceName: "resource-manager",
|
ServiceName: "resource-manager",
|
||||||
OperationName: "stackit.resourcemanager.v2.organization.created",
|
OperationName: "stackit.resourcemanager.v2.organization.created",
|
||||||
ResourceName: fmt.Sprintf("%s/%s", ObjectTypeOrganization.Plural(), identifier),
|
ResourceName: fmt.Sprintf("%s/%s", pkgAuditCommon.ObjectTypeOrganization.Plural(), identifier),
|
||||||
AuthenticationInfo: &auditV1.AuthenticationInfo{
|
AuthenticationInfo: &auditV1.AuthenticationInfo{
|
||||||
PrincipalId: uuid.NewString(),
|
PrincipalId: uuid.NewString(),
|
||||||
PrincipalEmail: "user@example.com",
|
PrincipalEmail: &email,
|
||||||
ServiceAccountName: nil,
|
ServiceAccountName: nil,
|
||||||
ServiceAccountDelegationInfo: nil,
|
ServiceAccountDelegationInfo: nil,
|
||||||
},
|
},
|
||||||
AuthorizationInfo: []*auditV1.AuthorizationInfo{{
|
AuthorizationInfo: []*auditV1.AuthorizationInfo{{
|
||||||
Resource: fmt.Sprintf("%s/%s", ObjectTypeOrganization.Plural(), identifier),
|
Resource: fmt.Sprintf("%s/%s", pkgAuditCommon.ObjectTypeOrganization.Plural(), identifier),
|
||||||
Permission: &permission,
|
Permission: &permission,
|
||||||
Granted: &permissionGranted,
|
Granted: &permissionGranted,
|
||||||
}},
|
}},
|
||||||
|
|
@ -102,7 +105,7 @@ func newOrganizationAuditEvent(
|
||||||
|
|
||||||
objectIdentifier := &auditV1.ObjectIdentifier{
|
objectIdentifier := &auditV1.ObjectIdentifier{
|
||||||
Identifier: identifier.String(),
|
Identifier: identifier.String(),
|
||||||
Type: string(ObjectTypeOrganization),
|
Type: string(pkgAuditCommon.ObjectTypeOrganization),
|
||||||
}
|
}
|
||||||
|
|
||||||
if customization != nil {
|
if customization != nil {
|
||||||
|
|
@ -112,7 +115,7 @@ func newOrganizationAuditEvent(
|
||||||
return auditEvent, objectIdentifier
|
return auditEvent, objectIdentifier
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFolderAuditEvent(
|
func NewFolderAuditEvent(
|
||||||
customization *func(
|
customization *func(
|
||||||
*auditV1.AuditLogEntry,
|
*auditV1.AuditLogEntry,
|
||||||
*auditV1.ObjectIdentifier,
|
*auditV1.ObjectIdentifier,
|
||||||
|
|
@ -131,20 +134,21 @@ func newFolderAuditEvent(
|
||||||
headers["Content-Type"] = "application/json"
|
headers["Content-Type"] = "application/json"
|
||||||
labels := make(map[string]string)
|
labels := make(map[string]string)
|
||||||
labels["label1"] = "value1"
|
labels["label1"] = "value1"
|
||||||
|
email := "user@example.com"
|
||||||
auditEvent := &auditV1.AuditLogEntry{
|
auditEvent := &auditV1.AuditLogEntry{
|
||||||
LogName: fmt.Sprintf("%s/%s/logs/%s", ObjectTypeFolder.Plural(), identifier, EventTypeAdminActivity),
|
LogName: fmt.Sprintf("%s/%s/logs/%s", pkgAuditCommon.ObjectTypeFolder.Plural(), identifier, pkgAuditCommon.EventTypeAdminActivity),
|
||||||
ProtoPayload: &auditV1.AuditLog{
|
ProtoPayload: &auditV1.AuditLog{
|
||||||
ServiceName: "resource-manager",
|
ServiceName: "resource-manager",
|
||||||
OperationName: "stackit.resourcemanager.v2.folder.created",
|
OperationName: "stackit.resourcemanager.v2.folder.created",
|
||||||
ResourceName: fmt.Sprintf("%s/%s", ObjectTypeFolder.Plural(), identifier),
|
ResourceName: fmt.Sprintf("%s/%s", pkgAuditCommon.ObjectTypeFolder.Plural(), identifier),
|
||||||
AuthenticationInfo: &auditV1.AuthenticationInfo{
|
AuthenticationInfo: &auditV1.AuthenticationInfo{
|
||||||
PrincipalId: uuid.NewString(),
|
PrincipalId: uuid.NewString(),
|
||||||
PrincipalEmail: "user@example.com",
|
PrincipalEmail: &email,
|
||||||
ServiceAccountName: nil,
|
ServiceAccountName: nil,
|
||||||
ServiceAccountDelegationInfo: nil,
|
ServiceAccountDelegationInfo: nil,
|
||||||
},
|
},
|
||||||
AuthorizationInfo: []*auditV1.AuthorizationInfo{{
|
AuthorizationInfo: []*auditV1.AuthorizationInfo{{
|
||||||
Resource: fmt.Sprintf("%s/%s", ObjectTypeFolder.Plural(), identifier),
|
Resource: fmt.Sprintf("%s/%s", pkgAuditCommon.ObjectTypeFolder.Plural(), identifier),
|
||||||
Permission: &permission,
|
Permission: &permission,
|
||||||
Granted: &permissionGranted,
|
Granted: &permissionGranted,
|
||||||
}},
|
}},
|
||||||
|
|
@ -192,7 +196,7 @@ func newFolderAuditEvent(
|
||||||
|
|
||||||
objectIdentifier := &auditV1.ObjectIdentifier{
|
objectIdentifier := &auditV1.ObjectIdentifier{
|
||||||
Identifier: identifier.String(),
|
Identifier: identifier.String(),
|
||||||
Type: string(ObjectTypeFolder),
|
Type: string(pkgAuditCommon.ObjectTypeFolder),
|
||||||
}
|
}
|
||||||
|
|
||||||
if customization != nil {
|
if customization != nil {
|
||||||
|
|
@ -202,7 +206,7 @@ func newFolderAuditEvent(
|
||||||
return auditEvent, objectIdentifier
|
return auditEvent, objectIdentifier
|
||||||
}
|
}
|
||||||
|
|
||||||
func newProjectAuditEvent(
|
func NewProjectAuditEvent(
|
||||||
customization *func(
|
customization *func(
|
||||||
*auditV1.AuditLogEntry,
|
*auditV1.AuditLogEntry,
|
||||||
*auditV1.ObjectIdentifier,
|
*auditV1.ObjectIdentifier,
|
||||||
|
|
@ -221,20 +225,21 @@ func newProjectAuditEvent(
|
||||||
headers["Content-Type"] = "application/json"
|
headers["Content-Type"] = "application/json"
|
||||||
labels := make(map[string]string)
|
labels := make(map[string]string)
|
||||||
labels["label1"] = "value1"
|
labels["label1"] = "value1"
|
||||||
|
email := "user@example.com"
|
||||||
auditEvent := &auditV1.AuditLogEntry{
|
auditEvent := &auditV1.AuditLogEntry{
|
||||||
LogName: fmt.Sprintf("%s/%s/logs/%s", ObjectTypeProject.Plural(), identifier, EventTypeAdminActivity),
|
LogName: fmt.Sprintf("%s/%s/logs/%s", pkgAuditCommon.ObjectTypeProject.Plural(), identifier, pkgAuditCommon.EventTypeAdminActivity),
|
||||||
ProtoPayload: &auditV1.AuditLog{
|
ProtoPayload: &auditV1.AuditLog{
|
||||||
ServiceName: "resource-manager",
|
ServiceName: "resource-manager",
|
||||||
OperationName: "stackit.resourcemanager.v2.project.created",
|
OperationName: "stackit.resourcemanager.v2.project.created",
|
||||||
ResourceName: fmt.Sprintf("%s/%s", ObjectTypeProject.Plural(), identifier),
|
ResourceName: fmt.Sprintf("%s/%s", pkgAuditCommon.ObjectTypeProject.Plural(), identifier),
|
||||||
AuthenticationInfo: &auditV1.AuthenticationInfo{
|
AuthenticationInfo: &auditV1.AuthenticationInfo{
|
||||||
PrincipalId: uuid.NewString(),
|
PrincipalId: uuid.NewString(),
|
||||||
PrincipalEmail: "user@example.com",
|
PrincipalEmail: &email,
|
||||||
ServiceAccountName: nil,
|
ServiceAccountName: nil,
|
||||||
ServiceAccountDelegationInfo: nil,
|
ServiceAccountDelegationInfo: nil,
|
||||||
},
|
},
|
||||||
AuthorizationInfo: []*auditV1.AuthorizationInfo{{
|
AuthorizationInfo: []*auditV1.AuthorizationInfo{{
|
||||||
Resource: fmt.Sprintf("%s/%s", ObjectTypeProject.Plural(), identifier),
|
Resource: fmt.Sprintf("%s/%s", pkgAuditCommon.ObjectTypeProject.Plural(), identifier),
|
||||||
Permission: &permission,
|
Permission: &permission,
|
||||||
Granted: &permissionGranted,
|
Granted: &permissionGranted,
|
||||||
}},
|
}},
|
||||||
|
|
@ -282,7 +287,7 @@ func newProjectAuditEvent(
|
||||||
|
|
||||||
objectIdentifier := &auditV1.ObjectIdentifier{
|
objectIdentifier := &auditV1.ObjectIdentifier{
|
||||||
Identifier: identifier.String(),
|
Identifier: identifier.String(),
|
||||||
Type: string(ObjectTypeProject),
|
Type: string(pkgAuditCommon.ObjectTypeProject),
|
||||||
}
|
}
|
||||||
|
|
||||||
if customization != nil {
|
if customization != nil {
|
||||||
|
|
@ -292,7 +297,7 @@ func newProjectAuditEvent(
|
||||||
return auditEvent, objectIdentifier
|
return auditEvent, objectIdentifier
|
||||||
}
|
}
|
||||||
|
|
||||||
func newProjectSystemAuditEvent(
|
func NewProjectSystemAuditEvent(
|
||||||
customization *func(*auditV1.AuditLogEntry)) *auditV1.AuditLogEntry {
|
customization *func(*auditV1.AuditLogEntry)) *auditV1.AuditLogEntry {
|
||||||
|
|
||||||
identifier := uuid.New()
|
identifier := uuid.New()
|
||||||
|
|
@ -306,20 +311,21 @@ func newProjectSystemAuditEvent(
|
||||||
serviceAccountId := uuid.NewString()
|
serviceAccountId := uuid.NewString()
|
||||||
serviceAccountName := fmt.Sprintf("projects/%s/service-accounts/%s", identifier, serviceAccountId)
|
serviceAccountName := fmt.Sprintf("projects/%s/service-accounts/%s", identifier, serviceAccountId)
|
||||||
delegationPrincipal := auditV1.ServiceAccountDelegationInfo{Authority: &auditV1.ServiceAccountDelegationInfo_SystemPrincipal_{}}
|
delegationPrincipal := auditV1.ServiceAccountDelegationInfo{Authority: &auditV1.ServiceAccountDelegationInfo_SystemPrincipal_{}}
|
||||||
|
email := "service-account@sa.stackit.cloud"
|
||||||
auditEvent := &auditV1.AuditLogEntry{
|
auditEvent := &auditV1.AuditLogEntry{
|
||||||
LogName: fmt.Sprintf("%s/%s/logs/%s", SystemIdentifier.Type, SystemIdentifier.Identifier, EventTypeSystemEvent),
|
LogName: fmt.Sprintf("%s/%s/logs/%s", pkgAuditCommon.SystemIdentifier.Type, pkgAuditCommon.SystemIdentifier.Identifier, pkgAuditCommon.EventTypeSystemEvent),
|
||||||
ProtoPayload: &auditV1.AuditLog{
|
ProtoPayload: &auditV1.AuditLog{
|
||||||
ServiceName: "resource-manager",
|
ServiceName: "resource-manager",
|
||||||
OperationName: "stackit.resourcemanager.v2.system.changed",
|
OperationName: "stackit.resourcemanager.v2.system.changed",
|
||||||
ResourceName: fmt.Sprintf("%s/%s", ObjectTypeProject.Plural(), identifier),
|
ResourceName: fmt.Sprintf("%s/%s", pkgAuditCommon.ObjectTypeProject.Plural(), identifier),
|
||||||
AuthenticationInfo: &auditV1.AuthenticationInfo{
|
AuthenticationInfo: &auditV1.AuthenticationInfo{
|
||||||
PrincipalId: serviceAccountId,
|
PrincipalId: serviceAccountId,
|
||||||
PrincipalEmail: "service-account@sa.stackit.cloud",
|
PrincipalEmail: &email,
|
||||||
ServiceAccountName: &serviceAccountName,
|
ServiceAccountName: &serviceAccountName,
|
||||||
ServiceAccountDelegationInfo: []*auditV1.ServiceAccountDelegationInfo{&delegationPrincipal},
|
ServiceAccountDelegationInfo: []*auditV1.ServiceAccountDelegationInfo{&delegationPrincipal},
|
||||||
},
|
},
|
||||||
AuthorizationInfo: []*auditV1.AuthorizationInfo{{
|
AuthorizationInfo: []*auditV1.AuthorizationInfo{{
|
||||||
Resource: fmt.Sprintf("%s/%s", ObjectTypeProject.Plural(), identifier),
|
Resource: fmt.Sprintf("%s/%s", pkgAuditCommon.ObjectTypeProject.Plural(), identifier),
|
||||||
Permission: nil,
|
Permission: nil,
|
||||||
Granted: nil,
|
Granted: nil,
|
||||||
}},
|
}},
|
||||||
|
|
@ -372,7 +378,7 @@ func newProjectSystemAuditEvent(
|
||||||
return auditEvent
|
return auditEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSystemAuditEvent(
|
func NewSystemAuditEvent(
|
||||||
customization *func(*auditV1.AuditLogEntry)) *auditV1.AuditLogEntry {
|
customization *func(*auditV1.AuditLogEntry)) *auditV1.AuditLogEntry {
|
||||||
|
|
||||||
identifier := uuid.Nil
|
identifier := uuid.Nil
|
||||||
|
|
@ -386,20 +392,21 @@ func newSystemAuditEvent(
|
||||||
serviceAccountId := uuid.NewString()
|
serviceAccountId := uuid.NewString()
|
||||||
serviceAccountName := fmt.Sprintf("projects/%s/service-accounts/%s", identifier, serviceAccountId)
|
serviceAccountName := fmt.Sprintf("projects/%s/service-accounts/%s", identifier, serviceAccountId)
|
||||||
delegationPrincipal := auditV1.ServiceAccountDelegationInfo{Authority: &auditV1.ServiceAccountDelegationInfo_SystemPrincipal_{}}
|
delegationPrincipal := auditV1.ServiceAccountDelegationInfo{Authority: &auditV1.ServiceAccountDelegationInfo_SystemPrincipal_{}}
|
||||||
|
email := "service-account@sa.stackit.cloud"
|
||||||
auditEvent := &auditV1.AuditLogEntry{
|
auditEvent := &auditV1.AuditLogEntry{
|
||||||
LogName: fmt.Sprintf("%s/%s/logs/%s", ObjectTypeSystem.Plural(), identifier, EventTypeSystemEvent),
|
LogName: fmt.Sprintf("%s/%s/logs/%s", pkgAuditCommon.ObjectTypeSystem.Plural(), identifier, pkgAuditCommon.EventTypeSystemEvent),
|
||||||
ProtoPayload: &auditV1.AuditLog{
|
ProtoPayload: &auditV1.AuditLog{
|
||||||
ServiceName: "resource-manager",
|
ServiceName: "resource-manager",
|
||||||
OperationName: "stackit.resourcemanager.v2.system.changed",
|
OperationName: "stackit.resourcemanager.v2.system.changed",
|
||||||
ResourceName: fmt.Sprintf("%s/%s", ObjectTypeSystem.Plural(), identifier),
|
ResourceName: fmt.Sprintf("%s/%s", pkgAuditCommon.ObjectTypeSystem.Plural(), identifier),
|
||||||
AuthenticationInfo: &auditV1.AuthenticationInfo{
|
AuthenticationInfo: &auditV1.AuthenticationInfo{
|
||||||
PrincipalId: serviceAccountId,
|
PrincipalId: serviceAccountId,
|
||||||
PrincipalEmail: "service-account@sa.stackit.cloud",
|
PrincipalEmail: &email,
|
||||||
ServiceAccountName: &serviceAccountName,
|
ServiceAccountName: &serviceAccountName,
|
||||||
ServiceAccountDelegationInfo: []*auditV1.ServiceAccountDelegationInfo{&delegationPrincipal},
|
ServiceAccountDelegationInfo: []*auditV1.ServiceAccountDelegationInfo{&delegationPrincipal},
|
||||||
},
|
},
|
||||||
AuthorizationInfo: []*auditV1.AuthorizationInfo{{
|
AuthorizationInfo: []*auditV1.AuthorizationInfo{{
|
||||||
Resource: fmt.Sprintf("%s/%s", ObjectTypeSystem.Plural(), identifier),
|
Resource: fmt.Sprintf("%s/%s", pkgAuditCommon.ObjectTypeSystem.Plural(), identifier),
|
||||||
Permission: nil,
|
Permission: nil,
|
||||||
Granted: nil,
|
Granted: nil,
|
||||||
}},
|
}},
|
||||||
|
|
@ -2,6 +2,7 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"go.opentelemetry.io/otel/propagation"
|
"go.opentelemetry.io/otel/propagation"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -24,7 +25,7 @@ func TraceParentAndStateFromContext(ctx context.Context) (string, string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddTraceParentAndStateToContext adds trace and state related information to the given context.
|
// AddTraceParentAndStateToContext adds trace and state related information to the given context.
|
||||||
func AddTraceParentAndStateToContext(ctx context.Context, traceParent string, traceState string) context.Context {
|
func AddTraceParentAndStateToContext(ctx context.Context, traceParent, traceState string) context.Context {
|
||||||
mapCarrier := propagation.MapCarrier{}
|
mapCarrier := propagation.MapCarrier{}
|
||||||
mapCarrier[traceParentHeader] = traceParent
|
mapCarrier[traceParentHeader] = traceParent
|
||||||
mapCarrier[traceStateHeader] = traceState
|
mapCarrier[traceStateHeader] = traceState
|
||||||
|
|
@ -2,10 +2,11 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"go.opentelemetry.io/otel"
|
"go.opentelemetry.io/otel"
|
||||||
"go.opentelemetry.io/otel/trace"
|
"go.opentelemetry.io/otel/trace"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_AddTraceParentAndStateToContext(t *testing.T) {
|
func Test_AddTraceParentAndStateToContext(t *testing.T) {
|
||||||
|
|
@ -4,43 +4,48 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Azure/go-amqp"
|
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/Azure/go-amqp"
|
||||||
|
|
||||||
|
pkgCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ConnectionClosedError = errors.New("amqp connection is closed")
|
const connectionTimeoutSeconds = 10
|
||||||
|
|
||||||
|
var ErrConnectionClosed = errors.New("amqp connection is closed")
|
||||||
|
|
||||||
type AmqpConnection struct {
|
type AmqpConnection struct {
|
||||||
connectionName string
|
ConnectionName string
|
||||||
lock sync.RWMutex
|
Lock sync.RWMutex
|
||||||
brokerUrl string
|
BrokerUrl string
|
||||||
username string
|
Username string
|
||||||
password string
|
Password string
|
||||||
conn amqpConn
|
Conn AmqpConn
|
||||||
dialer amqpDial
|
Dialer amqpDial
|
||||||
}
|
}
|
||||||
|
|
||||||
// amqpConn is an abstraction of amqp.Conn
|
// AmqpConn is an abstraction of amqp.Conn
|
||||||
type amqpConn interface {
|
type AmqpConn interface {
|
||||||
NewSession(ctx context.Context, opts *amqp.SessionOptions) (amqpSession, error)
|
NewSession(ctx context.Context, opts *amqp.SessionOptions) (AmqpSession, error)
|
||||||
Close() error
|
Close() error
|
||||||
Done() <-chan struct{}
|
Done() <-chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type defaultAmqpConn struct {
|
type defaultAmqpConn struct {
|
||||||
conn *amqp.Conn
|
Conn *amqp.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDefaultAmqpConn(conn *amqp.Conn) *defaultAmqpConn {
|
func newDefaultAmqpConn(conn *amqp.Conn) *defaultAmqpConn {
|
||||||
return &defaultAmqpConn{
|
return &defaultAmqpConn{
|
||||||
conn: conn,
|
Conn: conn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d defaultAmqpConn) NewSession(ctx context.Context, opts *amqp.SessionOptions) (amqpSession, error) {
|
func (d defaultAmqpConn) NewSession(ctx context.Context, opts *amqp.SessionOptions) (AmqpSession, error) {
|
||||||
session, err := d.conn.NewSession(ctx, opts)
|
session, err := d.Conn.NewSession(ctx, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -48,47 +53,47 @@ func (d defaultAmqpConn) NewSession(ctx context.Context, opts *amqp.SessionOptio
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d defaultAmqpConn) Close() error {
|
func (d defaultAmqpConn) Close() error {
|
||||||
return d.conn.Close()
|
return d.Conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d defaultAmqpConn) Done() <-chan struct{} {
|
func (d defaultAmqpConn) Done() <-chan struct{} {
|
||||||
return d.conn.Done()
|
return d.Conn.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ amqpConn = (*defaultAmqpConn)(nil)
|
var _ AmqpConn = (*defaultAmqpConn)(nil)
|
||||||
|
|
||||||
type amqpDial interface {
|
type amqpDial interface {
|
||||||
Dial(ctx context.Context, addr string, opts *amqp.ConnOptions) (amqpConn, error)
|
Dial(ctx context.Context, addr string, opts *amqp.ConnOptions) (AmqpConn, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type amqpSession interface {
|
type AmqpSession interface {
|
||||||
NewSender(ctx context.Context, target string, opts *amqp.SenderOptions) (amqpSender, error)
|
NewSender(ctx context.Context, target string, opts *amqp.SenderOptions) (AmqpSender, error)
|
||||||
Close(ctx context.Context) error
|
Close(ctx context.Context) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type defaultAmqpSession struct {
|
type defaultAmqpSession struct {
|
||||||
session *amqp.Session
|
Session *amqp.Session
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDefaultAmqpSession(session *amqp.Session) *defaultAmqpSession {
|
func newDefaultAmqpSession(session *amqp.Session) *defaultAmqpSession {
|
||||||
return &defaultAmqpSession{
|
return &defaultAmqpSession{
|
||||||
session: session,
|
Session: session,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *defaultAmqpSession) NewSender(ctx context.Context, target string, opts *amqp.SenderOptions) (amqpSender, error) {
|
func (s *defaultAmqpSession) NewSender(ctx context.Context, target string, opts *amqp.SenderOptions) (AmqpSender, error) {
|
||||||
return s.session.NewSender(ctx, target, opts)
|
return s.Session.NewSender(ctx, target, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *defaultAmqpSession) Close(ctx context.Context) error {
|
func (s *defaultAmqpSession) Close(ctx context.Context) error {
|
||||||
return s.session.Close(ctx)
|
return s.Session.Close(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ amqpSession = (*defaultAmqpSession)(nil)
|
var _ AmqpSession = (*defaultAmqpSession)(nil)
|
||||||
|
|
||||||
type defaultAmqpDialer struct{}
|
type defaultAmqpDialer struct{}
|
||||||
|
|
||||||
func (d *defaultAmqpDialer) Dial(ctx context.Context, addr string, opts *amqp.ConnOptions) (amqpConn, error) {
|
func (d *defaultAmqpDialer) Dial(ctx context.Context, addr string, opts *amqp.ConnOptions) (AmqpConn, error) {
|
||||||
dial, err := amqp.Dial(ctx, addr, opts)
|
dial, err := amqp.Dial(ctx, addr, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -98,31 +103,31 @@ func (d *defaultAmqpDialer) Dial(ctx context.Context, addr string, opts *amqp.Co
|
||||||
|
|
||||||
var _ amqpDial = (*defaultAmqpDialer)(nil)
|
var _ amqpDial = (*defaultAmqpDialer)(nil)
|
||||||
|
|
||||||
func NewAmqpConnection(config AmqpConnectionConfig, connectionName string) *AmqpConnection {
|
func NewAmqpConnection(config pkgCommon.AmqpConnectionConfig, connectionName string) *AmqpConnection {
|
||||||
return &AmqpConnection{
|
return &AmqpConnection{
|
||||||
connectionName: connectionName,
|
ConnectionName: connectionName,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
brokerUrl: config.BrokerUrl,
|
BrokerUrl: config.BrokerUrl,
|
||||||
username: config.Username,
|
Username: config.Username,
|
||||||
password: config.Password,
|
Password: config.Password,
|
||||||
dialer: &defaultAmqpDialer{},
|
Dialer: &defaultAmqpDialer{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AmqpConnection) NewSender(ctx context.Context, topic string) (*AmqpSenderSession, error) {
|
func (c *AmqpConnection) NewSender(ctx context.Context, topic string) (*AmqpSenderSession, error) {
|
||||||
if c.conn == nil {
|
if c.Conn == nil {
|
||||||
return nil, errors.New("connection is not initialized")
|
return nil, errors.New("connection is not initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.internalIsClosed() {
|
if c.internalIsClosed() {
|
||||||
return nil, ConnectionClosedError
|
return nil, ErrConnectionClosed
|
||||||
}
|
}
|
||||||
|
|
||||||
c.lock.RLock()
|
c.Lock.RLock()
|
||||||
defer c.lock.RUnlock()
|
defer c.Lock.RUnlock()
|
||||||
|
|
||||||
// new session
|
// new session
|
||||||
newSession, err := c.conn.NewSession(ctx, nil)
|
newSession, err := c.Conn.NewSession(ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("new session: %w", err)
|
return nil, fmt.Errorf("new session: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -157,8 +162,8 @@ func As[T any](value any, err error) (*T, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AmqpConnection) Connect() error {
|
func (c *AmqpConnection) Connect() error {
|
||||||
c.lock.Lock()
|
c.Lock.Lock()
|
||||||
defer c.lock.Unlock()
|
defer c.Lock.Unlock()
|
||||||
|
|
||||||
subCtx, cancel := context.WithTimeout(context.Background(), connectionTimeoutSeconds*time.Second)
|
subCtx, cancel := context.WithTimeout(context.Background(), connectionTimeoutSeconds*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
@ -170,11 +175,11 @@ func (c *AmqpConnection) Connect() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AmqpConnection) internalConnect(ctx context.Context) error {
|
func (c *AmqpConnection) internalConnect(ctx context.Context) error {
|
||||||
if c.conn == nil {
|
if c.Conn == nil {
|
||||||
// Set credentials if specified
|
// Set credentials if specified
|
||||||
auth := amqp.SASLTypeAnonymous()
|
auth := amqp.SASLTypeAnonymous()
|
||||||
if c.username != "" && c.password != "" {
|
if c.Username != "" && c.Password != "" {
|
||||||
auth = amqp.SASLTypePlain(c.username, c.password)
|
auth = amqp.SASLTypePlain(c.Username, c.Password)
|
||||||
} else {
|
} else {
|
||||||
slog.Debug("amqp connection: connect: using anonymous messaging")
|
slog.Debug("amqp connection: connect: using anonymous messaging")
|
||||||
}
|
}
|
||||||
|
|
@ -183,18 +188,18 @@ func (c *AmqpConnection) internalConnect(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize connection
|
// Initialize connection
|
||||||
conn, err := c.dialer.Dial(ctx, c.brokerUrl, options)
|
conn, err := c.Dialer.Dial(ctx, c.BrokerUrl, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("dial: %w", err)
|
return fmt.Errorf("dial: %w", err)
|
||||||
}
|
}
|
||||||
c.conn = conn
|
c.Conn = conn
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AmqpConnection) Close() error {
|
func (c *AmqpConnection) Close() error {
|
||||||
c.lock.Lock()
|
c.Lock.Lock()
|
||||||
defer c.lock.Unlock()
|
defer c.Lock.Unlock()
|
||||||
|
|
||||||
if err := c.internalClose(); err != nil {
|
if err := c.internalClose(); err != nil {
|
||||||
return fmt.Errorf("internal close: %w", err)
|
return fmt.Errorf("internal close: %w", err)
|
||||||
|
|
@ -203,28 +208,28 @@ func (c *AmqpConnection) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AmqpConnection) internalClose() error {
|
func (c *AmqpConnection) internalClose() error {
|
||||||
if c.conn != nil {
|
if c.Conn != nil {
|
||||||
if err := c.conn.Close(); err != nil {
|
if err := c.Conn.Close(); err != nil {
|
||||||
return fmt.Errorf("connection close: %w", err)
|
return fmt.Errorf("connection close: %w", err)
|
||||||
}
|
}
|
||||||
c.conn = nil
|
c.Conn = nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AmqpConnection) IsClosed() bool {
|
func (c *AmqpConnection) IsClosed() bool {
|
||||||
c.lock.RLock()
|
c.Lock.RLock()
|
||||||
defer c.lock.RUnlock()
|
defer c.Lock.RUnlock()
|
||||||
|
|
||||||
return c.internalIsClosed()
|
return c.internalIsClosed()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AmqpConnection) internalIsClosed() bool {
|
func (c *AmqpConnection) internalIsClosed() bool {
|
||||||
if c.conn == nil {
|
if c.Conn == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case <-c.conn.Done():
|
case <-c.Conn.Done():
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
|
|
@ -5,15 +5,17 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
pkgCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
type connectionProvider interface {
|
type connectionProvider interface {
|
||||||
NewAmqpConnection(config AmqpConnectionConfig, connectionName string) *AmqpConnection
|
NewAmqpConnection(config pkgCommon.AmqpConnectionConfig, connectionName string) *AmqpConnection
|
||||||
}
|
}
|
||||||
|
|
||||||
type defaultAmqpConnectionProvider struct{}
|
type defaultAmqpConnectionProvider struct{}
|
||||||
|
|
||||||
func (p defaultAmqpConnectionProvider) NewAmqpConnection(config AmqpConnectionConfig, connectionName string) *AmqpConnection {
|
func (p defaultAmqpConnectionProvider) NewAmqpConnection(config pkgCommon.AmqpConnectionConfig, connectionName string) *AmqpConnection {
|
||||||
return NewAmqpConnection(config, connectionName)
|
return NewAmqpConnection(config, connectionName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -26,26 +28,37 @@ type ConnectionPool interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type AmqpConnectionPool struct {
|
type AmqpConnectionPool struct {
|
||||||
config AmqpConnectionPoolConfig
|
Config pkgCommon.AmqpConnectionPoolConfig
|
||||||
connectionName string
|
ConnectionName string
|
||||||
connections []*AmqpConnection
|
Connections []*AmqpConnection
|
||||||
connectionProvider connectionProvider
|
ConnectionProvider connectionProvider
|
||||||
handleOffset int
|
HandleOffset int
|
||||||
lock sync.RWMutex
|
Lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConnectionPoolHandle struct {
|
type ConnectionPoolHandle struct {
|
||||||
connectionOffset int
|
ConnectionOffset int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAmqpConnectionPool(config AmqpConnectionPoolConfig, connectionName string) (ConnectionPool, error) {
|
func NewDefaultAmqpConnectionPool(config pkgCommon.AmqpConnectionConfig, connectionName string) (ConnectionPool, error) {
|
||||||
|
poolConfig := pkgCommon.AmqpConnectionPoolConfig{
|
||||||
|
Parameters: config,
|
||||||
|
PoolSize: 2,
|
||||||
|
}
|
||||||
|
return NewAmqpConnectionPool(poolConfig, connectionName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAmqpConnectionPool(config pkgCommon.AmqpConnectionPoolConfig, connectionName string) (ConnectionPool, error) {
|
||||||
|
if config.PoolSize == 0 {
|
||||||
|
config.PoolSize = 2
|
||||||
|
}
|
||||||
pool := &AmqpConnectionPool{
|
pool := &AmqpConnectionPool{
|
||||||
config: config,
|
Config: config,
|
||||||
connectionName: connectionName,
|
ConnectionName: connectionName,
|
||||||
connections: make([]*AmqpConnection, 0),
|
Connections: make([]*AmqpConnection, 0),
|
||||||
connectionProvider: defaultAmqpConnectionProvider{},
|
ConnectionProvider: defaultAmqpConnectionProvider{},
|
||||||
handleOffset: 0,
|
HandleOffset: 0,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := pool.initializeConnections(); err != nil {
|
if err := pool.initializeConnections(); err != nil {
|
||||||
|
|
@ -59,11 +72,11 @@ func NewAmqpConnectionPool(config AmqpConnectionPoolConfig, connectionName strin
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *AmqpConnectionPool) initializeConnections() error {
|
func (p *AmqpConnectionPool) initializeConnections() error {
|
||||||
if len(p.connections) < p.config.PoolSize {
|
if len(p.Connections) < p.Config.PoolSize {
|
||||||
p.lock.Lock()
|
p.Lock.Lock()
|
||||||
defer p.lock.Unlock()
|
defer p.Lock.Unlock()
|
||||||
|
|
||||||
numMissingConnections := p.config.PoolSize - len(p.connections)
|
numMissingConnections := p.Config.PoolSize - len(p.Connections)
|
||||||
|
|
||||||
for i := 0; i < numMissingConnections; i++ {
|
for i := 0; i < numMissingConnections; i++ {
|
||||||
if err := p.internalAddConnection(); err != nil {
|
if err := p.internalAddConnection(); err != nil {
|
||||||
|
|
@ -79,12 +92,12 @@ func (p *AmqpConnectionPool) internalAddConnection() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("new connection: %w", err)
|
return fmt.Errorf("new connection: %w", err)
|
||||||
}
|
}
|
||||||
p.connections = append(p.connections, newConnection)
|
p.Connections = append(p.Connections, newConnection)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *AmqpConnectionPool) internalNewConnection() (*AmqpConnection, error) {
|
func (p *AmqpConnectionPool) internalNewConnection() (*AmqpConnection, error) {
|
||||||
conn := p.connectionProvider.NewAmqpConnection(p.config.Parameters, p.connectionName)
|
conn := p.ConnectionProvider.NewAmqpConnection(p.Config.Parameters, p.ConnectionName)
|
||||||
if err := conn.Connect(); err != nil {
|
if err := conn.Connect(); err != nil {
|
||||||
slog.Warn("amqp connection: failed to connect to amqp broker", slog.Any("err", err))
|
slog.Warn("amqp connection: failed to connect to amqp broker", slog.Any("err", err))
|
||||||
|
|
||||||
|
|
@ -103,18 +116,18 @@ func (p *AmqpConnectionPool) internalNewConnection() (*AmqpConnection, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *AmqpConnectionPool) Close() error {
|
func (p *AmqpConnectionPool) Close() error {
|
||||||
p.lock.Lock()
|
p.Lock.Lock()
|
||||||
defer p.lock.Unlock()
|
defer p.Lock.Unlock()
|
||||||
|
|
||||||
closeErrors := make([]error, 0)
|
closeErrors := make([]error, 0)
|
||||||
for _, conn := range p.connections {
|
for _, conn := range p.Connections {
|
||||||
if conn != nil {
|
if conn != nil {
|
||||||
if err := conn.Close(); err != nil {
|
if err := conn.Close(); err != nil {
|
||||||
closeErrors = append(closeErrors, fmt.Errorf("pooled connection: %w", err))
|
closeErrors = append(closeErrors, fmt.Errorf("pooled connection: %w", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.connections = make([]*AmqpConnection, p.config.PoolSize)
|
p.Connections = make([]*AmqpConnection, p.Config.PoolSize)
|
||||||
if len(closeErrors) > 0 {
|
if len(closeErrors) > 0 {
|
||||||
return errors.Join(closeErrors...)
|
return errors.Join(closeErrors...)
|
||||||
}
|
}
|
||||||
|
|
@ -122,16 +135,16 @@ func (p *AmqpConnectionPool) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *AmqpConnectionPool) NewHandle() *ConnectionPoolHandle {
|
func (p *AmqpConnectionPool) NewHandle() *ConnectionPoolHandle {
|
||||||
p.lock.Lock()
|
p.Lock.Lock()
|
||||||
defer p.lock.Unlock()
|
defer p.Lock.Unlock()
|
||||||
|
|
||||||
offset := p.handleOffset
|
offset := p.HandleOffset
|
||||||
p.handleOffset += 1
|
p.HandleOffset++
|
||||||
|
|
||||||
offset = offset % p.config.PoolSize
|
offset %= p.Config.PoolSize
|
||||||
|
|
||||||
return &ConnectionPoolHandle{
|
return &ConnectionPoolHandle{
|
||||||
connectionOffset: offset,
|
ConnectionOffset: offset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -141,16 +154,16 @@ func (p *AmqpConnectionPool) GetConnection(handle *ConnectionPoolHandle) (*AmqpC
|
||||||
|
|
||||||
// renew the requested connection if the request connection is closed
|
// renew the requested connection if the request connection is closed
|
||||||
if conn == nil || addConnection {
|
if conn == nil || addConnection {
|
||||||
p.lock.Lock()
|
p.Lock.Lock()
|
||||||
|
|
||||||
// check that accessing the pool only with a valid index (out of bounds should only occur on shutdown)
|
// check that accessing the pool only with a valid index (out of bounds should only occur on shutdown)
|
||||||
connectionIndex := p.connectionIndex(handle, 0)
|
connectionIndex := p.connectionIndex(handle, 0)
|
||||||
if p.connections[connectionIndex] == nil {
|
if p.Connections[connectionIndex] == nil {
|
||||||
connection, err := p.internalNewConnection()
|
connection, err := p.internalNewConnection()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if conn == nil {
|
if conn == nil {
|
||||||
// case: connection could not be renewed and no connection to return has been found
|
// case: connection could not be renewed and no connection to return has been found
|
||||||
p.lock.Unlock()
|
p.Lock.Unlock()
|
||||||
return nil, fmt.Errorf("renew connection: %w", err)
|
return nil, fmt.Errorf("renew connection: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -158,11 +171,11 @@ func (p *AmqpConnectionPool) GetConnection(handle *ConnectionPoolHandle) (*AmqpC
|
||||||
slog.Warn("amqp connection pool: get connection: renew connection: ", slog.Any("err", err))
|
slog.Warn("amqp connection pool: get connection: renew connection: ", slog.Any("err", err))
|
||||||
} else {
|
} else {
|
||||||
// case: connection could be renewed and will be added to pool
|
// case: connection could be renewed and will be added to pool
|
||||||
p.connections[connectionIndex] = connection
|
p.Connections[connectionIndex] = connection
|
||||||
conn = connection
|
conn = connection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.lock.Unlock()
|
p.Lock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
if conn == nil {
|
if conn == nil {
|
||||||
|
|
@ -176,18 +189,18 @@ func (p *AmqpConnectionPool) nextConnectionForHandle(handle *ConnectionPoolHandl
|
||||||
// retry as long as there are remaining connections in the pool
|
// retry as long as there are remaining connections in the pool
|
||||||
var conn *AmqpConnection
|
var conn *AmqpConnection
|
||||||
var addConnection bool
|
var addConnection bool
|
||||||
for i := 0; i < p.config.PoolSize; i++ {
|
for i := 0; i < p.Config.PoolSize; i++ {
|
||||||
|
|
||||||
// get the next possible connection (considering the retry index)
|
// get the next possible connection (considering the retry index)
|
||||||
idx := p.connectionIndex(handle, i)
|
idx := p.connectionIndex(handle, i)
|
||||||
p.lock.RLock()
|
p.Lock.RLock()
|
||||||
if idx < len(p.connections) {
|
if idx < len(p.Connections) {
|
||||||
conn = p.connections[idx]
|
conn = p.Connections[idx]
|
||||||
} else {
|
} else {
|
||||||
// handle the edge case that the pool is empty on shutdown
|
// handle the edge case that the pool is empty on shutdown
|
||||||
conn = nil
|
conn = nil
|
||||||
}
|
}
|
||||||
p.lock.RUnlock()
|
p.Lock.RUnlock()
|
||||||
|
|
||||||
// remember that the requested is closed, retry with the next
|
// remember that the requested is closed, retry with the next
|
||||||
if conn == nil {
|
if conn == nil {
|
||||||
|
|
@ -197,9 +210,9 @@ func (p *AmqpConnectionPool) nextConnectionForHandle(handle *ConnectionPoolHandl
|
||||||
|
|
||||||
// if the connection is closed, mark it by setting it to nil
|
// if the connection is closed, mark it by setting it to nil
|
||||||
if conn.IsClosed() {
|
if conn.IsClosed() {
|
||||||
p.lock.Lock()
|
p.Lock.Lock()
|
||||||
p.connections[idx] = nil
|
p.Connections[idx] = nil
|
||||||
p.lock.Unlock()
|
p.Lock.Unlock()
|
||||||
|
|
||||||
addConnection = true
|
addConnection = true
|
||||||
continue
|
continue
|
||||||
|
|
@ -211,9 +224,8 @@ func (p *AmqpConnectionPool) nextConnectionForHandle(handle *ConnectionPoolHandl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *AmqpConnectionPool) connectionIndex(handle *ConnectionPoolHandle, iteration int) int {
|
func (p *AmqpConnectionPool) connectionIndex(handle *ConnectionPoolHandle, iteration int) int {
|
||||||
if iteration+handle.connectionOffset >= p.config.PoolSize {
|
if iteration+handle.ConnectionOffset >= p.Config.PoolSize {
|
||||||
return (iteration + handle.connectionOffset) % p.config.PoolSize
|
return (iteration + handle.ConnectionOffset) % p.Config.PoolSize
|
||||||
} else {
|
|
||||||
return iteration + handle.connectionOffset
|
|
||||||
}
|
}
|
||||||
|
return iteration + handle.ConnectionOffset
|
||||||
}
|
}
|
||||||
|
|
@ -3,17 +3,20 @@ package messaging
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/mock"
|
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
|
||||||
|
pkgMessagingCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
type connectionProviderMock struct {
|
type connectionProviderMock struct {
|
||||||
mock.Mock
|
mock.Mock
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *connectionProviderMock) NewAmqpConnection(config AmqpConnectionConfig, connectionName string) *AmqpConnection {
|
func (p *connectionProviderMock) NewAmqpConnection(config pkgMessagingCommon.AmqpConnectionConfig, connectionName string) *AmqpConnection {
|
||||||
args := p.Called(config, connectionName)
|
args := p.Called(config, connectionName)
|
||||||
return args.Get(0).(*AmqpConnection)
|
return args.Get(0).(*AmqpConnection)
|
||||||
}
|
}
|
||||||
|
|
@ -24,28 +27,28 @@ func Test_AmqpConnectionPool_GetHandle(t *testing.T) {
|
||||||
|
|
||||||
t.Run("next handle", func(t *testing.T) {
|
t.Run("next handle", func(t *testing.T) {
|
||||||
pool := AmqpConnectionPool{
|
pool := AmqpConnectionPool{
|
||||||
config: AmqpConnectionPoolConfig{PoolSize: 5},
|
Config: pkgMessagingCommon.AmqpConnectionPoolConfig{PoolSize: 5},
|
||||||
handleOffset: 0,
|
HandleOffset: 0,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
}
|
}
|
||||||
|
|
||||||
handle := pool.NewHandle()
|
handle := pool.NewHandle()
|
||||||
assert.NotNil(t, handle)
|
assert.NotNil(t, handle)
|
||||||
assert.Equal(t, 0, handle.connectionOffset)
|
assert.Equal(t, 0, handle.ConnectionOffset)
|
||||||
assert.Equal(t, 1, pool.handleOffset)
|
assert.Equal(t, 1, pool.HandleOffset)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("next handle high offset", func(t *testing.T) {
|
t.Run("next handle high offset", func(t *testing.T) {
|
||||||
pool := AmqpConnectionPool{
|
pool := AmqpConnectionPool{
|
||||||
config: AmqpConnectionPoolConfig{PoolSize: 5},
|
Config: pkgMessagingCommon.AmqpConnectionPoolConfig{PoolSize: 5},
|
||||||
handleOffset: 13,
|
HandleOffset: 13,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
}
|
}
|
||||||
|
|
||||||
handle := pool.NewHandle()
|
handle := pool.NewHandle()
|
||||||
assert.NotNil(t, handle)
|
assert.NotNil(t, handle)
|
||||||
assert.Equal(t, 3, handle.connectionOffset)
|
assert.Equal(t, 3, handle.ConnectionOffset)
|
||||||
assert.Equal(t, 14, pool.handleOffset)
|
assert.Equal(t, 14, pool.HandleOffset)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,24 +61,24 @@ func Test_AmqpConnectionPool_internalAddConnection(t *testing.T) {
|
||||||
dialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(conn, nil)
|
dialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(conn, nil)
|
||||||
|
|
||||||
connection := &AmqpConnection{
|
connection := &AmqpConnection{
|
||||||
connectionName: "test",
|
ConnectionName: "test",
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
dialer: dialer,
|
Dialer: dialer,
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionProvider := &connectionProviderMock{}
|
connectionProvider := &connectionProviderMock{}
|
||||||
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(connection)
|
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(connection)
|
||||||
pool := AmqpConnectionPool{
|
pool := AmqpConnectionPool{
|
||||||
config: AmqpConnectionPoolConfig{PoolSize: 5},
|
Config: pkgMessagingCommon.AmqpConnectionPoolConfig{PoolSize: 5},
|
||||||
handleOffset: 0,
|
HandleOffset: 0,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
connectionProvider: connectionProvider,
|
ConnectionProvider: connectionProvider,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := pool.internalAddConnection()
|
err := pool.internalAddConnection()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(pool.connections))
|
assert.Equal(t, 1, len(pool.Connections))
|
||||||
connectionProvider.AssertNumberOfCalls(t, "NewAmqpConnection", 1)
|
connectionProvider.AssertNumberOfCalls(t, "NewAmqpConnection", 1)
|
||||||
dialer.AssertNumberOfCalls(t, "Dial", 1)
|
dialer.AssertNumberOfCalls(t, "Dial", 1)
|
||||||
})
|
})
|
||||||
|
|
@ -89,24 +92,24 @@ func Test_AmqpConnectionPool_internalAddConnection(t *testing.T) {
|
||||||
dialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(conn, nil)
|
dialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(conn, nil)
|
||||||
|
|
||||||
connection := &AmqpConnection{
|
connection := &AmqpConnection{
|
||||||
connectionName: "test",
|
ConnectionName: "test",
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
dialer: dialer,
|
Dialer: dialer,
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionProvider := &connectionProviderMock{}
|
connectionProvider := &connectionProviderMock{}
|
||||||
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(connection)
|
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(connection)
|
||||||
pool := AmqpConnectionPool{
|
pool := AmqpConnectionPool{
|
||||||
config: AmqpConnectionPoolConfig{PoolSize: 5},
|
Config: pkgMessagingCommon.AmqpConnectionPoolConfig{PoolSize: 5},
|
||||||
handleOffset: 0,
|
HandleOffset: 0,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
connectionProvider: connectionProvider,
|
ConnectionProvider: connectionProvider,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := pool.internalAddConnection()
|
err := pool.internalAddConnection()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(pool.connections))
|
assert.Equal(t, 1, len(pool.Connections))
|
||||||
connectionProvider.AssertNumberOfCalls(t, "NewAmqpConnection", 1)
|
connectionProvider.AssertNumberOfCalls(t, "NewAmqpConnection", 1)
|
||||||
dialer.AssertNumberOfCalls(t, "Dial", 2)
|
dialer.AssertNumberOfCalls(t, "Dial", 2)
|
||||||
})
|
})
|
||||||
|
|
@ -117,24 +120,24 @@ func Test_AmqpConnectionPool_internalAddConnection(t *testing.T) {
|
||||||
dialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(c, errors.New("test error"))
|
dialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(c, errors.New("test error"))
|
||||||
|
|
||||||
connection := &AmqpConnection{
|
connection := &AmqpConnection{
|
||||||
connectionName: "test",
|
ConnectionName: "test",
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
dialer: dialer,
|
Dialer: dialer,
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionProvider := &connectionProviderMock{}
|
connectionProvider := &connectionProviderMock{}
|
||||||
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(connection)
|
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(connection)
|
||||||
pool := AmqpConnectionPool{
|
pool := AmqpConnectionPool{
|
||||||
config: AmqpConnectionPoolConfig{PoolSize: 5},
|
Config: pkgMessagingCommon.AmqpConnectionPoolConfig{PoolSize: 5},
|
||||||
handleOffset: 0,
|
HandleOffset: 0,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
connectionProvider: connectionProvider,
|
ConnectionProvider: connectionProvider,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := pool.internalAddConnection()
|
err := pool.internalAddConnection()
|
||||||
assert.EqualError(t, err, "new connection: new internal connection: internal connect: dial: test error")
|
assert.EqualError(t, err, "new connection: new internal connection: internal connect: dial: test error")
|
||||||
|
|
||||||
assert.Equal(t, 0, len(pool.connections))
|
assert.Equal(t, 0, len(pool.Connections))
|
||||||
connectionProvider.AssertNumberOfCalls(t, "NewAmqpConnection", 1)
|
connectionProvider.AssertNumberOfCalls(t, "NewAmqpConnection", 1)
|
||||||
dialer.AssertNumberOfCalls(t, "Dial", 2)
|
dialer.AssertNumberOfCalls(t, "Dial", 2)
|
||||||
})
|
})
|
||||||
|
|
@ -149,24 +152,24 @@ func Test_AmqpConnectionPool_initializeConnections(t *testing.T) {
|
||||||
dialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(conn, nil)
|
dialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(conn, nil)
|
||||||
|
|
||||||
connection := &AmqpConnection{
|
connection := &AmqpConnection{
|
||||||
connectionName: "test",
|
ConnectionName: "test",
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
dialer: dialer,
|
Dialer: dialer,
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionProvider := &connectionProviderMock{}
|
connectionProvider := &connectionProviderMock{}
|
||||||
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(connection)
|
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(connection)
|
||||||
pool := AmqpConnectionPool{
|
pool := AmqpConnectionPool{
|
||||||
config: AmqpConnectionPoolConfig{PoolSize: 5},
|
Config: pkgMessagingCommon.AmqpConnectionPoolConfig{PoolSize: 5},
|
||||||
handleOffset: 0,
|
HandleOffset: 0,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
connectionProvider: connectionProvider,
|
ConnectionProvider: connectionProvider,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := pool.initializeConnections()
|
err := pool.initializeConnections()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 5, len(pool.connections))
|
assert.Equal(t, 5, len(pool.Connections))
|
||||||
connectionProvider.AssertNumberOfCalls(t, "NewAmqpConnection", 5)
|
connectionProvider.AssertNumberOfCalls(t, "NewAmqpConnection", 5)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -177,9 +180,9 @@ func Test_AmqpConnectionPool_initializeConnections(t *testing.T) {
|
||||||
failingDialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(c, errors.New("test error"))
|
failingDialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(c, errors.New("test error"))
|
||||||
|
|
||||||
failingConnection := &AmqpConnection{
|
failingConnection := &AmqpConnection{
|
||||||
connectionName: "test",
|
ConnectionName: "test",
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
dialer: failingDialer,
|
Dialer: failingDialer,
|
||||||
}
|
}
|
||||||
|
|
||||||
conn := &amqpConnMock{}
|
conn := &amqpConnMock{}
|
||||||
|
|
@ -187,25 +190,25 @@ func Test_AmqpConnectionPool_initializeConnections(t *testing.T) {
|
||||||
successfulDialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(conn, nil)
|
successfulDialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(conn, nil)
|
||||||
|
|
||||||
successfulConnection := &AmqpConnection{
|
successfulConnection := &AmqpConnection{
|
||||||
connectionName: "test",
|
ConnectionName: "test",
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
dialer: successfulDialer,
|
Dialer: successfulDialer,
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionProvider := &connectionProviderMock{}
|
connectionProvider := &connectionProviderMock{}
|
||||||
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(successfulConnection).Times(4)
|
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(successfulConnection).Times(4)
|
||||||
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(failingConnection)
|
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(failingConnection)
|
||||||
pool := AmqpConnectionPool{
|
pool := AmqpConnectionPool{
|
||||||
config: AmqpConnectionPoolConfig{PoolSize: 5},
|
Config: pkgMessagingCommon.AmqpConnectionPoolConfig{PoolSize: 5},
|
||||||
handleOffset: 0,
|
HandleOffset: 0,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
connectionProvider: connectionProvider,
|
ConnectionProvider: connectionProvider,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := pool.initializeConnections()
|
err := pool.initializeConnections()
|
||||||
assert.EqualError(t, err, "new connection: new internal connection: internal connect: dial: test error")
|
assert.EqualError(t, err, "new connection: new internal connection: internal connect: dial: test error")
|
||||||
|
|
||||||
assert.Equal(t, 4, len(pool.connections))
|
assert.Equal(t, 4, len(pool.Connections))
|
||||||
connectionProvider.AssertNumberOfCalls(t, "NewAmqpConnection", 5)
|
connectionProvider.AssertNumberOfCalls(t, "NewAmqpConnection", 5)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -221,30 +224,30 @@ func Test_AmqpConnectionPool_Close(t *testing.T) {
|
||||||
dialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(conn, nil)
|
dialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(conn, nil)
|
||||||
|
|
||||||
connection := &AmqpConnection{
|
connection := &AmqpConnection{
|
||||||
connectionName: "test",
|
ConnectionName: "test",
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
dialer: dialer,
|
Dialer: dialer,
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionProvider := &connectionProviderMock{}
|
connectionProvider := &connectionProviderMock{}
|
||||||
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(connection)
|
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(connection)
|
||||||
pool := AmqpConnectionPool{
|
pool := AmqpConnectionPool{
|
||||||
config: AmqpConnectionPoolConfig{PoolSize: 5},
|
Config: pkgMessagingCommon.AmqpConnectionPoolConfig{PoolSize: 5},
|
||||||
handleOffset: 0,
|
HandleOffset: 0,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
connectionProvider: connectionProvider,
|
ConnectionProvider: connectionProvider,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := pool.initializeConnections()
|
err := pool.initializeConnections()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 5, len(pool.connections))
|
assert.Equal(t, 5, len(pool.Connections))
|
||||||
|
|
||||||
// close the pool
|
// close the pool
|
||||||
err = pool.Close()
|
err = pool.Close()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 5, len(pool.connections))
|
assert.Equal(t, 5, len(pool.Connections))
|
||||||
for _, c := range pool.connections {
|
for _, c := range pool.Connections {
|
||||||
assert.Nil(t, c)
|
assert.Nil(t, c)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -258,9 +261,9 @@ func Test_AmqpConnectionPool_Close(t *testing.T) {
|
||||||
failingDialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(failingConn, nil)
|
failingDialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(failingConn, nil)
|
||||||
|
|
||||||
failingConnection := &AmqpConnection{
|
failingConnection := &AmqpConnection{
|
||||||
connectionName: "test",
|
ConnectionName: "test",
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
dialer: failingDialer,
|
Dialer: failingDialer,
|
||||||
}
|
}
|
||||||
|
|
||||||
successfulConn := &amqpConnMock{}
|
successfulConn := &amqpConnMock{}
|
||||||
|
|
@ -269,9 +272,9 @@ func Test_AmqpConnectionPool_Close(t *testing.T) {
|
||||||
successfulDialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(successfulConn, nil)
|
successfulDialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(successfulConn, nil)
|
||||||
|
|
||||||
successfulConnection := &AmqpConnection{
|
successfulConnection := &AmqpConnection{
|
||||||
connectionName: "test",
|
ConnectionName: "test",
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
dialer: successfulDialer,
|
Dialer: successfulDialer,
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionProvider := &connectionProviderMock{}
|
connectionProvider := &connectionProviderMock{}
|
||||||
|
|
@ -280,22 +283,22 @@ func Test_AmqpConnectionPool_Close(t *testing.T) {
|
||||||
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(successfulConnection).Times(1)
|
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(successfulConnection).Times(1)
|
||||||
|
|
||||||
pool := AmqpConnectionPool{
|
pool := AmqpConnectionPool{
|
||||||
config: AmqpConnectionPoolConfig{PoolSize: 5},
|
Config: pkgMessagingCommon.AmqpConnectionPoolConfig{PoolSize: 5},
|
||||||
handleOffset: 0,
|
HandleOffset: 0,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
connectionProvider: connectionProvider,
|
ConnectionProvider: connectionProvider,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := pool.initializeConnections()
|
err := pool.initializeConnections()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 5, len(pool.connections))
|
assert.Equal(t, 5, len(pool.Connections))
|
||||||
|
|
||||||
// close the pool
|
// close the pool
|
||||||
err = pool.Close()
|
err = pool.Close()
|
||||||
assert.EqualError(t, err, "pooled connection: internal close: connection close: test error\npooled connection: internal close: connection close: test error")
|
assert.EqualError(t, err, "pooled connection: internal close: connection close: test error\npooled connection: internal close: connection close: test error")
|
||||||
assert.Equal(t, 5, len(pool.connections))
|
assert.Equal(t, 5, len(pool.Connections))
|
||||||
for _, c := range pool.connections {
|
for _, c := range pool.Connections {
|
||||||
assert.Nil(t, c)
|
assert.Nil(t, c)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -311,9 +314,9 @@ func Test_AmqpConnectionPool_nextConnectionForHandle(t *testing.T) {
|
||||||
conn := &amqpConnMock{}
|
conn := &amqpConnMock{}
|
||||||
conn.On("Done", mock.Anything).Return(channelReceiver(channel))
|
conn.On("Done", mock.Anything).Return(channelReceiver(channel))
|
||||||
return &AmqpConnection{
|
return &AmqpConnection{
|
||||||
connectionName: "test",
|
ConnectionName: "test",
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
conn: conn,
|
Conn: conn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -324,9 +327,9 @@ func Test_AmqpConnectionPool_nextConnectionForHandle(t *testing.T) {
|
||||||
conn := &amqpConnMock{}
|
conn := &amqpConnMock{}
|
||||||
conn.On("Done", mock.Anything).Return(channelReceiver(channel))
|
conn.On("Done", mock.Anything).Return(channelReceiver(channel))
|
||||||
return &AmqpConnection{
|
return &AmqpConnection{
|
||||||
connectionName: "test",
|
ConnectionName: "test",
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
conn: conn,
|
Conn: conn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -337,13 +340,13 @@ func Test_AmqpConnectionPool_nextConnectionForHandle(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pool := AmqpConnectionPool{
|
pool := AmqpConnectionPool{
|
||||||
config: AmqpConnectionPoolConfig{PoolSize: 5},
|
Config: pkgMessagingCommon.AmqpConnectionPoolConfig{PoolSize: 5},
|
||||||
handleOffset: 0,
|
HandleOffset: 0,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
connections: connections,
|
Connections: connections,
|
||||||
}
|
}
|
||||||
|
|
||||||
connection, addConnection := pool.nextConnectionForHandle(&ConnectionPoolHandle{connectionOffset: 1})
|
connection, addConnection := pool.nextConnectionForHandle(&ConnectionPoolHandle{ConnectionOffset: 1})
|
||||||
assert.NotNil(t, connection)
|
assert.NotNil(t, connection)
|
||||||
assert.False(t, addConnection)
|
assert.False(t, addConnection)
|
||||||
})
|
})
|
||||||
|
|
@ -357,13 +360,13 @@ func Test_AmqpConnectionPool_nextConnectionForHandle(t *testing.T) {
|
||||||
connections = append(connections, newActiveConnection())
|
connections = append(connections, newActiveConnection())
|
||||||
|
|
||||||
pool := AmqpConnectionPool{
|
pool := AmqpConnectionPool{
|
||||||
config: AmqpConnectionPoolConfig{PoolSize: 5},
|
Config: pkgMessagingCommon.AmqpConnectionPoolConfig{PoolSize: 5},
|
||||||
handleOffset: 0,
|
HandleOffset: 0,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
connections: connections,
|
Connections: connections,
|
||||||
}
|
}
|
||||||
|
|
||||||
connection, addConnection := pool.nextConnectionForHandle(&ConnectionPoolHandle{connectionOffset: 1})
|
connection, addConnection := pool.nextConnectionForHandle(&ConnectionPoolHandle{ConnectionOffset: 1})
|
||||||
assert.NotNil(t, connection)
|
assert.NotNil(t, connection)
|
||||||
assert.True(t, addConnection)
|
assert.True(t, addConnection)
|
||||||
})
|
})
|
||||||
|
|
@ -377,13 +380,13 @@ func Test_AmqpConnectionPool_nextConnectionForHandle(t *testing.T) {
|
||||||
connections = append(connections, newActiveConnection())
|
connections = append(connections, newActiveConnection())
|
||||||
|
|
||||||
pool := AmqpConnectionPool{
|
pool := AmqpConnectionPool{
|
||||||
config: AmqpConnectionPoolConfig{PoolSize: 5},
|
Config: pkgMessagingCommon.AmqpConnectionPoolConfig{PoolSize: 5},
|
||||||
handleOffset: 0,
|
HandleOffset: 0,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
connections: connections,
|
Connections: connections,
|
||||||
}
|
}
|
||||||
|
|
||||||
connection, addConnection := pool.nextConnectionForHandle(&ConnectionPoolHandle{connectionOffset: 1})
|
connection, addConnection := pool.nextConnectionForHandle(&ConnectionPoolHandle{ConnectionOffset: 1})
|
||||||
assert.NotNil(t, connection)
|
assert.NotNil(t, connection)
|
||||||
assert.True(t, addConnection)
|
assert.True(t, addConnection)
|
||||||
})
|
})
|
||||||
|
|
@ -397,13 +400,13 @@ func Test_AmqpConnectionPool_nextConnectionForHandle(t *testing.T) {
|
||||||
connections = append(connections, nil)
|
connections = append(connections, nil)
|
||||||
|
|
||||||
pool := AmqpConnectionPool{
|
pool := AmqpConnectionPool{
|
||||||
config: AmqpConnectionPoolConfig{PoolSize: 5},
|
Config: pkgMessagingCommon.AmqpConnectionPoolConfig{PoolSize: 5},
|
||||||
handleOffset: 0,
|
HandleOffset: 0,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
connections: connections,
|
Connections: connections,
|
||||||
}
|
}
|
||||||
|
|
||||||
connection, addConnection := pool.nextConnectionForHandle(&ConnectionPoolHandle{connectionOffset: 1})
|
connection, addConnection := pool.nextConnectionForHandle(&ConnectionPoolHandle{ConnectionOffset: 1})
|
||||||
assert.Nil(t, connection)
|
assert.Nil(t, connection)
|
||||||
assert.True(t, addConnection)
|
assert.True(t, addConnection)
|
||||||
})
|
})
|
||||||
|
|
@ -417,13 +420,13 @@ func Test_AmqpConnectionPool_nextConnectionForHandle(t *testing.T) {
|
||||||
connections = append(connections, nil)
|
connections = append(connections, nil)
|
||||||
|
|
||||||
pool := AmqpConnectionPool{
|
pool := AmqpConnectionPool{
|
||||||
config: AmqpConnectionPoolConfig{PoolSize: 5},
|
Config: pkgMessagingCommon.AmqpConnectionPoolConfig{PoolSize: 5},
|
||||||
handleOffset: 0,
|
HandleOffset: 0,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
connections: connections,
|
Connections: connections,
|
||||||
}
|
}
|
||||||
|
|
||||||
connection, addConnection := pool.nextConnectionForHandle(&ConnectionPoolHandle{connectionOffset: 23})
|
connection, addConnection := pool.nextConnectionForHandle(&ConnectionPoolHandle{ConnectionOffset: 23})
|
||||||
assert.NotNil(t, connection)
|
assert.NotNil(t, connection)
|
||||||
assert.False(t, addConnection)
|
assert.False(t, addConnection)
|
||||||
})
|
})
|
||||||
|
|
@ -437,13 +440,13 @@ func Test_AmqpConnectionPool_nextConnectionForHandle(t *testing.T) {
|
||||||
connections = append(connections, newActiveConnection())
|
connections = append(connections, newActiveConnection())
|
||||||
|
|
||||||
pool := AmqpConnectionPool{
|
pool := AmqpConnectionPool{
|
||||||
config: AmqpConnectionPoolConfig{PoolSize: 5},
|
Config: pkgMessagingCommon.AmqpConnectionPoolConfig{PoolSize: 5},
|
||||||
handleOffset: 0,
|
HandleOffset: 0,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
connections: connections,
|
Connections: connections,
|
||||||
}
|
}
|
||||||
|
|
||||||
connection, addConnection := pool.nextConnectionForHandle(&ConnectionPoolHandle{connectionOffset: 23})
|
connection, addConnection := pool.nextConnectionForHandle(&ConnectionPoolHandle{ConnectionOffset: 23})
|
||||||
assert.NotNil(t, connection)
|
assert.NotNil(t, connection)
|
||||||
assert.True(t, addConnection)
|
assert.True(t, addConnection)
|
||||||
})
|
})
|
||||||
|
|
@ -459,9 +462,9 @@ func Test_AmqpConnectionPool_GetConnection(t *testing.T) {
|
||||||
conn := &amqpConnMock{}
|
conn := &amqpConnMock{}
|
||||||
conn.On("Done", mock.Anything).Return(channelReceiver(channel))
|
conn.On("Done", mock.Anything).Return(channelReceiver(channel))
|
||||||
return &AmqpConnection{
|
return &AmqpConnection{
|
||||||
connectionName: "test",
|
ConnectionName: "test",
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
conn: conn,
|
Conn: conn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -472,13 +475,13 @@ func Test_AmqpConnectionPool_GetConnection(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pool := AmqpConnectionPool{
|
pool := AmqpConnectionPool{
|
||||||
config: AmqpConnectionPoolConfig{PoolSize: 5},
|
Config: pkgMessagingCommon.AmqpConnectionPoolConfig{PoolSize: 5},
|
||||||
handleOffset: 0,
|
HandleOffset: 0,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
connections: connections,
|
Connections: connections,
|
||||||
}
|
}
|
||||||
|
|
||||||
connection, err := pool.GetConnection(&ConnectionPoolHandle{connectionOffset: 1})
|
connection, err := pool.GetConnection(&ConnectionPoolHandle{ConnectionOffset: 1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, connection)
|
assert.NotNil(t, connection)
|
||||||
assert.Equal(t, connections[1], connection)
|
assert.Equal(t, connections[1], connection)
|
||||||
|
|
@ -492,14 +495,14 @@ func Test_AmqpConnectionPool_GetConnection(t *testing.T) {
|
||||||
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(newActiveConnection())
|
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(newActiveConnection())
|
||||||
|
|
||||||
pool := AmqpConnectionPool{
|
pool := AmqpConnectionPool{
|
||||||
config: AmqpConnectionPoolConfig{PoolSize: 5},
|
Config: pkgMessagingCommon.AmqpConnectionPoolConfig{PoolSize: 5},
|
||||||
handleOffset: 0,
|
HandleOffset: 0,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
connections: connections,
|
Connections: connections,
|
||||||
connectionProvider: connectionProvider,
|
ConnectionProvider: connectionProvider,
|
||||||
}
|
}
|
||||||
|
|
||||||
connection, err := pool.GetConnection(&ConnectionPoolHandle{connectionOffset: 1})
|
connection, err := pool.GetConnection(&ConnectionPoolHandle{ConnectionOffset: 1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, connection)
|
assert.NotNil(t, connection)
|
||||||
assert.Equal(t, connections[1], connection)
|
assert.Equal(t, connections[1], connection)
|
||||||
|
|
@ -520,21 +523,21 @@ func Test_AmqpConnectionPool_GetConnection(t *testing.T) {
|
||||||
var c *amqpConnMock = nil
|
var c *amqpConnMock = nil
|
||||||
dialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(c, fmt.Errorf("dial error"))
|
dialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(c, fmt.Errorf("dial error"))
|
||||||
connection := &AmqpConnection{
|
connection := &AmqpConnection{
|
||||||
connectionName: "test",
|
ConnectionName: "test",
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
dialer: dialer,
|
Dialer: dialer,
|
||||||
}
|
}
|
||||||
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(connection)
|
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(connection)
|
||||||
|
|
||||||
pool := AmqpConnectionPool{
|
pool := AmqpConnectionPool{
|
||||||
config: AmqpConnectionPoolConfig{PoolSize: 5},
|
Config: pkgMessagingCommon.AmqpConnectionPoolConfig{PoolSize: 5},
|
||||||
handleOffset: 0,
|
HandleOffset: 0,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
connections: connections,
|
Connections: connections,
|
||||||
connectionProvider: connectionProvider,
|
ConnectionProvider: connectionProvider,
|
||||||
}
|
}
|
||||||
|
|
||||||
connection, err := pool.GetConnection(&ConnectionPoolHandle{connectionOffset: 1})
|
connection, err := pool.GetConnection(&ConnectionPoolHandle{ConnectionOffset: 1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, connection)
|
assert.NotNil(t, connection)
|
||||||
assert.Nil(t, connections[1])
|
assert.Nil(t, connections[1])
|
||||||
|
|
@ -556,21 +559,21 @@ func Test_AmqpConnectionPool_GetConnection(t *testing.T) {
|
||||||
var c *amqpConnMock = nil
|
var c *amqpConnMock = nil
|
||||||
dialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(c, fmt.Errorf("dial error"))
|
dialer.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(c, fmt.Errorf("dial error"))
|
||||||
connection := &AmqpConnection{
|
connection := &AmqpConnection{
|
||||||
connectionName: "test",
|
ConnectionName: "test",
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
dialer: dialer,
|
Dialer: dialer,
|
||||||
}
|
}
|
||||||
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(connection)
|
connectionProvider.On("NewAmqpConnection", mock.Anything, mock.Anything).Return(connection)
|
||||||
|
|
||||||
pool := AmqpConnectionPool{
|
pool := AmqpConnectionPool{
|
||||||
config: AmqpConnectionPoolConfig{PoolSize: 5},
|
Config: pkgMessagingCommon.AmqpConnectionPoolConfig{PoolSize: 5},
|
||||||
handleOffset: 0,
|
HandleOffset: 0,
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
connections: connections,
|
Connections: connections,
|
||||||
connectionProvider: connectionProvider,
|
ConnectionProvider: connectionProvider,
|
||||||
}
|
}
|
||||||
|
|
||||||
connection, err := pool.GetConnection(&ConnectionPoolHandle{connectionOffset: 1})
|
connection, err := pool.GetConnection(&ConnectionPoolHandle{ConnectionOffset: 1})
|
||||||
assert.EqualError(t, err, "renew connection: new internal connection: internal connect: dial: dial error")
|
assert.EqualError(t, err, "renew connection: new internal connection: internal connect: dial: dial error")
|
||||||
assert.Nil(t, connection)
|
assert.Nil(t, connection)
|
||||||
assert.Equal(t, 5, len(connections))
|
assert.Equal(t, 5, len(connections))
|
||||||
|
|
@ -3,11 +3,14 @@ package messaging
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/Azure/go-amqp"
|
"github.com/Azure/go-amqp"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
"sync"
|
|
||||||
"testing"
|
pkgCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
type amqpConnMock struct {
|
type amqpConnMock struct {
|
||||||
|
|
@ -19,9 +22,9 @@ func (m *amqpConnMock) Done() <-chan struct{} {
|
||||||
return args.Get(0).(<-chan struct{})
|
return args.Get(0).(<-chan struct{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *amqpConnMock) NewSession(ctx context.Context, opts *amqp.SessionOptions) (amqpSession, error) {
|
func (m *amqpConnMock) NewSession(ctx context.Context, opts *amqp.SessionOptions) (AmqpSession, error) {
|
||||||
args := m.Called(ctx, opts)
|
args := m.Called(ctx, opts)
|
||||||
return args.Get(0).(amqpSession), args.Error(1)
|
return args.Get(0).(AmqpSession), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *amqpConnMock) Close() error {
|
func (m *amqpConnMock) Close() error {
|
||||||
|
|
@ -29,15 +32,15 @@ func (m *amqpConnMock) Close() error {
|
||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ amqpConn = (*amqpConnMock)(nil)
|
var _ AmqpConn = (*amqpConnMock)(nil)
|
||||||
|
|
||||||
type amqpDialMock struct {
|
type amqpDialMock struct {
|
||||||
mock.Mock
|
mock.Mock
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *amqpDialMock) Dial(ctx context.Context, addr string, opts *amqp.ConnOptions) (amqpConn, error) {
|
func (m *amqpDialMock) Dial(ctx context.Context, addr string, opts *amqp.ConnOptions) (AmqpConn, error) {
|
||||||
args := m.Called(ctx, addr, opts)
|
args := m.Called(ctx, addr, opts)
|
||||||
return args.Get(0).(amqpConn), args.Error(1)
|
return args.Get(0).(AmqpConn), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ amqpDial = (*amqpDialMock)(nil)
|
var _ amqpDial = (*amqpDialMock)(nil)
|
||||||
|
|
@ -46,9 +49,9 @@ type amqpSessionMock struct {
|
||||||
mock.Mock
|
mock.Mock
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *amqpSessionMock) NewSender(ctx context.Context, target string, opts *amqp.SenderOptions) (amqpSender, error) {
|
func (m *amqpSessionMock) NewSender(ctx context.Context, target string, opts *amqp.SenderOptions) (AmqpSender, error) {
|
||||||
args := m.Called(ctx, target, opts)
|
args := m.Called(ctx, target, opts)
|
||||||
return args.Get(0).(amqpSender), args.Error(1)
|
return args.Get(0).(AmqpSender), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *amqpSessionMock) Close(ctx context.Context) error {
|
func (m *amqpSessionMock) Close(ctx context.Context) error {
|
||||||
|
|
@ -56,12 +59,12 @@ func (m *amqpSessionMock) Close(ctx context.Context) error {
|
||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ amqpSession = (*amqpSessionMock)(nil)
|
var _ AmqpSession = (*amqpSessionMock)(nil)
|
||||||
|
|
||||||
func Test_AmqpConnection_IsClosed(t *testing.T) {
|
func Test_AmqpConnection_IsClosed(t *testing.T) {
|
||||||
connection := &AmqpConnection{
|
connection := &AmqpConnection{
|
||||||
connectionName: "test",
|
ConnectionName: "test",
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
}
|
}
|
||||||
|
|
||||||
channelReceiver := func(channel chan struct{}) <-chan struct{} {
|
channelReceiver := func(channel chan struct{}) <-chan struct{} {
|
||||||
|
|
@ -77,7 +80,7 @@ func Test_AmqpConnection_IsClosed(t *testing.T) {
|
||||||
close(channel)
|
close(channel)
|
||||||
amqpConnMock := &amqpConnMock{}
|
amqpConnMock := &amqpConnMock{}
|
||||||
amqpConnMock.On("Done").Return(channelReceiver(channel))
|
amqpConnMock.On("Done").Return(channelReceiver(channel))
|
||||||
connection.conn = amqpConnMock
|
connection.Conn = amqpConnMock
|
||||||
|
|
||||||
assert.True(t, connection.IsClosed())
|
assert.True(t, connection.IsClosed())
|
||||||
})
|
})
|
||||||
|
|
@ -86,7 +89,7 @@ func Test_AmqpConnection_IsClosed(t *testing.T) {
|
||||||
channel := make(chan struct{})
|
channel := make(chan struct{})
|
||||||
amqpConnMock := &amqpConnMock{}
|
amqpConnMock := &amqpConnMock{}
|
||||||
amqpConnMock.On("Done").Return(channelReceiver(channel))
|
amqpConnMock.On("Done").Return(channelReceiver(channel))
|
||||||
connection.conn = amqpConnMock
|
connection.Conn = amqpConnMock
|
||||||
|
|
||||||
assert.False(t, connection.IsClosed())
|
assert.False(t, connection.IsClosed())
|
||||||
})
|
})
|
||||||
|
|
@ -94,8 +97,8 @@ func Test_AmqpConnection_IsClosed(t *testing.T) {
|
||||||
|
|
||||||
func Test_AmqpConnection_Close(t *testing.T) {
|
func Test_AmqpConnection_Close(t *testing.T) {
|
||||||
connection := &AmqpConnection{
|
connection := &AmqpConnection{
|
||||||
connectionName: "test",
|
ConnectionName: "test",
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("already closed", func(t *testing.T) {
|
t.Run("already closed", func(t *testing.T) {
|
||||||
|
|
@ -107,66 +110,66 @@ func Test_AmqpConnection_Close(t *testing.T) {
|
||||||
|
|
||||||
amqpConnMock := &amqpConnMock{}
|
amqpConnMock := &amqpConnMock{}
|
||||||
amqpConnMock.On("Close").Return(err)
|
amqpConnMock.On("Close").Return(err)
|
||||||
connection.conn = amqpConnMock
|
connection.Conn = amqpConnMock
|
||||||
|
|
||||||
assert.EqualError(t, connection.Close(), "internal close: connection close: test error")
|
assert.EqualError(t, connection.Close(), "internal close: connection close: test error")
|
||||||
assert.NotNil(t, connection.conn)
|
assert.NotNil(t, connection.Conn)
|
||||||
amqpConnMock.AssertNumberOfCalls(t, "Close", 1)
|
amqpConnMock.AssertNumberOfCalls(t, "Close", 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("close without error", func(t *testing.T) {
|
t.Run("close without error", func(t *testing.T) {
|
||||||
amqpConnMock := &amqpConnMock{}
|
amqpConnMock := &amqpConnMock{}
|
||||||
amqpConnMock.On("Close").Return(nil)
|
amqpConnMock.On("Close").Return(nil)
|
||||||
connection.conn = amqpConnMock
|
connection.Conn = amqpConnMock
|
||||||
|
|
||||||
assert.Nil(t, connection.Close())
|
assert.Nil(t, connection.Close())
|
||||||
assert.Nil(t, connection.conn)
|
assert.Nil(t, connection.Conn)
|
||||||
amqpConnMock.AssertNumberOfCalls(t, "Close", 1)
|
amqpConnMock.AssertNumberOfCalls(t, "Close", 1)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_AmqpConnection_Connect(t *testing.T) {
|
func Test_AmqpConnection_Connect(t *testing.T) {
|
||||||
connection := &AmqpConnection{
|
connection := &AmqpConnection{
|
||||||
connectionName: "test",
|
ConnectionName: "test",
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("already connected", func(t *testing.T) {
|
t.Run("already connected", func(t *testing.T) {
|
||||||
connection.conn = &amqpConnMock{}
|
connection.Conn = &amqpConnMock{}
|
||||||
assert.NoError(t, connection.Connect())
|
assert.NoError(t, connection.Connect())
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("dial error", func(t *testing.T) {
|
t.Run("dial error", func(t *testing.T) {
|
||||||
connection.conn = nil
|
connection.Conn = nil
|
||||||
connection.username = "user"
|
connection.Username = "user"
|
||||||
connection.password = "pass"
|
connection.Password = "pass"
|
||||||
|
|
||||||
amqpDialMock := &amqpDialMock{}
|
amqpDialMock := &amqpDialMock{}
|
||||||
var c *amqpConnMock = nil
|
var c *amqpConnMock = nil
|
||||||
amqpDialMock.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(c, errors.New("test error"))
|
amqpDialMock.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(c, errors.New("test error"))
|
||||||
connection.dialer = amqpDialMock
|
connection.Dialer = amqpDialMock
|
||||||
|
|
||||||
assert.EqualError(t, connection.Connect(), "internal connect: dial: test error")
|
assert.EqualError(t, connection.Connect(), "internal connect: dial: test error")
|
||||||
assert.Nil(t, connection.conn)
|
assert.Nil(t, connection.Conn)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("connect without error", func(t *testing.T) {
|
t.Run("connect without error", func(t *testing.T) {
|
||||||
connection.conn = nil
|
connection.Conn = nil
|
||||||
|
|
||||||
amqpDialMock := &amqpDialMock{}
|
amqpDialMock := &amqpDialMock{}
|
||||||
amqpConn := &amqpConnMock{}
|
amqpConn := &amqpConnMock{}
|
||||||
amqpDialMock.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(amqpConn, nil)
|
amqpDialMock.On("Dial", mock.Anything, mock.Anything, mock.Anything).Return(amqpConn, nil)
|
||||||
connection.dialer = amqpDialMock
|
connection.Dialer = amqpDialMock
|
||||||
|
|
||||||
assert.NoError(t, connection.Connect())
|
assert.NoError(t, connection.Connect())
|
||||||
assert.Equal(t, amqpConn, connection.conn)
|
assert.Equal(t, amqpConn, connection.Conn)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_AmqpConnection_NewSender(t *testing.T) {
|
func Test_AmqpConnection_NewSender(t *testing.T) {
|
||||||
connection := &AmqpConnection{
|
connection := &AmqpConnection{
|
||||||
connectionName: "test",
|
ConnectionName: "test",
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
}
|
}
|
||||||
|
|
||||||
channelReceiver := func(channel chan struct{}) <-chan struct{} {
|
channelReceiver := func(channel chan struct{}) <-chan struct{} {
|
||||||
|
|
@ -185,7 +188,7 @@ func Test_AmqpConnection_NewSender(t *testing.T) {
|
||||||
|
|
||||||
conn := &amqpConnMock{}
|
conn := &amqpConnMock{}
|
||||||
conn.On("Done").Return(channelReceiver(channel))
|
conn.On("Done").Return(channelReceiver(channel))
|
||||||
connection.conn = conn
|
connection.Conn = conn
|
||||||
|
|
||||||
sender, err := connection.NewSender(context.Background(), "topic")
|
sender, err := connection.NewSender(context.Background(), "topic")
|
||||||
assert.EqualError(t, err, "amqp connection is closed")
|
assert.EqualError(t, err, "amqp connection is closed")
|
||||||
|
|
@ -199,7 +202,7 @@ func Test_AmqpConnection_NewSender(t *testing.T) {
|
||||||
conn := &amqpConnMock{}
|
conn := &amqpConnMock{}
|
||||||
conn.On("NewSession", mock.Anything, mock.Anything).Return(session, errors.New("test error"))
|
conn.On("NewSession", mock.Anything, mock.Anything).Return(session, errors.New("test error"))
|
||||||
conn.On("Done").Return(channelReceiver(channel))
|
conn.On("Done").Return(channelReceiver(channel))
|
||||||
connection.conn = conn
|
connection.Conn = conn
|
||||||
|
|
||||||
sender, err := connection.NewSender(context.Background(), "topic")
|
sender, err := connection.NewSender(context.Background(), "topic")
|
||||||
assert.EqualError(t, err, "new session: test error")
|
assert.EqualError(t, err, "new session: test error")
|
||||||
|
|
@ -217,7 +220,7 @@ func Test_AmqpConnection_NewSender(t *testing.T) {
|
||||||
conn := &amqpConnMock{}
|
conn := &amqpConnMock{}
|
||||||
conn.On("Done").Return(channelReceiver(channel))
|
conn.On("Done").Return(channelReceiver(channel))
|
||||||
conn.On("NewSession", mock.Anything, mock.Anything).Return(sessionMock, nil)
|
conn.On("NewSession", mock.Anything, mock.Anything).Return(sessionMock, nil)
|
||||||
connection.conn = conn
|
connection.Conn = conn
|
||||||
|
|
||||||
sender, err := connection.NewSender(context.Background(), "topic")
|
sender, err := connection.NewSender(context.Background(), "topic")
|
||||||
assert.EqualError(t, err, "new internal sender: test error")
|
assert.EqualError(t, err, "new internal sender: test error")
|
||||||
|
|
@ -235,7 +238,7 @@ func Test_AmqpConnection_NewSender(t *testing.T) {
|
||||||
conn := &amqpConnMock{}
|
conn := &amqpConnMock{}
|
||||||
conn.On("Done").Return(channelReceiver(channel))
|
conn.On("Done").Return(channelReceiver(channel))
|
||||||
conn.On("NewSession", mock.Anything, mock.Anything).Return(sessionMock, nil)
|
conn.On("NewSession", mock.Anything, mock.Anything).Return(sessionMock, nil)
|
||||||
connection.conn = conn
|
connection.Conn = conn
|
||||||
|
|
||||||
sender, err := connection.NewSender(context.Background(), "topic")
|
sender, err := connection.NewSender(context.Background(), "topic")
|
||||||
assert.EqualError(t, err, "new internal sender: test error\nclose session: close error")
|
assert.EqualError(t, err, "new internal sender: test error\nclose session: close error")
|
||||||
|
|
@ -252,29 +255,29 @@ func Test_AmqpConnection_NewSender(t *testing.T) {
|
||||||
conn := &amqpConnMock{}
|
conn := &amqpConnMock{}
|
||||||
conn.On("Done").Return(channelReceiver(channel))
|
conn.On("Done").Return(channelReceiver(channel))
|
||||||
conn.On("NewSession", mock.Anything, mock.Anything).Return(sessionMock, nil)
|
conn.On("NewSession", mock.Anything, mock.Anything).Return(sessionMock, nil)
|
||||||
connection.conn = conn
|
connection.Conn = conn
|
||||||
|
|
||||||
sender, err := connection.NewSender(context.Background(), "topic")
|
sender, err := connection.NewSender(context.Background(), "topic")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, sender)
|
assert.NotNil(t, sender)
|
||||||
assert.Equal(t, amqpSender, sender.sender)
|
assert.Equal(t, amqpSender, sender.Sender)
|
||||||
assert.Equal(t, sessionMock, sender.session)
|
assert.Equal(t, sessionMock, sender.Session)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_AmqpConnection_NewAmqpConnection(t *testing.T) {
|
func Test_AmqpConnection_NewAmqpConnection(t *testing.T) {
|
||||||
config := AmqpConnectionConfig{
|
config := pkgCommon.AmqpConnectionConfig{
|
||||||
BrokerUrl: "brokerUrl",
|
BrokerUrl: "brokerUrl",
|
||||||
Username: "username",
|
Username: "username",
|
||||||
Password: "password",
|
Password: "password",
|
||||||
}
|
}
|
||||||
connection := NewAmqpConnection(config, "connectionName")
|
connection := NewAmqpConnection(config, "connectionName")
|
||||||
assert.NotNil(t, connection)
|
assert.NotNil(t, connection)
|
||||||
assert.Equal(t, connection.connectionName, "connectionName")
|
assert.Equal(t, connection.ConnectionName, "connectionName")
|
||||||
assert.Equal(t, connection.brokerUrl, "brokerUrl")
|
assert.Equal(t, connection.BrokerUrl, "brokerUrl")
|
||||||
assert.Equal(t, connection.username, "username")
|
assert.Equal(t, connection.Username, "username")
|
||||||
assert.Equal(t, connection.password, "password")
|
assert.Equal(t, connection.Password, "password")
|
||||||
assert.NotNil(t, connection.dialer)
|
assert.NotNil(t, connection.Dialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_As(t *testing.T) {
|
func Test_As(t *testing.T) {
|
||||||
|
|
@ -4,19 +4,22 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Azure/go-amqp"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/Azure/go-amqp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type amqpSender interface {
|
const amqpTopicPrefix = "topic://"
|
||||||
|
|
||||||
|
type AmqpSender interface {
|
||||||
Send(ctx context.Context, msg *amqp.Message, opts *amqp.SendOptions) error
|
Send(ctx context.Context, msg *amqp.Message, opts *amqp.SendOptions) error
|
||||||
Close(ctx context.Context) error
|
Close(ctx context.Context) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type AmqpSenderSession struct {
|
type AmqpSenderSession struct {
|
||||||
session amqpSession
|
Session AmqpSession
|
||||||
sender amqpSender
|
Sender AmqpSender
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AmqpSenderSession) Send(
|
func (s *AmqpSenderSession) Send(
|
||||||
|
|
@ -26,11 +29,11 @@ func (s *AmqpSenderSession) Send(
|
||||||
applicationProperties map[string]any,
|
applicationProperties map[string]any,
|
||||||
) error {
|
) error {
|
||||||
// check topic name
|
// check topic name
|
||||||
if !strings.HasPrefix(topic, AmqpTopicPrefix) {
|
if !strings.HasPrefix(topic, amqpTopicPrefix) {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"topic %q name lacks mandatory prefix %q",
|
"topic %q name lacks mandatory prefix %q",
|
||||||
topic,
|
topic,
|
||||||
AmqpTopicPrefix,
|
amqpTopicPrefix,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,7 +57,7 @@ func (s *AmqpSenderSession) Send(
|
||||||
// send
|
// send
|
||||||
ctx, cancelFn := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancelFn := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancelFn()
|
defer cancelFn()
|
||||||
return s.sender.Send(ctx, &message, nil)
|
return s.Sender.Send(ctx, &message, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AmqpSenderSession) Close() error {
|
func (s *AmqpSenderSession) Close() error {
|
||||||
|
|
@ -62,11 +65,11 @@ func (s *AmqpSenderSession) Close() error {
|
||||||
defer cancelFn()
|
defer cancelFn()
|
||||||
|
|
||||||
var closeErrors []error
|
var closeErrors []error
|
||||||
senderErr := s.sender.Close(ctx)
|
senderErr := s.Sender.Close(ctx)
|
||||||
if senderErr != nil {
|
if senderErr != nil {
|
||||||
closeErrors = append(closeErrors, senderErr)
|
closeErrors = append(closeErrors, senderErr)
|
||||||
}
|
}
|
||||||
sessionErr := s.session.Close(ctx)
|
sessionErr := s.Session.Close(ctx)
|
||||||
if sessionErr != nil {
|
if sessionErr != nil {
|
||||||
closeErrors = append(closeErrors, sessionErr)
|
closeErrors = append(closeErrors, sessionErr)
|
||||||
}
|
}
|
||||||
|
|
@ -3,10 +3,11 @@ package messaging
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/Azure/go-amqp"
|
"github.com/Azure/go-amqp"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type amqpSenderMock struct {
|
type amqpSenderMock struct {
|
||||||
|
|
@ -21,7 +22,7 @@ func (m *amqpSenderMock) Close(ctx context.Context) error {
|
||||||
return m.Called(ctx).Error(0)
|
return m.Called(ctx).Error(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ amqpSender = (*amqpSenderMock)(nil)
|
var _ AmqpSender = (*amqpSenderMock)(nil)
|
||||||
|
|
||||||
func Test_AmqpSenderSession_Close(t *testing.T) {
|
func Test_AmqpSenderSession_Close(t *testing.T) {
|
||||||
|
|
||||||
|
|
@ -32,8 +33,8 @@ func Test_AmqpSenderSession_Close(t *testing.T) {
|
||||||
session.On("Close", mock.Anything).Return(nil)
|
session.On("Close", mock.Anything).Return(nil)
|
||||||
|
|
||||||
senderSession := &AmqpSenderSession{
|
senderSession := &AmqpSenderSession{
|
||||||
sender: sender,
|
Sender: sender,
|
||||||
session: session,
|
Session: session,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := senderSession.Close()
|
err := senderSession.Close()
|
||||||
|
|
@ -50,8 +51,8 @@ func Test_AmqpSenderSession_Close(t *testing.T) {
|
||||||
session.On("Close", mock.Anything).Return(nil)
|
session.On("Close", mock.Anything).Return(nil)
|
||||||
|
|
||||||
senderSession := &AmqpSenderSession{
|
senderSession := &AmqpSenderSession{
|
||||||
sender: sender,
|
Sender: sender,
|
||||||
session: session,
|
Session: session,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := senderSession.Close()
|
err := senderSession.Close()
|
||||||
|
|
@ -68,8 +69,8 @@ func Test_AmqpSenderSession_Close(t *testing.T) {
|
||||||
session.On("Close", mock.Anything).Return(errors.New("session error"))
|
session.On("Close", mock.Anything).Return(errors.New("session error"))
|
||||||
|
|
||||||
senderSession := &AmqpSenderSession{
|
senderSession := &AmqpSenderSession{
|
||||||
sender: sender,
|
Sender: sender,
|
||||||
session: session,
|
Session: session,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := senderSession.Close()
|
err := senderSession.Close()
|
||||||
|
|
@ -86,8 +87,8 @@ func Test_AmqpSenderSession_Close(t *testing.T) {
|
||||||
session.On("Close", mock.Anything).Return(errors.New("session error"))
|
session.On("Close", mock.Anything).Return(errors.New("session error"))
|
||||||
|
|
||||||
senderSession := &AmqpSenderSession{
|
senderSession := &AmqpSenderSession{
|
||||||
sender: sender,
|
Sender: sender,
|
||||||
session: session,
|
Session: session,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := senderSession.Close()
|
err := senderSession.Close()
|
||||||
|
|
@ -105,8 +106,8 @@ func Test_AmqpSenderSession_Send(t *testing.T) {
|
||||||
session := &amqpSessionMock{}
|
session := &amqpSessionMock{}
|
||||||
|
|
||||||
senderSession := &AmqpSenderSession{
|
senderSession := &AmqpSenderSession{
|
||||||
sender: sender,
|
Sender: sender,
|
||||||
session: session,
|
Session: session,
|
||||||
}
|
}
|
||||||
|
|
||||||
data := [][]byte{[]byte("data")}
|
data := [][]byte{[]byte("data")}
|
||||||
|
|
@ -119,8 +120,8 @@ func Test_AmqpSenderSession_Send(t *testing.T) {
|
||||||
session := &amqpSessionMock{}
|
session := &amqpSessionMock{}
|
||||||
|
|
||||||
senderSession := &AmqpSenderSession{
|
senderSession := &AmqpSenderSession{
|
||||||
sender: sender,
|
Sender: sender,
|
||||||
session: session,
|
Session: session,
|
||||||
}
|
}
|
||||||
|
|
||||||
data := [][]byte{[]byte("data")}
|
data := [][]byte{[]byte("data")}
|
||||||
|
|
@ -134,8 +135,8 @@ func Test_AmqpSenderSession_Send(t *testing.T) {
|
||||||
session := &amqpSessionMock{}
|
session := &amqpSessionMock{}
|
||||||
|
|
||||||
senderSession := &AmqpSenderSession{
|
senderSession := &AmqpSenderSession{
|
||||||
sender: sender,
|
Sender: sender,
|
||||||
session: session,
|
Session: session,
|
||||||
}
|
}
|
||||||
|
|
||||||
data := [][]byte{[]byte("data")}
|
data := [][]byte{[]byte("data")}
|
||||||
|
|
@ -171,8 +172,8 @@ func Test_AmqpSenderSession_Send(t *testing.T) {
|
||||||
session := &amqpSessionMock{}
|
session := &amqpSessionMock{}
|
||||||
|
|
||||||
senderSession := &AmqpSenderSession{
|
senderSession := &AmqpSenderSession{
|
||||||
sender: sender,
|
Sender: sender,
|
||||||
session: session,
|
Session: session,
|
||||||
}
|
}
|
||||||
|
|
||||||
data := [][]byte{[]byte("data")}
|
data := [][]byte{[]byte("data")}
|
||||||
|
|
@ -2,31 +2,24 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/audit/messaging"
|
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
|
||||||
"errors"
|
"errors"
|
||||||
"go.opentelemetry.io/otel"
|
"fmt"
|
||||||
"go.opentelemetry.io/otel/trace"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
internalAuditApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/internal/audit/api"
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
|
pkgMessagingApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
const DataTypeLegacyAuditEventV1 = "audit.v1.LegacyAuditEvent"
|
const DataTypeLegacyAuditEventV1 = "audit.v1.LegacyAuditEvent"
|
||||||
|
|
||||||
// LegacyTopicNameResolver implements TopicNameResolver.
|
// StaticTopicNameConfig provides topic name information required for the topic name resolution.
|
||||||
// A hard-coded topic name is used, routing identifiers are ignored.
|
type StaticTopicNameConfig struct {
|
||||||
type LegacyTopicNameResolver struct {
|
|
||||||
topicName string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve implements TopicNameResolver.Resolve
|
|
||||||
func (r *LegacyTopicNameResolver) Resolve(*RoutableIdentifier) (string, error) {
|
|
||||||
return r.topicName, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// LegacyTopicNameConfig provides topic name information required for the topic name resolution.
|
|
||||||
type LegacyTopicNameConfig struct {
|
|
||||||
TopicName string
|
TopicName string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,33 +27,39 @@ type LegacyTopicNameConfig struct {
|
||||||
//
|
//
|
||||||
// Note: The implementation will be deprecated and replaced with the "routableAuditApi" once the new audit log routing is implemented
|
// Note: The implementation will be deprecated and replaced with the "routableAuditApi" once the new audit log routing is implemented
|
||||||
type LegacyAuditApi struct {
|
type LegacyAuditApi struct {
|
||||||
messagingApi messaging.Api
|
messagingApi pkgMessagingApi.Api
|
||||||
topicNameResolver TopicNameResolver
|
topicNameResolver pkgAuditCommon.TopicNameResolver
|
||||||
tracer trace.Tracer
|
tracer trace.Tracer
|
||||||
validator ProtobufValidator
|
validator pkgAuditCommon.ProtobufValidator
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLegacyAuditApi can be used to initialize the audit log api.
|
// NewLegacyAuditApi can be used to initialize the audit log api.
|
||||||
//
|
//
|
||||||
// Note: The NewLegacyAuditApi method will be deprecated and replaced with "newRoutableAuditApi" once the new audit log routing is implemented
|
// Note: The NewLegacyAuditApi method will be deprecated and replaced with "newRoutableAuditApi" once the new audit log routing is implemented
|
||||||
func NewLegacyAuditApi(
|
func NewLegacyAuditApi(
|
||||||
messagingApi messaging.Api,
|
messagingApi pkgMessagingApi.Api,
|
||||||
topicNameConfig LegacyTopicNameConfig,
|
topicNameConfig StaticTopicNameConfig,
|
||||||
validator ProtobufValidator,
|
validator pkgAuditCommon.ProtobufValidator,
|
||||||
) (AuditApi, error) {
|
) (pkgAuditCommon.AuditApi, error) {
|
||||||
|
|
||||||
if messagingApi == nil {
|
if messagingApi == nil {
|
||||||
return nil, ErrMessagingApiNil
|
return nil, pkgAuditCommon.ErrMessagingApiNil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Topic resolver
|
// Topic resolver
|
||||||
if topicNameConfig.TopicName == "" {
|
if topicNameConfig.TopicName == "" {
|
||||||
return nil, errors.New("topic name is required")
|
return nil, errors.New("topic name is required")
|
||||||
}
|
}
|
||||||
var topicNameResolver TopicNameResolver = &LegacyTopicNameResolver{topicName: topicNameConfig.TopicName}
|
if !pkgAuditCommon.TopicNamePattern.MatchString(topicNameConfig.TopicName) {
|
||||||
|
return nil, fmt.Errorf("invalid topic name: %s - "+
|
||||||
|
"expected stackit-platform/t/swz/audit-log/{region}/{version}/{eventSource}/{additionalParts} "+
|
||||||
|
"where region is one of [conway, eu01, eu02, sx-stoi01], version is vX.Y, eventSource is the service name "+
|
||||||
|
"and additionalParts is a describing string the audit log relates to or 'events'", topicNameConfig.TopicName)
|
||||||
|
}
|
||||||
|
var topicNameResolver pkgAuditCommon.TopicNameResolver = &pkgAuditCommon.StaticTopicNameTestResolver{TopicName: topicNameConfig.TopicName}
|
||||||
|
|
||||||
// Audit api
|
// Audit api
|
||||||
var auditApi AuditApi = &LegacyAuditApi{
|
var auditApi pkgAuditCommon.AuditApi = &LegacyAuditApi{
|
||||||
messagingApi: messagingApi,
|
messagingApi: messagingApi,
|
||||||
topicNameResolver: topicNameResolver,
|
topicNameResolver: topicNameResolver,
|
||||||
tracer: otel.Tracer("legacy-audit-api"),
|
tracer: otel.Tracer("legacy-audit-api"),
|
||||||
|
|
@ -75,7 +74,7 @@ func (a *LegacyAuditApi) Log(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
event *auditV1.AuditLogEntry,
|
event *auditV1.AuditLogEntry,
|
||||||
visibility auditV1.Visibility,
|
visibility auditV1.Visibility,
|
||||||
routableIdentifier *RoutableIdentifier,
|
routableIdentifier *pkgAuditCommon.RoutableIdentifier,
|
||||||
) error {
|
) error {
|
||||||
|
|
||||||
cloudEvent, err := a.ValidateAndSerialize(ctx, event, visibility, routableIdentifier)
|
cloudEvent, err := a.ValidateAndSerialize(ctx, event, visibility, routableIdentifier)
|
||||||
|
|
@ -92,21 +91,21 @@ func (a *LegacyAuditApi) ValidateAndSerialize(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
event *auditV1.AuditLogEntry,
|
event *auditV1.AuditLogEntry,
|
||||||
visibility auditV1.Visibility,
|
visibility auditV1.Visibility,
|
||||||
routableIdentifier *RoutableIdentifier,
|
routableIdentifier *pkgAuditCommon.RoutableIdentifier,
|
||||||
) (*CloudEvent, error) {
|
) (*pkgAuditCommon.CloudEvent, error) {
|
||||||
|
|
||||||
ctx, span := a.tracer.Start(ctx, "validate-and-serialize")
|
ctx, span := a.tracer.Start(ctx, "validate-and-serialize")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
routableEvent, err := validateAndSerializePartially(a.validator, event, visibility, routableIdentifier)
|
routableEvent, err := internalAuditApi.ValidateAndSerializePartially(a.validator, event, visibility, routableIdentifier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reject event type data-access as the downstream services
|
// Reject event type data-access as the downstream services
|
||||||
// cannot handle it at the moment
|
// cannot handle it at the moment
|
||||||
if strings.HasSuffix(event.LogName, string(EventTypeDataAccess)) {
|
if strings.HasSuffix(event.LogName, string(pkgAuditCommon.EventTypeDataAccess)) {
|
||||||
return nil, ErrUnsupportedEventTypeDataAccess
|
return nil, pkgAuditCommon.ErrUnsupportedEventTypeDataAccess
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do nothing with the serialized data in the legacy solution
|
// Do nothing with the serialized data in the legacy solution
|
||||||
|
|
@ -116,19 +115,19 @@ func (a *LegacyAuditApi) ValidateAndSerialize(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert attributes
|
// Convert attributes
|
||||||
legacyBytes, err := convertAndSerializeIntoLegacyFormat(event, routableEvent)
|
legacyBytes, err := internalAuditApi.ConvertAndSerializeIntoLegacyFormat(event, routableEvent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
traceParent, traceState := TraceParentAndStateFromContext(ctx)
|
traceParent, traceState := internalAuditApi.TraceParentAndStateFromContext(ctx)
|
||||||
|
|
||||||
message := CloudEvent{
|
message := pkgAuditCommon.CloudEvent{
|
||||||
SpecVersion: "1.0",
|
SpecVersion: "1.0",
|
||||||
Source: event.ProtoPayload.ServiceName,
|
Source: event.ProtoPayload.ServiceName,
|
||||||
Id: event.InsertId,
|
Id: event.InsertId,
|
||||||
Time: event.ProtoPayload.RequestMetadata.RequestAttributes.Time.AsTime(),
|
Time: event.ProtoPayload.RequestMetadata.RequestAttributes.Time.AsTime(),
|
||||||
DataContentType: ContentTypeCloudEventsJson,
|
DataContentType: pkgAuditCommon.ContentTypeCloudEventsJson,
|
||||||
DataType: DataTypeLegacyAuditEventV1,
|
DataType: DataTypeLegacyAuditEventV1,
|
||||||
Subject: event.ProtoPayload.ResourceName,
|
Subject: event.ProtoPayload.ResourceName,
|
||||||
Data: legacyBytes,
|
Data: legacyBytes,
|
||||||
|
|
@ -141,15 +140,15 @@ func (a *LegacyAuditApi) ValidateAndSerialize(
|
||||||
// Send implements AuditApi.Send
|
// Send implements AuditApi.Send
|
||||||
func (a *LegacyAuditApi) Send(
|
func (a *LegacyAuditApi) Send(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
routableIdentifier *RoutableIdentifier,
|
routableIdentifier *pkgAuditCommon.RoutableIdentifier,
|
||||||
cloudEvent *CloudEvent,
|
cloudEvent *pkgAuditCommon.CloudEvent,
|
||||||
) error {
|
) error {
|
||||||
|
|
||||||
if cloudEvent != nil && cloudEvent.TraceParent != nil && cloudEvent.TraceState != nil {
|
if cloudEvent != nil && cloudEvent.TraceParent != nil && cloudEvent.TraceState != nil {
|
||||||
ctx = AddTraceParentAndStateToContext(ctx, *cloudEvent.TraceParent, *cloudEvent.TraceState)
|
ctx = internalAuditApi.AddTraceParentAndStateToContext(ctx, *cloudEvent.TraceParent, *cloudEvent.TraceState)
|
||||||
}
|
}
|
||||||
ctx, span := a.tracer.Start(ctx, "send")
|
ctx, span := a.tracer.Start(ctx, "send")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
return send(a.topicNameResolver, a.messagingApi, ctx, routableIdentifier, cloudEvent)
|
return internalAuditApi.Send(a.topicNameResolver, a.messagingApi, ctx, routableIdentifier, cloudEvent)
|
||||||
}
|
}
|
||||||
|
|
@ -4,14 +4,16 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go.opentelemetry.io/otel"
|
|
||||||
"go.opentelemetry.io/otel/trace"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/audit/messaging"
|
"go.opentelemetry.io/otel"
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
"go.opentelemetry.io/otel/trace"
|
||||||
|
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
internalAuditApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/internal/audit/api"
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
|
pkgMessagingApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ContextKey string
|
type ContextKey string
|
||||||
|
|
@ -26,25 +28,25 @@ var ErrTopicNameEmpty = errors.New("empty topic name provided")
|
||||||
//
|
//
|
||||||
// Note: The implementation will be deprecated and replaced with the "routableAuditApi" once the new audit log routing is implemented
|
// Note: The implementation will be deprecated and replaced with the "routableAuditApi" once the new audit log routing is implemented
|
||||||
type DynamicLegacyAuditApi struct {
|
type DynamicLegacyAuditApi struct {
|
||||||
messagingApi messaging.Api
|
messagingApi pkgMessagingApi.Api
|
||||||
tracer trace.Tracer
|
tracer trace.Tracer
|
||||||
validator ProtobufValidator
|
validator pkgAuditCommon.ProtobufValidator
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDynamicLegacyAuditApi can be used to initialize the audit log api.
|
// NewDynamicLegacyAuditApi can be used to initialize the audit log api.
|
||||||
//
|
//
|
||||||
// Note: The NewLegacyAuditApi method will be deprecated and replaced with "newRoutableAuditApi" once the new audit log routing is implemented
|
// Note: The NewLegacyAuditApi method will be deprecated and replaced with "newRoutableAuditApi" once the new audit log routing is implemented
|
||||||
func NewDynamicLegacyAuditApi(
|
func NewDynamicLegacyAuditApi(
|
||||||
messagingApi messaging.Api,
|
messagingApi pkgMessagingApi.Api,
|
||||||
validator ProtobufValidator,
|
validator pkgAuditCommon.ProtobufValidator,
|
||||||
) (AuditApi, error) {
|
) (pkgAuditCommon.AuditApi, error) {
|
||||||
|
|
||||||
if messagingApi == nil {
|
if messagingApi == nil {
|
||||||
return nil, ErrMessagingApiNil
|
return nil, pkgAuditCommon.ErrMessagingApiNil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Audit api
|
// Audit api
|
||||||
var auditApi AuditApi = &DynamicLegacyAuditApi{
|
var auditApi pkgAuditCommon.AuditApi = &DynamicLegacyAuditApi{
|
||||||
messagingApi: messagingApi,
|
messagingApi: messagingApi,
|
||||||
tracer: otel.Tracer("dynamic-legacy-audit-api"),
|
tracer: otel.Tracer("dynamic-legacy-audit-api"),
|
||||||
validator: validator,
|
validator: validator,
|
||||||
|
|
@ -58,7 +60,7 @@ func (a *DynamicLegacyAuditApi) Log(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
event *auditV1.AuditLogEntry,
|
event *auditV1.AuditLogEntry,
|
||||||
visibility auditV1.Visibility,
|
visibility auditV1.Visibility,
|
||||||
routableIdentifier *RoutableIdentifier,
|
routableIdentifier *pkgAuditCommon.RoutableIdentifier,
|
||||||
) error {
|
) error {
|
||||||
|
|
||||||
cloudEvent, err := a.ValidateAndSerialize(ctx, event, visibility, routableIdentifier)
|
cloudEvent, err := a.ValidateAndSerialize(ctx, event, visibility, routableIdentifier)
|
||||||
|
|
@ -75,21 +77,21 @@ func (a *DynamicLegacyAuditApi) ValidateAndSerialize(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
event *auditV1.AuditLogEntry,
|
event *auditV1.AuditLogEntry,
|
||||||
visibility auditV1.Visibility,
|
visibility auditV1.Visibility,
|
||||||
routableIdentifier *RoutableIdentifier,
|
routableIdentifier *pkgAuditCommon.RoutableIdentifier,
|
||||||
) (*CloudEvent, error) {
|
) (*pkgAuditCommon.CloudEvent, error) {
|
||||||
|
|
||||||
ctx, span := a.tracer.Start(ctx, "validate-and-serialize")
|
ctx, span := a.tracer.Start(ctx, "validate-and-serialize")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
routableEvent, err := validateAndSerializePartially(a.validator, event, visibility, routableIdentifier)
|
routableEvent, err := internalAuditApi.ValidateAndSerializePartially(a.validator, event, visibility, routableIdentifier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reject event type data-access as the downstream services
|
// Reject event type data-access as the downstream services
|
||||||
// cannot handle it at the moment
|
// cannot handle it at the moment
|
||||||
if strings.HasSuffix(event.LogName, string(EventTypeDataAccess)) {
|
if strings.HasSuffix(event.LogName, string(pkgAuditCommon.EventTypeDataAccess)) {
|
||||||
return nil, ErrUnsupportedEventTypeDataAccess
|
return nil, pkgAuditCommon.ErrUnsupportedEventTypeDataAccess
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do nothing with the serialized data in the legacy solution
|
// Do nothing with the serialized data in the legacy solution
|
||||||
|
|
@ -99,19 +101,19 @@ func (a *DynamicLegacyAuditApi) ValidateAndSerialize(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert attributes
|
// Convert attributes
|
||||||
legacyBytes, err := convertAndSerializeIntoLegacyFormat(event, routableEvent)
|
legacyBytes, err := internalAuditApi.ConvertAndSerializeIntoLegacyFormat(event, routableEvent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
traceParent, traceState := TraceParentAndStateFromContext(ctx)
|
traceParent, traceState := internalAuditApi.TraceParentAndStateFromContext(ctx)
|
||||||
|
|
||||||
message := CloudEvent{
|
message := pkgAuditCommon.CloudEvent{
|
||||||
SpecVersion: "1.0",
|
SpecVersion: "1.0",
|
||||||
Source: event.ProtoPayload.ServiceName,
|
Source: event.ProtoPayload.ServiceName,
|
||||||
Id: event.InsertId,
|
Id: event.InsertId,
|
||||||
Time: event.ProtoPayload.RequestMetadata.RequestAttributes.Time.AsTime(),
|
Time: event.ProtoPayload.RequestMetadata.RequestAttributes.Time.AsTime(),
|
||||||
DataContentType: ContentTypeCloudEventsJson,
|
DataContentType: pkgAuditCommon.ContentTypeCloudEventsJson,
|
||||||
DataType: DataTypeLegacyAuditEventV1,
|
DataType: DataTypeLegacyAuditEventV1,
|
||||||
Subject: event.ProtoPayload.ResourceName,
|
Subject: event.ProtoPayload.ResourceName,
|
||||||
Data: legacyBytes,
|
Data: legacyBytes,
|
||||||
|
|
@ -126,8 +128,8 @@ func (a *DynamicLegacyAuditApi) ValidateAndSerialize(
|
||||||
// Requires to have the topic name set as key "topic" in the context.
|
// Requires to have the topic name set as key "topic" in the context.
|
||||||
func (a *DynamicLegacyAuditApi) Send(
|
func (a *DynamicLegacyAuditApi) Send(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
routableIdentifier *RoutableIdentifier,
|
routableIdentifier *pkgAuditCommon.RoutableIdentifier,
|
||||||
cloudEvent *CloudEvent,
|
cloudEvent *pkgAuditCommon.CloudEvent,
|
||||||
) error {
|
) error {
|
||||||
|
|
||||||
rawTopicName := ctx.Value(ContextKeyTopic)
|
rawTopicName := ctx.Value(ContextKeyTopic)
|
||||||
|
|
@ -135,17 +137,23 @@ func (a *DynamicLegacyAuditApi) Send(
|
||||||
return ErrNoTopicNameProvided
|
return ErrNoTopicNameProvided
|
||||||
}
|
}
|
||||||
topicName := fmt.Sprintf("%s", rawTopicName)
|
topicName := fmt.Sprintf("%s", rawTopicName)
|
||||||
if len(topicName) == 0 {
|
if topicName == "" {
|
||||||
return ErrTopicNameEmpty
|
return ErrTopicNameEmpty
|
||||||
}
|
}
|
||||||
|
if !pkgAuditCommon.TopicNamePattern.MatchString(topicName) {
|
||||||
|
return fmt.Errorf("invalid topic name: %s - "+
|
||||||
|
"expected stackit-platform/t/swz/audit-log/{region}/{version}/{eventSource}/{additionalParts} "+
|
||||||
|
"where region is one of [conway, eu01, eu02, sx-stoi01], version is vX.Y, eventSource is the service name "+
|
||||||
|
"and additionalParts is a describing string the audit log relates to or 'events'", topicName)
|
||||||
|
}
|
||||||
|
|
||||||
var topicNameResolver TopicNameResolver = &LegacyTopicNameResolver{topicName: topicName}
|
var topicNameResolver pkgAuditCommon.TopicNameResolver = &pkgAuditCommon.StaticTopicNameTestResolver{TopicName: topicName}
|
||||||
|
|
||||||
if cloudEvent != nil && cloudEvent.TraceParent != nil && cloudEvent.TraceState != nil {
|
if cloudEvent != nil && cloudEvent.TraceParent != nil && cloudEvent.TraceState != nil {
|
||||||
ctx = AddTraceParentAndStateToContext(ctx, *cloudEvent.TraceParent, *cloudEvent.TraceState)
|
ctx = internalAuditApi.AddTraceParentAndStateToContext(ctx, *cloudEvent.TraceParent, *cloudEvent.TraceState)
|
||||||
}
|
}
|
||||||
ctx, span := a.tracer.Start(ctx, "send")
|
ctx, span := a.tracer.Start(ctx, "send")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
return send(topicNameResolver, a.messagingApi, ctx, routableIdentifier, cloudEvent)
|
return internalAuditApi.Send(topicNameResolver, a.messagingApi, ctx, routableIdentifier, cloudEvent)
|
||||||
}
|
}
|
||||||
|
|
@ -4,18 +4,22 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"go.opentelemetry.io/otel"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/audit/messaging"
|
"buf.build/go/protovalidate"
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
|
||||||
|
|
||||||
"github.com/bufbuild/protovalidate-go"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
|
|
||||||
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
internalAuditApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/internal/audit/api"
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
|
pkgMessagingApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/api"
|
||||||
|
pkgMessagingCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/common"
|
||||||
|
pkgMessagingTest "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDynamicLegacyAuditApi(t *testing.T) {
|
func TestDynamicLegacyAuditApi(t *testing.T) {
|
||||||
|
|
@ -25,14 +29,14 @@ func TestDynamicLegacyAuditApi(t *testing.T) {
|
||||||
defer cancelFn()
|
defer cancelFn()
|
||||||
|
|
||||||
// Start solace docker container
|
// Start solace docker container
|
||||||
solaceContainer, err := messaging.NewSolaceContainer(context.Background())
|
solaceContainer, err := pkgMessagingTest.NewSolaceContainer(context.Background())
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer solaceContainer.Stop()
|
defer solaceContainer.Stop()
|
||||||
|
|
||||||
// Instantiate the messaging api
|
// Instantiate the messaging api
|
||||||
messagingApi, err := messaging.NewAmqpApi(
|
amqpApi, err := pkgMessagingApi.NewAmqpApi(
|
||||||
messaging.AmqpConnectionPoolConfig{
|
pkgMessagingCommon.AmqpConnectionPoolConfig{
|
||||||
Parameters: messaging.AmqpConnectionConfig{BrokerUrl: solaceContainer.AmqpConnectionString},
|
Parameters: pkgMessagingCommon.AmqpConnectionConfig{BrokerUrl: solaceContainer.AmqpConnectionString},
|
||||||
PoolSize: 1,
|
PoolSize: 1,
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
@ -41,7 +45,7 @@ func TestDynamicLegacyAuditApi(t *testing.T) {
|
||||||
validator, err := protovalidate.New()
|
validator, err := protovalidate.New()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
topicSubscriptionTopicPattern := "audit-log/>"
|
topicSubscriptionTopicPattern := "stackit-platform/t/swz/audit-log/>"
|
||||||
|
|
||||||
// Check that event-type data-access is rejected as it is currently
|
// Check that event-type data-access is rejected as it is currently
|
||||||
// not supported by downstream services
|
// not supported by downstream services
|
||||||
|
|
@ -53,29 +57,29 @@ func TestDynamicLegacyAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
||||||
|
|
||||||
topicName := "topic://audit-log/eu01/v1/resource-manager/organization-rejected"
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/organization-rejected"
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
// Instantiate audit api
|
// Instantiate audit api
|
||||||
auditApi, err := NewDynamicLegacyAuditApi(
|
auditApi, err := NewDynamicLegacyAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
validator,
|
validator,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newOrganizationAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewOrganizationAuditEvent(nil)
|
||||||
event.LogName = strings.Replace(event.LogName, string(EventTypeAdminActivity), string(EventTypeDataAccess), 1)
|
event.LogName = strings.Replace(event.LogName, string(pkgAuditCommon.EventTypeAdminActivity), string(pkgAuditCommon.EventTypeDataAccess), 1)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
||||||
ctx := context.WithValue(ctx, ContextKeyTopic, topicName)
|
ctxWithTopic := context.WithValue(ctx, ContextKeyTopic, topicName)
|
||||||
assert.ErrorIs(t, auditApi.Log(
|
assert.ErrorIs(t, auditApi.Log(
|
||||||
ctx,
|
ctxWithTopic,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier),
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
||||||
), ErrUnsupportedEventTypeDataAccess)
|
), pkgAuditCommon.ErrUnsupportedEventTypeDataAccess)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Check logging of organization events
|
// Check logging of organization events
|
||||||
|
|
@ -87,27 +91,27 @@ func TestDynamicLegacyAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
||||||
|
|
||||||
topicName := "topic://audit-log/eu01/v1/resource-manager/organization-created"
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/organization-created"
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
// Instantiate audit api
|
// Instantiate audit api
|
||||||
auditApi, err := NewDynamicLegacyAuditApi(
|
auditApi, err := NewDynamicLegacyAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
validator,
|
validator,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newOrganizationAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewOrganizationAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
||||||
ctx := context.WithValue(ctx, ContextKeyTopic, topicName)
|
ctxWithTopic := context.WithValue(ctx, ContextKeyTopic, topicName)
|
||||||
assert.NoError(t, auditApi.Log(
|
assert.NoError(t, auditApi.Log(
|
||||||
ctx,
|
ctxWithTopic,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier),
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
||||||
))
|
))
|
||||||
|
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
|
|
@ -124,27 +128,27 @@ func TestDynamicLegacyAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
||||||
|
|
||||||
topicName := "topic://audit-log/eu01/v1/resource-manager/organization-created"
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/organization-created"
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
// Instantiate audit api
|
// Instantiate audit api
|
||||||
auditApi, err := NewDynamicLegacyAuditApi(
|
auditApi, err := NewDynamicLegacyAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
validator,
|
validator,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newOrganizationAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewOrganizationAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
||||||
ctx := context.WithValue(ctx, ContextKeyTopic, topicName)
|
ctxWithTopic := context.WithValue(ctx, ContextKeyTopic, topicName)
|
||||||
assert.NoError(t, auditApi.Log(
|
assert.NoError(t, auditApi.Log(
|
||||||
ctx,
|
ctxWithTopic,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier),
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
||||||
))
|
))
|
||||||
|
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
|
|
@ -162,27 +166,27 @@ func TestDynamicLegacyAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
||||||
|
|
||||||
topicName := "topic://audit-log/eu01/v1/resource-manager/folder-created"
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/folder-created"
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
// Instantiate audit api
|
// Instantiate audit api
|
||||||
auditApi, err := NewDynamicLegacyAuditApi(
|
auditApi, err := NewDynamicLegacyAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
validator,
|
validator,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newFolderAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewFolderAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
||||||
ctx := context.WithValue(ctx, ContextKeyTopic, topicName)
|
ctxWithTopic := context.WithValue(ctx, ContextKeyTopic, topicName)
|
||||||
assert.NoError(t, auditApi.Log(
|
assert.NoError(t, auditApi.Log(
|
||||||
ctx,
|
ctxWithTopic,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier),
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
||||||
))
|
))
|
||||||
|
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
|
|
@ -199,27 +203,27 @@ func TestDynamicLegacyAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
||||||
|
|
||||||
topicName := "topic://audit-log/eu01/v1/resource-manager/folder-created"
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/folder-created"
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
// Instantiate audit api
|
// Instantiate audit api
|
||||||
auditApi, err := NewDynamicLegacyAuditApi(
|
auditApi, err := NewDynamicLegacyAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
validator,
|
validator,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newFolderAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewFolderAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
||||||
ctx := context.WithValue(ctx, ContextKeyTopic, topicName)
|
ctxWithTopic := context.WithValue(ctx, ContextKeyTopic, topicName)
|
||||||
assert.NoError(t, auditApi.Log(
|
assert.NoError(t, auditApi.Log(
|
||||||
ctx,
|
ctxWithTopic,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier),
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
||||||
))
|
))
|
||||||
|
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
|
|
@ -237,27 +241,27 @@ func TestDynamicLegacyAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
||||||
|
|
||||||
topicName := "topic://audit-log/eu01/v1/resource-manager/project-created"
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/project-created"
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
// Instantiate audit api
|
// Instantiate audit api
|
||||||
auditApi, err := NewDynamicLegacyAuditApi(
|
auditApi, err := NewDynamicLegacyAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
validator,
|
validator,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newProjectAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewProjectAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
||||||
ctx := context.WithValue(ctx, ContextKeyTopic, topicName)
|
ctxWithTopic := context.WithValue(ctx, ContextKeyTopic, topicName)
|
||||||
assert.NoError(t, auditApi.Log(
|
assert.NoError(t, auditApi.Log(
|
||||||
ctx,
|
ctxWithTopic,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier),
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
||||||
))
|
))
|
||||||
|
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
|
|
@ -274,27 +278,27 @@ func TestDynamicLegacyAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
||||||
|
|
||||||
topicName := "topic://audit-log/eu01/v1/resource-manager/project-created"
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/project-created"
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
// Instantiate audit api
|
// Instantiate audit api
|
||||||
auditApi, err := NewDynamicLegacyAuditApi(
|
auditApi, err := NewDynamicLegacyAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
validator,
|
validator,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newProjectAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewProjectAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
||||||
ctx := context.WithValue(ctx, ContextKeyTopic, topicName)
|
ctxWithTopic := context.WithValue(ctx, ContextKeyTopic, topicName)
|
||||||
assert.NoError(t, auditApi.Log(
|
assert.NoError(t, auditApi.Log(
|
||||||
ctx,
|
ctxWithTopic,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier),
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
||||||
))
|
))
|
||||||
|
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
|
|
@ -311,28 +315,28 @@ func TestDynamicLegacyAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
||||||
|
|
||||||
topicName := "topic://audit-log/eu01/v1/resource-manager/project-system-changed"
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/project-system-changed"
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
// Instantiate audit api
|
// Instantiate audit api
|
||||||
auditApi, err := NewDynamicLegacyAuditApi(
|
auditApi, err := NewDynamicLegacyAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
validator,
|
validator,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event := newProjectSystemAuditEvent(nil)
|
event := internalAuditApi.NewProjectSystemAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
||||||
ctx := context.WithValue(ctx, ContextKeyTopic, topicName)
|
ctxWithTopic := context.WithValue(ctx, ContextKeyTopic, topicName)
|
||||||
assert.NoError(t,
|
assert.NoError(t,
|
||||||
auditApi.Log(
|
auditApi.Log(
|
||||||
ctx,
|
ctxWithTopic,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
RoutableSystemIdentifier,
|
pkgAuditCommon.RoutableSystemIdentifier,
|
||||||
))
|
))
|
||||||
|
|
||||||
// Receive the event from solace
|
// Receive the event from solace
|
||||||
|
|
@ -345,7 +349,7 @@ func TestDynamicLegacyAuditApi(t *testing.T) {
|
||||||
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:tracestate"])
|
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:tracestate"])
|
||||||
|
|
||||||
// Check deserialized message
|
// Check deserialized message
|
||||||
var auditEvent LegacyAuditEvent
|
var auditEvent internalAuditApi.LegacyAuditEvent
|
||||||
assert.NoError(t, json.Unmarshal(message.Data[0], &auditEvent))
|
assert.NoError(t, json.Unmarshal(message.Data[0], &auditEvent))
|
||||||
|
|
||||||
assert.Equal(t, event.ProtoPayload.ResourceName, *auditEvent.ResourceName)
|
assert.Equal(t, event.ProtoPayload.ResourceName, *auditEvent.ResourceName)
|
||||||
|
|
@ -367,28 +371,28 @@ func TestDynamicLegacyAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
||||||
|
|
||||||
topicName := "topic://audit-log/eu01/v1/resource-manager/system-changed"
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/system-changed"
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
// Instantiate audit api
|
// Instantiate audit api
|
||||||
auditApi, err := NewDynamicLegacyAuditApi(
|
auditApi, err := NewDynamicLegacyAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
validator,
|
validator,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event := newSystemAuditEvent(nil)
|
event := internalAuditApi.NewSystemAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
||||||
ctx := context.WithValue(ctx, ContextKeyTopic, topicName)
|
ctxWithTopic := context.WithValue(ctx, ContextKeyTopic, topicName)
|
||||||
assert.NoError(t,
|
assert.NoError(t,
|
||||||
auditApi.Log(
|
auditApi.Log(
|
||||||
ctx,
|
ctxWithTopic,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
RoutableSystemIdentifier,
|
pkgAuditCommon.RoutableSystemIdentifier,
|
||||||
))
|
))
|
||||||
|
|
||||||
// Receive the event from solace
|
// Receive the event from solace
|
||||||
|
|
@ -401,7 +405,7 @@ func TestDynamicLegacyAuditApi(t *testing.T) {
|
||||||
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:tracestate"])
|
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:tracestate"])
|
||||||
|
|
||||||
// Check deserialized message
|
// Check deserialized message
|
||||||
var auditEvent LegacyAuditEvent
|
var auditEvent internalAuditApi.LegacyAuditEvent
|
||||||
assert.NoError(t, json.Unmarshal(message.Data[0], &auditEvent))
|
assert.NoError(t, json.Unmarshal(message.Data[0], &auditEvent))
|
||||||
|
|
||||||
assert.Equal(t, event.ProtoPayload.OperationName, auditEvent.EventName)
|
assert.Equal(t, event.ProtoPayload.OperationName, auditEvent.EventName)
|
||||||
|
|
@ -422,29 +426,29 @@ func TestDynamicLegacyAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
||||||
|
|
||||||
topicName := "topic://audit-log/eu01/v1/resource-manager/organization-created"
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/organization-created"
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
// Instantiate audit api
|
// Instantiate audit api
|
||||||
auditApi, err := NewDynamicLegacyAuditApi(
|
auditApi, err := NewDynamicLegacyAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
validator,
|
validator,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newOrganizationAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewOrganizationAuditEvent(nil)
|
||||||
escapedQuery := url.QueryEscape("param=value")
|
escapedQuery := url.QueryEscape("param=value")
|
||||||
event.ProtoPayload.RequestMetadata.RequestAttributes.Query = &escapedQuery
|
event.ProtoPayload.RequestMetadata.RequestAttributes.Query = &escapedQuery
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
||||||
ctx := context.WithValue(ctx, ContextKeyTopic, topicName)
|
ctxWithTopic := context.WithValue(ctx, ContextKeyTopic, topicName)
|
||||||
assert.NoError(t, auditApi.Log(
|
assert.NoError(t, auditApi.Log(
|
||||||
ctx,
|
ctxWithTopic,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier),
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
||||||
))
|
))
|
||||||
|
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
|
|
@ -465,15 +469,15 @@ func TestDynamicLegacyAuditApi_ValidateAndSerialize_ValidationFailed(t *testing.
|
||||||
|
|
||||||
validator := &ProtobufValidatorMock{}
|
validator := &ProtobufValidatorMock{}
|
||||||
validator.On("Validate", mock.Anything).Return(expectedError)
|
validator.On("Validate", mock.Anything).Return(expectedError)
|
||||||
var protobufValidator ProtobufValidator = validator
|
var protobufValidator pkgAuditCommon.ProtobufValidator = validator
|
||||||
|
|
||||||
auditApi := DynamicLegacyAuditApi{
|
auditApi := DynamicLegacyAuditApi{
|
||||||
tracer: otel.Tracer("test"),
|
tracer: otel.Tracer("test"),
|
||||||
validator: protobufValidator,
|
validator: protobufValidator,
|
||||||
}
|
}
|
||||||
|
|
||||||
event := newSystemAuditEvent(nil)
|
event := internalAuditApi.NewSystemAuditEvent(nil)
|
||||||
_, err := auditApi.ValidateAndSerialize(context.Background(), event, auditV1.Visibility_VISIBILITY_PUBLIC, RoutableSystemIdentifier)
|
_, err := auditApi.ValidateAndSerialize(context.Background(), event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.RoutableSystemIdentifier)
|
||||||
assert.ErrorIs(t, err, expectedError)
|
assert.ErrorIs(t, err, expectedError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -482,22 +486,22 @@ func TestDynamicLegacyAuditApi_Log_ValidationFailed(t *testing.T) {
|
||||||
|
|
||||||
validator := &ProtobufValidatorMock{}
|
validator := &ProtobufValidatorMock{}
|
||||||
validator.On("Validate", mock.Anything).Return(expectedError)
|
validator.On("Validate", mock.Anything).Return(expectedError)
|
||||||
var protobufValidator ProtobufValidator = validator
|
var protobufValidator pkgAuditCommon.ProtobufValidator = validator
|
||||||
|
|
||||||
auditApi := DynamicLegacyAuditApi{
|
auditApi := DynamicLegacyAuditApi{
|
||||||
tracer: otel.Tracer("test"),
|
tracer: otel.Tracer("test"),
|
||||||
validator: protobufValidator,
|
validator: protobufValidator,
|
||||||
}
|
}
|
||||||
|
|
||||||
event := newSystemAuditEvent(nil)
|
event := internalAuditApi.NewSystemAuditEvent(nil)
|
||||||
err := auditApi.Log(context.Background(), event, auditV1.Visibility_VISIBILITY_PUBLIC, RoutableSystemIdentifier)
|
err := auditApi.Log(context.Background(), event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.RoutableSystemIdentifier)
|
||||||
assert.ErrorIs(t, err, expectedError)
|
assert.ErrorIs(t, err, expectedError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDynamicLegacyAuditApi_Log_NilEvent(t *testing.T) {
|
func TestDynamicLegacyAuditApi_Log_NilEvent(t *testing.T) {
|
||||||
auditApi := DynamicLegacyAuditApi{tracer: otel.Tracer("test")}
|
auditApi := DynamicLegacyAuditApi{tracer: otel.Tracer("test")}
|
||||||
err := auditApi.Log(context.Background(), nil, auditV1.Visibility_VISIBILITY_PUBLIC, RoutableSystemIdentifier)
|
err := auditApi.Log(context.Background(), nil, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.RoutableSystemIdentifier)
|
||||||
assert.ErrorIs(t, err, ErrEventNil)
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrEventNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDynamicLegacyAuditApi_ConvertAndSerializeIntoLegacyFormatInvalidObjectIdentifierType(t *testing.T) {
|
func TestDynamicLegacyAuditApi_ConvertAndSerializeIntoLegacyFormatInvalidObjectIdentifierType(t *testing.T) {
|
||||||
|
|
@ -505,16 +509,16 @@ func TestDynamicLegacyAuditApi_ConvertAndSerializeIntoLegacyFormatInvalidObjectI
|
||||||
objectIdentifier *auditV1.ObjectIdentifier) {
|
objectIdentifier *auditV1.ObjectIdentifier) {
|
||||||
objectIdentifier.Type = "invalid"
|
objectIdentifier.Type = "invalid"
|
||||||
}
|
}
|
||||||
event, objectIdentifier := newProjectAuditEvent(&customization)
|
event, objectIdentifier := internalAuditApi.NewProjectAuditEvent(&customization)
|
||||||
|
|
||||||
validator := &ProtobufValidatorMock{}
|
validator := &ProtobufValidatorMock{}
|
||||||
validator.On("Validate", mock.Anything).Return(nil)
|
validator.On("Validate", mock.Anything).Return(nil)
|
||||||
var protobufValidator ProtobufValidator = validator
|
var protobufValidator pkgAuditCommon.ProtobufValidator = validator
|
||||||
|
|
||||||
auditApi := DynamicLegacyAuditApi{
|
auditApi := DynamicLegacyAuditApi{
|
||||||
tracer: otel.Tracer("test"),
|
tracer: otel.Tracer("test"),
|
||||||
validator: protobufValidator,
|
validator: protobufValidator,
|
||||||
}
|
}
|
||||||
_, err := auditApi.ValidateAndSerialize(context.Background(), event, auditV1.Visibility_VISIBILITY_PUBLIC, NewRoutableIdentifier(objectIdentifier))
|
_, err := auditApi.ValidateAndSerialize(context.Background(), event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.NewRoutableIdentifier(objectIdentifier))
|
||||||
assert.ErrorIs(t, err, ErrUnsupportedRoutableType)
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrUnsupportedRoutableType)
|
||||||
}
|
}
|
||||||
|
|
@ -5,19 +5,23 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go.opentelemetry.io/otel"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/audit/messaging"
|
"buf.build/go/protovalidate"
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
|
||||||
|
|
||||||
"github.com/Azure/go-amqp"
|
"github.com/Azure/go-amqp"
|
||||||
"github.com/bufbuild/protovalidate-go"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
|
|
||||||
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
internalAuditApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/internal/audit/api"
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
|
pkgMessagingApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/api"
|
||||||
|
pkgMessagingCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/common"
|
||||||
|
pkgMessagingTest "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLegacyAuditApi(t *testing.T) {
|
func TestLegacyAuditApi(t *testing.T) {
|
||||||
|
|
@ -27,13 +31,13 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
defer cancelFn()
|
defer cancelFn()
|
||||||
|
|
||||||
// Start solace docker container
|
// Start solace docker container
|
||||||
solaceContainer, err := messaging.NewSolaceContainer(context.Background())
|
solaceContainer, err := pkgMessagingTest.NewSolaceContainer(context.Background())
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer solaceContainer.Stop()
|
defer solaceContainer.Stop()
|
||||||
|
|
||||||
// Instantiate the messaging api
|
// Instantiate the messaging api
|
||||||
messagingApi, err := messaging.NewAmqpApi(messaging.AmqpConnectionPoolConfig{
|
amqpApi, err := pkgMessagingApi.NewAmqpApi(pkgMessagingCommon.AmqpConnectionPoolConfig{
|
||||||
Parameters: messaging.AmqpConnectionConfig{BrokerUrl: solaceContainer.AmqpConnectionString},
|
Parameters: pkgMessagingCommon.AmqpConnectionConfig{BrokerUrl: solaceContainer.AmqpConnectionString},
|
||||||
PoolSize: 1,
|
PoolSize: 1,
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
@ -42,7 +46,7 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
validator, err := protovalidate.New()
|
validator, err := protovalidate.New()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
topicSubscriptionTopicPattern := "audit-log/>"
|
topicSubscriptionTopicPattern := "stackit-platform/t/swz/audit-log/>"
|
||||||
|
|
||||||
// Check that event-type data-access is rejected as it is currently
|
// Check that event-type data-access is rejected as it is currently
|
||||||
// not supported by downstream services
|
// not supported by downstream services
|
||||||
|
|
@ -54,28 +58,28 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
||||||
|
|
||||||
topicName := "topic://audit-log/eu01/v1/resource-manager/organization-rejected"
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/organization-rejected"
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
// Instantiate audit api
|
// Instantiate audit api
|
||||||
auditApi, err := NewLegacyAuditApi(
|
auditApi, err := NewLegacyAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
LegacyTopicNameConfig{TopicName: topicName},
|
StaticTopicNameConfig{TopicName: topicName},
|
||||||
validator,
|
validator,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newOrganizationAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewOrganizationAuditEvent(nil)
|
||||||
event.LogName = strings.Replace(event.LogName, string(EventTypeAdminActivity), string(EventTypeDataAccess), 1)
|
event.LogName = strings.Replace(event.LogName, string(pkgAuditCommon.EventTypeAdminActivity), string(pkgAuditCommon.EventTypeDataAccess), 1)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
assert.ErrorIs(t, auditApi.Log(
|
assert.ErrorIs(t, auditApi.Log(
|
||||||
ctx,
|
ctx,
|
||||||
event,
|
event,
|
||||||
auditV1.Visibility_VISIBILITY_PUBLIC,
|
auditV1.Visibility_VISIBILITY_PUBLIC,
|
||||||
NewRoutableIdentifier(objectIdentifier),
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
||||||
), ErrUnsupportedEventTypeDataAccess)
|
), pkgAuditCommon.ErrUnsupportedEventTypeDataAccess)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Check logging of organization events
|
// Check logging of organization events
|
||||||
|
|
@ -87,19 +91,19 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
||||||
|
|
||||||
topicName := "topic://audit-log/eu01/v1/resource-manager/organization-created"
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/organization-created"
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
// Instantiate audit api
|
// Instantiate audit api
|
||||||
auditApi, err := NewLegacyAuditApi(
|
auditApi, err := NewLegacyAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
LegacyTopicNameConfig{TopicName: topicName},
|
StaticTopicNameConfig{TopicName: topicName},
|
||||||
validator,
|
validator,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newOrganizationAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewOrganizationAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
||||||
|
|
@ -107,7 +111,7 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
ctx,
|
ctx,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier),
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
||||||
))
|
))
|
||||||
|
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
|
|
@ -124,19 +128,19 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
||||||
|
|
||||||
topicName := "topic://audit-log/eu01/v1/resource-manager/organization-created"
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/organization-created"
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
// Instantiate audit api
|
// Instantiate audit api
|
||||||
auditApi, err := NewLegacyAuditApi(
|
auditApi, err := NewLegacyAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
LegacyTopicNameConfig{TopicName: topicName},
|
StaticTopicNameConfig{TopicName: topicName},
|
||||||
validator,
|
validator,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newOrganizationAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewOrganizationAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
||||||
|
|
@ -144,7 +148,7 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
ctx,
|
ctx,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier),
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
||||||
))
|
))
|
||||||
|
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
|
|
@ -162,19 +166,19 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
||||||
|
|
||||||
topicName := "topic://audit-log/eu01/v1/resource-manager/folder-created"
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/folder-created"
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
// Instantiate audit api
|
// Instantiate audit api
|
||||||
auditApi, err := NewLegacyAuditApi(
|
auditApi, err := NewLegacyAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
LegacyTopicNameConfig{TopicName: topicName},
|
StaticTopicNameConfig{TopicName: topicName},
|
||||||
validator,
|
validator,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newFolderAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewFolderAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
||||||
|
|
@ -182,7 +186,7 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
ctx,
|
ctx,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier),
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
||||||
))
|
))
|
||||||
|
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
|
|
@ -199,19 +203,19 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
||||||
|
|
||||||
topicName := "topic://audit-log/eu01/v1/resource-manager/folder-created"
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/folder-created"
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
// Instantiate audit api
|
// Instantiate audit api
|
||||||
auditApi, err := NewLegacyAuditApi(
|
auditApi, err := NewLegacyAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
LegacyTopicNameConfig{TopicName: topicName},
|
StaticTopicNameConfig{TopicName: topicName},
|
||||||
validator,
|
validator,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newFolderAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewFolderAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
||||||
|
|
@ -219,7 +223,7 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
ctx,
|
ctx,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier),
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
||||||
))
|
))
|
||||||
|
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
|
|
@ -237,19 +241,19 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
||||||
|
|
||||||
topicName := "topic://audit-log/eu01/v1/resource-manager/project-created"
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/project-created"
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
// Instantiate audit api
|
// Instantiate audit api
|
||||||
auditApi, err := NewLegacyAuditApi(
|
auditApi, err := NewLegacyAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
LegacyTopicNameConfig{TopicName: topicName},
|
StaticTopicNameConfig{TopicName: topicName},
|
||||||
validator,
|
validator,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newProjectAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewProjectAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
||||||
|
|
@ -257,7 +261,7 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
ctx,
|
ctx,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier),
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
||||||
))
|
))
|
||||||
|
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
|
|
@ -274,19 +278,19 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
||||||
|
|
||||||
topicName := "topic://audit-log/eu01/v1/resource-manager/project-created"
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/project-created"
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
// Instantiate audit api
|
// Instantiate audit api
|
||||||
auditApi, err := NewLegacyAuditApi(
|
auditApi, err := NewLegacyAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
LegacyTopicNameConfig{TopicName: topicName},
|
StaticTopicNameConfig{TopicName: topicName},
|
||||||
validator,
|
validator,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newProjectAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewProjectAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
||||||
|
|
@ -294,7 +298,7 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
ctx,
|
ctx,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier),
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
||||||
))
|
))
|
||||||
|
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
|
|
@ -311,19 +315,19 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
||||||
|
|
||||||
topicName := "topic://audit-log/eu01/v1/resource-manager/project-system-changed"
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/project-system-changed"
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
// Instantiate audit api
|
// Instantiate audit api
|
||||||
auditApi, err := NewLegacyAuditApi(
|
auditApi, err := NewLegacyAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
LegacyTopicNameConfig{TopicName: topicName},
|
StaticTopicNameConfig{TopicName: topicName},
|
||||||
validator,
|
validator,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event := newProjectSystemAuditEvent(nil)
|
event := internalAuditApi.NewProjectSystemAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
||||||
|
|
@ -332,7 +336,7 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
ctx,
|
ctx,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
RoutableSystemIdentifier,
|
pkgAuditCommon.RoutableSystemIdentifier,
|
||||||
))
|
))
|
||||||
|
|
||||||
// Receive the event from solace
|
// Receive the event from solace
|
||||||
|
|
@ -345,7 +349,7 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:tracestate"])
|
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:tracestate"])
|
||||||
|
|
||||||
// Check deserialized message
|
// Check deserialized message
|
||||||
var auditEvent LegacyAuditEvent
|
var auditEvent internalAuditApi.LegacyAuditEvent
|
||||||
assert.NoError(t, json.Unmarshal(message.Data[0], &auditEvent))
|
assert.NoError(t, json.Unmarshal(message.Data[0], &auditEvent))
|
||||||
|
|
||||||
assert.Equal(t, event.ProtoPayload.ResourceName, *auditEvent.ResourceName)
|
assert.Equal(t, event.ProtoPayload.ResourceName, *auditEvent.ResourceName)
|
||||||
|
|
@ -367,19 +371,19 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
||||||
|
|
||||||
topicName := "topic://audit-log/eu01/v1/resource-manager/system-changed"
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/system-changed"
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
// Instantiate audit api
|
// Instantiate audit api
|
||||||
auditApi, err := NewLegacyAuditApi(
|
auditApi, err := NewLegacyAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
LegacyTopicNameConfig{TopicName: topicName},
|
StaticTopicNameConfig{TopicName: topicName},
|
||||||
validator,
|
validator,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event := newSystemAuditEvent(nil)
|
event := internalAuditApi.NewSystemAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
||||||
|
|
@ -388,7 +392,7 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
ctx,
|
ctx,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
RoutableSystemIdentifier,
|
pkgAuditCommon.RoutableSystemIdentifier,
|
||||||
))
|
))
|
||||||
|
|
||||||
// Receive the event from solace
|
// Receive the event from solace
|
||||||
|
|
@ -401,7 +405,7 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:tracestate"])
|
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:tracestate"])
|
||||||
|
|
||||||
// Check deserialized message
|
// Check deserialized message
|
||||||
var auditEvent LegacyAuditEvent
|
var auditEvent internalAuditApi.LegacyAuditEvent
|
||||||
assert.NoError(t, json.Unmarshal(message.Data[0], &auditEvent))
|
assert.NoError(t, json.Unmarshal(message.Data[0], &auditEvent))
|
||||||
|
|
||||||
assert.Equal(t, event.ProtoPayload.OperationName, auditEvent.EventName)
|
assert.Equal(t, event.ProtoPayload.OperationName, auditEvent.EventName)
|
||||||
|
|
@ -422,19 +426,19 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
||||||
|
|
||||||
topicName := "topic://audit-log/eu01/v1/resource-manager/organization-created"
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/organization-created"
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
// Instantiate audit api
|
// Instantiate audit api
|
||||||
auditApi, err := NewLegacyAuditApi(
|
auditApi, err := NewLegacyAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
LegacyTopicNameConfig{TopicName: topicName},
|
StaticTopicNameConfig{TopicName: topicName},
|
||||||
validator,
|
validator,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newOrganizationAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewOrganizationAuditEvent(nil)
|
||||||
escapedQuery := url.QueryEscape("param=value")
|
escapedQuery := url.QueryEscape("param=value")
|
||||||
event.ProtoPayload.RequestMetadata.RequestAttributes.Query = &escapedQuery
|
event.ProtoPayload.RequestMetadata.RequestAttributes.Query = &escapedQuery
|
||||||
|
|
||||||
|
|
@ -444,7 +448,7 @@ func TestLegacyAuditApi(t *testing.T) {
|
||||||
ctx,
|
ctx,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier),
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
||||||
))
|
))
|
||||||
|
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
|
|
@ -467,7 +471,7 @@ func validateSentMessage(
|
||||||
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:tracestate"])
|
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:tracestate"])
|
||||||
|
|
||||||
// Check deserialized message
|
// Check deserialized message
|
||||||
var auditEvent LegacyAuditEvent
|
var auditEvent internalAuditApi.LegacyAuditEvent
|
||||||
assert.NoError(t, json.Unmarshal(message.Data[0], &auditEvent))
|
assert.NoError(t, json.Unmarshal(message.Data[0], &auditEvent))
|
||||||
|
|
||||||
var severity string
|
var severity string
|
||||||
|
|
@ -513,13 +517,13 @@ func validateSentMessageWithDetails(
|
||||||
|
|
||||||
// Check topic name
|
// Check topic name
|
||||||
assert.Equal(t, topicName, *message.Properties.To)
|
assert.Equal(t, topicName, *message.Properties.To)
|
||||||
assert.Equal(t, ContentTypeCloudEventsJson, message.ApplicationProperties["cloudEvents:datacontenttype"])
|
assert.Equal(t, pkgAuditCommon.ContentTypeCloudEventsJson, message.ApplicationProperties["cloudEvents:datacontenttype"])
|
||||||
assert.Equal(t, DataTypeLegacyAuditEventV1, message.ApplicationProperties["cloudEvents:type"])
|
assert.Equal(t, DataTypeLegacyAuditEventV1, message.ApplicationProperties["cloudEvents:type"])
|
||||||
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:traceparent"])
|
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:traceparent"])
|
||||||
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:tracestate"])
|
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:tracestate"])
|
||||||
|
|
||||||
// Check deserialized message
|
// Check deserialized message
|
||||||
var auditEvent LegacyAuditEvent
|
var auditEvent internalAuditApi.LegacyAuditEvent
|
||||||
assert.NoError(t, json.Unmarshal(message.Data[0], &auditEvent))
|
assert.NoError(t, json.Unmarshal(message.Data[0], &auditEvent))
|
||||||
|
|
||||||
assert.Equal(t, event.ProtoPayload.OperationName, auditEvent.EventName)
|
assert.Equal(t, event.ProtoPayload.OperationName, auditEvent.EventName)
|
||||||
|
|
@ -570,20 +574,20 @@ func validateSentMessageWithDetails(
|
||||||
func TestLegacyAuditApi_NewLegacyAuditApi(t *testing.T) {
|
func TestLegacyAuditApi_NewLegacyAuditApi(t *testing.T) {
|
||||||
|
|
||||||
t.Run("messaging api nil", func(t *testing.T) {
|
t.Run("messaging api nil", func(t *testing.T) {
|
||||||
auditApi, err := NewLegacyAuditApi(nil, LegacyTopicNameConfig{}, nil)
|
auditApi, err := NewLegacyAuditApi(nil, StaticTopicNameConfig{}, nil)
|
||||||
assert.Nil(t, auditApi)
|
assert.Nil(t, auditApi)
|
||||||
assert.EqualError(t, err, "messaging api nil")
|
assert.EqualError(t, err, "messaging api nil")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("topic name is blank", func(t *testing.T) {
|
t.Run("topic name is blank", func(t *testing.T) {
|
||||||
// Start solace docker container
|
// Start solace docker container
|
||||||
solaceContainer, err := messaging.NewSolaceContainer(context.Background())
|
solaceContainer, err := pkgMessagingTest.NewSolaceContainer(context.Background())
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer solaceContainer.Stop()
|
defer solaceContainer.Stop()
|
||||||
|
|
||||||
// Instantiate the messaging api
|
// Instantiate the messaging api
|
||||||
messagingApi, err := messaging.NewAmqpApi(messaging.AmqpConnectionPoolConfig{
|
amqpApi, err := pkgMessagingApi.NewAmqpApi(pkgMessagingCommon.AmqpConnectionPoolConfig{
|
||||||
Parameters: messaging.AmqpConnectionConfig{BrokerUrl: solaceContainer.AmqpConnectionString},
|
Parameters: pkgMessagingCommon.AmqpConnectionConfig{BrokerUrl: solaceContainer.AmqpConnectionString},
|
||||||
PoolSize: 1,
|
PoolSize: 1,
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
@ -592,7 +596,7 @@ func TestLegacyAuditApi_NewLegacyAuditApi(t *testing.T) {
|
||||||
validator, err := protovalidate.New()
|
validator, err := protovalidate.New()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
auditApi, err := NewLegacyAuditApi(messagingApi, LegacyTopicNameConfig{
|
auditApi, err := NewLegacyAuditApi(amqpApi, StaticTopicNameConfig{
|
||||||
TopicName: "",
|
TopicName: "",
|
||||||
}, validator)
|
}, validator)
|
||||||
|
|
||||||
|
|
@ -606,15 +610,15 @@ func TestLegacyAuditApi_ValidateAndSerialize_ValidationFailed(t *testing.T) {
|
||||||
|
|
||||||
validator := &ProtobufValidatorMock{}
|
validator := &ProtobufValidatorMock{}
|
||||||
validator.On("Validate", mock.Anything).Return(expectedError)
|
validator.On("Validate", mock.Anything).Return(expectedError)
|
||||||
var protobufValidator ProtobufValidator = validator
|
var protobufValidator pkgAuditCommon.ProtobufValidator = validator
|
||||||
|
|
||||||
auditApi := LegacyAuditApi{
|
auditApi := LegacyAuditApi{
|
||||||
tracer: otel.Tracer("test"),
|
tracer: otel.Tracer("test"),
|
||||||
validator: protobufValidator,
|
validator: protobufValidator,
|
||||||
}
|
}
|
||||||
|
|
||||||
event := newSystemAuditEvent(nil)
|
event := internalAuditApi.NewSystemAuditEvent(nil)
|
||||||
_, err := auditApi.ValidateAndSerialize(context.Background(), event, auditV1.Visibility_VISIBILITY_PUBLIC, RoutableSystemIdentifier)
|
_, err := auditApi.ValidateAndSerialize(context.Background(), event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.RoutableSystemIdentifier)
|
||||||
assert.ErrorIs(t, err, expectedError)
|
assert.ErrorIs(t, err, expectedError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -623,22 +627,22 @@ func TestLegacyAuditApi_Log_ValidationFailed(t *testing.T) {
|
||||||
|
|
||||||
validator := &ProtobufValidatorMock{}
|
validator := &ProtobufValidatorMock{}
|
||||||
validator.On("Validate", mock.Anything).Return(expectedError)
|
validator.On("Validate", mock.Anything).Return(expectedError)
|
||||||
var protobufValidator ProtobufValidator = validator
|
var protobufValidator pkgAuditCommon.ProtobufValidator = validator
|
||||||
|
|
||||||
auditApi := LegacyAuditApi{
|
auditApi := LegacyAuditApi{
|
||||||
tracer: otel.Tracer("test"),
|
tracer: otel.Tracer("test"),
|
||||||
validator: protobufValidator,
|
validator: protobufValidator,
|
||||||
}
|
}
|
||||||
|
|
||||||
event := newSystemAuditEvent(nil)
|
event := internalAuditApi.NewSystemAuditEvent(nil)
|
||||||
err := auditApi.Log(context.Background(), event, auditV1.Visibility_VISIBILITY_PUBLIC, RoutableSystemIdentifier)
|
err := auditApi.Log(context.Background(), event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.RoutableSystemIdentifier)
|
||||||
assert.ErrorIs(t, err, expectedError)
|
assert.ErrorIs(t, err, expectedError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLegacyAuditApi_Log_NilEvent(t *testing.T) {
|
func TestLegacyAuditApi_Log_NilEvent(t *testing.T) {
|
||||||
auditApi := LegacyAuditApi{tracer: otel.Tracer("test")}
|
auditApi := LegacyAuditApi{tracer: otel.Tracer("test")}
|
||||||
err := auditApi.Log(context.Background(), nil, auditV1.Visibility_VISIBILITY_PUBLIC, RoutableSystemIdentifier)
|
err := auditApi.Log(context.Background(), nil, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.RoutableSystemIdentifier)
|
||||||
assert.ErrorIs(t, err, ErrEventNil)
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrEventNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLegacyAuditApi_ConvertAndSerializeIntoLegacyFormatInvalidObjectIdentifierType(t *testing.T) {
|
func TestLegacyAuditApi_ConvertAndSerializeIntoLegacyFormatInvalidObjectIdentifierType(t *testing.T) {
|
||||||
|
|
@ -646,16 +650,16 @@ func TestLegacyAuditApi_ConvertAndSerializeIntoLegacyFormatInvalidObjectIdentifi
|
||||||
objectIdentifier *auditV1.ObjectIdentifier) {
|
objectIdentifier *auditV1.ObjectIdentifier) {
|
||||||
objectIdentifier.Type = "invalid"
|
objectIdentifier.Type = "invalid"
|
||||||
}
|
}
|
||||||
event, objectIdentifier := newProjectAuditEvent(&customization)
|
event, objectIdentifier := internalAuditApi.NewProjectAuditEvent(&customization)
|
||||||
|
|
||||||
validator := &ProtobufValidatorMock{}
|
validator := &ProtobufValidatorMock{}
|
||||||
validator.On("Validate", mock.Anything).Return(nil)
|
validator.On("Validate", mock.Anything).Return(nil)
|
||||||
var protobufValidator ProtobufValidator = validator
|
var protobufValidator pkgAuditCommon.ProtobufValidator = validator
|
||||||
|
|
||||||
auditApi := LegacyAuditApi{
|
auditApi := LegacyAuditApi{
|
||||||
tracer: otel.Tracer("test"),
|
tracer: otel.Tracer("test"),
|
||||||
validator: protobufValidator,
|
validator: protobufValidator,
|
||||||
}
|
}
|
||||||
_, err := auditApi.ValidateAndSerialize(context.Background(), event, auditV1.Visibility_VISIBILITY_PUBLIC, NewRoutableIdentifier(objectIdentifier))
|
_, err := auditApi.ValidateAndSerialize(context.Background(), event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.NewRoutableIdentifier(objectIdentifier))
|
||||||
assert.ErrorIs(t, err, ErrUnsupportedRoutableType)
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrUnsupportedRoutableType)
|
||||||
}
|
}
|
||||||
|
|
@ -3,30 +3,31 @@ package api
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go.opentelemetry.io/otel"
|
|
||||||
"go.opentelemetry.io/otel/trace"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"buf.build/go/protovalidate"
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
internalApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/internal/audit/api"
|
||||||
"github.com/bufbuild/protovalidate-go"
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MockAuditApi is an implementation of AuditApi that does nothing and has no dependency to external systems.
|
// MockAuditApi is an implementation of AuditApi that does nothing and has no dependency to external systems.
|
||||||
type MockAuditApi struct {
|
type MockAuditApi struct {
|
||||||
tracer trace.Tracer
|
tracer trace.Tracer
|
||||||
validator ProtobufValidator
|
validator pkgAuditCommon.ProtobufValidator
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMockAuditApi() (AuditApi, error) {
|
func NewMockAuditApi() (pkgAuditCommon.AuditApi, error) {
|
||||||
validator, err := protovalidate.New()
|
validator, err := protovalidate.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var protobufValidator ProtobufValidator = validator
|
var protobufValidator pkgAuditCommon.ProtobufValidator = validator
|
||||||
var auditApi AuditApi = &MockAuditApi{
|
var auditApi pkgAuditCommon.AuditApi = &MockAuditApi{
|
||||||
tracer: otel.Tracer("mock-audit-api"),
|
tracer: otel.Tracer("mock-audit-api"),
|
||||||
validator: protobufValidator,
|
validator: protobufValidator,
|
||||||
}
|
}
|
||||||
|
|
@ -39,7 +40,7 @@ func (a *MockAuditApi) Log(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
event *auditV1.AuditLogEntry,
|
event *auditV1.AuditLogEntry,
|
||||||
visibility auditV1.Visibility,
|
visibility auditV1.Visibility,
|
||||||
routableIdentifier *RoutableIdentifier,
|
routableIdentifier *pkgAuditCommon.RoutableIdentifier,
|
||||||
) error {
|
) error {
|
||||||
|
|
||||||
_, err := a.ValidateAndSerialize(ctx, event, visibility, routableIdentifier)
|
_, err := a.ValidateAndSerialize(ctx, event, visibility, routableIdentifier)
|
||||||
|
|
@ -51,21 +52,21 @@ func (a *MockAuditApi) ValidateAndSerialize(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
event *auditV1.AuditLogEntry,
|
event *auditV1.AuditLogEntry,
|
||||||
visibility auditV1.Visibility,
|
visibility auditV1.Visibility,
|
||||||
routableIdentifier *RoutableIdentifier,
|
routableIdentifier *pkgAuditCommon.RoutableIdentifier,
|
||||||
) (*CloudEvent, error) {
|
) (*pkgAuditCommon.CloudEvent, error) {
|
||||||
|
|
||||||
ctx, span := a.tracer.Start(ctx, "validate-and-serialize")
|
ctx, span := a.tracer.Start(ctx, "validate-and-serialize")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
routableEvent, err := validateAndSerializePartially(a.validator, event, visibility, routableIdentifier)
|
routableEvent, err := internalApi.ValidateAndSerializePartially(a.validator, event, visibility, routableIdentifier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reject event type data-access as the downstream services
|
// Reject event type data-access as the downstream services
|
||||||
// cannot handle it at the moment
|
// cannot handle it at the moment
|
||||||
if strings.HasSuffix(event.LogName, string(EventTypeDataAccess)) {
|
if strings.HasSuffix(event.LogName, string(pkgAuditCommon.EventTypeDataAccess)) {
|
||||||
return nil, ErrUnsupportedEventTypeDataAccess
|
return nil, pkgAuditCommon.ErrUnsupportedEventTypeDataAccess
|
||||||
}
|
}
|
||||||
|
|
||||||
routableEventBytes, err := proto.Marshal(routableEvent)
|
routableEventBytes, err := proto.Marshal(routableEvent)
|
||||||
|
|
@ -73,9 +74,9 @@ func (a *MockAuditApi) ValidateAndSerialize(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
traceParent, traceState := TraceParentAndStateFromContext(ctx)
|
traceParent, traceState := internalApi.TraceParentAndStateFromContext(ctx)
|
||||||
|
|
||||||
message := CloudEvent{
|
message := pkgAuditCommon.CloudEvent{
|
||||||
SpecVersion: "1.0",
|
SpecVersion: "1.0",
|
||||||
Source: event.ProtoPayload.ServiceName,
|
Source: event.ProtoPayload.ServiceName,
|
||||||
Id: event.InsertId,
|
Id: event.InsertId,
|
||||||
|
|
@ -92,6 +93,6 @@ func (a *MockAuditApi) ValidateAndSerialize(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send implements AuditApi.Send
|
// Send implements AuditApi.Send
|
||||||
func (a *MockAuditApi) Send(context.Context, *RoutableIdentifier, *CloudEvent) error {
|
func (a *MockAuditApi) Send(context.Context, *pkgAuditCommon.RoutableIdentifier, *pkgAuditCommon.CloudEvent) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -5,19 +5,38 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
"buf.build/go/protovalidate"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
internalAuditApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/internal/audit/api"
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ProtobufValidatorMock struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ProtobufValidatorMock) Validate(msg proto.Message, options ...protovalidate.ValidationOption) error {
|
||||||
|
var args mock.Arguments
|
||||||
|
if len(options) > 0 {
|
||||||
|
args = m.Called(msg, options)
|
||||||
|
} else {
|
||||||
|
args = m.Called(msg)
|
||||||
|
}
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
func TestMockAuditApi_Log(t *testing.T) {
|
func TestMockAuditApi_Log(t *testing.T) {
|
||||||
|
|
||||||
auditApi, err := NewMockAuditApi()
|
auditApi, err := NewMockAuditApi()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newOrganizationAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewOrganizationAuditEvent(nil)
|
||||||
routableObjectIdentifier := NewRoutableIdentifier(objectIdentifier)
|
routableObjectIdentifier := pkgAuditCommon.NewRoutableIdentifier(objectIdentifier)
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
t.Run("Log", func(t *testing.T) {
|
t.Run("Log", func(t *testing.T) {
|
||||||
|
|
@ -26,13 +45,13 @@ func TestMockAuditApi_Log(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("reject data access event", func(t *testing.T) {
|
t.Run("reject data access event", func(t *testing.T) {
|
||||||
event, objectIdentifier := newOrganizationAuditEvent(nil)
|
orgEvent, objIdentifier := internalAuditApi.NewOrganizationAuditEvent(nil)
|
||||||
event.LogName = strings.Replace(event.LogName, string(EventTypeAdminActivity), string(EventTypeDataAccess), 1)
|
orgEvent.LogName = strings.Replace(orgEvent.LogName, string(pkgAuditCommon.EventTypeAdminActivity), string(pkgAuditCommon.EventTypeDataAccess), 1)
|
||||||
routableObjectIdentifier := NewRoutableIdentifier(objectIdentifier)
|
rtIdentifier := pkgAuditCommon.NewRoutableIdentifier(objIdentifier)
|
||||||
|
|
||||||
assert.ErrorIs(t, auditApi.Log(
|
assert.ErrorIs(t, auditApi.Log(
|
||||||
context.Background(), event, auditV1.Visibility_VISIBILITY_PUBLIC, routableObjectIdentifier),
|
context.Background(), orgEvent, auditV1.Visibility_VISIBILITY_PUBLIC, rtIdentifier),
|
||||||
ErrUnsupportedEventTypeDataAccess)
|
pkgAuditCommon.ErrUnsupportedEventTypeDataAccess)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("ValidateAndSerialize", func(t *testing.T) {
|
t.Run("ValidateAndSerialize", func(t *testing.T) {
|
||||||
|
|
@ -50,11 +69,11 @@ func TestMockAuditApi_Log(t *testing.T) {
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
||||||
_, err := auditApi.ValidateAndSerialize(context.Background(), nil, visibility, routableObjectIdentifier)
|
_, err := auditApi.ValidateAndSerialize(context.Background(), nil, visibility, routableObjectIdentifier)
|
||||||
|
|
||||||
assert.ErrorIs(t, err, ErrEventNil)
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrEventNil)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Send", func(t *testing.T) {
|
t.Run("Send", func(t *testing.T) {
|
||||||
var cloudEvent = CloudEvent{}
|
var cloudEvent = pkgAuditCommon.CloudEvent{}
|
||||||
|
|
||||||
assert.Nil(t, auditApi.Send(context.Background(), routableObjectIdentifier, &cloudEvent))
|
assert.Nil(t, auditApi.Send(context.Background(), routableObjectIdentifier, &cloudEvent))
|
||||||
})
|
})
|
||||||
|
|
@ -4,14 +4,16 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go.opentelemetry.io/otel"
|
|
||||||
"go.opentelemetry.io/otel/trace"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
"dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/audit/messaging"
|
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
internalAuditApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/internal/audit/api"
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
|
pkgMessagingApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// routableTopicNameResolver implements TopicNameResolver.
|
// routableTopicNameResolver implements TopicNameResolver.
|
||||||
|
|
@ -25,23 +27,23 @@ type routableTopicNameResolver struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve implements TopicNameResolver.Resolve.
|
// Resolve implements TopicNameResolver.Resolve.
|
||||||
func (r *routableTopicNameResolver) Resolve(routableIdentifier *RoutableIdentifier) (string, error) {
|
func (r *routableTopicNameResolver) Resolve(routableIdentifier *pkgAuditCommon.RoutableIdentifier) (string, error) {
|
||||||
|
|
||||||
if routableIdentifier == nil {
|
if routableIdentifier == nil {
|
||||||
return "", ErrObjectIdentifierNil
|
return "", pkgAuditCommon.ErrObjectIdentifierNil
|
||||||
}
|
}
|
||||||
|
|
||||||
switch routableIdentifier.Type {
|
switch routableIdentifier.Type {
|
||||||
case ObjectTypeOrganization:
|
case pkgAuditCommon.ObjectTypeOrganization:
|
||||||
return fmt.Sprintf("topic://%s/%s", r.organizationTopicPrefix, routableIdentifier.Identifier), nil
|
return fmt.Sprintf("topic://%s/%s", r.organizationTopicPrefix, routableIdentifier.Identifier), nil
|
||||||
case ObjectTypeProject:
|
case pkgAuditCommon.ObjectTypeProject:
|
||||||
return fmt.Sprintf("topic://%s/%s", r.projectTopicPrefix, routableIdentifier.Identifier), nil
|
return fmt.Sprintf("topic://%s/%s", r.projectTopicPrefix, routableIdentifier.Identifier), nil
|
||||||
case ObjectTypeFolder:
|
case pkgAuditCommon.ObjectTypeFolder:
|
||||||
return fmt.Sprintf("topic://%s/%s", r.folderTopicPrefix, routableIdentifier.Identifier), nil
|
return fmt.Sprintf("topic://%s/%s", r.folderTopicPrefix, routableIdentifier.Identifier), nil
|
||||||
case ObjectTypeSystem:
|
case pkgAuditCommon.ObjectTypeSystem:
|
||||||
return r.systemTopicName, nil
|
return r.systemTopicName, nil
|
||||||
default:
|
default:
|
||||||
return "", ErrUnsupportedObjectIdentifierType
|
return "", pkgAuditCommon.ErrUnsupportedObjectIdentifierType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,18 +59,18 @@ type topicNameConfig struct {
|
||||||
// Warning: It is only there for local (compatibility) testing.
|
// Warning: It is only there for local (compatibility) testing.
|
||||||
// DO NOT USE IT!
|
// DO NOT USE IT!
|
||||||
type routableAuditApi struct {
|
type routableAuditApi struct {
|
||||||
messagingApi messaging.Api
|
messagingApi pkgMessagingApi.Api
|
||||||
topicNameResolver TopicNameResolver
|
topicNameResolver pkgAuditCommon.TopicNameResolver
|
||||||
tracer trace.Tracer
|
tracer trace.Tracer
|
||||||
validator ProtobufValidator
|
validator pkgAuditCommon.ProtobufValidator
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRoutableAuditApi can be used to initialize the audit log api.
|
// NewRoutableAuditApi can be used to initialize the audit log api.
|
||||||
func newRoutableAuditApi(
|
func newRoutableAuditApi(
|
||||||
messagingApi messaging.Api,
|
messagingApi pkgMessagingApi.Api,
|
||||||
topicNameConfig topicNameConfig,
|
topicNameConfig topicNameConfig,
|
||||||
validator ProtobufValidator,
|
validator pkgAuditCommon.ProtobufValidator,
|
||||||
) (AuditApi, error) {
|
) (pkgAuditCommon.AuditApi, error) {
|
||||||
|
|
||||||
if messagingApi == nil {
|
if messagingApi == nil {
|
||||||
return nil, errors.New("messaging api nil")
|
return nil, errors.New("messaging api nil")
|
||||||
|
|
@ -88,7 +90,7 @@ func newRoutableAuditApi(
|
||||||
return nil, errors.New("system topic name is required")
|
return nil, errors.New("system topic name is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
var topicNameResolver TopicNameResolver = &routableTopicNameResolver{
|
var topicNameResolver pkgAuditCommon.TopicNameResolver = &routableTopicNameResolver{
|
||||||
folderTopicPrefix: topicNameConfig.FolderTopicPrefix,
|
folderTopicPrefix: topicNameConfig.FolderTopicPrefix,
|
||||||
organizationTopicPrefix: topicNameConfig.OrganizationTopicPrefix,
|
organizationTopicPrefix: topicNameConfig.OrganizationTopicPrefix,
|
||||||
projectTopicPrefix: topicNameConfig.ProjectTopicPrefix,
|
projectTopicPrefix: topicNameConfig.ProjectTopicPrefix,
|
||||||
|
|
@ -96,7 +98,7 @@ func newRoutableAuditApi(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Audit api
|
// Audit api
|
||||||
var auditApi AuditApi = &routableAuditApi{
|
var auditApi pkgAuditCommon.AuditApi = &routableAuditApi{
|
||||||
messagingApi: messagingApi,
|
messagingApi: messagingApi,
|
||||||
topicNameResolver: topicNameResolver,
|
topicNameResolver: topicNameResolver,
|
||||||
tracer: otel.Tracer("routable-audit-api"),
|
tracer: otel.Tracer("routable-audit-api"),
|
||||||
|
|
@ -111,7 +113,7 @@ func (a *routableAuditApi) Log(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
event *auditV1.AuditLogEntry,
|
event *auditV1.AuditLogEntry,
|
||||||
visibility auditV1.Visibility,
|
visibility auditV1.Visibility,
|
||||||
routableIdentifier *RoutableIdentifier,
|
routableIdentifier *pkgAuditCommon.RoutableIdentifier,
|
||||||
) error {
|
) error {
|
||||||
|
|
||||||
cloudEvent, err := a.ValidateAndSerialize(ctx, event, visibility, routableIdentifier)
|
cloudEvent, err := a.ValidateAndSerialize(ctx, event, visibility, routableIdentifier)
|
||||||
|
|
@ -127,13 +129,13 @@ func (a *routableAuditApi) ValidateAndSerialize(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
event *auditV1.AuditLogEntry,
|
event *auditV1.AuditLogEntry,
|
||||||
visibility auditV1.Visibility,
|
visibility auditV1.Visibility,
|
||||||
routableIdentifier *RoutableIdentifier,
|
routableIdentifier *pkgAuditCommon.RoutableIdentifier,
|
||||||
) (*CloudEvent, error) {
|
) (*pkgAuditCommon.CloudEvent, error) {
|
||||||
|
|
||||||
ctx, span := a.tracer.Start(ctx, "validate-and-serialize")
|
ctx, span := a.tracer.Start(ctx, "validate-and-serialize")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
routableEvent, err := validateAndSerializePartially(
|
routableEvent, err := internalAuditApi.ValidateAndSerializePartially(
|
||||||
a.validator,
|
a.validator,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
|
|
@ -145,8 +147,8 @@ func (a *routableAuditApi) ValidateAndSerialize(
|
||||||
|
|
||||||
// Reject event type data-access as the downstream services
|
// Reject event type data-access as the downstream services
|
||||||
// cannot handle it at the moment
|
// cannot handle it at the moment
|
||||||
if strings.HasSuffix(event.LogName, string(EventTypeDataAccess)) {
|
if strings.HasSuffix(event.LogName, string(pkgAuditCommon.EventTypeDataAccess)) {
|
||||||
return nil, ErrUnsupportedEventTypeDataAccess
|
return nil, pkgAuditCommon.ErrUnsupportedEventTypeDataAccess
|
||||||
}
|
}
|
||||||
|
|
||||||
routableEventBytes, err := proto.Marshal(routableEvent)
|
routableEventBytes, err := proto.Marshal(routableEvent)
|
||||||
|
|
@ -154,14 +156,14 @@ func (a *routableAuditApi) ValidateAndSerialize(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
traceParent, traceState := TraceParentAndStateFromContext(ctx)
|
traceParent, traceState := internalAuditApi.TraceParentAndStateFromContext(ctx)
|
||||||
|
|
||||||
message := CloudEvent{
|
message := pkgAuditCommon.CloudEvent{
|
||||||
SpecVersion: "1.0",
|
SpecVersion: "1.0",
|
||||||
Source: event.ProtoPayload.ServiceName,
|
Source: event.ProtoPayload.ServiceName,
|
||||||
Id: event.InsertId,
|
Id: event.InsertId,
|
||||||
Time: event.ProtoPayload.RequestMetadata.RequestAttributes.Time.AsTime(),
|
Time: event.ProtoPayload.RequestMetadata.RequestAttributes.Time.AsTime(),
|
||||||
DataContentType: ContentTypeCloudEventsProtobuf,
|
DataContentType: pkgAuditCommon.ContentTypeCloudEventsProtobuf,
|
||||||
DataType: fmt.Sprintf("%v", routableEvent.ProtoReflect().Descriptor().FullName()),
|
DataType: fmt.Sprintf("%v", routableEvent.ProtoReflect().Descriptor().FullName()),
|
||||||
Subject: event.ProtoPayload.ResourceName,
|
Subject: event.ProtoPayload.ResourceName,
|
||||||
Data: routableEventBytes,
|
Data: routableEventBytes,
|
||||||
|
|
@ -175,15 +177,15 @@ func (a *routableAuditApi) ValidateAndSerialize(
|
||||||
// Send implements AuditApi.Send
|
// Send implements AuditApi.Send
|
||||||
func (a *routableAuditApi) Send(
|
func (a *routableAuditApi) Send(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
routableIdentifier *RoutableIdentifier,
|
routableIdentifier *pkgAuditCommon.RoutableIdentifier,
|
||||||
cloudEvent *CloudEvent,
|
cloudEvent *pkgAuditCommon.CloudEvent,
|
||||||
) error {
|
) error {
|
||||||
|
|
||||||
if cloudEvent != nil && cloudEvent.TraceParent != nil && cloudEvent.TraceState != nil {
|
if cloudEvent != nil && cloudEvent.TraceParent != nil && cloudEvent.TraceState != nil {
|
||||||
ctx = AddTraceParentAndStateToContext(ctx, *cloudEvent.TraceParent, *cloudEvent.TraceState)
|
ctx = internalAuditApi.AddTraceParentAndStateToContext(ctx, *cloudEvent.TraceParent, *cloudEvent.TraceState)
|
||||||
}
|
}
|
||||||
ctx, span := a.tracer.Start(ctx, "send")
|
ctx, span := a.tracer.Start(ctx, "send")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
return send(a.topicNameResolver, a.messagingApi, ctx, routableIdentifier, cloudEvent)
|
return internalAuditApi.Send(a.topicNameResolver, a.messagingApi, ctx, routableIdentifier, cloudEvent)
|
||||||
}
|
}
|
||||||
|
|
@ -4,21 +4,24 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go.opentelemetry.io/otel"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"buf.build/go/protovalidate"
|
||||||
|
|
||||||
"dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/audit/messaging"
|
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
|
||||||
|
|
||||||
"github.com/Azure/go-amqp"
|
"github.com/Azure/go-amqp"
|
||||||
"github.com/bufbuild/protovalidate-go"
|
"github.com/google/uuid"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
internalAuditApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/internal/audit/api"
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
|
pkgMessagingApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/api"
|
||||||
|
pgkMessagingCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/common"
|
||||||
|
pkgMessagingTest "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRoutableAuditApi(t *testing.T) {
|
func TestRoutableAuditApi(t *testing.T) {
|
||||||
|
|
@ -28,13 +31,13 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
defer cancelFn()
|
defer cancelFn()
|
||||||
|
|
||||||
// Start solace docker container
|
// Start solace docker container
|
||||||
solaceContainer, err := messaging.NewSolaceContainer(context.Background())
|
solaceContainer, err := pkgMessagingTest.NewSolaceContainer(context.Background())
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer solaceContainer.Stop()
|
defer solaceContainer.Stop()
|
||||||
|
|
||||||
// Instantiate the messaging api
|
// Instantiate the messaging api
|
||||||
messagingApi, err := messaging.NewAmqpApi(messaging.AmqpConnectionPoolConfig{
|
amqpApi, err := pkgMessagingApi.NewAmqpApi(pgkMessagingCommon.AmqpConnectionPoolConfig{
|
||||||
Parameters: messaging.AmqpConnectionConfig{BrokerUrl: solaceContainer.AmqpConnectionString},
|
Parameters: pgkMessagingCommon.AmqpConnectionConfig{BrokerUrl: solaceContainer.AmqpConnectionString},
|
||||||
PoolSize: 1,
|
PoolSize: 1,
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
@ -50,7 +53,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
systemTopicName := "topic://system/admin-events"
|
systemTopicName := "topic://system/admin-events"
|
||||||
|
|
||||||
auditApi, err := newRoutableAuditApi(
|
auditApi, err := newRoutableAuditApi(
|
||||||
messagingApi,
|
amqpApi,
|
||||||
topicNameConfig{
|
topicNameConfig{
|
||||||
FolderTopicPrefix: folderTopicPrefix,
|
FolderTopicPrefix: folderTopicPrefix,
|
||||||
OrganizationTopicPrefix: organizationTopicPrefix,
|
OrganizationTopicPrefix: organizationTopicPrefix,
|
||||||
|
|
@ -71,8 +74,8 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, "org/*"))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, "org/*"))
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newOrganizationAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewOrganizationAuditEvent(nil)
|
||||||
event.LogName = strings.Replace(event.LogName, string(EventTypeAdminActivity), string(EventTypeDataAccess), 1)
|
event.LogName = strings.Replace(event.LogName, string(pkgAuditCommon.EventTypeAdminActivity), string(pkgAuditCommon.EventTypeDataAccess), 1)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
||||||
|
|
@ -80,7 +83,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
ctx,
|
ctx,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier)), ErrUnsupportedEventTypeDataAccess)
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier)), pkgAuditCommon.ErrUnsupportedEventTypeDataAccess)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Check logging of organization events
|
// Check logging of organization events
|
||||||
|
|
@ -93,7 +96,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, "org/*"))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, "org/*"))
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newOrganizationAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewOrganizationAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
||||||
|
|
@ -101,7 +104,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
ctx,
|
ctx,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier)))
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier)))
|
||||||
|
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
@ -124,7 +127,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, "org/*"))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, "org/*"))
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newOrganizationAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewOrganizationAuditEvent(nil)
|
||||||
topicName := fmt.Sprintf("org/%s", objectIdentifier.Identifier)
|
topicName := fmt.Sprintf("org/%s", objectIdentifier.Identifier)
|
||||||
assert.NoError(
|
assert.NoError(
|
||||||
t,
|
t,
|
||||||
|
|
@ -137,7 +140,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
ctx,
|
ctx,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier)))
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier)))
|
||||||
|
|
||||||
// Receive the event from solace
|
// Receive the event from solace
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
|
|
@ -163,7 +166,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, "folder/*"))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, "folder/*"))
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newFolderAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewFolderAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
||||||
|
|
@ -171,7 +174,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
ctx,
|
ctx,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier)))
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier)))
|
||||||
|
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
@ -194,7 +197,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, "folder/*"))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, "folder/*"))
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newFolderAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewFolderAuditEvent(nil)
|
||||||
topicName := fmt.Sprintf("folder/%s", objectIdentifier.Identifier)
|
topicName := fmt.Sprintf("folder/%s", objectIdentifier.Identifier)
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicName))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicName))
|
||||||
|
|
||||||
|
|
@ -205,7 +208,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
ctx,
|
ctx,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier)))
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier)))
|
||||||
|
|
||||||
// Receive the event from solace
|
// Receive the event from solace
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
|
|
@ -230,7 +233,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, "project/*"))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, "project/*"))
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newProjectAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewProjectAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
||||||
|
|
@ -239,7 +242,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
ctx,
|
ctx,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier)))
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier)))
|
||||||
|
|
||||||
// Receive the event from solace
|
// Receive the event from solace
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
|
|
@ -263,7 +266,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, "project/*"))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, "project/*"))
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newProjectAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewProjectAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
||||||
|
|
@ -272,7 +275,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
ctx,
|
ctx,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier)))
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier)))
|
||||||
|
|
||||||
// Receive the event from solace
|
// Receive the event from solace
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
|
|
@ -297,7 +300,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, "system/*"))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, "system/*"))
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event := newProjectSystemAuditEvent(nil)
|
event := internalAuditApi.NewProjectSystemAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
||||||
|
|
@ -306,7 +309,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
ctx,
|
ctx,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
RoutableSystemIdentifier,
|
pkgAuditCommon.RoutableSystemIdentifier,
|
||||||
))
|
))
|
||||||
|
|
||||||
// Receive the event from solace
|
// Receive the event from solace
|
||||||
|
|
@ -332,7 +335,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
validateRoutableEventPayload(
|
validateRoutableEventPayload(
|
||||||
t,
|
t,
|
||||||
message.Data[0],
|
message.Data[0],
|
||||||
RoutableSystemIdentifier.ToObjectIdentifier(),
|
pkgAuditCommon.RoutableSystemIdentifier.ToObjectIdentifier(),
|
||||||
event,
|
event,
|
||||||
"stackit.resourcemanager.v2.system.changed",
|
"stackit.resourcemanager.v2.system.changed",
|
||||||
visibility)
|
visibility)
|
||||||
|
|
@ -347,7 +350,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, "system/*"))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, "system/*"))
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event := newSystemAuditEvent(nil)
|
event := internalAuditApi.NewSystemAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
||||||
|
|
@ -356,7 +359,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
ctx,
|
ctx,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
RoutableSystemIdentifier,
|
pkgAuditCommon.RoutableSystemIdentifier,
|
||||||
))
|
))
|
||||||
|
|
||||||
// Receive the event from solace
|
// Receive the event from solace
|
||||||
|
|
@ -382,7 +385,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
validateRoutableEventPayload(
|
validateRoutableEventPayload(
|
||||||
t,
|
t,
|
||||||
message.Data[0],
|
message.Data[0],
|
||||||
SystemIdentifier,
|
pkgAuditCommon.SystemIdentifier,
|
||||||
event,
|
event,
|
||||||
"stackit.resourcemanager.v2.system.changed",
|
"stackit.resourcemanager.v2.system.changed",
|
||||||
visibility)
|
visibility)
|
||||||
|
|
@ -398,7 +401,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, "org/*"))
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, "org/*"))
|
||||||
|
|
||||||
// Instantiate test data
|
// Instantiate test data
|
||||||
event, objectIdentifier := newOrganizationAuditEvent(nil)
|
event, objectIdentifier := internalAuditApi.NewOrganizationAuditEvent(nil)
|
||||||
|
|
||||||
// Log the event to solace
|
// Log the event to solace
|
||||||
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
||||||
|
|
@ -406,7 +409,7 @@ func TestRoutableAuditApi(t *testing.T) {
|
||||||
ctx,
|
ctx,
|
||||||
event,
|
event,
|
||||||
visibility,
|
visibility,
|
||||||
NewRoutableIdentifier(objectIdentifier)))
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier)))
|
||||||
|
|
||||||
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
@ -444,7 +447,7 @@ func validateSentEvent(
|
||||||
_, isUuid := uuid.Parse(fmt.Sprintf("%s", applicationProperties["cloudEvents:id"]))
|
_, isUuid := uuid.Parse(fmt.Sprintf("%s", applicationProperties["cloudEvents:id"]))
|
||||||
assert.True(t, true, isUuid)
|
assert.True(t, true, isUuid)
|
||||||
assert.Equal(t, event.ProtoPayload.RequestMetadata.RequestAttributes.Time.AsTime().UnixMilli(), applicationProperties["cloudEvents:time"])
|
assert.Equal(t, event.ProtoPayload.RequestMetadata.RequestAttributes.Time.AsTime().UnixMilli(), applicationProperties["cloudEvents:time"])
|
||||||
assert.Equal(t, ContentTypeCloudEventsProtobuf, applicationProperties["cloudEvents:datacontenttype"])
|
assert.Equal(t, pkgAuditCommon.ContentTypeCloudEventsProtobuf, applicationProperties["cloudEvents:datacontenttype"])
|
||||||
assert.Equal(t, "audit.v1.RoutableAuditEvent", applicationProperties["cloudEvents:type"])
|
assert.Equal(t, "audit.v1.RoutableAuditEvent", applicationProperties["cloudEvents:type"])
|
||||||
assert.Equal(t, "", applicationProperties["cloudEvents:traceparent"])
|
assert.Equal(t, "", applicationProperties["cloudEvents:traceparent"])
|
||||||
assert.Equal(t, "", applicationProperties["cloudEvents:tracestate"])
|
assert.Equal(t, "", applicationProperties["cloudEvents:tracestate"])
|
||||||
|
|
@ -486,8 +489,8 @@ func validateRoutableEventPayload(
|
||||||
|
|
||||||
func TestRoutableTopicNameResolver_Resolve_UnsupportedIdentifierType(t *testing.T) {
|
func TestRoutableTopicNameResolver_Resolve_UnsupportedIdentifierType(t *testing.T) {
|
||||||
resolver := routableTopicNameResolver{}
|
resolver := routableTopicNameResolver{}
|
||||||
_, err := resolver.Resolve(NewRoutableIdentifier(&auditV1.ObjectIdentifier{Type: "unsupported"}))
|
_, err := resolver.Resolve(pkgAuditCommon.NewRoutableIdentifier(&auditV1.ObjectIdentifier{Type: "unsupported"}))
|
||||||
assert.ErrorIs(t, err, ErrUnsupportedObjectIdentifierType)
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrUnsupportedObjectIdentifierType)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewRoutableAuditApi_NewRoutableAuditApi_MessagingApiNil(t *testing.T) {
|
func TestNewRoutableAuditApi_NewRoutableAuditApi_MessagingApiNil(t *testing.T) {
|
||||||
|
|
@ -501,15 +504,15 @@ func TestRoutableAuditApi_ValidateAndSerialize_ValidationFailed(t *testing.T) {
|
||||||
|
|
||||||
validator := &ProtobufValidatorMock{}
|
validator := &ProtobufValidatorMock{}
|
||||||
validator.On("Validate", mock.Anything).Return(expectedError)
|
validator.On("Validate", mock.Anything).Return(expectedError)
|
||||||
var protobufValidator ProtobufValidator = validator
|
var protobufValidator pkgAuditCommon.ProtobufValidator = validator
|
||||||
|
|
||||||
auditApi := routableAuditApi{
|
auditApi := routableAuditApi{
|
||||||
tracer: otel.Tracer("test"),
|
tracer: otel.Tracer("test"),
|
||||||
validator: protobufValidator,
|
validator: protobufValidator,
|
||||||
}
|
}
|
||||||
|
|
||||||
event := newSystemAuditEvent(nil)
|
event := internalAuditApi.NewSystemAuditEvent(nil)
|
||||||
_, err := auditApi.ValidateAndSerialize(context.Background(), event, auditV1.Visibility_VISIBILITY_PUBLIC, RoutableSystemIdentifier)
|
_, err := auditApi.ValidateAndSerialize(context.Background(), event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.RoutableSystemIdentifier)
|
||||||
assert.ErrorIs(t, err, expectedError)
|
assert.ErrorIs(t, err, expectedError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -518,20 +521,20 @@ func TestRoutableAuditApi_Log_ValidationFailed(t *testing.T) {
|
||||||
|
|
||||||
validator := &ProtobufValidatorMock{}
|
validator := &ProtobufValidatorMock{}
|
||||||
validator.On("Validate", mock.Anything).Return(expectedError)
|
validator.On("Validate", mock.Anything).Return(expectedError)
|
||||||
var protobufValidator ProtobufValidator = validator
|
var protobufValidator pkgAuditCommon.ProtobufValidator = validator
|
||||||
|
|
||||||
auditApi := routableAuditApi{
|
auditApi := routableAuditApi{
|
||||||
tracer: otel.Tracer("test"),
|
tracer: otel.Tracer("test"),
|
||||||
validator: protobufValidator,
|
validator: protobufValidator,
|
||||||
}
|
}
|
||||||
|
|
||||||
event := newSystemAuditEvent(nil)
|
event := internalAuditApi.NewSystemAuditEvent(nil)
|
||||||
err := auditApi.Log(context.Background(), event, auditV1.Visibility_VISIBILITY_PUBLIC, RoutableSystemIdentifier)
|
err := auditApi.Log(context.Background(), event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.RoutableSystemIdentifier)
|
||||||
assert.ErrorIs(t, err, expectedError)
|
assert.ErrorIs(t, err, expectedError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRoutableAuditApi_Log_NilEvent(t *testing.T) {
|
func TestRoutableAuditApi_Log_NilEvent(t *testing.T) {
|
||||||
auditApi := routableAuditApi{tracer: otel.Tracer("test")}
|
auditApi := routableAuditApi{tracer: otel.Tracer("test")}
|
||||||
err := auditApi.Log(context.Background(), nil, auditV1.Visibility_VISIBILITY_PUBLIC, RoutableSystemIdentifier)
|
err := auditApi.Log(context.Background(), nil, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.RoutableSystemIdentifier)
|
||||||
assert.ErrorIs(t, err, ErrEventNil)
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrEventNil)
|
||||||
}
|
}
|
||||||
|
|
@ -5,6 +5,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
const base64AuditEventV1 = "v1"
|
const base64AuditEventV1 = "v1"
|
||||||
|
|
@ -14,16 +16,16 @@ var ErrRoutableIdentifierNil = errors.New("routableIdentifier must not be nil")
|
||||||
var ErrUnsupportedBase64StringVersion = errors.New("unsupported base64 cloud event string version")
|
var ErrUnsupportedBase64StringVersion = errors.New("unsupported base64 cloud event string version")
|
||||||
|
|
||||||
type serializableEvent struct {
|
type serializableEvent struct {
|
||||||
CloudEvent CloudEvent `json:"cloudEvent"`
|
CloudEvent pkgAuditCommon.CloudEvent `json:"cloudEvent"`
|
||||||
RoutableIdentifier RoutableIdentifier `json:"routableIdentifier"`
|
RoutableIdentifier pkgAuditCommon.RoutableIdentifier `json:"routableIdentifier"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToBase64(
|
func ToBase64(
|
||||||
cloudEvent *CloudEvent,
|
cloudEvent *pkgAuditCommon.CloudEvent,
|
||||||
routableIdentifier *RoutableIdentifier) (*string, error) {
|
routableIdentifier *pkgAuditCommon.RoutableIdentifier) (*string, error) {
|
||||||
|
|
||||||
if cloudEvent == nil {
|
if cloudEvent == nil {
|
||||||
return nil, ErrCloudEventNil
|
return nil, pkgAuditCommon.ErrCloudEventNil
|
||||||
}
|
}
|
||||||
|
|
||||||
if routableIdentifier == nil {
|
if routableIdentifier == nil {
|
||||||
|
|
@ -41,11 +43,11 @@ func ToBase64(
|
||||||
}
|
}
|
||||||
|
|
||||||
base64Str := base64.StdEncoding.EncodeToString(serializedEvent)
|
base64Str := base64.StdEncoding.EncodeToString(serializedEvent)
|
||||||
base64Str = base64Str + base64AuditEventV1
|
base64Str += base64AuditEventV1
|
||||||
return &base64Str, nil
|
return &base64Str, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromBase64(base64Str string) (*CloudEvent, *RoutableIdentifier, error) {
|
func FromBase64(base64Str string) (*pkgAuditCommon.CloudEvent, *pkgAuditCommon.RoutableIdentifier, error) {
|
||||||
if base64Str == "" {
|
if base64Str == "" {
|
||||||
return nil, nil, ErrBase64StringEmpty
|
return nil, nil, ErrBase64StringEmpty
|
||||||
}
|
}
|
||||||
|
|
@ -2,24 +2,27 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_ToBase64(t *testing.T) {
|
func Test_ToBase64(t *testing.T) {
|
||||||
|
|
||||||
t.Run("cloud event nil", func(t *testing.T) {
|
t.Run("cloud event nil", func(t *testing.T) {
|
||||||
var cloudEvent *CloudEvent = nil
|
var cloudEvent *pkgAuditCommon.CloudEvent = nil
|
||||||
routableIdentifier := RoutableSystemIdentifier
|
routableIdentifier := pkgAuditCommon.RoutableSystemIdentifier
|
||||||
|
|
||||||
base64str, err := ToBase64(cloudEvent, routableIdentifier)
|
base64str, err := ToBase64(cloudEvent, routableIdentifier)
|
||||||
assert.ErrorIs(t, err, ErrCloudEventNil)
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrCloudEventNil)
|
||||||
assert.Nil(t, base64str)
|
assert.Nil(t, base64str)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("routable identifier nil", func(t *testing.T) {
|
t.Run("routable identifier nil", func(t *testing.T) {
|
||||||
cloudEvent := &CloudEvent{}
|
cloudEvent := &pkgAuditCommon.CloudEvent{}
|
||||||
var routableIdentifier *RoutableIdentifier = nil
|
var routableIdentifier *pkgAuditCommon.RoutableIdentifier = nil
|
||||||
|
|
||||||
base64str, err := ToBase64(cloudEvent, routableIdentifier)
|
base64str, err := ToBase64(cloudEvent, routableIdentifier)
|
||||||
assert.ErrorIs(t, err, ErrRoutableIdentifierNil)
|
assert.ErrorIs(t, err, ErrRoutableIdentifierNil)
|
||||||
|
|
@ -27,8 +30,8 @@ func Test_ToBase64(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("encoded event", func(t *testing.T) {
|
t.Run("encoded event", func(t *testing.T) {
|
||||||
e := &CloudEvent{}
|
e := &pkgAuditCommon.CloudEvent{}
|
||||||
r := RoutableSystemIdentifier
|
r := pkgAuditCommon.RoutableSystemIdentifier
|
||||||
base64str, err := ToBase64(e, r)
|
base64str, err := ToBase64(e, r)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
|
@ -72,8 +75,8 @@ func Test_FromBase64(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("decoded event", func(t *testing.T) {
|
t.Run("decoded event", func(t *testing.T) {
|
||||||
e := &CloudEvent{}
|
e := &pkgAuditCommon.CloudEvent{}
|
||||||
r := RoutableSystemIdentifier
|
r := pkgAuditCommon.RoutableSystemIdentifier
|
||||||
base64str, err := ToBase64(e, r)
|
base64str, err := ToBase64(e, r)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
|
@ -2,14 +2,18 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/audit/utils"
|
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"go.opentelemetry.io/otel"
|
"go.opentelemetry.io/otel"
|
||||||
"go.opentelemetry.io/otel/trace"
|
"go.opentelemetry.io/otel/trace"
|
||||||
"time"
|
|
||||||
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
internalAuditApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/internal/audit/api"
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
|
pkgAuditUtils "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const quadZero = "0.0.0.0"
|
const quadZero = "0.0.0.0"
|
||||||
|
|
@ -22,7 +26,7 @@ type AuditParameters struct {
|
||||||
Details map[string]interface{}
|
Details map[string]interface{}
|
||||||
|
|
||||||
// The type of the event
|
// The type of the event
|
||||||
EventType EventType
|
EventType pkgAuditCommon.EventType
|
||||||
|
|
||||||
// A set of user-defined (key, value) data that provides additional
|
// A set of user-defined (key, value) data that provides additional
|
||||||
// information about the log entry.
|
// information about the log entry.
|
||||||
|
|
@ -32,7 +36,7 @@ type AuditParameters struct {
|
||||||
ObjectId string
|
ObjectId string
|
||||||
|
|
||||||
// Type of the object, the audit event refers to
|
// Type of the object, the audit event refers to
|
||||||
ObjectType ObjectType
|
ObjectType pkgAuditCommon.ObjectType
|
||||||
|
|
||||||
ResponseBody any
|
ResponseBody any
|
||||||
|
|
||||||
|
|
@ -42,14 +46,14 @@ type AuditParameters struct {
|
||||||
|
|
||||||
func getObjectIdAndTypeFromAuditParams(
|
func getObjectIdAndTypeFromAuditParams(
|
||||||
auditParams *AuditParameters,
|
auditParams *AuditParameters,
|
||||||
) (string, *ObjectType, error) {
|
) (string, *pkgAuditCommon.ObjectType, error) {
|
||||||
|
|
||||||
objectId := auditParams.ObjectId
|
objectId := auditParams.ObjectId
|
||||||
if objectId == "" {
|
if objectId == "" {
|
||||||
return "", nil, errors.New("object id missing")
|
return "", nil, errors.New("object id missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
var objectType *ObjectType
|
var objectType *pkgAuditCommon.ObjectType
|
||||||
if auditParams.ObjectType != "" {
|
if auditParams.ObjectType != "" {
|
||||||
objectType = &auditParams.ObjectType
|
objectType = &auditParams.ObjectType
|
||||||
}
|
}
|
||||||
|
|
@ -66,9 +70,9 @@ func getObjectIdAndTypeFromAuditParams(
|
||||||
// AuditLogEntryBuilder collects audit params to construct auditV1.AuditLogEntry
|
// AuditLogEntryBuilder collects audit params to construct auditV1.AuditLogEntry
|
||||||
type AuditLogEntryBuilder struct {
|
type AuditLogEntryBuilder struct {
|
||||||
auditParams AuditParameters
|
auditParams AuditParameters
|
||||||
auditRequest AuditRequest
|
auditRequest internalAuditApi.AuditRequest
|
||||||
auditResponse AuditResponse
|
auditResponse internalAuditApi.AuditResponse
|
||||||
auditMetadata AuditMetadata
|
auditMetadata internalAuditApi.AuditMetadata
|
||||||
|
|
||||||
// Region and optional zone id. If both, separated with a - (dash).
|
// Region and optional zone id. If both, separated with a - (dash).
|
||||||
// Example: eu01
|
// Example: eu01
|
||||||
|
|
@ -88,23 +92,23 @@ func NewAuditLogEntryBuilder() *AuditLogEntryBuilder {
|
||||||
|
|
||||||
return &AuditLogEntryBuilder{
|
return &AuditLogEntryBuilder{
|
||||||
auditParams: AuditParameters{
|
auditParams: AuditParameters{
|
||||||
EventType: EventTypeAdminActivity,
|
EventType: pkgAuditCommon.EventTypeAdminActivity,
|
||||||
},
|
},
|
||||||
auditRequest: AuditRequest{
|
auditRequest: internalAuditApi.AuditRequest{
|
||||||
Request: &ApiRequest{},
|
Request: &pkgAuditCommon.ApiRequest{},
|
||||||
RequestClientIP: quadZero,
|
RequestClientIP: quadZero,
|
||||||
RequestCorrelationId: nil,
|
RequestCorrelationId: nil,
|
||||||
RequestId: nil,
|
RequestId: nil,
|
||||||
RequestTime: &requestTime,
|
RequestTime: &requestTime,
|
||||||
},
|
},
|
||||||
auditResponse: AuditResponse{
|
auditResponse: internalAuditApi.AuditResponse{
|
||||||
ResponseBodyBytes: nil,
|
ResponseBodyBytes: nil,
|
||||||
ResponseStatusCode: 200,
|
ResponseStatusCode: 200,
|
||||||
ResponseHeaders: make(map[string][]string),
|
ResponseHeaders: make(map[string][]string),
|
||||||
ResponseNumItems: nil,
|
ResponseNumItems: nil,
|
||||||
ResponseTime: nil,
|
ResponseTime: nil,
|
||||||
},
|
},
|
||||||
auditMetadata: AuditMetadata{
|
auditMetadata: internalAuditApi.AuditMetadata{
|
||||||
AuditInsertId: "",
|
AuditInsertId: "",
|
||||||
AuditLabels: nil,
|
AuditLabels: nil,
|
||||||
AuditLogName: "",
|
AuditLogName: "",
|
||||||
|
|
@ -124,7 +128,7 @@ func NewAuditLogEntryBuilder() *AuditLogEntryBuilder {
|
||||||
|
|
||||||
func (builder *AuditLogEntryBuilder) AsSystemEvent() *AuditLogEntryBuilder {
|
func (builder *AuditLogEntryBuilder) AsSystemEvent() *AuditLogEntryBuilder {
|
||||||
if builder.auditRequest.Request == nil {
|
if builder.auditRequest.Request == nil {
|
||||||
builder.auditRequest.Request = &ApiRequest{}
|
builder.auditRequest.Request = &pkgAuditCommon.ApiRequest{}
|
||||||
}
|
}
|
||||||
if builder.auditRequest.Request.Header == nil {
|
if builder.auditRequest.Request.Header == nil {
|
||||||
builder.auditRequest.Request.Header = map[string][]string{"user-agent": {"none"}}
|
builder.auditRequest.Request.Header = map[string][]string{"user-agent": {"none"}}
|
||||||
|
|
@ -147,16 +151,25 @@ func (builder *AuditLogEntryBuilder) AsSystemEvent() *AuditLogEntryBuilder {
|
||||||
if builder.auditRequest.RequestClientIP == "" {
|
if builder.auditRequest.RequestClientIP == "" {
|
||||||
builder.auditRequest.RequestClientIP = quadZero
|
builder.auditRequest.RequestClientIP = quadZero
|
||||||
}
|
}
|
||||||
builder.WithEventType(EventTypeSystemEvent)
|
builder.WithEventType(pkgAuditCommon.EventTypeSystemEvent)
|
||||||
return builder
|
return builder
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithRequiredApiRequest adds api request details
|
// WithRequiredApiRequest adds api request details
|
||||||
func (builder *AuditLogEntryBuilder) WithRequiredApiRequest(request ApiRequest) *AuditLogEntryBuilder {
|
func (builder *AuditLogEntryBuilder) WithRequiredApiRequest(request pkgAuditCommon.ApiRequest) *AuditLogEntryBuilder {
|
||||||
builder.auditRequest.Request = &request
|
builder.auditRequest.Request = &request
|
||||||
return builder
|
return builder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetApiRequest returns the api request details
|
||||||
|
func (builder *AuditLogEntryBuilder) GetApiRequest() *pkgAuditCommon.ApiRequest {
|
||||||
|
return builder.auditRequest.Request
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *AuditLogEntryBuilder) GetApiRequestBody() *pkgAuditCommon.ApiRequest {
|
||||||
|
return builder.auditRequest.Request
|
||||||
|
}
|
||||||
|
|
||||||
// WithRequiredLocation adds the region and optional zone id. If both, separated with a - (dash).
|
// WithRequiredLocation adds the region and optional zone id. If both, separated with a - (dash).
|
||||||
// Example: eu01
|
// Example: eu01
|
||||||
func (builder *AuditLogEntryBuilder) WithRequiredLocation(location string) *AuditLogEntryBuilder {
|
func (builder *AuditLogEntryBuilder) WithRequiredLocation(location string) *AuditLogEntryBuilder {
|
||||||
|
|
@ -209,7 +222,7 @@ func (builder *AuditLogEntryBuilder) WithRequiredObjectId(objectId string) *Audi
|
||||||
|
|
||||||
// WithRequiredObjectType adds the object type.
|
// WithRequiredObjectType adds the object type.
|
||||||
// May be prefilled by audit middleware (if the type can be extracted from the url path).
|
// May be prefilled by audit middleware (if the type can be extracted from the url path).
|
||||||
func (builder *AuditLogEntryBuilder) WithRequiredObjectType(objectType ObjectType) *AuditLogEntryBuilder {
|
func (builder *AuditLogEntryBuilder) WithRequiredObjectType(objectType pkgAuditCommon.ObjectType) *AuditLogEntryBuilder {
|
||||||
builder.auditParams.ObjectType = objectType
|
builder.auditParams.ObjectType = objectType
|
||||||
return builder
|
return builder
|
||||||
}
|
}
|
||||||
|
|
@ -266,7 +279,7 @@ func (builder *AuditLogEntryBuilder) WithNumResponseItems(numResponseItems int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithEventType overwrites the default event type EventTypeAdminActivity
|
// WithEventType overwrites the default event type EventTypeAdminActivity
|
||||||
func (builder *AuditLogEntryBuilder) WithEventType(eventType EventType) *AuditLogEntryBuilder {
|
func (builder *AuditLogEntryBuilder) WithEventType(eventType pkgAuditCommon.EventType) *AuditLogEntryBuilder {
|
||||||
builder.auditParams.EventType = eventType
|
builder.auditParams.EventType = eventType
|
||||||
return builder
|
return builder
|
||||||
}
|
}
|
||||||
|
|
@ -296,7 +309,7 @@ func (builder *AuditLogEntryBuilder) WithResponseBody(responseBody any) *AuditLo
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithResponseBodyBytes adds the response body as bytes (serialized json or protobuf message expected)
|
// WithResponseBodyBytes adds the response body as bytes (serialized json or protobuf message expected)
|
||||||
func (builder *AuditLogEntryBuilder) WithResponseBodyBytes(responseBody *[]byte) *AuditLogEntryBuilder {
|
func (builder *AuditLogEntryBuilder) WithResponseBodyBytes(responseBody []byte) *AuditLogEntryBuilder {
|
||||||
builder.auditResponse.ResponseBodyBytes = responseBody
|
builder.auditResponse.ResponseBodyBytes = responseBody
|
||||||
return builder
|
return builder
|
||||||
}
|
}
|
||||||
|
|
@ -346,26 +359,26 @@ func (builder *AuditLogEntryBuilder) Build(ctx context.Context, sequenceNumber S
|
||||||
|
|
||||||
resourceName := fmt.Sprintf("%s/%s", objectType.Plural(), objectId)
|
resourceName := fmt.Sprintf("%s/%s", objectType.Plural(), objectId)
|
||||||
var logIdentifier string
|
var logIdentifier string
|
||||||
var logType ObjectType
|
var logType pkgAuditCommon.ObjectType
|
||||||
if builder.auditParams.EventType == EventTypeSystemEvent {
|
if builder.auditParams.EventType == pkgAuditCommon.EventTypeSystemEvent {
|
||||||
logIdentifier = SystemIdentifier.Identifier
|
logIdentifier = pkgAuditCommon.SystemIdentifier.Identifier
|
||||||
logType = ObjectTypeSystem
|
logType = pkgAuditCommon.ObjectTypeSystem
|
||||||
} else {
|
} else {
|
||||||
logIdentifier = objectId
|
logIdentifier = objectId
|
||||||
logType = *objectType
|
logType = *objectType
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.auditMetadata.AuditInsertId = NewInsertId(time.Now().UTC(), builder.location, builder.workerId, uint64(sequenceNumber))
|
builder.auditMetadata.AuditInsertId = internalAuditApi.NewInsertId(time.Now().UTC(), builder.location, builder.workerId, uint64(sequenceNumber))
|
||||||
builder.auditMetadata.AuditLogName = fmt.Sprintf("%s/%s/logs/%s", logType.Plural(), logIdentifier, builder.auditParams.EventType)
|
builder.auditMetadata.AuditLogName = fmt.Sprintf("%s/%s/logs/%s", logType.Plural(), logIdentifier, builder.auditParams.EventType)
|
||||||
builder.auditMetadata.AuditResourceName = resourceName
|
builder.auditMetadata.AuditResourceName = resourceName
|
||||||
|
|
||||||
var details *map[string]interface{} = nil
|
var details map[string]interface{}
|
||||||
if len(builder.auditParams.Details) > 0 {
|
if len(builder.auditParams.Details) > 0 {
|
||||||
details = &builder.auditParams.Details
|
details = builder.auditParams.Details
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instantiate the audit event
|
// Instantiate the audit event
|
||||||
return NewAuditLogEntry(
|
return internalAuditApi.NewAuditLogEntry(
|
||||||
builder.auditRequest,
|
builder.auditRequest,
|
||||||
builder.auditResponse,
|
builder.auditResponse,
|
||||||
details,
|
details,
|
||||||
|
|
@ -378,7 +391,7 @@ func (builder *AuditLogEntryBuilder) Build(ctx context.Context, sequenceNumber S
|
||||||
type AuditEventBuilder struct {
|
type AuditEventBuilder struct {
|
||||||
|
|
||||||
// The audit api used to validate, serialize and send events
|
// The audit api used to validate, serialize and send events
|
||||||
api AuditApi
|
api pkgAuditCommon.AuditApi
|
||||||
|
|
||||||
// The audit log entry builder which is used to build the actual protobuf message
|
// The audit log entry builder which is used to build the actual protobuf message
|
||||||
auditLogEntryBuilder *AuditLogEntryBuilder
|
auditLogEntryBuilder *AuditLogEntryBuilder
|
||||||
|
|
@ -387,7 +400,7 @@ type AuditEventBuilder struct {
|
||||||
built bool
|
built bool
|
||||||
|
|
||||||
// Sequence number generator providing sequential increasing numbers for the insert IDs
|
// Sequence number generator providing sequential increasing numbers for the insert IDs
|
||||||
sequenceNumberGenerator utils.SequenceNumberGenerator
|
sequenceNumberGenerator pkgAuditUtils.SequenceNumberGenerator
|
||||||
|
|
||||||
// Opentelemetry tracer
|
// Opentelemetry tracer
|
||||||
tracer trace.Tracer
|
tracer trace.Tracer
|
||||||
|
|
@ -400,10 +413,10 @@ type AuditEventBuilder struct {
|
||||||
// validates input and returns a cloud event that can be sent to the audit log system.
|
// validates input and returns a cloud event that can be sent to the audit log system.
|
||||||
func NewAuditEventBuilder(
|
func NewAuditEventBuilder(
|
||||||
// The audit api used to validate, serialize and send events
|
// The audit api used to validate, serialize and send events
|
||||||
api AuditApi,
|
api pkgAuditCommon.AuditApi,
|
||||||
|
|
||||||
// The sequence number generator can be used to get and revert sequence numbers to build audit log events
|
// The sequence number generator can be used to get and revert sequence numbers to build audit log events
|
||||||
sequenceNumberGenerator utils.SequenceNumberGenerator,
|
sequenceNumberGenerator pkgAuditUtils.SequenceNumberGenerator,
|
||||||
|
|
||||||
// The service name in lowercase (allowed characters are [a-z-]).
|
// The service name in lowercase (allowed characters are [a-z-]).
|
||||||
serviceName string,
|
serviceName string,
|
||||||
|
|
@ -450,11 +463,16 @@ func (builder *AuditEventBuilder) WithAuditLogEntryBuilder(auditLogEntryBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithRequiredApiRequest adds api request details
|
// WithRequiredApiRequest adds api request details
|
||||||
func (builder *AuditEventBuilder) WithRequiredApiRequest(request ApiRequest) *AuditEventBuilder {
|
func (builder *AuditEventBuilder) WithRequiredApiRequest(request pkgAuditCommon.ApiRequest) *AuditEventBuilder {
|
||||||
builder.auditLogEntryBuilder.WithRequiredApiRequest(request)
|
builder.auditLogEntryBuilder.WithRequiredApiRequest(request)
|
||||||
return builder
|
return builder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetApiRequest returns the api request details
|
||||||
|
func (builder *AuditEventBuilder) GetApiRequest() *pkgAuditCommon.ApiRequest {
|
||||||
|
return builder.auditLogEntryBuilder.GetApiRequest()
|
||||||
|
}
|
||||||
|
|
||||||
// WithRequiredRequestClientIp adds the client ip
|
// WithRequiredRequestClientIp adds the client ip
|
||||||
func (builder *AuditEventBuilder) WithRequiredRequestClientIp(requestClientIp string) *AuditEventBuilder {
|
func (builder *AuditEventBuilder) WithRequiredRequestClientIp(requestClientIp string) *AuditEventBuilder {
|
||||||
builder.auditLogEntryBuilder.WithRequiredRequestClientIp(requestClientIp)
|
builder.auditLogEntryBuilder.WithRequiredRequestClientIp(requestClientIp)
|
||||||
|
|
@ -488,7 +506,7 @@ func (builder *AuditEventBuilder) WithRequiredObjectId(objectId string) *AuditEv
|
||||||
|
|
||||||
// WithRequiredObjectType adds the object type.
|
// WithRequiredObjectType adds the object type.
|
||||||
// May be prefilled by audit middleware (if the type can be extracted from the url path).
|
// May be prefilled by audit middleware (if the type can be extracted from the url path).
|
||||||
func (builder *AuditEventBuilder) WithRequiredObjectType(objectType ObjectType) *AuditEventBuilder {
|
func (builder *AuditEventBuilder) WithRequiredObjectType(objectType pkgAuditCommon.ObjectType) *AuditEventBuilder {
|
||||||
builder.auditLogEntryBuilder.WithRequiredObjectType(objectType)
|
builder.auditLogEntryBuilder.WithRequiredObjectType(objectType)
|
||||||
return builder
|
return builder
|
||||||
}
|
}
|
||||||
|
|
@ -545,7 +563,7 @@ func (builder *AuditEventBuilder) WithNumResponseItems(numResponseItems int64) *
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithEventType overwrites the default event type EventTypeAdminActivity
|
// WithEventType overwrites the default event type EventTypeAdminActivity
|
||||||
func (builder *AuditEventBuilder) WithEventType(eventType EventType) *AuditEventBuilder {
|
func (builder *AuditEventBuilder) WithEventType(eventType pkgAuditCommon.EventType) *AuditEventBuilder {
|
||||||
builder.auditLogEntryBuilder.WithEventType(eventType)
|
builder.auditLogEntryBuilder.WithEventType(eventType)
|
||||||
return builder
|
return builder
|
||||||
}
|
}
|
||||||
|
|
@ -575,7 +593,7 @@ func (builder *AuditEventBuilder) WithResponseBody(responseBody any) *AuditEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithResponseBodyBytes adds the response body as bytes (serialized json or protobuf message expected)
|
// WithResponseBodyBytes adds the response body as bytes (serialized json or protobuf message expected)
|
||||||
func (builder *AuditEventBuilder) WithResponseBodyBytes(responseBody *[]byte) *AuditEventBuilder {
|
func (builder *AuditEventBuilder) WithResponseBodyBytes(responseBody []byte) *AuditEventBuilder {
|
||||||
builder.auditLogEntryBuilder.WithResponseBodyBytes(responseBody)
|
builder.auditLogEntryBuilder.WithResponseBodyBytes(responseBody)
|
||||||
return builder
|
return builder
|
||||||
}
|
}
|
||||||
|
|
@ -621,7 +639,7 @@ func (builder *AuditEventBuilder) MarkAsBuilt() {
|
||||||
// - The RoutableIdentifier required for routing the cloud event
|
// - The RoutableIdentifier required for routing the cloud event
|
||||||
// - The operation name
|
// - The operation name
|
||||||
// - Error if the event cannot be built
|
// - Error if the event cannot be built
|
||||||
func (builder *AuditEventBuilder) Build(ctx context.Context, sequenceNumber SequenceNumber) (*CloudEvent, *RoutableIdentifier, error) {
|
func (builder *AuditEventBuilder) Build(ctx context.Context, sequenceNumber SequenceNumber) (*pkgAuditCommon.CloudEvent, *pkgAuditCommon.RoutableIdentifier, error) {
|
||||||
if builder.auditLogEntryBuilder == nil {
|
if builder.auditLogEntryBuilder == nil {
|
||||||
return nil, nil, fmt.Errorf("audit log entry builder not set")
|
return nil, nil, fmt.Errorf("audit log entry builder not set")
|
||||||
}
|
}
|
||||||
|
|
@ -632,19 +650,19 @@ func (builder *AuditEventBuilder) Build(ctx context.Context, sequenceNumber Sequ
|
||||||
visibility := builder.visibility
|
visibility := builder.visibility
|
||||||
objectId := builder.auditLogEntryBuilder.auditParams.ObjectId
|
objectId := builder.auditLogEntryBuilder.auditParams.ObjectId
|
||||||
objectType := builder.auditLogEntryBuilder.auditParams.ObjectType
|
objectType := builder.auditLogEntryBuilder.auditParams.ObjectType
|
||||||
var routingIdentifier *RoutableIdentifier
|
var routingIdentifier *pkgAuditCommon.RoutableIdentifier
|
||||||
if builder.auditLogEntryBuilder.auditParams.EventType == EventTypeSystemEvent {
|
if builder.auditLogEntryBuilder.auditParams.EventType == pkgAuditCommon.EventTypeSystemEvent {
|
||||||
routingIdentifier = NewAuditRoutingIdentifier(uuid.Nil.String(), ObjectTypeSystem)
|
routingIdentifier = internalAuditApi.NewAuditRoutingIdentifier(uuid.Nil.String(), pkgAuditCommon.ObjectTypeSystem)
|
||||||
if objectId == "" {
|
if objectId == "" {
|
||||||
objectId = uuid.Nil.String()
|
objectId = uuid.Nil.String()
|
||||||
builder.WithRequiredObjectId(objectId)
|
builder.WithRequiredObjectId(objectId)
|
||||||
}
|
}
|
||||||
if objectType == "" {
|
if objectType == "" {
|
||||||
objectType = ObjectTypeSystem
|
objectType = pkgAuditCommon.ObjectTypeSystem
|
||||||
builder.WithRequiredObjectType(objectType)
|
builder.WithRequiredObjectType(objectType)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
routingIdentifier = NewAuditRoutingIdentifier(objectId, objectType)
|
routingIdentifier = internalAuditApi.NewAuditRoutingIdentifier(objectId, objectType)
|
||||||
}
|
}
|
||||||
|
|
||||||
auditLogEntry, err := builder.auditLogEntryBuilder.Build(ctx, sequenceNumber)
|
auditLogEntry, err := builder.auditLogEntryBuilder.Build(ctx, sequenceNumber)
|
||||||
|
|
@ -2,17 +2,21 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/audit/utils"
|
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/bufbuild/protovalidate-go"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"buf.build/go/protovalidate"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
"google.golang.org/protobuf/types/known/structpb"
|
"google.golang.org/protobuf/types/known/structpb"
|
||||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||||
"testing"
|
|
||||||
"time"
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
internalAuditApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/internal/audit/api"
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
|
pkgAuditUtils "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_getObjectIdAndTypeFromAuditParams(t *testing.T) {
|
func Test_getObjectIdAndTypeFromAuditParams(t *testing.T) {
|
||||||
|
|
@ -40,7 +44,7 @@ func Test_getObjectIdAndTypeFromAuditParams(t *testing.T) {
|
||||||
objectId, objectType, err := getObjectIdAndTypeFromAuditParams(
|
objectId, objectType, err := getObjectIdAndTypeFromAuditParams(
|
||||||
&AuditParameters{
|
&AuditParameters{
|
||||||
ObjectId: "value",
|
ObjectId: "value",
|
||||||
ObjectType: ObjectTypeFromPluralString("invalid"),
|
ObjectType: pkgAuditCommon.ObjectTypeFromPluralString("invalid"),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert.EqualError(t, err, "unknown object type")
|
assert.EqualError(t, err, "unknown object type")
|
||||||
|
|
@ -54,12 +58,12 @@ func Test_getObjectIdAndTypeFromAuditParams(t *testing.T) {
|
||||||
objectId, objectType, err := getObjectIdAndTypeFromAuditParams(
|
objectId, objectType, err := getObjectIdAndTypeFromAuditParams(
|
||||||
&AuditParameters{
|
&AuditParameters{
|
||||||
ObjectId: "value",
|
ObjectId: "value",
|
||||||
ObjectType: ObjectTypeProject,
|
ObjectType: pkgAuditCommon.ObjectTypeProject,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "value", objectId)
|
assert.Equal(t, "value", objectId)
|
||||||
assert.Equal(t, ObjectTypeProject, *objectType)
|
assert.Equal(t, pkgAuditCommon.ObjectTypeProject, *objectType)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -76,7 +80,7 @@ func Test_AuditLogEntryBuilder(t *testing.T) {
|
||||||
t.Run("details missing", func(t *testing.T) {
|
t.Run("details missing", func(t *testing.T) {
|
||||||
logEntry, err := NewAuditLogEntryBuilder().WithRequiredLocation("eu01").
|
logEntry, err := NewAuditLogEntryBuilder().WithRequiredLocation("eu01").
|
||||||
WithRequiredObjectId("1").
|
WithRequiredObjectId("1").
|
||||||
WithRequiredObjectType(ObjectTypeProject).
|
WithRequiredObjectType(pkgAuditCommon.ObjectTypeProject).
|
||||||
Build(context.Background(), SequenceNumber(1))
|
Build(context.Background(), SequenceNumber(1))
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
@ -86,23 +90,23 @@ func Test_AuditLogEntryBuilder(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
err = validator.Validate(logEntry)
|
err = validator.Validate(logEntry)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Equal(t, "validation error:\n - proto_payload.service_name: value is required [required]\n - proto_payload.operation_name: value is required [required]\n - proto_payload.request_metadata.caller_supplied_user_agent: value is required [required]\n - proto_payload.request_metadata.request_attributes.method: value is required [required]\n - proto_payload.request_metadata.request_attributes.headers: value is required [required]\n - proto_payload.request_metadata.request_attributes.path: value is required [required]\n - proto_payload.request_metadata.request_attributes.host: value is required [required]\n - proto_payload.request_metadata.request_attributes.scheme: value is required [required]\n - proto_payload.request_metadata.request_attributes.protocol: value is required [required]\n - insert_id: value does not match regex pattern `^[0-9]+/[a-z0-9-]+/[a-z0-9-]+/[0-9]+$` [string.pattern]", err.Error())
|
assert.Equal(t, "validation errors:\n - proto_payload.service_name: value is required\n - proto_payload.operation_name: value is required\n - proto_payload.request_metadata.caller_supplied_user_agent: value is required\n - proto_payload.request_metadata.request_attributes.method: value is required\n - proto_payload.request_metadata.request_attributes.headers: value is required\n - proto_payload.request_metadata.request_attributes.path: value is required\n - proto_payload.request_metadata.request_attributes.host: value is required\n - proto_payload.request_metadata.request_attributes.scheme: value is required\n - proto_payload.request_metadata.request_attributes.protocol: value is required\n - insert_id: value does not match regex pattern `^[0-9]+/[a-z0-9-]+/[a-z0-9-]+/[0-9]+$`", err.Error())
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("required only", func(t *testing.T) {
|
t.Run("required only", func(t *testing.T) {
|
||||||
builder := NewAuditLogEntryBuilder().
|
builder := NewAuditLogEntryBuilder().
|
||||||
WithRequiredLocation("eu01").
|
WithRequiredLocation("eu01").
|
||||||
WithRequiredObjectId("1").
|
WithRequiredObjectId("1").
|
||||||
WithRequiredObjectType(ObjectTypeProject).
|
WithRequiredObjectType(pkgAuditCommon.ObjectTypeProject).
|
||||||
WithRequiredOperation("stackit.demo-service.v1.operation").
|
WithRequiredOperation("stackit.demo-service.v1.operation").
|
||||||
WithRequiredApiRequest(ApiRequest{
|
WithRequiredApiRequest(pkgAuditCommon.ApiRequest{
|
||||||
Body: nil,
|
Body: nil,
|
||||||
Header: TestHeaders,
|
Header: internalAuditApi.TestHeaders,
|
||||||
Host: "localhost",
|
Host: "localhost",
|
||||||
Method: "POST",
|
Method: "POST",
|
||||||
Scheme: "https",
|
Scheme: "https",
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
URL: RequestUrl{
|
URL: pkgAuditCommon.RequestUrl{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
RawQuery: nil,
|
RawQuery: nil,
|
||||||
},
|
},
|
||||||
|
|
@ -126,7 +130,7 @@ func Test_AuditLogEntryBuilder(t *testing.T) {
|
||||||
|
|
||||||
authenticationInfo := logEntry.ProtoPayload.AuthenticationInfo
|
authenticationInfo := logEntry.ProtoPayload.AuthenticationInfo
|
||||||
assert.NotNil(t, authenticationInfo)
|
assert.NotNil(t, authenticationInfo)
|
||||||
assert.Equal(t, "Christian.Schaible@novatec-gmbh.de", authenticationInfo.PrincipalEmail)
|
assert.Equal(t, "Christian.Schaible@novatec-gmbh.de", *authenticationInfo.PrincipalEmail)
|
||||||
assert.Equal(t, "cd94f01a-df2e-4456-902e-48f5e57f0b63", authenticationInfo.PrincipalId)
|
assert.Equal(t, "cd94f01a-df2e-4456-902e-48f5e57f0b63", authenticationInfo.PrincipalId)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
||||||
|
|
@ -195,16 +199,16 @@ func Test_AuditLogEntryBuilder(t *testing.T) {
|
||||||
builder := NewAuditLogEntryBuilder().
|
builder := NewAuditLogEntryBuilder().
|
||||||
WithRequiredLocation("eu01").
|
WithRequiredLocation("eu01").
|
||||||
WithRequiredObjectId("1").
|
WithRequiredObjectId("1").
|
||||||
WithRequiredObjectType(ObjectTypeProject).
|
WithRequiredObjectType(pkgAuditCommon.ObjectTypeProject).
|
||||||
WithRequiredOperation("stackit.demo-service.v1.operation").
|
WithRequiredOperation("stackit.demo-service.v1.operation").
|
||||||
WithRequiredApiRequest(ApiRequest{
|
WithRequiredApiRequest(pkgAuditCommon.ApiRequest{
|
||||||
Body: nil,
|
Body: nil,
|
||||||
Header: TestHeaders,
|
Header: internalAuditApi.TestHeaders,
|
||||||
Host: "localhost",
|
Host: "localhost",
|
||||||
Method: "POST",
|
Method: "POST",
|
||||||
Scheme: "https",
|
Scheme: "https",
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
URL: RequestUrl{
|
URL: pkgAuditCommon.RequestUrl{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
RawQuery: nil,
|
RawQuery: nil,
|
||||||
},
|
},
|
||||||
|
|
@ -215,7 +219,7 @@ func Test_AuditLogEntryBuilder(t *testing.T) {
|
||||||
WithAuditPermission(permission).
|
WithAuditPermission(permission).
|
||||||
WithAuditPermissionCheckResult(permissionCheckResult).
|
WithAuditPermissionCheckResult(permissionCheckResult).
|
||||||
WithDetails(details).
|
WithDetails(details).
|
||||||
WithEventType(EventTypePolicyDenied).
|
WithEventType(pkgAuditCommon.EventTypePolicyDenied).
|
||||||
WithLabels(map[string]string{"key": "label"}).
|
WithLabels(map[string]string{"key": "label"}).
|
||||||
WithNumResponseItems(int64(10)).
|
WithNumResponseItems(int64(10)).
|
||||||
WithRequestCorrelationId("correlationId").
|
WithRequestCorrelationId("correlationId").
|
||||||
|
|
@ -242,7 +246,7 @@ func Test_AuditLogEntryBuilder(t *testing.T) {
|
||||||
|
|
||||||
authenticationInfo := logEntry.ProtoPayload.AuthenticationInfo
|
authenticationInfo := logEntry.ProtoPayload.AuthenticationInfo
|
||||||
assert.NotNil(t, authenticationInfo)
|
assert.NotNil(t, authenticationInfo)
|
||||||
assert.Equal(t, "Christian.Schaible@novatec-gmbh.de", authenticationInfo.PrincipalEmail)
|
assert.Equal(t, "Christian.Schaible@novatec-gmbh.de", *authenticationInfo.PrincipalEmail)
|
||||||
assert.Equal(t, "cd94f01a-df2e-4456-902e-48f5e57f0b63", authenticationInfo.PrincipalId)
|
assert.Equal(t, "cd94f01a-df2e-4456-902e-48f5e57f0b63", authenticationInfo.PrincipalId)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
||||||
|
|
@ -306,11 +310,105 @@ func Test_AuditLogEntryBuilder(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("with service account token", func(t *testing.T) {
|
||||||
|
builder := NewAuditLogEntryBuilder().
|
||||||
|
WithRequiredLocation("eu01").
|
||||||
|
WithRequiredObjectId("1").
|
||||||
|
WithRequiredObjectType(pkgAuditCommon.ObjectTypeProject).
|
||||||
|
WithRequiredOperation("stackit.demo-service.v1.operation").
|
||||||
|
WithRequiredApiRequest(pkgAuditCommon.ApiRequest{
|
||||||
|
Body: nil,
|
||||||
|
Header: internalAuditApi.TestHeadersSa,
|
||||||
|
Host: "localhost",
|
||||||
|
Method: "POST",
|
||||||
|
Scheme: "https",
|
||||||
|
Proto: "HTTP/1.1",
|
||||||
|
URL: pkgAuditCommon.RequestUrl{
|
||||||
|
Path: "/",
|
||||||
|
RawQuery: nil,
|
||||||
|
},
|
||||||
|
}).
|
||||||
|
WithRequiredRequestClientIp("127.0.0.1").
|
||||||
|
WithRequiredServiceName("demo-service").
|
||||||
|
WithRequiredWorkerId("worker-id")
|
||||||
|
|
||||||
|
logEntry, err := builder.Build(context.Background(), SequenceNumber(1))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, logEntry)
|
||||||
|
|
||||||
|
assert.Equal(t, "projects/1/logs/admin-activity", logEntry.LogName)
|
||||||
|
assert.Nil(t, logEntry.Labels)
|
||||||
|
assert.Equal(t, auditV1.LogSeverity_LOG_SEVERITY_DEFAULT, logEntry.Severity)
|
||||||
|
assert.NotNil(t, logEntry.Timestamp)
|
||||||
|
assert.Nil(t, logEntry.CorrelationId)
|
||||||
|
assert.Regexp(t, "[0-9]+/eu01/worker-id/1", logEntry.InsertId)
|
||||||
|
|
||||||
|
assert.NotNil(t, logEntry.ProtoPayload)
|
||||||
|
|
||||||
|
authenticationInfo := logEntry.ProtoPayload.AuthenticationInfo
|
||||||
|
assert.NotNil(t, authenticationInfo)
|
||||||
|
assert.Equal(t, "my-service-yifc9e1@sa.stackit.cloud", *authenticationInfo.PrincipalEmail)
|
||||||
|
assert.Equal(t, "10f38b01_534b_47bb_a03a_e294ca2be4de", authenticationInfo.PrincipalId)
|
||||||
|
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
||||||
|
assert.Equal(t, "projects/dacc7830-843e-4c5e-86ff-aa0fb51d636f/service-accounts/10f38b01-534b-47bb-a03a-e294ca2be4de", *authenticationInfo.ServiceAccountName)
|
||||||
|
|
||||||
|
assert.Nil(t, logEntry.ProtoPayload.AuthorizationInfo)
|
||||||
|
assert.Nil(t, logEntry.ProtoPayload.Metadata)
|
||||||
|
assert.Equal(t, "stackit.demo-service.v1.operation", logEntry.ProtoPayload.OperationName)
|
||||||
|
assert.Nil(t, logEntry.ProtoPayload.Request)
|
||||||
|
|
||||||
|
requestMetadata := logEntry.ProtoPayload.RequestMetadata
|
||||||
|
assert.NotNil(t, requestMetadata)
|
||||||
|
assert.Equal(t, "127.0.0.1", requestMetadata.CallerIp)
|
||||||
|
assert.Equal(t, "custom", requestMetadata.CallerSuppliedUserAgent)
|
||||||
|
|
||||||
|
requestAttributes := requestMetadata.RequestAttributes
|
||||||
|
assert.NotNil(t, requestAttributes)
|
||||||
|
assert.Equal(t, "/", requestAttributes.Path)
|
||||||
|
assert.NotNil(t, requestAttributes.Time)
|
||||||
|
assert.Equal(t, "localhost", requestAttributes.Host)
|
||||||
|
assert.Equal(t, auditV1.AttributeContext_HTTP_METHOD_POST, requestAttributes.Method)
|
||||||
|
assert.Nil(t, requestAttributes.Id)
|
||||||
|
assert.Equal(t, "https", requestAttributes.Scheme)
|
||||||
|
assert.Equal(t, map[string]string{"user-agent": "custom"}, requestAttributes.Headers)
|
||||||
|
assert.Nil(t, requestAttributes.Query)
|
||||||
|
assert.Equal(t, "HTTP/1.1", requestAttributes.Protocol)
|
||||||
|
|
||||||
|
requestAttributesAuth := requestAttributes.Auth
|
||||||
|
assert.NotNil(t, requestAttributesAuth)
|
||||||
|
assert.Equal(t, "10f38b01_534b_47bb_a03a_e294ca2be4de/stackit%2Fserviceaccount", requestAttributesAuth.Principal)
|
||||||
|
assert.Equal(t, []string{"stackit", "api"}, requestAttributesAuth.Audiences)
|
||||||
|
assert.NotNil(t, requestAttributesAuth.Claims)
|
||||||
|
|
||||||
|
assert.Equal(t, "projects/1", logEntry.ProtoPayload.ResourceName)
|
||||||
|
assert.Nil(t, logEntry.ProtoPayload.Response)
|
||||||
|
|
||||||
|
responseMetadata := logEntry.ProtoPayload.ResponseMetadata
|
||||||
|
assert.NotNil(t, responseMetadata)
|
||||||
|
assert.Nil(t, responseMetadata.ErrorDetails)
|
||||||
|
assert.Nil(t, responseMetadata.ErrorMessage)
|
||||||
|
assert.Equal(t, wrapperspb.Int32(200), responseMetadata.StatusCode)
|
||||||
|
|
||||||
|
responseAttributes := responseMetadata.ResponseAttributes
|
||||||
|
assert.NotNil(t, responseAttributes)
|
||||||
|
assert.Nil(t, responseAttributes.Headers)
|
||||||
|
assert.Nil(t, responseAttributes.NumResponseItems)
|
||||||
|
assert.Nil(t, responseAttributes.Size)
|
||||||
|
assert.NotNil(t, responseAttributes.Time)
|
||||||
|
|
||||||
|
assert.Equal(t, "demo-service", logEntry.ProtoPayload.ServiceName)
|
||||||
|
|
||||||
|
validator, err := protovalidate.New()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = validator.Validate(logEntry)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("system event", func(t *testing.T) {
|
t.Run("system event", func(t *testing.T) {
|
||||||
builder := NewAuditLogEntryBuilder().
|
builder := NewAuditLogEntryBuilder().
|
||||||
WithRequiredLocation("eu01").
|
WithRequiredLocation("eu01").
|
||||||
WithRequiredObjectId("1").
|
WithRequiredObjectId("1").
|
||||||
WithRequiredObjectType(ObjectTypeProject).
|
WithRequiredObjectType(pkgAuditCommon.ObjectTypeProject).
|
||||||
WithRequiredOperation("stackit.demo-service.v1.operation").
|
WithRequiredOperation("stackit.demo-service.v1.operation").
|
||||||
WithRequiredServiceName("demo-service").
|
WithRequiredServiceName("demo-service").
|
||||||
WithRequiredWorkerId("worker-id").
|
WithRequiredWorkerId("worker-id").
|
||||||
|
|
@ -331,7 +429,7 @@ func Test_AuditLogEntryBuilder(t *testing.T) {
|
||||||
|
|
||||||
authenticationInfo := logEntry.ProtoPayload.AuthenticationInfo
|
authenticationInfo := logEntry.ProtoPayload.AuthenticationInfo
|
||||||
assert.NotNil(t, authenticationInfo)
|
assert.NotNil(t, authenticationInfo)
|
||||||
assert.Equal(t, EmailAddressDoNotReplyAtStackItDotCloud, authenticationInfo.PrincipalEmail)
|
assert.Nil(t, authenticationInfo.PrincipalEmail)
|
||||||
assert.Equal(t, "none", authenticationInfo.PrincipalId)
|
assert.Equal(t, "none", authenticationInfo.PrincipalId)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
||||||
|
|
@ -399,16 +497,16 @@ func Test_AuditLogEntryBuilder(t *testing.T) {
|
||||||
builder := NewAuditLogEntryBuilder().
|
builder := NewAuditLogEntryBuilder().
|
||||||
WithRequiredLocation("eu01").
|
WithRequiredLocation("eu01").
|
||||||
WithRequiredObjectId("1").
|
WithRequiredObjectId("1").
|
||||||
WithRequiredObjectType(ObjectTypeProject).
|
WithRequiredObjectType(pkgAuditCommon.ObjectTypeProject).
|
||||||
WithRequiredOperation("stackit.demo-service.v1.operation").
|
WithRequiredOperation("stackit.demo-service.v1.operation").
|
||||||
WithRequiredApiRequest(ApiRequest{
|
WithRequiredApiRequest(pkgAuditCommon.ApiRequest{
|
||||||
Body: nil,
|
Body: nil,
|
||||||
Header: TestHeaders,
|
Header: internalAuditApi.TestHeaders,
|
||||||
Host: "localhost",
|
Host: "localhost",
|
||||||
Method: "POST",
|
Method: "POST",
|
||||||
Scheme: "https",
|
Scheme: "https",
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
URL: RequestUrl{
|
URL: pkgAuditCommon.RequestUrl{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
RawQuery: nil,
|
RawQuery: nil,
|
||||||
},
|
},
|
||||||
|
|
@ -419,7 +517,7 @@ func Test_AuditLogEntryBuilder(t *testing.T) {
|
||||||
WithAuditPermission(permission).
|
WithAuditPermission(permission).
|
||||||
WithAuditPermissionCheckResult(permissionCheckResult).
|
WithAuditPermissionCheckResult(permissionCheckResult).
|
||||||
WithDetails(details).
|
WithDetails(details).
|
||||||
WithEventType(EventTypeSystemEvent).
|
WithEventType(pkgAuditCommon.EventTypeSystemEvent).
|
||||||
WithLabels(map[string]string{"key": "label"}).
|
WithLabels(map[string]string{"key": "label"}).
|
||||||
WithNumResponseItems(int64(10)).
|
WithNumResponseItems(int64(10)).
|
||||||
WithRequestCorrelationId("correlationId").
|
WithRequestCorrelationId("correlationId").
|
||||||
|
|
@ -451,21 +549,21 @@ func Test_AuditLogEntryBuilder(t *testing.T) {
|
||||||
responseBodyBytes, err := ResponseBodyToBytes(responseBody)
|
responseBodyBytes, err := ResponseBodyToBytes(responseBody)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
builder := NewAuditLogEntryBuilder().
|
builder := NewAuditLogEntryBuilder().
|
||||||
WithRequiredApiRequest(ApiRequest{
|
WithRequiredApiRequest(pkgAuditCommon.ApiRequest{
|
||||||
Body: nil,
|
Body: nil,
|
||||||
Header: TestHeaders,
|
Header: internalAuditApi.TestHeaders,
|
||||||
Host: "localhost",
|
Host: "localhost",
|
||||||
Method: "POST",
|
Method: "POST",
|
||||||
Scheme: "https",
|
Scheme: "https",
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
URL: RequestUrl{
|
URL: pkgAuditCommon.RequestUrl{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
RawQuery: nil,
|
RawQuery: nil,
|
||||||
},
|
},
|
||||||
}).
|
}).
|
||||||
WithRequiredLocation("eu01").
|
WithRequiredLocation("eu01").
|
||||||
WithRequiredObjectId("1").
|
WithRequiredObjectId("1").
|
||||||
WithRequiredObjectType(ObjectTypeProject).
|
WithRequiredObjectType(pkgAuditCommon.ObjectTypeProject).
|
||||||
WithRequiredOperation("stackit.demo-service.v1.operation").
|
WithRequiredOperation("stackit.demo-service.v1.operation").
|
||||||
WithRequiredRequestClientIp("127.0.0.1").
|
WithRequiredRequestClientIp("127.0.0.1").
|
||||||
WithRequiredServiceName("demo-service").
|
WithRequiredServiceName("demo-service").
|
||||||
|
|
@ -480,21 +578,21 @@ func Test_AuditLogEntryBuilder(t *testing.T) {
|
||||||
|
|
||||||
t.Run("with invalid response body", func(t *testing.T) {
|
t.Run("with invalid response body", func(t *testing.T) {
|
||||||
builder := NewAuditLogEntryBuilder().
|
builder := NewAuditLogEntryBuilder().
|
||||||
WithRequiredApiRequest(ApiRequest{
|
WithRequiredApiRequest(pkgAuditCommon.ApiRequest{
|
||||||
Body: nil,
|
Body: nil,
|
||||||
Header: TestHeaders,
|
Header: internalAuditApi.TestHeaders,
|
||||||
Host: "localhost",
|
Host: "localhost",
|
||||||
Method: "POST",
|
Method: "POST",
|
||||||
Scheme: "https",
|
Scheme: "https",
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
URL: RequestUrl{
|
URL: pkgAuditCommon.RequestUrl{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
RawQuery: nil,
|
RawQuery: nil,
|
||||||
},
|
},
|
||||||
}).
|
}).
|
||||||
WithRequiredLocation("eu01").
|
WithRequiredLocation("eu01").
|
||||||
WithRequiredObjectId("1").
|
WithRequiredObjectId("1").
|
||||||
WithRequiredObjectType(ObjectTypeProject).
|
WithRequiredObjectType(pkgAuditCommon.ObjectTypeProject).
|
||||||
WithRequiredOperation("stackit.demo-service.v1.operation").
|
WithRequiredOperation("stackit.demo-service.v1.operation").
|
||||||
WithRequiredRequestClientIp("127.0.0.1").
|
WithRequiredRequestClientIp("127.0.0.1").
|
||||||
WithRequiredServiceName("demo-service").
|
WithRequiredServiceName("demo-service").
|
||||||
|
|
@ -505,13 +603,141 @@ func Test_AuditLogEntryBuilder(t *testing.T) {
|
||||||
assert.EqualError(t, err, "json: cannot unmarshal string into Go value of type map[string]interface {}\ninvalid response")
|
assert.EqualError(t, err, "json: cannot unmarshal string into Go value of type map[string]interface {}\ninvalid response")
|
||||||
assert.Nil(t, logEntry)
|
assert.Nil(t, logEntry)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("get api request", func(t *testing.T) {
|
||||||
|
requestBody := map[string]interface{}{"key": "response"}
|
||||||
|
requestBodyBytes, err := ResponseBodyToBytes(requestBody)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
builder := NewAuditLogEntryBuilder().
|
||||||
|
WithRequiredApiRequest(pkgAuditCommon.ApiRequest{
|
||||||
|
Body: requestBodyBytes,
|
||||||
|
Header: internalAuditApi.TestHeaders,
|
||||||
|
Host: "localhost",
|
||||||
|
Method: "POST",
|
||||||
|
Scheme: "https",
|
||||||
|
Proto: "HTTP/1.1",
|
||||||
|
URL: pkgAuditCommon.RequestUrl{
|
||||||
|
Path: "/",
|
||||||
|
RawQuery: nil,
|
||||||
|
},
|
||||||
|
}).
|
||||||
|
WithRequiredLocation("eu01").
|
||||||
|
WithRequiredObjectId("1").
|
||||||
|
WithRequiredObjectType(pkgAuditCommon.ObjectTypeProject).
|
||||||
|
WithRequiredOperation("stackit.demo-service.v1.operation").
|
||||||
|
WithRequiredRequestClientIp("127.0.0.1").
|
||||||
|
WithRequiredServiceName("demo-service").
|
||||||
|
WithRequiredWorkerId("worker-id")
|
||||||
|
|
||||||
|
// get the request before building the auditlog entry
|
||||||
|
apiRequest := builder.GetApiRequest()
|
||||||
|
assert.NotNil(t, apiRequest)
|
||||||
|
assert.Equal(t, requestBodyBytes, apiRequest.Body)
|
||||||
|
|
||||||
|
logEntry, err := builder.Build(context.Background(), SequenceNumber(1))
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, logEntry)
|
||||||
|
|
||||||
|
// get the request after building the auditlog entry
|
||||||
|
apiRequest = builder.GetApiRequest()
|
||||||
|
assert.NotNil(t, apiRequest)
|
||||||
|
assert.Equal(t, requestBodyBytes, apiRequest.Body)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("get invalid api request", func(t *testing.T) {
|
||||||
|
requestBodyBytes := []byte("invalid")
|
||||||
|
builder := NewAuditLogEntryBuilder().
|
||||||
|
WithRequiredApiRequest(pkgAuditCommon.ApiRequest{
|
||||||
|
Body: requestBodyBytes,
|
||||||
|
Header: internalAuditApi.TestHeaders,
|
||||||
|
Host: "localhost",
|
||||||
|
Method: "POST",
|
||||||
|
Scheme: "https",
|
||||||
|
Proto: "HTTP/1.1",
|
||||||
|
URL: pkgAuditCommon.RequestUrl{
|
||||||
|
Path: "/",
|
||||||
|
RawQuery: nil,
|
||||||
|
},
|
||||||
|
}).
|
||||||
|
WithRequiredLocation("eu01").
|
||||||
|
WithRequiredObjectId("1").
|
||||||
|
WithRequiredObjectType(pkgAuditCommon.ObjectTypeProject).
|
||||||
|
WithRequiredOperation("stackit.demo-service.v1.operation").
|
||||||
|
WithRequiredRequestClientIp("127.0.0.1").
|
||||||
|
WithRequiredServiceName("demo-service").
|
||||||
|
WithRequiredWorkerId("worker-id")
|
||||||
|
|
||||||
|
// get the request before building the auditlog entry
|
||||||
|
apiRequest := builder.GetApiRequest()
|
||||||
|
assert.NotNil(t, apiRequest)
|
||||||
|
assert.Equal(t, requestBodyBytes, apiRequest.Body)
|
||||||
|
|
||||||
|
logEntry, err := builder.Build(context.Background(), SequenceNumber(1))
|
||||||
|
|
||||||
|
assert.EqualError(t, err, "invalid character 'i' looking for beginning of value\ninvalid request body")
|
||||||
|
assert.Nil(t, logEntry)
|
||||||
|
|
||||||
|
// get the request after building the auditlog entry
|
||||||
|
apiRequest = builder.GetApiRequest()
|
||||||
|
assert.NotNil(t, apiRequest)
|
||||||
|
assert.Equal(t, requestBodyBytes, apiRequest.Body)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("modify request body", func(t *testing.T) {
|
||||||
|
requestBodyBytes := []byte("{\"key\":\"value\"}")
|
||||||
|
builder := NewAuditLogEntryBuilder().
|
||||||
|
WithRequiredApiRequest(pkgAuditCommon.ApiRequest{
|
||||||
|
Body: requestBodyBytes,
|
||||||
|
Header: internalAuditApi.TestHeaders,
|
||||||
|
Host: "localhost",
|
||||||
|
Method: "POST",
|
||||||
|
Scheme: "https",
|
||||||
|
Proto: "HTTP/1.1",
|
||||||
|
URL: pkgAuditCommon.RequestUrl{
|
||||||
|
Path: "/",
|
||||||
|
RawQuery: nil,
|
||||||
|
},
|
||||||
|
}).
|
||||||
|
WithRequiredLocation("eu01").
|
||||||
|
WithRequiredObjectId("1").
|
||||||
|
WithRequiredObjectType(pkgAuditCommon.ObjectTypeProject).
|
||||||
|
WithRequiredOperation("stackit.demo-service.v1.operation").
|
||||||
|
WithRequiredRequestClientIp("127.0.0.1").
|
||||||
|
WithRequiredServiceName("demo-service").
|
||||||
|
WithRequiredWorkerId("worker-id")
|
||||||
|
|
||||||
|
// get the request before building the auditlog entry
|
||||||
|
apiRequest := builder.GetApiRequest()
|
||||||
|
assert.NotNil(t, apiRequest)
|
||||||
|
assert.Equal(t, requestBodyBytes, apiRequest.Body)
|
||||||
|
|
||||||
|
// update the request body
|
||||||
|
updatedBodyBytes := []byte("{\"key\":\"updated\"}")
|
||||||
|
apiRequest.Body = updatedBodyBytes
|
||||||
|
|
||||||
|
// build the audit log entry
|
||||||
|
logEntry, err := builder.Build(context.Background(), SequenceNumber(1))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, logEntry)
|
||||||
|
|
||||||
|
// check the request body from the serialized event
|
||||||
|
requestBodyJson, err := logEntry.ProtoPayload.Request.MarshalJSON()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, updatedBodyBytes, requestBodyJson)
|
||||||
|
|
||||||
|
// check the request after building the auditlog entry
|
||||||
|
apiRequest = builder.GetApiRequest()
|
||||||
|
assert.NotNil(t, apiRequest)
|
||||||
|
assert.Equal(t, updatedBodyBytes, apiRequest.Body)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_AuditEventBuilder(t *testing.T) {
|
func Test_AuditEventBuilder(t *testing.T) {
|
||||||
|
|
||||||
t.Run("nothing set", func(t *testing.T) {
|
t.Run("nothing set", func(t *testing.T) {
|
||||||
api, _ := NewMockAuditApi()
|
api, _ := NewMockAuditApi()
|
||||||
sequenceNumberGenerator := utils.NewDefaultSequenceNumberGenerator()
|
sequenceNumberGenerator := pkgAuditUtils.NewDefaultSequenceNumberGenerator()
|
||||||
|
|
||||||
cloudEvent, routingIdentifier, err := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01").
|
cloudEvent, routingIdentifier, err := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01").
|
||||||
Build(context.Background(), SequenceNumber(1))
|
Build(context.Background(), SequenceNumber(1))
|
||||||
|
|
@ -524,44 +750,44 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
|
|
||||||
t.Run("details missing", func(t *testing.T) {
|
t.Run("details missing", func(t *testing.T) {
|
||||||
api, _ := NewMockAuditApi()
|
api, _ := NewMockAuditApi()
|
||||||
sequenceNumberGenerator := utils.NewDefaultSequenceNumberGenerator()
|
sequenceNumberGenerator := pkgAuditUtils.NewDefaultSequenceNumberGenerator()
|
||||||
|
|
||||||
cloudEvent, routingIdentifier, err := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01").
|
cloudEvent, routingIdentifier, err := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01").
|
||||||
WithRequiredObjectId("objectId").
|
WithRequiredObjectId("objectId").
|
||||||
WithRequiredObjectType(ObjectTypeProject).
|
WithRequiredObjectType(pkgAuditCommon.ObjectTypeProject).
|
||||||
Build(context.Background(), SequenceNumber(1))
|
Build(context.Background(), SequenceNumber(1))
|
||||||
|
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Equal(t, "validation error:\n - log_name: value does not match regex pattern `^[a-z-]+/[a-z0-9-]+/logs/(?:admin-activity|system-event|policy-denied|data-access)$` [string.pattern]\n - proto_payload.operation_name: value is required [required]\n - proto_payload.resource_name: value does not match regex pattern `^[a-z]+/[a-z0-9-]+(?:/[a-z0-9-]+/[a-z0-9-_]+)*$` [string.pattern]\n - proto_payload.request_metadata.caller_supplied_user_agent: value is required [required]\n - proto_payload.request_metadata.request_attributes.method: value is required [required]\n - proto_payload.request_metadata.request_attributes.headers: value is required [required]\n - proto_payload.request_metadata.request_attributes.path: value is required [required]\n - proto_payload.request_metadata.request_attributes.host: value is required [required]\n - proto_payload.request_metadata.request_attributes.scheme: value is required [required]\n - proto_payload.request_metadata.request_attributes.protocol: value is required [required]", err.Error())
|
assert.Equal(t, "validation errors:\n - log_name: value does not match regex pattern `^[a-z-]+/[a-z0-9-]+/logs/(?:admin-activity|system-event|policy-denied|data-access)$`\n - proto_payload.operation_name: value is required\n - proto_payload.resource_name: value does not match regex pattern `^[a-z]+/[a-z0-9-]+(?:/[a-z0-9-]+/[a-z0-9-_]+)*$`\n - proto_payload.request_metadata.caller_supplied_user_agent: value is required\n - proto_payload.request_metadata.request_attributes.method: value is required\n - proto_payload.request_metadata.request_attributes.headers: value is required\n - proto_payload.request_metadata.request_attributes.path: value is required\n - proto_payload.request_metadata.request_attributes.host: value is required\n - proto_payload.request_metadata.request_attributes.scheme: value is required\n - proto_payload.request_metadata.request_attributes.protocol: value is required", err.Error())
|
||||||
assert.Nil(t, cloudEvent)
|
assert.Nil(t, cloudEvent)
|
||||||
assert.Nil(t, routingIdentifier)
|
assert.Nil(t, routingIdentifier)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("required only", func(t *testing.T) {
|
t.Run("required only", func(t *testing.T) {
|
||||||
api, _ := NewMockAuditApi()
|
api, _ := NewMockAuditApi()
|
||||||
sequenceNumberGenerator := utils.NewDefaultSequenceNumberGenerator()
|
sequenceNumberGenerator := pkgAuditUtils.NewDefaultSequenceNumberGenerator()
|
||||||
|
|
||||||
objectId := uuid.NewString()
|
objectId := uuid.NewString()
|
||||||
operation := "stackit.demo-service.v1.operation"
|
operation := "stackit.demo-service.v1.operation"
|
||||||
builder := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01").
|
builder := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01").
|
||||||
WithRequiredObjectId(objectId).
|
WithRequiredObjectId(objectId).
|
||||||
WithRequiredObjectType(ObjectTypeProject).
|
WithRequiredObjectType(pkgAuditCommon.ObjectTypeProject).
|
||||||
WithRequiredOperation(operation).
|
WithRequiredOperation(operation).
|
||||||
WithRequiredApiRequest(ApiRequest{
|
WithRequiredApiRequest(pkgAuditCommon.ApiRequest{
|
||||||
Body: nil,
|
Body: nil,
|
||||||
Header: TestHeaders,
|
Header: internalAuditApi.TestHeaders,
|
||||||
Host: "localhost",
|
Host: "localhost",
|
||||||
Method: "POST",
|
Method: "POST",
|
||||||
Scheme: "https",
|
Scheme: "https",
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
URL: RequestUrl{
|
URL: pkgAuditCommon.RequestUrl{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
RawQuery: nil,
|
RawQuery: nil,
|
||||||
},
|
},
|
||||||
}).
|
}).
|
||||||
WithRequiredRequestClientIp("127.0.0.1")
|
WithRequiredRequestClientIp("127.0.0.1")
|
||||||
|
|
||||||
routableIdentifier := RoutableIdentifier{Identifier: objectId, Type: ObjectTypeProject}
|
routableIdentifier := pkgAuditCommon.RoutableIdentifier{Identifier: objectId, Type: pkgAuditCommon.ObjectTypeProject}
|
||||||
|
|
||||||
cloudEvent, routingIdentifier, err := builder.Build(context.Background(), SequenceNumber(1))
|
cloudEvent, routingIdentifier, err := builder.Build(context.Background(), SequenceNumber(1))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
@ -604,7 +830,7 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
|
|
||||||
authenticationInfo := logEntry.ProtoPayload.AuthenticationInfo
|
authenticationInfo := logEntry.ProtoPayload.AuthenticationInfo
|
||||||
assert.NotNil(t, authenticationInfo)
|
assert.NotNil(t, authenticationInfo)
|
||||||
assert.Equal(t, "Christian.Schaible@novatec-gmbh.de", authenticationInfo.PrincipalEmail)
|
assert.Equal(t, "Christian.Schaible@novatec-gmbh.de", *authenticationInfo.PrincipalEmail)
|
||||||
assert.Equal(t, "cd94f01a-df2e-4456-902e-48f5e57f0b63", authenticationInfo.PrincipalId)
|
assert.Equal(t, "cd94f01a-df2e-4456-902e-48f5e57f0b63", authenticationInfo.PrincipalId)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
||||||
|
|
@ -663,7 +889,7 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
|
|
||||||
t.Run("with details", func(t *testing.T) {
|
t.Run("with details", func(t *testing.T) {
|
||||||
api, _ := NewMockAuditApi()
|
api, _ := NewMockAuditApi()
|
||||||
sequenceNumberGenerator := utils.NewDefaultSequenceNumberGenerator()
|
sequenceNumberGenerator := pkgAuditUtils.NewDefaultSequenceNumberGenerator()
|
||||||
|
|
||||||
objectId := uuid.NewString()
|
objectId := uuid.NewString()
|
||||||
operation := "stackit.demo-service.v1.operation"
|
operation := "stackit.demo-service.v1.operation"
|
||||||
|
|
@ -677,16 +903,16 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
builder := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01").
|
builder := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01").
|
||||||
WithRequiredObjectId(objectId).
|
WithRequiredObjectId(objectId).
|
||||||
WithRequiredObjectType(ObjectTypeProject).
|
WithRequiredObjectType(pkgAuditCommon.ObjectTypeProject).
|
||||||
WithRequiredOperation(operation).
|
WithRequiredOperation(operation).
|
||||||
WithRequiredApiRequest(ApiRequest{
|
WithRequiredApiRequest(pkgAuditCommon.ApiRequest{
|
||||||
Body: nil,
|
Body: nil,
|
||||||
Header: TestHeaders,
|
Header: internalAuditApi.TestHeaders,
|
||||||
Host: "localhost",
|
Host: "localhost",
|
||||||
Method: "POST",
|
Method: "POST",
|
||||||
Scheme: "https",
|
Scheme: "https",
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
URL: RequestUrl{
|
URL: pkgAuditCommon.RequestUrl{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
RawQuery: nil,
|
RawQuery: nil,
|
||||||
},
|
},
|
||||||
|
|
@ -695,7 +921,7 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
WithAuditPermission(permission).
|
WithAuditPermission(permission).
|
||||||
WithAuditPermissionCheckResult(permissionCheckResult).
|
WithAuditPermissionCheckResult(permissionCheckResult).
|
||||||
WithDetails(details).
|
WithDetails(details).
|
||||||
WithEventType(EventTypeAdminActivity).
|
WithEventType(pkgAuditCommon.EventTypeAdminActivity).
|
||||||
WithLabels(map[string]string{"key": "label"}).
|
WithLabels(map[string]string{"key": "label"}).
|
||||||
WithNumResponseItems(int64(10)).
|
WithNumResponseItems(int64(10)).
|
||||||
WithRequestCorrelationId("correlationId").
|
WithRequestCorrelationId("correlationId").
|
||||||
|
|
@ -708,7 +934,7 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
WithStatusCode(400).
|
WithStatusCode(400).
|
||||||
WithVisibility(auditV1.Visibility_VISIBILITY_PRIVATE)
|
WithVisibility(auditV1.Visibility_VISIBILITY_PRIVATE)
|
||||||
|
|
||||||
routableIdentifier := RoutableIdentifier{Identifier: objectId, Type: ObjectTypeProject}
|
routableIdentifier := pkgAuditCommon.RoutableIdentifier{Identifier: objectId, Type: pkgAuditCommon.ObjectTypeProject}
|
||||||
|
|
||||||
cloudEvent, routingIdentifier, err := builder.Build(context.Background(), SequenceNumber(1))
|
cloudEvent, routingIdentifier, err := builder.Build(context.Background(), SequenceNumber(1))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
@ -751,7 +977,7 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
|
|
||||||
authenticationInfo := logEntry.ProtoPayload.AuthenticationInfo
|
authenticationInfo := logEntry.ProtoPayload.AuthenticationInfo
|
||||||
assert.NotNil(t, authenticationInfo)
|
assert.NotNil(t, authenticationInfo)
|
||||||
assert.Equal(t, "Christian.Schaible@novatec-gmbh.de", authenticationInfo.PrincipalEmail)
|
assert.Equal(t, "Christian.Schaible@novatec-gmbh.de", *authenticationInfo.PrincipalEmail)
|
||||||
assert.Equal(t, "cd94f01a-df2e-4456-902e-48f5e57f0b63", authenticationInfo.PrincipalId)
|
assert.Equal(t, "cd94f01a-df2e-4456-902e-48f5e57f0b63", authenticationInfo.PrincipalId)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
||||||
|
|
@ -817,13 +1043,13 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
|
|
||||||
t.Run("system event with object reference", func(t *testing.T) {
|
t.Run("system event with object reference", func(t *testing.T) {
|
||||||
api, _ := NewMockAuditApi()
|
api, _ := NewMockAuditApi()
|
||||||
sequenceNumberGenerator := utils.NewDefaultSequenceNumberGenerator()
|
sequenceNumberGenerator := pkgAuditUtils.NewDefaultSequenceNumberGenerator()
|
||||||
|
|
||||||
objectId := uuid.NewString()
|
objectId := uuid.NewString()
|
||||||
operation := "stackit.demo-service.v1.operation"
|
operation := "stackit.demo-service.v1.operation"
|
||||||
builder := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01").
|
builder := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01").
|
||||||
WithRequiredObjectId(objectId).
|
WithRequiredObjectId(objectId).
|
||||||
WithRequiredObjectType(ObjectTypeProject).
|
WithRequiredObjectType(pkgAuditCommon.ObjectTypeProject).
|
||||||
WithRequiredOperation(operation).
|
WithRequiredOperation(operation).
|
||||||
AsSystemEvent()
|
AsSystemEvent()
|
||||||
|
|
||||||
|
|
@ -831,8 +1057,8 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, builder.IsBuilt())
|
assert.True(t, builder.IsBuilt())
|
||||||
|
|
||||||
assert.Equal(t, SystemIdentifier.Identifier, routingIdentifier.ToObjectIdentifier().Identifier)
|
assert.Equal(t, pkgAuditCommon.SystemIdentifier.Identifier, routingIdentifier.ToObjectIdentifier().Identifier)
|
||||||
assert.Equal(t, SystemIdentifier.Type, routingIdentifier.ToObjectIdentifier().Type)
|
assert.Equal(t, pkgAuditCommon.SystemIdentifier.Type, routingIdentifier.ToObjectIdentifier().Type)
|
||||||
|
|
||||||
assert.NotNil(t, cloudEvent)
|
assert.NotNil(t, cloudEvent)
|
||||||
assert.Equal(t, "application/cloudevents+protobuf", cloudEvent.DataContentType)
|
assert.Equal(t, "application/cloudevents+protobuf", cloudEvent.DataContentType)
|
||||||
|
|
@ -849,8 +1075,8 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
assert.NotNil(t, cloudEvent.Data)
|
assert.NotNil(t, cloudEvent.Data)
|
||||||
assert.NoError(t, proto.Unmarshal(cloudEvent.Data, &routableAuditEvent))
|
assert.NoError(t, proto.Unmarshal(cloudEvent.Data, &routableAuditEvent))
|
||||||
|
|
||||||
assert.Equal(t, SystemIdentifier.Identifier, routableAuditEvent.ObjectIdentifier.Identifier)
|
assert.Equal(t, pkgAuditCommon.SystemIdentifier.Identifier, routableAuditEvent.ObjectIdentifier.Identifier)
|
||||||
assert.Equal(t, SystemIdentifier.Type, routableAuditEvent.ObjectIdentifier.Type)
|
assert.Equal(t, pkgAuditCommon.SystemIdentifier.Type, routableAuditEvent.ObjectIdentifier.Type)
|
||||||
assert.Equal(t, auditV1.Visibility_VISIBILITY_PRIVATE, routableAuditEvent.Visibility)
|
assert.Equal(t, auditV1.Visibility_VISIBILITY_PRIVATE, routableAuditEvent.Visibility)
|
||||||
assert.Equal(t, operation, routableAuditEvent.OperationName)
|
assert.Equal(t, operation, routableAuditEvent.OperationName)
|
||||||
|
|
||||||
|
|
@ -869,7 +1095,7 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
|
|
||||||
authenticationInfo := logEntry.ProtoPayload.AuthenticationInfo
|
authenticationInfo := logEntry.ProtoPayload.AuthenticationInfo
|
||||||
assert.NotNil(t, authenticationInfo)
|
assert.NotNil(t, authenticationInfo)
|
||||||
assert.Equal(t, EmailAddressDoNotReplyAtStackItDotCloud, authenticationInfo.PrincipalEmail)
|
assert.Nil(t, authenticationInfo.PrincipalEmail)
|
||||||
assert.Equal(t, "none", authenticationInfo.PrincipalId)
|
assert.Equal(t, "none", authenticationInfo.PrincipalId)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
||||||
|
|
@ -929,7 +1155,7 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
|
|
||||||
t.Run("system event", func(t *testing.T) {
|
t.Run("system event", func(t *testing.T) {
|
||||||
api, _ := NewMockAuditApi()
|
api, _ := NewMockAuditApi()
|
||||||
sequenceNumberGenerator := utils.NewDefaultSequenceNumberGenerator()
|
sequenceNumberGenerator := pkgAuditUtils.NewDefaultSequenceNumberGenerator()
|
||||||
|
|
||||||
operation := "stackit.demo-service.v1.operation"
|
operation := "stackit.demo-service.v1.operation"
|
||||||
builder := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01").
|
builder := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01").
|
||||||
|
|
@ -940,8 +1166,8 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, builder.IsBuilt())
|
assert.True(t, builder.IsBuilt())
|
||||||
|
|
||||||
assert.Equal(t, SystemIdentifier.Identifier, routingIdentifier.ToObjectIdentifier().Identifier)
|
assert.Equal(t, pkgAuditCommon.SystemIdentifier.Identifier, routingIdentifier.ToObjectIdentifier().Identifier)
|
||||||
assert.Equal(t, SystemIdentifier.Type, routingIdentifier.ToObjectIdentifier().Type)
|
assert.Equal(t, pkgAuditCommon.SystemIdentifier.Type, routingIdentifier.ToObjectIdentifier().Type)
|
||||||
|
|
||||||
assert.NotNil(t, cloudEvent)
|
assert.NotNil(t, cloudEvent)
|
||||||
assert.Equal(t, "application/cloudevents+protobuf", cloudEvent.DataContentType)
|
assert.Equal(t, "application/cloudevents+protobuf", cloudEvent.DataContentType)
|
||||||
|
|
@ -958,8 +1184,8 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
assert.NotNil(t, cloudEvent.Data)
|
assert.NotNil(t, cloudEvent.Data)
|
||||||
assert.NoError(t, proto.Unmarshal(cloudEvent.Data, &routableAuditEvent))
|
assert.NoError(t, proto.Unmarshal(cloudEvent.Data, &routableAuditEvent))
|
||||||
|
|
||||||
assert.Equal(t, SystemIdentifier.Identifier, routableAuditEvent.ObjectIdentifier.Identifier)
|
assert.Equal(t, pkgAuditCommon.SystemIdentifier.Identifier, routableAuditEvent.ObjectIdentifier.Identifier)
|
||||||
assert.Equal(t, SystemIdentifier.Type, routableAuditEvent.ObjectIdentifier.Type)
|
assert.Equal(t, pkgAuditCommon.SystemIdentifier.Type, routableAuditEvent.ObjectIdentifier.Type)
|
||||||
assert.Equal(t, auditV1.Visibility_VISIBILITY_PRIVATE, routableAuditEvent.Visibility)
|
assert.Equal(t, auditV1.Visibility_VISIBILITY_PRIVATE, routableAuditEvent.Visibility)
|
||||||
assert.Equal(t, operation, routableAuditEvent.OperationName)
|
assert.Equal(t, operation, routableAuditEvent.OperationName)
|
||||||
|
|
||||||
|
|
@ -978,7 +1204,7 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
|
|
||||||
authenticationInfo := logEntry.ProtoPayload.AuthenticationInfo
|
authenticationInfo := logEntry.ProtoPayload.AuthenticationInfo
|
||||||
assert.NotNil(t, authenticationInfo)
|
assert.NotNil(t, authenticationInfo)
|
||||||
assert.Equal(t, EmailAddressDoNotReplyAtStackItDotCloud, authenticationInfo.PrincipalEmail)
|
assert.Nil(t, authenticationInfo.PrincipalEmail)
|
||||||
assert.Equal(t, "none", authenticationInfo.PrincipalId)
|
assert.Equal(t, "none", authenticationInfo.PrincipalId)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
assert.Nil(t, authenticationInfo.ServiceAccountDelegationInfo)
|
||||||
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
assert.Nil(t, authenticationInfo.ServiceAccountName)
|
||||||
|
|
@ -1038,7 +1264,7 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
|
|
||||||
t.Run("with response body unserialized", func(t *testing.T) {
|
t.Run("with response body unserialized", func(t *testing.T) {
|
||||||
api, _ := NewMockAuditApi()
|
api, _ := NewMockAuditApi()
|
||||||
sequenceNumberGenerator := utils.NewDefaultSequenceNumberGenerator()
|
sequenceNumberGenerator := pkgAuditUtils.NewDefaultSequenceNumberGenerator()
|
||||||
|
|
||||||
objectId := uuid.NewString()
|
objectId := uuid.NewString()
|
||||||
operation := "stackit.demo-service.v1.operation"
|
operation := "stackit.demo-service.v1.operation"
|
||||||
|
|
@ -1050,16 +1276,16 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
responseBody := map[string]interface{}{"key": "response"}
|
responseBody := map[string]interface{}{"key": "response"}
|
||||||
builder := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01").
|
builder := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01").
|
||||||
WithRequiredObjectId(objectId).
|
WithRequiredObjectId(objectId).
|
||||||
WithRequiredObjectType(ObjectTypeProject).
|
WithRequiredObjectType(pkgAuditCommon.ObjectTypeProject).
|
||||||
WithRequiredOperation(operation).
|
WithRequiredOperation(operation).
|
||||||
WithRequiredApiRequest(ApiRequest{
|
WithRequiredApiRequest(pkgAuditCommon.ApiRequest{
|
||||||
Body: nil,
|
Body: nil,
|
||||||
Header: TestHeaders,
|
Header: internalAuditApi.TestHeaders,
|
||||||
Host: "localhost",
|
Host: "localhost",
|
||||||
Method: "POST",
|
Method: "POST",
|
||||||
Scheme: "https",
|
Scheme: "https",
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
URL: RequestUrl{
|
URL: pkgAuditCommon.RequestUrl{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
RawQuery: nil,
|
RawQuery: nil,
|
||||||
},
|
},
|
||||||
|
|
@ -1068,7 +1294,7 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
WithAuditPermission(permission).
|
WithAuditPermission(permission).
|
||||||
WithAuditPermissionCheckResult(permissionCheckResult).
|
WithAuditPermissionCheckResult(permissionCheckResult).
|
||||||
WithDetails(details).
|
WithDetails(details).
|
||||||
WithEventType(EventTypeAdminActivity).
|
WithEventType(pkgAuditCommon.EventTypeAdminActivity).
|
||||||
WithLabels(map[string]string{"key": "label"}).
|
WithLabels(map[string]string{"key": "label"}).
|
||||||
WithNumResponseItems(int64(10)).
|
WithNumResponseItems(int64(10)).
|
||||||
WithRequestCorrelationId("correlationId").
|
WithRequestCorrelationId("correlationId").
|
||||||
|
|
@ -1081,7 +1307,7 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
WithStatusCode(400).
|
WithStatusCode(400).
|
||||||
WithVisibility(auditV1.Visibility_VISIBILITY_PRIVATE)
|
WithVisibility(auditV1.Visibility_VISIBILITY_PRIVATE)
|
||||||
|
|
||||||
routableIdentifier := RoutableIdentifier{Identifier: objectId, Type: ObjectTypeProject}
|
routableIdentifier := pkgAuditCommon.RoutableIdentifier{Identifier: objectId, Type: pkgAuditCommon.ObjectTypeProject}
|
||||||
|
|
||||||
cloudEvent, routingIdentifier, err := builder.Build(context.Background(), SequenceNumber(1))
|
cloudEvent, routingIdentifier, err := builder.Build(context.Background(), SequenceNumber(1))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
@ -1111,7 +1337,7 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
|
|
||||||
t.Run("mark as built", func(t *testing.T) {
|
t.Run("mark as built", func(t *testing.T) {
|
||||||
api, _ := NewMockAuditApi()
|
api, _ := NewMockAuditApi()
|
||||||
sequenceNumberGenerator := utils.NewDefaultSequenceNumberGenerator()
|
sequenceNumberGenerator := pkgAuditUtils.NewDefaultSequenceNumberGenerator()
|
||||||
|
|
||||||
builder := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01")
|
builder := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01")
|
||||||
builder.MarkAsBuilt()
|
builder.MarkAsBuilt()
|
||||||
|
|
@ -1121,7 +1347,7 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
|
|
||||||
t.Run("no entry builder", func(t *testing.T) {
|
t.Run("no entry builder", func(t *testing.T) {
|
||||||
api, _ := NewMockAuditApi()
|
api, _ := NewMockAuditApi()
|
||||||
sequenceNumberGenerator := utils.NewDefaultSequenceNumberGenerator()
|
sequenceNumberGenerator := pkgAuditUtils.NewDefaultSequenceNumberGenerator()
|
||||||
|
|
||||||
cloudEvent, routingIdentifier, err := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01").
|
cloudEvent, routingIdentifier, err := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01").
|
||||||
WithAuditLogEntryBuilder(nil).Build(context.Background(), SequenceNumber(1))
|
WithAuditLogEntryBuilder(nil).Build(context.Background(), SequenceNumber(1))
|
||||||
|
|
@ -1133,7 +1359,7 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
|
|
||||||
t.Run("next sequence number", func(t *testing.T) {
|
t.Run("next sequence number", func(t *testing.T) {
|
||||||
api, _ := NewMockAuditApi()
|
api, _ := NewMockAuditApi()
|
||||||
sequenceNumberGenerator := utils.NewDefaultSequenceNumberGenerator()
|
sequenceNumberGenerator := pkgAuditUtils.NewDefaultSequenceNumberGenerator()
|
||||||
|
|
||||||
builder := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01")
|
builder := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01")
|
||||||
assert.Equal(t, SequenceNumber(0), builder.NextSequenceNumber())
|
assert.Equal(t, SequenceNumber(0), builder.NextSequenceNumber())
|
||||||
|
|
@ -1142,7 +1368,7 @@ func Test_AuditEventBuilder(t *testing.T) {
|
||||||
|
|
||||||
t.Run("revert sequence number", func(t *testing.T) {
|
t.Run("revert sequence number", func(t *testing.T) {
|
||||||
api, _ := NewMockAuditApi()
|
api, _ := NewMockAuditApi()
|
||||||
sequenceNumberGenerator := utils.NewDefaultSequenceNumberGenerator()
|
sequenceNumberGenerator := pkgAuditUtils.NewDefaultSequenceNumberGenerator()
|
||||||
|
|
||||||
builder := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01")
|
builder := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", "worker-id", "eu01")
|
||||||
assert.Equal(t, SequenceNumber(0), builder.NextSequenceNumber())
|
assert.Equal(t, SequenceNumber(0), builder.NextSequenceNumber())
|
||||||
|
|
@ -1,20 +1,23 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
|
||||||
"dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/log"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
"google.golang.org/protobuf/encoding/protojson"
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
"time"
|
|
||||||
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
|
pkgLog "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LogEvent logs an event to the terminal
|
// LogEvent logs an event to the terminal
|
||||||
func LogEvent(event *CloudEvent) error {
|
func LogEvent(event *pkgAuditCommon.CloudEvent) error {
|
||||||
|
|
||||||
if event.DataType == DataTypeLegacyAuditEventV1 {
|
if event.DataType == DataTypeLegacyAuditEventV1 {
|
||||||
log.AuditLogger.Info(string(event.Data))
|
pkgLog.AuditLogger.Info(string(event.Data))
|
||||||
return nil
|
return nil
|
||||||
} else if event.DataType != "audit.v1.RoutableAuditEvent" {
|
} else if event.DataType != "audit.v1.RoutableAuditEvent" {
|
||||||
return errors.New("Unsupported data type " + event.DataType)
|
return errors.New("Unsupported data type " + event.DataType)
|
||||||
|
|
@ -75,7 +78,7 @@ func LogEvent(event *CloudEvent) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.AuditLogger.Info(string(cloudEventJson))
|
pkgLog.AuditLogger.Info(string(cloudEventJson))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2,37 +2,41 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/audit/utils"
|
"testing"
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
|
||||||
"github.com/bufbuild/protovalidate-go"
|
"buf.build/go/protovalidate"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"testing"
|
|
||||||
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
internalAuditApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/internal/audit/api"
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
|
pkgAuditUtils "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_LogEvent(t *testing.T) {
|
func Test_LogEvent(t *testing.T) {
|
||||||
|
|
||||||
api, _ := NewMockAuditApi()
|
api, _ := NewMockAuditApi()
|
||||||
sequenceNumberGenerator := utils.NewDefaultSequenceNumberGenerator()
|
sequenceNumberGenerator := pkgAuditUtils.NewDefaultSequenceNumberGenerator()
|
||||||
|
|
||||||
t.Run("new format", func(t *testing.T) {
|
t.Run("new format", func(t *testing.T) {
|
||||||
eventBuilder := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", uuid.NewString(), "eu01")
|
eventBuilder := NewAuditEventBuilder(api, sequenceNumberGenerator, "demo-service", uuid.NewString(), "eu01")
|
||||||
|
|
||||||
cloudEvent, _, err := eventBuilder.
|
cloudEvent, _, err := eventBuilder.
|
||||||
WithRequiredApiRequest(ApiRequest{
|
WithRequiredApiRequest(pkgAuditCommon.ApiRequest{
|
||||||
Body: nil,
|
Body: nil,
|
||||||
Header: TestHeaders,
|
Header: internalAuditApi.TestHeaders,
|
||||||
Host: "localhost",
|
Host: "localhost",
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
Scheme: "https",
|
Scheme: "https",
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
URL: RequestUrl{
|
URL: pkgAuditCommon.RequestUrl{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
RawQuery: nil,
|
RawQuery: nil,
|
||||||
},
|
},
|
||||||
}).
|
}).
|
||||||
WithRequiredObjectId(uuid.NewString()).
|
WithRequiredObjectId(uuid.NewString()).
|
||||||
WithRequiredObjectType(ObjectTypeProject).
|
WithRequiredObjectType(pkgAuditCommon.ObjectTypeProject).
|
||||||
WithRequiredOperation("stackit.demo-service.v1.project.update").
|
WithRequiredOperation("stackit.demo-service.v1.project.update").
|
||||||
WithRequiredRequestClientIp("0.0.0.0").
|
WithRequiredRequestClientIp("0.0.0.0").
|
||||||
Build(context.Background(), eventBuilder.NextSequenceNumber())
|
Build(context.Background(), eventBuilder.NextSequenceNumber())
|
||||||
|
|
@ -44,21 +48,21 @@ func Test_LogEvent(t *testing.T) {
|
||||||
t.Run("legacy format", func(t *testing.T) {
|
t.Run("legacy format", func(t *testing.T) {
|
||||||
objectId := uuid.NewString()
|
objectId := uuid.NewString()
|
||||||
entry, err := NewAuditLogEntryBuilder().
|
entry, err := NewAuditLogEntryBuilder().
|
||||||
WithRequiredApiRequest(ApiRequest{
|
WithRequiredApiRequest(pkgAuditCommon.ApiRequest{
|
||||||
Body: nil,
|
Body: nil,
|
||||||
Header: TestHeaders,
|
Header: internalAuditApi.TestHeaders,
|
||||||
Host: "localhost",
|
Host: "localhost",
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
Scheme: "https",
|
Scheme: "https",
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
URL: RequestUrl{
|
URL: pkgAuditCommon.RequestUrl{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
RawQuery: nil,
|
RawQuery: nil,
|
||||||
},
|
},
|
||||||
}).
|
}).
|
||||||
WithRequiredLocation("eu01").
|
WithRequiredLocation("eu01").
|
||||||
WithRequiredObjectId(objectId).
|
WithRequiredObjectId(objectId).
|
||||||
WithRequiredObjectType(ObjectTypeProject).
|
WithRequiredObjectType(pkgAuditCommon.ObjectTypeProject).
|
||||||
WithRequiredOperation("stackit.demo-service.v1.project.update").
|
WithRequiredOperation("stackit.demo-service.v1.project.update").
|
||||||
WithRequiredRequestClientIp("0.0.0.0").
|
WithRequiredRequestClientIp("0.0.0.0").
|
||||||
WithRequiredServiceName("demo-service").
|
WithRequiredServiceName("demo-service").
|
||||||
|
|
@ -68,25 +72,25 @@ func Test_LogEvent(t *testing.T) {
|
||||||
|
|
||||||
validator, err := protovalidate.New()
|
validator, err := protovalidate.New()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
var protoValidator ProtobufValidator = validator
|
var protoValidator pkgAuditCommon.ProtobufValidator = validator
|
||||||
|
|
||||||
routableIdentifier := RoutableIdentifier{
|
routableIdentifier := pkgAuditCommon.RoutableIdentifier{
|
||||||
Identifier: objectId,
|
Identifier: objectId,
|
||||||
Type: ObjectTypeProject,
|
Type: pkgAuditCommon.ObjectTypeProject,
|
||||||
}
|
}
|
||||||
|
|
||||||
routableEvent, err := validateAndSerializePartially(protoValidator, entry, auditV1.Visibility_VISIBILITY_PUBLIC, &routableIdentifier)
|
routableEvent, err := internalAuditApi.ValidateAndSerializePartially(protoValidator, entry, auditV1.Visibility_VISIBILITY_PUBLIC, &routableIdentifier)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
legacyBytes, err := convertAndSerializeIntoLegacyFormat(entry, routableEvent)
|
legacyBytes, err := internalAuditApi.ConvertAndSerializeIntoLegacyFormat(entry, routableEvent)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
cloudEvent := CloudEvent{
|
cloudEvent := pkgAuditCommon.CloudEvent{
|
||||||
SpecVersion: "1.0",
|
SpecVersion: "1.0",
|
||||||
Source: entry.ProtoPayload.ServiceName,
|
Source: entry.ProtoPayload.ServiceName,
|
||||||
Id: entry.InsertId,
|
Id: entry.InsertId,
|
||||||
Time: entry.ProtoPayload.RequestMetadata.RequestAttributes.Time.AsTime(),
|
Time: entry.ProtoPayload.RequestMetadata.RequestAttributes.Time.AsTime(),
|
||||||
DataContentType: ContentTypeCloudEventsJson,
|
DataContentType: pkgAuditCommon.ContentTypeCloudEventsJson,
|
||||||
DataType: DataTypeLegacyAuditEventV1,
|
DataType: DataTypeLegacyAuditEventV1,
|
||||||
Subject: entry.ProtoPayload.ResourceName,
|
Subject: entry.ProtoPayload.ResourceName,
|
||||||
Data: legacyBytes,
|
Data: legacyBytes,
|
||||||
91
pkg/audit/api/utils.go
Normal file
91
pkg/audit/api/utils.go
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
var objectTypeIdPattern = regexp.MustCompile(".*/(projects|folders|organizations)/([0-9a-fA-F-]{36})(?:/.*)?")
|
||||||
|
|
||||||
|
// GetCalledServiceNameFromRequest extracts the called service name from subdomain name
|
||||||
|
func GetCalledServiceNameFromRequest(request *pkgAuditCommon.ApiRequest, fallbackName string) string {
|
||||||
|
if request == nil {
|
||||||
|
return fallbackName
|
||||||
|
}
|
||||||
|
|
||||||
|
var calledServiceName = fallbackName
|
||||||
|
host := request.Host
|
||||||
|
ip := net.ParseIP(host)
|
||||||
|
if ip == nil && !strings.Contains(host, "localhost") {
|
||||||
|
dotIdx := strings.Index(host, ".")
|
||||||
|
if dotIdx != -1 {
|
||||||
|
calledServiceName = host[0:dotIdx]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return calledServiceName
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetObjectIdAndTypeFromUrlPath(path string) (
|
||||||
|
string,
|
||||||
|
*pkgAuditCommon.ObjectType,
|
||||||
|
error,
|
||||||
|
) {
|
||||||
|
|
||||||
|
// Extract object id and type from request url
|
||||||
|
objectTypeIdMatches := objectTypeIdPattern.FindStringSubmatch(path)
|
||||||
|
if len(objectTypeIdMatches) > 0 {
|
||||||
|
objectType := pkgAuditCommon.ObjectTypeFromPluralString(objectTypeIdMatches[1])
|
||||||
|
err := objectType.IsSupportedType()
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
objectId := objectTypeIdMatches[2]
|
||||||
|
|
||||||
|
return objectId, &objectType, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResponseBodyToBytes converts a JSON or Protobuf response into a byte array
|
||||||
|
func ResponseBodyToBytes(response any) ([]byte, error) {
|
||||||
|
if response == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
responseBytes, isBytes := response.([]byte)
|
||||||
|
if isBytes {
|
||||||
|
return responseBytes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
responseProtoMessage, isProtoMessage := response.(proto.Message)
|
||||||
|
if isProtoMessage {
|
||||||
|
responseJson, err := protojson.Marshal(responseProtoMessage)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return responseJson, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
responseJson, err := json.Marshal(response)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return responseJson, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToArrayMap(input map[string]string) map[string][]string {
|
||||||
|
output := map[string][]string{}
|
||||||
|
for key, value := range input {
|
||||||
|
output[key] = []string{value}
|
||||||
|
}
|
||||||
|
return output
|
||||||
|
}
|
||||||
154
pkg/audit/api/utils_test.go
Normal file
154
pkg/audit/api/utils_test.go
Normal file
|
|
@ -0,0 +1,154 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
|
|
||||||
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_GetCalledServiceNameFromRequest(t *testing.T) {
|
||||||
|
|
||||||
|
t.Run("request is nil", func(t *testing.T) {
|
||||||
|
serviceName := GetCalledServiceNameFromRequest(nil, "resource-manager")
|
||||||
|
assert.Equal(t, "resource-manager", serviceName)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("localhost", func(t *testing.T) {
|
||||||
|
request := pkgAuditCommon.ApiRequest{Host: "localhost:8080"}
|
||||||
|
serviceName := GetCalledServiceNameFromRequest(&request, "resource-manager")
|
||||||
|
assert.Equal(t, "resource-manager", serviceName)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("cf", func(t *testing.T) {
|
||||||
|
request := pkgAuditCommon.ApiRequest{Host: "stackit-resource-manager-go-dev.apps.01.cf.eu01.stackit.cloud"}
|
||||||
|
serviceName := GetCalledServiceNameFromRequest(&request, "resource-manager")
|
||||||
|
assert.Equal(t, "stackit-resource-manager-go-dev", serviceName)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("cf invalid host", func(t *testing.T) {
|
||||||
|
request := pkgAuditCommon.ApiRequest{Host: ""}
|
||||||
|
serviceName := GetCalledServiceNameFromRequest(&request, "resource-manager")
|
||||||
|
assert.Equal(t, "resource-manager", serviceName)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ip", func(t *testing.T) {
|
||||||
|
request := pkgAuditCommon.ApiRequest{Host: "127.0.0.1"}
|
||||||
|
serviceName := GetCalledServiceNameFromRequest(&request, "resource-manager")
|
||||||
|
assert.Equal(t, "resource-manager", serviceName)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Run("ip short", func(t *testing.T) {
|
||||||
|
request := pkgAuditCommon.ApiRequest{Host: "::1"}
|
||||||
|
serviceName := GetCalledServiceNameFromRequest(&request, "resource-manager")
|
||||||
|
assert.Equal(t, "resource-manager", serviceName)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_GetObjectIdAndTypeFromUrlPath(t *testing.T) {
|
||||||
|
|
||||||
|
t.Run("object id and type not in url", func(t *testing.T) {
|
||||||
|
objectId, objectType, err := GetObjectIdAndTypeFromUrlPath("/v2/projects/audit")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "", objectId)
|
||||||
|
assert.Nil(t, objectType)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("object id and type in url", func(t *testing.T) {
|
||||||
|
objectId, objectType, err := GetObjectIdAndTypeFromUrlPath("/v2/projects/f17d4064-9b65-4334-b6a7-8fed96340124")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "f17d4064-9b65-4334-b6a7-8fed96340124", objectId)
|
||||||
|
assert.Equal(t, pkgAuditCommon.ObjectTypeProject, *objectType)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("multiple object ids and types in url", func(t *testing.T) {
|
||||||
|
objectId, objectType, err := GetObjectIdAndTypeFromUrlPath("/v2/organization/8ee58bec-d496-4bb9-af8d-72fda4d78b6b/projects/f17d4064-9b65-4334-b6a7-8fed96340124")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "f17d4064-9b65-4334-b6a7-8fed96340124", objectId)
|
||||||
|
assert.Equal(t, pkgAuditCommon.ObjectTypeProject, *objectType)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_ResponseBodyToBytes(t *testing.T) {
|
||||||
|
|
||||||
|
t.Run(
|
||||||
|
"nil response body", func(t *testing.T) {
|
||||||
|
bytes, err := ResponseBodyToBytes(nil)
|
||||||
|
assert.Nil(t, bytes)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Run(
|
||||||
|
"bytes", func(t *testing.T) {
|
||||||
|
responseBody := []byte("data")
|
||||||
|
bytes, err := ResponseBodyToBytes(responseBody)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, responseBody, bytes)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Run(
|
||||||
|
"Protobuf message", func(t *testing.T) {
|
||||||
|
protobufMessage := auditV1.ObjectIdentifier{Identifier: uuid.NewString(), Type: string(pkgAuditCommon.ObjectTypeProject)}
|
||||||
|
bytes, err := ResponseBodyToBytes(&protobufMessage)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
expected, err := protojson.Marshal(&protobufMessage)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, expected, bytes)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Run(
|
||||||
|
"struct", func(t *testing.T) {
|
||||||
|
type CustomObject struct {
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
responseBody := CustomObject{Value: "data"}
|
||||||
|
bytes, err := ResponseBodyToBytes(responseBody)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
expected, err := json.Marshal(responseBody)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, expected, bytes)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Run(
|
||||||
|
"map", func(t *testing.T) {
|
||||||
|
|
||||||
|
responseBody := map[string]interface{}{"value": "data"}
|
||||||
|
bytes, err := ResponseBodyToBytes(responseBody)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
expected, err := json.Marshal(responseBody)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, expected, bytes)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_ToArrayMap(t *testing.T) {
|
||||||
|
|
||||||
|
t.Run("empty map", func(t *testing.T) {
|
||||||
|
result := ToArrayMap(map[string]string{})
|
||||||
|
assert.Equal(t, map[string][]string{}, result)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("empty map", func(t *testing.T) {
|
||||||
|
result := ToArrayMap(map[string]string{"key1": "value1", "key2": "value2"})
|
||||||
|
assert.Equal(t, map[string][]string{
|
||||||
|
"key1": {"value1"},
|
||||||
|
"key2": {"value2"},
|
||||||
|
}, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -1,16 +1,23 @@
|
||||||
package api
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"regexp"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"buf.build/go/protovalidate"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
|
|
||||||
"google.golang.org/protobuf/proto"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ContentTypeCloudEventsProtobuf the cloudevents protobuf content-type sent in metadata of messages
|
||||||
|
const ContentTypeCloudEventsProtobuf = "application/cloudevents+protobuf"
|
||||||
|
const ContentTypeCloudEventsJson = "application/cloudevents+json; charset=UTF-8"
|
||||||
|
|
||||||
|
var TopicNamePattern = regexp.MustCompile(`^topic://stackit-platform/t/swz/audit-log/(?:conway|eu01|eu02|sx-stoi01)/[Vv][1-9](?:\.\d)?/[A-Za-z0-9-]+/[A-Za-z0-9-/]+`)
|
||||||
|
|
||||||
type EventType string
|
type EventType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -47,13 +54,7 @@ func ObjectTypeFromPluralString(value string) ObjectType {
|
||||||
|
|
||||||
func (t ObjectType) IsSupportedType() error {
|
func (t ObjectType) IsSupportedType() error {
|
||||||
switch t {
|
switch t {
|
||||||
case ObjectTypeOrganization:
|
case ObjectTypeOrganization, ObjectTypeFolder, ObjectTypeProject, ObjectTypeSystem:
|
||||||
fallthrough
|
|
||||||
case ObjectTypeFolder:
|
|
||||||
fallthrough
|
|
||||||
case ObjectTypeProject:
|
|
||||||
fallthrough
|
|
||||||
case ObjectTypeSystem:
|
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
return ErrUnknownObjectType
|
return ErrUnknownObjectType
|
||||||
|
|
@ -148,7 +149,7 @@ type AuditApi interface {
|
||||||
// ProtobufValidator is an abstraction for validators.
|
// ProtobufValidator is an abstraction for validators.
|
||||||
// Concrete implementations are e.g. protovalidate.Validator
|
// Concrete implementations are e.g. protovalidate.Validator
|
||||||
type ProtobufValidator interface {
|
type ProtobufValidator interface {
|
||||||
Validate(msg proto.Message) error
|
Validate(msg proto.Message, options ...protovalidate.ValidationOption) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// CloudEvent is a representation of a cloudevents.io object.
|
// CloudEvent is a representation of a cloudevents.io object.
|
||||||
|
|
@ -223,6 +224,17 @@ type TopicNameResolver interface {
|
||||||
Resolve(routableIdentifier *RoutableIdentifier) (string, error)
|
Resolve(routableIdentifier *RoutableIdentifier) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StaticTopicNameTestResolver implements TopicNameResolver.
|
||||||
|
// A hard-coded topic name is used, routable identifiers are ignored.
|
||||||
|
type StaticTopicNameTestResolver struct {
|
||||||
|
TopicName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve implements TopicNameResolver.Resolve
|
||||||
|
func (r *StaticTopicNameTestResolver) Resolve(*RoutableIdentifier) (string, error) {
|
||||||
|
return r.TopicName, nil
|
||||||
|
}
|
||||||
|
|
||||||
type RoutableIdentifier struct {
|
type RoutableIdentifier struct {
|
||||||
Identifier string
|
Identifier string
|
||||||
Type ObjectType
|
Type ObjectType
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package api
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
||||||
49
pkg/audit/common/errors.go
Normal file
49
pkg/audit/common/errors.go
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrAttributeIdentifierInvalid indicates that the object identifier
|
||||||
|
// and the identifier in the checked attribute do not match
|
||||||
|
var ErrAttributeIdentifierInvalid = errors.New("attribute identifier invalid")
|
||||||
|
|
||||||
|
// ErrAttributeTypeInvalid indicates that an invalid type has been provided.
|
||||||
|
var ErrAttributeTypeInvalid = errors.New("attribute type invalid")
|
||||||
|
|
||||||
|
// ErrCloudEventNil states that the given cloud event is nil
|
||||||
|
var ErrCloudEventNil = errors.New("cloud event nil")
|
||||||
|
|
||||||
|
// ErrEventNil indicates that the event was nil
|
||||||
|
var ErrEventNil = errors.New("event is nil")
|
||||||
|
|
||||||
|
// ErrInvalidRoutableIdentifierForSystemEvent states that the routable identifier is not valid for a system event
|
||||||
|
var ErrInvalidRoutableIdentifierForSystemEvent = errors.New("invalid identifier for system event")
|
||||||
|
|
||||||
|
// ErrMessagingApiNil states that the messaging api is nilØØ
|
||||||
|
var ErrMessagingApiNil = errors.New("messaging api nil")
|
||||||
|
|
||||||
|
// ErrObjectIdentifierNil indicates that the object identifier was nil
|
||||||
|
var ErrObjectIdentifierNil = errors.New("object identifier is nil")
|
||||||
|
|
||||||
|
// ErrObjectIdentifierVisibilityMismatch indicates that a reference mismatch was detected.
|
||||||
|
//
|
||||||
|
// Valid combinations are:
|
||||||
|
// * Visibility: Public, ObjectIdentifier: <type>
|
||||||
|
// * Visibility: Private, ObjectIdentifier: <type | system>
|
||||||
|
var ErrObjectIdentifierVisibilityMismatch = errors.New("object reference visibility mismatch")
|
||||||
|
|
||||||
|
// ErrTopicNameResolverNil states that the topic name resolve is nil
|
||||||
|
var ErrTopicNameResolverNil = errors.New("topic name resolver nil")
|
||||||
|
|
||||||
|
// ErrUnknownObjectType indicates that the given input is an unknown object type
|
||||||
|
var ErrUnknownObjectType = errors.New("unknown object type")
|
||||||
|
|
||||||
|
// ErrUnsupportedEventTypeDataAccess states that the event type "data-access" is currently not supported
|
||||||
|
var ErrUnsupportedEventTypeDataAccess = errors.New("unsupported event type data access")
|
||||||
|
|
||||||
|
// ErrUnsupportedObjectIdentifierType indicates that an unsupported object identifier type has been provided
|
||||||
|
var ErrUnsupportedObjectIdentifierType = errors.New("unsupported object identifier type")
|
||||||
|
|
||||||
|
// ErrUnsupportedRoutableType indicates that the given input is an unsupported routable type
|
||||||
|
var ErrUnsupportedRoutableType = errors.New("unsupported routable type")
|
||||||
59
pkg/audit/common/model.go
Normal file
59
pkg/audit/common/model.go
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
type ApiRequest struct {
|
||||||
|
|
||||||
|
// Body
|
||||||
|
//
|
||||||
|
// Required: false
|
||||||
|
Body []byte
|
||||||
|
|
||||||
|
// The (HTTP) request headers / gRPC metadata.
|
||||||
|
//
|
||||||
|
// Internal IP-Addresses have to be removed (e.g. in x-forwarded-xxx headers).
|
||||||
|
//
|
||||||
|
// Required: true
|
||||||
|
Header map[string][]string
|
||||||
|
|
||||||
|
// The HTTP request `Host` header value.
|
||||||
|
//
|
||||||
|
// Required: true
|
||||||
|
Host string
|
||||||
|
|
||||||
|
// Method
|
||||||
|
//
|
||||||
|
// Required: true
|
||||||
|
Method string
|
||||||
|
|
||||||
|
// The URL scheme, such as `http`, `https` or `gRPC`.
|
||||||
|
//
|
||||||
|
// Required: true
|
||||||
|
Scheme string
|
||||||
|
|
||||||
|
// The network protocol used with the request, such as "http/1.1",
|
||||||
|
// "spdy/3", "h2", "h2c", "webrtc", "tcp", "udp", "quic". See
|
||||||
|
// https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
|
||||||
|
// for details.
|
||||||
|
//
|
||||||
|
// Required: true
|
||||||
|
Proto string
|
||||||
|
|
||||||
|
// The url
|
||||||
|
//
|
||||||
|
// Required: true
|
||||||
|
URL RequestUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
type RequestUrl struct {
|
||||||
|
|
||||||
|
// The gRPC / HTTP URL path.
|
||||||
|
//
|
||||||
|
// Required: true
|
||||||
|
Path string
|
||||||
|
|
||||||
|
// The HTTP URL query in the format of "name1=value1&name2=value2", as it
|
||||||
|
// appears in the first line of the HTTP request.
|
||||||
|
// The input should be escaped to not contain any special characters.
|
||||||
|
//
|
||||||
|
// Required: false
|
||||||
|
RawQuery *string
|
||||||
|
}
|
||||||
|
|
@ -40,7 +40,7 @@ func (g *DefaultSequenceNumberGenerator) Next() uint64 {
|
||||||
var next uint64
|
var next uint64
|
||||||
if len(g.backlog) == 0 {
|
if len(g.backlog) == 0 {
|
||||||
next = g.sequenceNumber
|
next = g.sequenceNumber
|
||||||
g.sequenceNumber += 1
|
g.sequenceNumber++
|
||||||
} else {
|
} else {
|
||||||
next = g.backlog[0]
|
next = g.backlog[0]
|
||||||
g.backlog = g.backlog[1:]
|
g.backlog = g.backlog[1:]
|
||||||
|
|
@ -53,7 +53,7 @@ func (g *DefaultSequenceNumberGenerator) Revert(value uint64) {
|
||||||
g.sequenceNumberLock.Lock()
|
g.sequenceNumberLock.Lock()
|
||||||
defer g.sequenceNumberLock.Unlock()
|
defer g.sequenceNumberLock.Unlock()
|
||||||
if value == g.sequenceNumber-1 {
|
if value == g.sequenceNumber-1 {
|
||||||
g.sequenceNumber -= 1
|
g.sequenceNumber--
|
||||||
} else if !slices.Contains(g.backlog, value) {
|
} else if !slices.Contains(g.backlog, value) {
|
||||||
g.backlog = append(g.backlog, value)
|
g.backlog = append(g.backlog, value)
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_DefaultSequenceNumberGenerator(t *testing.T) {
|
func Test_DefaultSequenceNumberGenerator(t *testing.T) {
|
||||||
|
|
@ -16,11 +16,12 @@ type Logger interface {
|
||||||
|
|
||||||
func wrapErr(err []error) error {
|
func wrapErr(err []error) error {
|
||||||
var e error
|
var e error
|
||||||
if len(err) == 0 {
|
switch {
|
||||||
|
case len(err) == 0:
|
||||||
e = nil
|
e = nil
|
||||||
} else if len(err) == 1 {
|
case len(err) == 1:
|
||||||
e = err[0]
|
e = err[0]
|
||||||
} else {
|
default:
|
||||||
e = errors.Join(err...)
|
e = errors.Join(err...)
|
||||||
}
|
}
|
||||||
return e
|
return e
|
||||||
|
|
@ -1,59 +1,54 @@
|
||||||
package messaging
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/log"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
internalMessaging "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/internal/messaging"
|
||||||
|
pkgLog "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/log"
|
||||||
|
pkgMessagingCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Api is an abstraction for a messaging system that can be used to send
|
|
||||||
// audit logs to the audit log system.
|
|
||||||
type Api interface {
|
|
||||||
|
|
||||||
// Send method will send the given data to the specified topic synchronously.
|
|
||||||
// Parameters:
|
|
||||||
// * ctx - the context object
|
|
||||||
// * topic - the messaging topic where to send the data to
|
|
||||||
// * data - the serialized data as byte array
|
|
||||||
// * contentType - the contentType of the serialized data
|
|
||||||
// * applicationProperties - properties to send with the message (i.e. cloud event headers)
|
|
||||||
//
|
|
||||||
// It returns technical errors for connection issues or sending problems.
|
|
||||||
Send(ctx context.Context, topic string, data []byte, contentType string, applicationProperties map[string]any) error
|
|
||||||
|
|
||||||
// Close the underlying connection to the messaging system.
|
|
||||||
// Parameters:
|
|
||||||
// * ctx - the context object
|
|
||||||
//
|
|
||||||
// It returns an error if the connection cannot be closed successfully
|
|
||||||
Close(ctx context.Context) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// AmqpApi implements Api.
|
// AmqpApi implements Api.
|
||||||
type AmqpApi struct {
|
type AmqpApi struct {
|
||||||
config AmqpConnectionPoolConfig
|
connection *internalMessaging.AmqpConnection
|
||||||
connection *AmqpConnection
|
connectionPool internalMessaging.ConnectionPool
|
||||||
connectionPool ConnectionPool
|
connectionPoolHandle *internalMessaging.ConnectionPoolHandle
|
||||||
connectionPoolHandle *ConnectionPoolHandle
|
senderCache map[string]*internalMessaging.AmqpSenderSession
|
||||||
senderCache map[string]*AmqpSenderSession
|
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Api = &AmqpApi{}
|
var _ Api = &AmqpApi{}
|
||||||
|
|
||||||
func NewAmqpApi(amqpConfig AmqpConnectionPoolConfig) (Api, error) {
|
func NewDefaultAmqpApi(amqpConfig pkgMessagingCommon.AmqpConnectionConfig) (Api, error) {
|
||||||
connectionPool, err := NewAmqpConnectionPool(amqpConfig, "sdk")
|
connectionPool, err := internalMessaging.NewDefaultAmqpConnectionPool(amqpConfig, "sdk")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("new amqp connection pool: %w", err)
|
return nil, fmt.Errorf("new amqp connection pool: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
amqpApi := &AmqpApi{config: amqpConfig,
|
amqpApi := &AmqpApi{
|
||||||
connectionPool: connectionPool,
|
connectionPool: connectionPool,
|
||||||
connectionPoolHandle: connectionPool.NewHandle(),
|
connectionPoolHandle: connectionPool.NewHandle(),
|
||||||
senderCache: make(map[string]*AmqpSenderSession),
|
senderCache: make(map[string]*internalMessaging.AmqpSenderSession),
|
||||||
|
}
|
||||||
|
|
||||||
|
var messagingApi Api = amqpApi
|
||||||
|
return messagingApi, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAmqpApi(amqpConfig pkgMessagingCommon.AmqpConnectionPoolConfig) (Api, error) {
|
||||||
|
connectionPool, err := internalMessaging.NewAmqpConnectionPool(amqpConfig, "sdk")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("new amqp connection pool: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
amqpApi := &AmqpApi{
|
||||||
|
connectionPool: connectionPool,
|
||||||
|
connectionPoolHandle: connectionPool.NewHandle(),
|
||||||
|
senderCache: make(map[string]*internalMessaging.AmqpSenderSession),
|
||||||
}
|
}
|
||||||
|
|
||||||
var messagingApi Api = amqpApi
|
var messagingApi Api = amqpApi
|
||||||
|
|
@ -95,7 +90,7 @@ func (a *AmqpApi) Send(_ context.Context, topic string, data []byte, contentType
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpApi) senderFromCache(topic string) *AmqpSenderSession {
|
func (a *AmqpApi) senderFromCache(topic string) *internalMessaging.AmqpSenderSession {
|
||||||
a.lock.RLock()
|
a.lock.RLock()
|
||||||
defer a.lock.RUnlock()
|
defer a.lock.RUnlock()
|
||||||
return a.senderCache[topic]
|
return a.senderCache[topic]
|
||||||
|
|
@ -127,7 +122,7 @@ func (a *AmqpApi) newSender(topic string) error {
|
||||||
|
|
||||||
// Close implements Api.Close
|
// Close implements Api.Close
|
||||||
func (a *AmqpApi) Close(_ context.Context) error {
|
func (a *AmqpApi) Close(_ context.Context) error {
|
||||||
log.AuditLogger.Info("close audit amqp connection pool")
|
pkgLog.AuditLogger.Info("close audit amqp connection pool")
|
||||||
|
|
||||||
a.lock.Lock()
|
a.lock.Lock()
|
||||||
defer a.lock.Unlock()
|
defer a.lock.Unlock()
|
||||||
|
|
@ -1,16 +1,73 @@
|
||||||
package messaging
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/mock"
|
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/Azure/go-amqp"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
|
||||||
|
internalMessaging "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/internal/messaging"
|
||||||
|
pkgMessagingCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/common"
|
||||||
|
pkgMessagingTest "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type amqpConnMock struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *amqpConnMock) Done() <-chan struct{} {
|
||||||
|
args := m.Called()
|
||||||
|
return args.Get(0).(<-chan struct{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *amqpConnMock) NewSession(ctx context.Context, opts *amqp.SessionOptions) (internalMessaging.AmqpSession, error) {
|
||||||
|
args := m.Called(ctx, opts)
|
||||||
|
return args.Get(0).(internalMessaging.AmqpSession), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *amqpConnMock) Close() error {
|
||||||
|
args := m.Called()
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ internalMessaging.AmqpConn = (*amqpConnMock)(nil)
|
||||||
|
|
||||||
|
type amqpSenderMock struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *amqpSenderMock) Send(ctx context.Context, msg *amqp.Message, opts *amqp.SendOptions) error {
|
||||||
|
return m.Called(ctx, msg, opts).Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *amqpSenderMock) Close(ctx context.Context) error {
|
||||||
|
return m.Called(ctx).Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ internalMessaging.AmqpSender = (*amqpSenderMock)(nil)
|
||||||
|
|
||||||
|
type amqpSessionMock struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *amqpSessionMock) NewSender(ctx context.Context, target string, opts *amqp.SenderOptions) (internalMessaging.AmqpSender, error) {
|
||||||
|
args := m.Called(ctx, target, opts)
|
||||||
|
return args.Get(0).(internalMessaging.AmqpSender), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *amqpSessionMock) Close(ctx context.Context) error {
|
||||||
|
args := m.Called(ctx)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ internalMessaging.AmqpSession = (*amqpSessionMock)(nil)
|
||||||
|
|
||||||
type connectionPoolMock struct {
|
type connectionPoolMock struct {
|
||||||
mock.Mock
|
mock.Mock
|
||||||
}
|
}
|
||||||
|
|
@ -19,20 +76,20 @@ func (m *connectionPoolMock) Close() error {
|
||||||
return m.Called().Error(0)
|
return m.Called().Error(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *connectionPoolMock) NewHandle() *ConnectionPoolHandle {
|
func (m *connectionPoolMock) NewHandle() *internalMessaging.ConnectionPoolHandle {
|
||||||
return m.Called().Get(0).(*ConnectionPoolHandle)
|
return m.Called().Get(0).(*internalMessaging.ConnectionPoolHandle)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *connectionPoolMock) GetConnection(handle *ConnectionPoolHandle) (*AmqpConnection, error) {
|
func (m *connectionPoolMock) GetConnection(handle *internalMessaging.ConnectionPoolHandle) (*internalMessaging.AmqpConnection, error) {
|
||||||
return m.Called(handle).Get(0).(*AmqpConnection), m.Called(handle).Error(1)
|
return m.Called(handle).Get(0).(*internalMessaging.AmqpConnection), m.Called(handle).Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ ConnectionPool = (*connectionPoolMock)(nil)
|
var _ internalMessaging.ConnectionPool = (*connectionPoolMock)(nil)
|
||||||
|
|
||||||
func Test_NewAmqpMessagingApi(t *testing.T) {
|
func Test_NewAmqpMessagingApi(t *testing.T) {
|
||||||
_, err := NewAmqpApi(
|
_, err := NewAmqpApi(
|
||||||
AmqpConnectionPoolConfig{
|
pkgMessagingCommon.AmqpConnectionPoolConfig{
|
||||||
Parameters: AmqpConnectionConfig{BrokerUrl: "not-handled-protocol://localhost:5672"},
|
Parameters: pkgMessagingCommon.AmqpConnectionConfig{BrokerUrl: "not-handled-protocol://localhost:5672"},
|
||||||
PoolSize: 1,
|
PoolSize: 1,
|
||||||
})
|
})
|
||||||
assert.EqualError(t, err, "new amqp connection pool: initialize connections: new connection: new internal connection: internal connect: dial: unsupported scheme \"not-handled-protocol\"")
|
assert.EqualError(t, err, "new amqp connection pool: initialize connections: new connection: new internal connection: internal connect: dial: unsupported scheme \"not-handled-protocol\"")
|
||||||
|
|
@ -44,15 +101,15 @@ func Test_AmqpMessagingApi_Send(t *testing.T) {
|
||||||
defer cancelFn()
|
defer cancelFn()
|
||||||
|
|
||||||
// Start solace docker container
|
// Start solace docker container
|
||||||
solaceContainer, err := NewSolaceContainer(context.Background())
|
solaceContainer, err := pkgMessagingTest.NewSolaceContainer(context.Background())
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer solaceContainer.Stop()
|
defer solaceContainer.Stop()
|
||||||
|
|
||||||
t.Run("Missing topic prefix", func(t *testing.T) {
|
t.Run("Missing topic prefix", func(t *testing.T) {
|
||||||
defer solaceContainer.StopOnError()
|
defer solaceContainer.StopOnError()
|
||||||
|
|
||||||
api, err := NewAmqpApi(AmqpConnectionPoolConfig{
|
api, err := NewAmqpApi(pkgMessagingCommon.AmqpConnectionPoolConfig{
|
||||||
Parameters: AmqpConnectionConfig{BrokerUrl: solaceContainer.AmqpConnectionString},
|
Parameters: pkgMessagingCommon.AmqpConnectionConfig{BrokerUrl: solaceContainer.AmqpConnectionString},
|
||||||
PoolSize: 1,
|
PoolSize: 1,
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
@ -72,10 +129,7 @@ func Test_AmqpMessagingApi_Send(t *testing.T) {
|
||||||
topicName := fmt.Sprintf("topic://auditlog/%s", "amqp-send-successfully")
|
topicName := fmt.Sprintf("topic://auditlog/%s", "amqp-send-successfully")
|
||||||
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
||||||
|
|
||||||
api, err := NewAmqpApi(AmqpConnectionPoolConfig{
|
api, err := NewDefaultAmqpApi(pkgMessagingCommon.AmqpConnectionConfig{BrokerUrl: solaceContainer.AmqpConnectionString})
|
||||||
Parameters: AmqpConnectionConfig{BrokerUrl: solaceContainer.AmqpConnectionString},
|
|
||||||
PoolSize: 1,
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
data := []byte("data")
|
data := []byte("data")
|
||||||
|
|
@ -103,27 +157,27 @@ func Test_AmqpMessagingApi_Send_Special_Cases(t *testing.T) {
|
||||||
return channel
|
return channel
|
||||||
}
|
}
|
||||||
|
|
||||||
newActiveConnection := func() *AmqpConnection {
|
newActiveConnection := func() *internalMessaging.AmqpConnection {
|
||||||
channel := make(chan struct{})
|
channel := make(chan struct{})
|
||||||
conn := &amqpConnMock{}
|
conn := &amqpConnMock{}
|
||||||
conn.On("Done", mock.Anything).Return(channelReceiver(channel))
|
conn.On("Done", mock.Anything).Return(channelReceiver(channel))
|
||||||
return &AmqpConnection{
|
return &internalMessaging.AmqpConnection{
|
||||||
connectionName: "test",
|
ConnectionName: "test",
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
conn: conn,
|
Conn: conn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newClosedConnection := func() *AmqpConnection {
|
newClosedConnection := func() *internalMessaging.AmqpConnection {
|
||||||
channel := make(chan struct{})
|
channel := make(chan struct{})
|
||||||
close(channel)
|
close(channel)
|
||||||
|
|
||||||
conn := &amqpConnMock{}
|
conn := &amqpConnMock{}
|
||||||
conn.On("Done", mock.Anything).Return(channelReceiver(channel))
|
conn.On("Done", mock.Anything).Return(channelReceiver(channel))
|
||||||
return &AmqpConnection{
|
return &internalMessaging.AmqpConnection{
|
||||||
connectionName: "test",
|
ConnectionName: "test",
|
||||||
lock: sync.RWMutex{},
|
Lock: sync.RWMutex{},
|
||||||
conn: conn,
|
Conn: conn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -135,16 +189,16 @@ func Test_AmqpMessagingApi_Send_Special_Cases(t *testing.T) {
|
||||||
session.On("NewSender", mock.Anything, mock.Anything, mock.Anything).Return(sender, nil)
|
session.On("NewSender", mock.Anything, mock.Anything, mock.Anything).Return(sender, nil)
|
||||||
|
|
||||||
connection := newActiveConnection()
|
connection := newActiveConnection()
|
||||||
conn := connection.conn.(*amqpConnMock)
|
conn := connection.Conn.(*amqpConnMock)
|
||||||
conn.On("NewSession", mock.Anything, mock.Anything).Return(session, nil)
|
conn.On("NewSession", mock.Anything, mock.Anything).Return(session, nil)
|
||||||
|
|
||||||
pool := &connectionPoolMock{}
|
pool := &connectionPoolMock{}
|
||||||
pool.On("GetConnection", mock.Anything).Return(connection, nil)
|
pool.On("GetConnection", mock.Anything).Return(connection, nil)
|
||||||
|
|
||||||
amqpApi := &AmqpApi{config: AmqpConnectionPoolConfig{},
|
amqpApi := &AmqpApi{
|
||||||
connectionPool: pool,
|
connectionPool: pool,
|
||||||
connectionPoolHandle: &ConnectionPoolHandle{connectionOffset: 0},
|
connectionPoolHandle: &internalMessaging.ConnectionPoolHandle{ConnectionOffset: 0},
|
||||||
senderCache: make(map[string]*AmqpSenderSession),
|
senderCache: make(map[string]*internalMessaging.AmqpSenderSession),
|
||||||
}
|
}
|
||||||
|
|
||||||
err := amqpApi.Send(context.Background(), "topic://some-topic", []byte("data"), "application/json", make(map[string]any))
|
err := amqpApi.Send(context.Background(), "topic://some-topic", []byte("data"), "application/json", make(map[string]any))
|
||||||
|
|
@ -163,19 +217,19 @@ func Test_AmqpMessagingApi_Send_Special_Cases(t *testing.T) {
|
||||||
session.On("NewSender", mock.Anything, mock.Anything, mock.Anything).Return(sender, nil)
|
session.On("NewSender", mock.Anything, mock.Anything, mock.Anything).Return(sender, nil)
|
||||||
|
|
||||||
connection := newActiveConnection()
|
connection := newActiveConnection()
|
||||||
conn := connection.conn.(*amqpConnMock)
|
conn := connection.Conn.(*amqpConnMock)
|
||||||
conn.On("NewSession", mock.Anything, mock.Anything).Return(session, nil)
|
conn.On("NewSession", mock.Anything, mock.Anything).Return(session, nil)
|
||||||
|
|
||||||
pool := &connectionPoolMock{}
|
pool := &connectionPoolMock{}
|
||||||
pool.On("GetConnection", mock.Anything).Return(connection, nil)
|
pool.On("GetConnection", mock.Anything).Return(connection, nil)
|
||||||
|
|
||||||
closedConnection := newClosedConnection()
|
closedConnection := newClosedConnection()
|
||||||
closedConnMock := closedConnection.conn.(*amqpConnMock)
|
closedConnMock := closedConnection.Conn.(*amqpConnMock)
|
||||||
amqpApi := &AmqpApi{config: AmqpConnectionPoolConfig{},
|
amqpApi := &AmqpApi{
|
||||||
connection: closedConnection,
|
connection: closedConnection,
|
||||||
connectionPool: pool,
|
connectionPool: pool,
|
||||||
connectionPoolHandle: &ConnectionPoolHandle{connectionOffset: 0},
|
connectionPoolHandle: &internalMessaging.ConnectionPoolHandle{ConnectionOffset: 0},
|
||||||
senderCache: make(map[string]*AmqpSenderSession),
|
senderCache: make(map[string]*internalMessaging.AmqpSenderSession),
|
||||||
}
|
}
|
||||||
|
|
||||||
err := amqpApi.Send(context.Background(), "topic://some-topic", []byte("data"), "application/json", make(map[string]any))
|
err := amqpApi.Send(context.Background(), "topic://some-topic", []byte("data"), "application/json", make(map[string]any))
|
||||||
|
|
@ -188,15 +242,15 @@ func Test_AmqpMessagingApi_Send_Special_Cases(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("connection nil get connection fail", func(t *testing.T) {
|
t.Run("connection nil get connection fail", func(t *testing.T) {
|
||||||
var connection *AmqpConnection = nil
|
var connection *internalMessaging.AmqpConnection = nil
|
||||||
|
|
||||||
pool := &connectionPoolMock{}
|
pool := &connectionPoolMock{}
|
||||||
pool.On("GetConnection", mock.Anything).Return(connection, errors.New("connection error"))
|
pool.On("GetConnection", mock.Anything).Return(connection, errors.New("connection error"))
|
||||||
|
|
||||||
amqpApi := &AmqpApi{config: AmqpConnectionPoolConfig{},
|
amqpApi := &AmqpApi{
|
||||||
connectionPool: pool,
|
connectionPool: pool,
|
||||||
connectionPoolHandle: &ConnectionPoolHandle{connectionOffset: 0},
|
connectionPoolHandle: &internalMessaging.ConnectionPoolHandle{ConnectionOffset: 0},
|
||||||
senderCache: make(map[string]*AmqpSenderSession),
|
senderCache: make(map[string]*internalMessaging.AmqpSenderSession),
|
||||||
}
|
}
|
||||||
|
|
||||||
err := amqpApi.Send(context.Background(), "topic://some-topic", []byte("data"), "application/json", make(map[string]any))
|
err := amqpApi.Send(context.Background(), "topic://some-topic", []byte("data"), "application/json", make(map[string]any))
|
||||||
|
|
@ -213,12 +267,12 @@ func Test_AmqpMessagingApi_Send_Special_Cases(t *testing.T) {
|
||||||
session.On("NewSender", mock.Anything, mock.Anything, mock.Anything).Return(sender, nil)
|
session.On("NewSender", mock.Anything, mock.Anything, mock.Anything).Return(sender, nil)
|
||||||
|
|
||||||
connection := newActiveConnection()
|
connection := newActiveConnection()
|
||||||
conn := connection.conn.(*amqpConnMock)
|
conn := connection.Conn.(*amqpConnMock)
|
||||||
conn.On("NewSession", mock.Anything, mock.Anything).Return(session, nil)
|
conn.On("NewSession", mock.Anything, mock.Anything).Return(session, nil)
|
||||||
|
|
||||||
amqpApi := &AmqpApi{config: AmqpConnectionPoolConfig{},
|
amqpApi := &AmqpApi{
|
||||||
connection: connection,
|
connection: connection,
|
||||||
senderCache: make(map[string]*AmqpSenderSession),
|
senderCache: make(map[string]*internalMessaging.AmqpSenderSession),
|
||||||
}
|
}
|
||||||
|
|
||||||
err := amqpApi.Send(context.Background(), "topic://some-topic", []byte("data"), "application/json", make(map[string]any))
|
err := amqpApi.Send(context.Background(), "topic://some-topic", []byte("data"), "application/json", make(map[string]any))
|
||||||
|
|
@ -236,12 +290,12 @@ func Test_AmqpMessagingApi_Send_Special_Cases(t *testing.T) {
|
||||||
session.On("Close", mock.Anything).Return(nil)
|
session.On("Close", mock.Anything).Return(nil)
|
||||||
|
|
||||||
connection := newActiveConnection()
|
connection := newActiveConnection()
|
||||||
conn := connection.conn.(*amqpConnMock)
|
conn := connection.Conn.(*amqpConnMock)
|
||||||
conn.On("NewSession", mock.Anything, mock.Anything).Return(session, nil)
|
conn.On("NewSession", mock.Anything, mock.Anything).Return(session, nil)
|
||||||
|
|
||||||
amqpApi := &AmqpApi{config: AmqpConnectionPoolConfig{},
|
amqpApi := &AmqpApi{
|
||||||
connection: connection,
|
connection: connection,
|
||||||
senderCache: make(map[string]*AmqpSenderSession),
|
senderCache: make(map[string]*internalMessaging.AmqpSenderSession),
|
||||||
}
|
}
|
||||||
|
|
||||||
err := amqpApi.Send(context.Background(), "topic://some-topic", []byte("data"), "application/json", make(map[string]any))
|
err := amqpApi.Send(context.Background(), "topic://some-topic", []byte("data"), "application/json", make(map[string]any))
|
||||||
|
|
@ -256,9 +310,9 @@ func Test_AmqpMessagingApi_Send_Special_Cases(t *testing.T) {
|
||||||
sender.On("Send", mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
sender.On("Send", mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
||||||
|
|
||||||
topic := "topic://some-topic"
|
topic := "topic://some-topic"
|
||||||
amqpApi := &AmqpApi{config: AmqpConnectionPoolConfig{},
|
amqpApi := &AmqpApi{
|
||||||
connection: newActiveConnection(),
|
connection: newActiveConnection(),
|
||||||
senderCache: map[string]*AmqpSenderSession{topic: {sender: sender}},
|
senderCache: map[string]*internalMessaging.AmqpSenderSession{topic: {Sender: sender}},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := amqpApi.Send(context.Background(), topic, []byte("data"), "application/json", make(map[string]any))
|
err := amqpApi.Send(context.Background(), topic, []byte("data"), "application/json", make(map[string]any))
|
||||||
|
|
@ -276,10 +330,10 @@ func Test_AmqpMessagingApi_Send_Special_Cases(t *testing.T) {
|
||||||
|
|
||||||
topic := "topic://some-topic"
|
topic := "topic://some-topic"
|
||||||
connection := newActiveConnection()
|
connection := newActiveConnection()
|
||||||
connection.conn.(*amqpConnMock).On("NewSession", mock.Anything, mock.Anything, mock.Anything).Return(session, nil)
|
connection.Conn.(*amqpConnMock).On("NewSession", mock.Anything, mock.Anything, mock.Anything).Return(session, nil)
|
||||||
amqpApi := &AmqpApi{config: AmqpConnectionPoolConfig{},
|
amqpApi := &AmqpApi{
|
||||||
connection: connection,
|
connection: connection,
|
||||||
senderCache: map[string]*AmqpSenderSession{topic: {sender: sender}},
|
senderCache: map[string]*internalMessaging.AmqpSenderSession{topic: {Sender: sender}},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := amqpApi.Send(context.Background(), topic, []byte("data"), "application/json", make(map[string]any))
|
err := amqpApi.Send(context.Background(), topic, []byte("data"), "application/json", make(map[string]any))
|
||||||
|
|
@ -295,10 +349,10 @@ func Test_AmqpMessagingApi_Close(t *testing.T) {
|
||||||
pool := &connectionPoolMock{}
|
pool := &connectionPoolMock{}
|
||||||
pool.On("Close").Return(nil)
|
pool.On("Close").Return(nil)
|
||||||
|
|
||||||
amqpApi := &AmqpApi{config: AmqpConnectionPoolConfig{},
|
amqpApi := &AmqpApi{
|
||||||
connectionPool: pool,
|
connectionPool: pool,
|
||||||
connectionPoolHandle: &ConnectionPoolHandle{connectionOffset: 0},
|
connectionPoolHandle: &internalMessaging.ConnectionPoolHandle{ConnectionOffset: 0},
|
||||||
senderCache: make(map[string]*AmqpSenderSession),
|
senderCache: make(map[string]*internalMessaging.AmqpSenderSession),
|
||||||
}
|
}
|
||||||
|
|
||||||
err := amqpApi.Close(context.Background())
|
err := amqpApi.Close(context.Background())
|
||||||
|
|
@ -311,10 +365,10 @@ func Test_AmqpMessagingApi_Close(t *testing.T) {
|
||||||
pool := &connectionPoolMock{}
|
pool := &connectionPoolMock{}
|
||||||
pool.On("Close").Return(errors.New("close error"))
|
pool.On("Close").Return(errors.New("close error"))
|
||||||
|
|
||||||
amqpApi := &AmqpApi{config: AmqpConnectionPoolConfig{},
|
amqpApi := &AmqpApi{
|
||||||
connectionPool: pool,
|
connectionPool: pool,
|
||||||
connectionPoolHandle: &ConnectionPoolHandle{connectionOffset: 0},
|
connectionPoolHandle: &internalMessaging.ConnectionPoolHandle{ConnectionOffset: 0},
|
||||||
senderCache: make(map[string]*AmqpSenderSession),
|
senderCache: make(map[string]*internalMessaging.AmqpSenderSession),
|
||||||
}
|
}
|
||||||
|
|
||||||
err := amqpApi.Close(context.Background())
|
err := amqpApi.Close(context.Background())
|
||||||
|
|
@ -331,15 +385,15 @@ func Test_AmqpMessagingApi_Close(t *testing.T) {
|
||||||
session.On("Close", mock.Anything).Return(nil)
|
session.On("Close", mock.Anything).Return(nil)
|
||||||
sender := &amqpSenderMock{}
|
sender := &amqpSenderMock{}
|
||||||
sender.On("Close", mock.Anything).Return(nil)
|
sender.On("Close", mock.Anything).Return(nil)
|
||||||
senderSession := &AmqpSenderSession{
|
senderSession := &internalMessaging.AmqpSenderSession{
|
||||||
session: session,
|
Session: session,
|
||||||
sender: sender,
|
Sender: sender,
|
||||||
}
|
}
|
||||||
|
|
||||||
amqpApi := &AmqpApi{config: AmqpConnectionPoolConfig{},
|
amqpApi := &AmqpApi{
|
||||||
connectionPool: pool,
|
connectionPool: pool,
|
||||||
connectionPoolHandle: &ConnectionPoolHandle{connectionOffset: 0},
|
connectionPoolHandle: &internalMessaging.ConnectionPoolHandle{ConnectionOffset: 0},
|
||||||
senderCache: map[string]*AmqpSenderSession{"key": senderSession},
|
senderCache: map[string]*internalMessaging.AmqpSenderSession{"key": senderSession},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := amqpApi.Close(context.Background())
|
err := amqpApi.Close(context.Background())
|
||||||
|
|
@ -359,15 +413,15 @@ func Test_AmqpMessagingApi_Close(t *testing.T) {
|
||||||
session.On("Close", mock.Anything).Return(nil)
|
session.On("Close", mock.Anything).Return(nil)
|
||||||
sender := &amqpSenderMock{}
|
sender := &amqpSenderMock{}
|
||||||
sender.On("Close", mock.Anything).Return(errors.New("close sender error"))
|
sender.On("Close", mock.Anything).Return(errors.New("close sender error"))
|
||||||
senderSession := &AmqpSenderSession{
|
senderSession := &internalMessaging.AmqpSenderSession{
|
||||||
session: session,
|
Session: session,
|
||||||
sender: sender,
|
Sender: sender,
|
||||||
}
|
}
|
||||||
|
|
||||||
amqpApi := &AmqpApi{config: AmqpConnectionPoolConfig{},
|
amqpApi := &AmqpApi{
|
||||||
connectionPool: pool,
|
connectionPool: pool,
|
||||||
connectionPoolHandle: &ConnectionPoolHandle{connectionOffset: 0},
|
connectionPoolHandle: &internalMessaging.ConnectionPoolHandle{ConnectionOffset: 0},
|
||||||
senderCache: map[string]*AmqpSenderSession{"key": senderSession},
|
senderCache: map[string]*internalMessaging.AmqpSenderSession{"key": senderSession},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := amqpApi.Close(context.Background())
|
err := amqpApi.Close(context.Background())
|
||||||
|
|
@ -387,15 +441,15 @@ func Test_AmqpMessagingApi_Close(t *testing.T) {
|
||||||
session.On("Close", mock.Anything).Return(errors.New("close session error"))
|
session.On("Close", mock.Anything).Return(errors.New("close session error"))
|
||||||
sender := &amqpSenderMock{}
|
sender := &amqpSenderMock{}
|
||||||
sender.On("Close", mock.Anything).Return(errors.New("close sender error"))
|
sender.On("Close", mock.Anything).Return(errors.New("close sender error"))
|
||||||
senderSession := &AmqpSenderSession{
|
senderSession := &internalMessaging.AmqpSenderSession{
|
||||||
session: session,
|
Session: session,
|
||||||
sender: sender,
|
Sender: sender,
|
||||||
}
|
}
|
||||||
|
|
||||||
amqpApi := &AmqpApi{config: AmqpConnectionPoolConfig{},
|
amqpApi := &AmqpApi{
|
||||||
connectionPool: pool,
|
connectionPool: pool,
|
||||||
connectionPoolHandle: &ConnectionPoolHandle{connectionOffset: 0},
|
connectionPoolHandle: &internalMessaging.ConnectionPoolHandle{ConnectionOffset: 0},
|
||||||
senderCache: map[string]*AmqpSenderSession{"key": senderSession},
|
senderCache: map[string]*internalMessaging.AmqpSenderSession{"key": senderSession},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := amqpApi.Close(context.Background())
|
err := amqpApi.Close(context.Background())
|
||||||
28
pkg/messaging/api/messaging.go
Normal file
28
pkg/messaging/api/messaging.go
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Api is an abstraction for a messaging system that can be used to send
|
||||||
|
// audit logs to the audit log system.
|
||||||
|
type Api interface {
|
||||||
|
|
||||||
|
// Send method will send the given data to the specified topic synchronously.
|
||||||
|
// Parameters:
|
||||||
|
// * ctx - the context object
|
||||||
|
// * topic - the messaging topic where to send the data to
|
||||||
|
// * data - the serialized data as byte array
|
||||||
|
// * contentType - the contentType of the serialized data
|
||||||
|
// * applicationProperties - properties to send with the message (i.e. cloud event headers)
|
||||||
|
//
|
||||||
|
// It returns technical errors for connection issues or sending problems.
|
||||||
|
Send(ctx context.Context, topic string, data []byte, contentType string, applicationProperties map[string]any) error
|
||||||
|
|
||||||
|
// Close the underlying connection to the messaging system.
|
||||||
|
// Parameters:
|
||||||
|
// * ctx - the context object
|
||||||
|
//
|
||||||
|
// It returns an error if the connection cannot be closed successfully
|
||||||
|
Close(ctx context.Context) error
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,4 @@
|
||||||
package messaging
|
package common
|
||||||
|
|
||||||
const AmqpTopicPrefix = "topic://"
|
|
||||||
const connectionTimeoutSeconds = 10
|
|
||||||
|
|
||||||
type AmqpConnectionConfig struct {
|
type AmqpConnectionConfig struct {
|
||||||
BrokerUrl string `json:"brokerUrl"`
|
BrokerUrl string `json:"brokerUrl"`
|
||||||
|
|
@ -1,25 +1,28 @@
|
||||||
package messaging
|
package test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/log"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Azure/go-amqp"
|
|
||||||
"github.com/testcontainers/testcontainers-go"
|
|
||||||
"github.com/testcontainers/testcontainers-go/wait"
|
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/Azure/go-amqp"
|
||||||
|
docker "github.com/docker/docker/api/types/container"
|
||||||
|
"github.com/testcontainers/testcontainers-go"
|
||||||
|
"github.com/testcontainers/testcontainers-go/wait"
|
||||||
|
|
||||||
|
pkgLog "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const AmqpQueuePrefix = "queue://"
|
||||||
AmqpQueuePrefix = "queue://"
|
const AmqpTopicPrefix = "topic://"
|
||||||
)
|
const dockerImage = "schwarzit-docker.jfrog.io/solace/solace-pubsub-standard:10.8.1.241"
|
||||||
|
|
||||||
var ErrResourceNotFound = errors.New("resource not found")
|
var ErrResourceNotFound = errors.New("resource not found")
|
||||||
|
|
||||||
|
|
@ -132,12 +135,13 @@ func NewSolaceContainer(ctx context.Context) (*SolaceContainer, error) {
|
||||||
|
|
||||||
// Start docker container
|
// Start docker container
|
||||||
request := testcontainers.ContainerRequest{
|
request := testcontainers.ContainerRequest{
|
||||||
Image: "solace/solace-pubsub-standard:10.8",
|
Image: dockerImage,
|
||||||
ExposedPorts: []string{"5672/tcp", "8080/tcp"},
|
ExposedPorts: []string{"5672/tcp", "8080/tcp"},
|
||||||
SkipReaper: true,
|
HostConfigModifier: func(config *docker.HostConfig) {
|
||||||
AutoRemove: true,
|
config.AutoRemove = true
|
||||||
ShmSize: 1024 * 1024 * 1024, // 1 GB,
|
config.ShmSize = 1024 * 1024 * 1024 // 1 GB,
|
||||||
Env: env,
|
},
|
||||||
|
Env: env,
|
||||||
WaitingFor: wait.ForLog("Running pre-startup checks:").
|
WaitingFor: wait.ForLog("Running pre-startup checks:").
|
||||||
WithStartupTimeout(90 * time.Second),
|
WithStartupTimeout(90 * time.Second),
|
||||||
}
|
}
|
||||||
|
|
@ -167,7 +171,7 @@ func NewSolaceContainer(ctx context.Context) (*SolaceContainer, error) {
|
||||||
_ = container.Terminate(ctx)
|
_ = container.Terminate(ctx)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
log.AuditLogger.Info("UI Port: " + sempPort.Port())
|
pkgLog.AuditLogger.Info("UI Port: " + sempPort.Port())
|
||||||
|
|
||||||
// Construct connection strings
|
// Construct connection strings
|
||||||
amqpConnectionString := fmt.Sprintf("amqp://%s:%s/", host, amqpPort.Port())
|
amqpConnectionString := fmt.Sprintf("amqp://%s:%s/", host, amqpPort.Port())
|
||||||
|
|
@ -295,8 +299,8 @@ func (c SolaceContainer) NewAmqpConnection(ctx context.Context) (*amqp.Conn, err
|
||||||
func (c SolaceContainer) ValidateTopicName(topicSubscriptionTopicPattern string, topicName string) error {
|
func (c SolaceContainer) ValidateTopicName(topicSubscriptionTopicPattern string, topicName string) error {
|
||||||
// Cut off the topic:// prefix
|
// Cut off the topic:// prefix
|
||||||
var name string
|
var name string
|
||||||
if strings.HasPrefix(topicName, "topic://") {
|
if strings.HasPrefix(topicName, AmqpTopicPrefix) {
|
||||||
name = topicName[len("topic://"):]
|
name = topicName[len(AmqpTopicPrefix):]
|
||||||
} else {
|
} else {
|
||||||
name = topicName
|
name = topicName
|
||||||
}
|
}
|
||||||
|
|
@ -131,7 +131,8 @@ message AuditLog {
|
||||||
// Required: true
|
// Required: true
|
||||||
string service_name = 1 [
|
string service_name = 1 [
|
||||||
(buf.validate.field).required = true,
|
(buf.validate.field).required = true,
|
||||||
(buf.validate.field).string.min_len = 1
|
(buf.validate.field).string.min_len = 1,
|
||||||
|
(buf.validate.field).string.pattern = ".*\\S.*"
|
||||||
];
|
];
|
||||||
|
|
||||||
// The name of the service method or operation.
|
// The name of the service method or operation.
|
||||||
|
|
@ -232,17 +233,18 @@ message AuthenticationInfo {
|
||||||
// Required: true
|
// Required: true
|
||||||
string principal_id = 1 [
|
string principal_id = 1 [
|
||||||
(buf.validate.field).required = true,
|
(buf.validate.field).required = true,
|
||||||
(buf.validate.field).string.min_len = 1
|
(buf.validate.field).string.min_len = 1,
|
||||||
|
(buf.validate.field).string.pattern = ".*\\S.*"
|
||||||
];
|
];
|
||||||
|
|
||||||
// The email address of the authenticated user.
|
// The email address of the authenticated user.
|
||||||
// Service accounts have email addresses that can be used.
|
// Service accounts have email addresses that can be used.
|
||||||
//
|
//
|
||||||
// Required: true
|
// Required: false
|
||||||
string principal_email = 2 [
|
optional string principal_email = 2 [
|
||||||
(buf.validate.field).required = true,
|
(buf.validate.field).string.min_len = 5,
|
||||||
(buf.validate.field).string.min_len = 1,
|
(buf.validate.field).string.max_len = 255,
|
||||||
(buf.validate.field).string.max_len = 255
|
(buf.validate.field).string.email = true
|
||||||
];
|
];
|
||||||
|
|
||||||
// The name of the service account used to create or exchange
|
// The name of the service account used to create or exchange
|
||||||
|
|
@ -325,7 +327,7 @@ message AttributeContext {
|
||||||
// Required: true
|
// Required: true
|
||||||
string principal = 1 [
|
string principal = 1 [
|
||||||
(buf.validate.field).required = true,
|
(buf.validate.field).required = true,
|
||||||
(buf.validate.field).string.pattern = "^[a-zA-Z0-9-%.]+/[a-zA-Z0-9-%.]+$"
|
(buf.validate.field).string.pattern = "^[a-zA-Z0-9-%._]+/[a-zA-Z0-9-%.]+$"
|
||||||
];
|
];
|
||||||
|
|
||||||
// The intended audience(s) for this authentication information. Reflects
|
// The intended audience(s) for this authentication information. Reflects
|
||||||
|
|
@ -414,7 +416,8 @@ message AttributeContext {
|
||||||
string path = 4 [
|
string path = 4 [
|
||||||
(buf.validate.field).required = true,
|
(buf.validate.field).required = true,
|
||||||
(buf.validate.field).string.min_len = 1,
|
(buf.validate.field).string.min_len = 1,
|
||||||
(buf.validate.field).string.max_len = 255
|
(buf.validate.field).string.max_len = 255,
|
||||||
|
(buf.validate.field).string.pattern = ".*\\S.*"
|
||||||
];
|
];
|
||||||
|
|
||||||
// The HTTP request `Host` header value.
|
// The HTTP request `Host` header value.
|
||||||
|
|
@ -422,7 +425,8 @@ message AttributeContext {
|
||||||
// Required: true
|
// Required: true
|
||||||
string host = 5 [
|
string host = 5 [
|
||||||
(buf.validate.field).required = true,
|
(buf.validate.field).required = true,
|
||||||
(buf.validate.field).string.min_len = 1
|
(buf.validate.field).string.min_len = 1,
|
||||||
|
(buf.validate.field).string.pattern = ".*\\S.*"
|
||||||
];
|
];
|
||||||
|
|
||||||
// The URL scheme, such as `http`, `https` or `gRPC`.
|
// The URL scheme, such as `http`, `https` or `gRPC`.
|
||||||
|
|
@ -430,7 +434,8 @@ message AttributeContext {
|
||||||
// Required: true
|
// Required: true
|
||||||
string scheme = 6 [
|
string scheme = 6 [
|
||||||
(buf.validate.field).required = true,
|
(buf.validate.field).required = true,
|
||||||
(buf.validate.field).string.min_len = 1
|
(buf.validate.field).string.min_len = 1,
|
||||||
|
(buf.validate.field).string.pattern = ".*\\S.*"
|
||||||
];
|
];
|
||||||
|
|
||||||
// The HTTP URL query in the format of "name1=value1&name2=value2", as it
|
// The HTTP URL query in the format of "name1=value1&name2=value2", as it
|
||||||
|
|
@ -457,7 +462,8 @@ message AttributeContext {
|
||||||
// Required: true
|
// Required: true
|
||||||
string protocol = 9 [
|
string protocol = 9 [
|
||||||
(buf.validate.field).required = true,
|
(buf.validate.field).required = true,
|
||||||
(buf.validate.field).string.min_len = 1
|
(buf.validate.field).string.min_len = 1,
|
||||||
|
(buf.validate.field).string.pattern = ".*\\S.*"
|
||||||
];
|
];
|
||||||
|
|
||||||
// The request authentication.
|
// The request authentication.
|
||||||
|
|
@ -521,7 +527,8 @@ message RequestMetadata {
|
||||||
string caller_supplied_user_agent = 2 [
|
string caller_supplied_user_agent = 2 [
|
||||||
(buf.validate.field).required = true,
|
(buf.validate.field).required = true,
|
||||||
(buf.validate.field).string.min_len = 1,
|
(buf.validate.field).string.min_len = 1,
|
||||||
(buf.validate.field).string.max_len = 255
|
(buf.validate.field).string.max_len = 255,
|
||||||
|
(buf.validate.field).string.pattern = ".*\\S.*"
|
||||||
];
|
];
|
||||||
|
|
||||||
// This field contains request attributes like request url, time, etc.
|
// This field contains request attributes like request url, time, etc.
|
||||||
|
|
@ -577,7 +584,8 @@ message ServiceAccountDelegationInfo {
|
||||||
// Required: true
|
// Required: true
|
||||||
string principal_id = 1 [
|
string principal_id = 1 [
|
||||||
(buf.validate.field).required = true,
|
(buf.validate.field).required = true,
|
||||||
(buf.validate.field).string.min_len = 1
|
(buf.validate.field).string.min_len = 1,
|
||||||
|
(buf.validate.field).string.pattern = ".*\\S.*"
|
||||||
];
|
];
|
||||||
|
|
||||||
// The email address of the authenticated user.
|
// The email address of the authenticated user.
|
||||||
|
|
@ -587,7 +595,8 @@ message ServiceAccountDelegationInfo {
|
||||||
string principal_email = 2 [
|
string principal_email = 2 [
|
||||||
(buf.validate.field).required = true,
|
(buf.validate.field).required = true,
|
||||||
(buf.validate.field).string.min_len = 1,
|
(buf.validate.field).string.min_len = 1,
|
||||||
(buf.validate.field).string.max_len = 255
|
(buf.validate.field).string.max_len = 255,
|
||||||
|
(buf.validate.field).string.pattern = ".*\\S.*"
|
||||||
];
|
];
|
||||||
|
|
||||||
// Metadata about the service that uses the service account.
|
// Metadata about the service that uses the service account.
|
||||||
|
|
|
||||||
13
sonar-project.properties
Normal file
13
sonar-project.properties
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
sonar.projectKey=xx-sit-odj-sec-ident:audit-go
|
||||||
|
sonar.host.url=https://sonarqube.schwarz
|
||||||
|
sonar.projectName=audit-go
|
||||||
|
sonar.sources=.
|
||||||
|
sonar.exclusions=**/*_test.go,**/vendor/**,**/mocks/**,**/*.yml,**/gen/**, **/test/solace.go
|
||||||
|
sonar.tests=.
|
||||||
|
sonar.test.inclusions=**/*_test.go
|
||||||
|
sonar.test.exclusions=**/vendor/**,**/mocks/**
|
||||||
|
sonar.issuesReport.html.enable=true
|
||||||
|
sonar.log.level=INFO
|
||||||
|
sonar.go.coverage.reportPaths=out/cover.out
|
||||||
|
sonar.go.tests.reportPaths=out/report.json
|
||||||
|
sonar.go.golangci-lint.reportPaths=out/lint.xml
|
||||||
Loading…
Reference in a new issue