Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 111-cli-expansion-stateful-behaviour-more-command-feedback
  • 120-integration-tests-fail
  • 138-making-gnmi-response-processing-more-error-tolerable
  • 140-refactor-pipelines
  • 156-a-setrequest-to-change-a-specific-path-of-an-ond-only-works-for-paths-with-string-values
  • 186-creating-a-device-based-on-plugin-or-csbi-is-not-possible
  • 195-requesting-changes-does-not-work-in-storemode-database
  • 223-database-pnd-store-is-missing-option-to-search-by-name
  • 225-adding-support-and-visualization-for-the-test-coverage2
  • 233-structs-like-loadeddevice-loadedsbi-loadedrole-loadeduser-are-never-passed-as-pointer
  • 242-improve-security-by-enabling-and-enforcing-more-linting-rules
  • 242-improve-security-by-enabling-and-enforcing-more-linting-rules-govet
  • 246-implement-our-own-version-to-send-gnmi-requests
  • 258-deal-with-read-only-fields-in-yang
  • 282-refactoring-of-the-current-test-setup
  • 289-quantum-safe-communication-between-rabbitmq-and-sdn-controller
  • 291-lab-vm-for-arm64-apple
  • 296-related-existing-work-about-change-logic-for-yang-models
  • 320-deadline-and-cancellation-for-grpc-calls
  • 336-add-error-handling-for-mne-watching-if-the-provided-paths-do-not-exist
  • 349-integration-test-for-lab01
  • 350-applying-a-sdn-configuration-should-also-update-the-internal-configuration-of-managed-network
  • 351-link-shadowing-of-global-variables
  • 383-re-organize-comands-in-cli
  • 392-remove-renovate
  • PSD_VGU_Logging
  • add-backup-script
  • add-dockerignore
  • add-script-with-docker-stats
  • add-sr-linux-yang-models
  • add-support-for-mtls-in-plugins
  • allow-slashes-in-branch-names
  • arm-build
  • bump-ygot-generator-to-0-0-5
  • check-unit-tests
  • ci-refactor-1337
  • cli-docs
  • create-health-check-api
  • custom-marshal-for-grpc-gateway
  • deployment-docker-compose
  • develop
  • docker-build-cache-experiments
  • fbi1478-master-patch-42436
  • fix-docker-registry-error
  • fix-linting-in-makefile
  • fix-viper
  • go-plugin-playground
  • gosdn-storage-cleanup
  • heiss_bachelor_thesis
  • hotfix-unique-list-error-from-a-device-get-request
  • integration-test-pipeline-fix
  • inventory-manager-netbox
  • istaester/add-git-hooks
  • istaester/architecture-figures
  • istaester/basic-persistance-layer
  • istaester/bump-ygot-version
  • istaester/cli-tests
  • istaester/db
  • istaester/handle-makefile-in-editorconfig
  • istaester/init-monorepo
  • istaester/plugin-registry
  • istaester/provide-pnd-service
  • istaester/tooling
  • istaester/update-readme
  • master
  • mb/plugin-registry
  • mk/benchmark-stores
  • mpsd-at-vgu
  • neil/cobra-tests
  • new-integration-test-setup-v1
  • profile
  • proto-getters
  • recursive-read-only-try-1337
  • registry-used-by-app
  • remove-stuff
  • renovate/babel-runtime-7.x-lockfile
  • renovate/buf.build-gen-go-bufbuild-protovalidate-protocolbuffers-go-1.x
  • renovate/dompurify-3.x-lockfile
  • renovate/eslint-9.x-lockfile
  • renovate/eslint-plugin-prettier-5.x-lockfile
  • renovate/eslint-plugin-react-7.x-lockfile
  • renovate/eslint-plugin-react-hooks-5.x-lockfile
  • renovate/eslint-plugin-react-refresh-0.x-lockfile
  • renovate/fortawesome-fontawesome-svg-core-6.x-lockfile
  • renovate/fortawesome-free-regular-svg-icons-6.x-lockfile
  • renovate/fortawesome-free-solid-svg-icons-6.x-lockfile
  • renovate/github.com-aristanetworks-goarista-digest
  • renovate/github.com-bufbuild-protovalidate-go-0.x
  • renovate/github.com-docker-docker-27.x
  • renovate/github.com-docker-docker-28.x
  • renovate/github.com-grpc-ecosystem-grpc-gateway-v2-2.x
  • renovate/github.com-hashicorp-go-plugin-1.x
  • renovate/github.com-lesismal-nbio-1.x
  • renovate/github.com-openconfig-gnmi-0.x
  • renovate/github.com-prometheus-client_golang-1.x
  • renovate/go.mongodb.org-mongo-driver-2.x
  • renovate/golangci-golangci-lint-1.x
  • renovate/google.golang.org-genproto-googleapis-api-digest
  • renovate/react-18.x-lockfile
  • renovate/react-bootstrap-2.x-lockfile
  • 0.1.0
101 results

Target

Select target project
  • danet/gosdn
1 result
Select Git revision
  • 111-cli-expansion-stateful-behaviour-more-command-feedback
  • 120-integration-tests-fail
  • 138-making-gnmi-response-processing-more-error-tolerable
  • 140-refactor-pipelines
  • 156-a-setrequest-to-change-a-specific-path-of-an-ond-only-works-for-paths-with-string-values
  • 186-creating-a-device-based-on-plugin-or-csbi-is-not-possible
  • 195-requesting-changes-does-not-work-in-storemode-database
  • 223-database-pnd-store-is-missing-option-to-search-by-name
  • 225-adding-support-and-visualization-for-the-test-coverage2
  • 233-structs-like-loadeddevice-loadedsbi-loadedrole-loadeduser-are-never-passed-as-pointer
  • 242-improve-security-by-enabling-and-enforcing-more-linting-rules
  • 242-improve-security-by-enabling-and-enforcing-more-linting-rules-govet
  • 246-implement-our-own-version-to-send-gnmi-requests
  • 258-deal-with-read-only-fields-in-yang
  • 282-refactoring-of-the-current-test-setup
  • 289-quantum-safe-communication-between-rabbitmq-and-sdn-controller
  • 291-lab-vm-for-arm64-apple
  • 296-related-existing-work-about-change-logic-for-yang-models
  • 320-deadline-and-cancellation-for-grpc-calls
  • 336-add-error-handling-for-mne-watching-if-the-provided-paths-do-not-exist
  • 349-integration-test-for-lab01
  • 350-applying-a-sdn-configuration-should-also-update-the-internal-configuration-of-managed-network
  • 351-link-shadowing-of-global-variables
  • 383-re-organize-comands-in-cli
  • 392-remove-renovate
  • PSD_VGU_Logging
  • add-backup-script
  • add-dockerignore
  • add-script-with-docker-stats
  • add-sr-linux-yang-models
  • add-support-for-mtls-in-plugins
  • allow-slashes-in-branch-names
  • arm-build
  • bump-ygot-generator-to-0-0-5
  • check-unit-tests
  • ci-refactor-1337
  • cli-docs
  • create-health-check-api
  • custom-marshal-for-grpc-gateway
  • deployment-docker-compose
  • develop
  • docker-build-cache-experiments
  • fbi1478-master-patch-42436
  • fix-docker-registry-error
  • fix-linting-in-makefile
  • fix-viper
  • go-plugin-playground
  • gosdn-storage-cleanup
  • heiss_bachelor_thesis
  • hotfix-unique-list-error-from-a-device-get-request
  • integration-test-pipeline-fix
  • inventory-manager-netbox
  • istaester/add-git-hooks
  • istaester/architecture-figures
  • istaester/basic-persistance-layer
  • istaester/bump-ygot-version
  • istaester/cli-tests
  • istaester/db
  • istaester/handle-makefile-in-editorconfig
  • istaester/init-monorepo
  • istaester/plugin-registry
  • istaester/provide-pnd-service
  • istaester/tooling
  • istaester/update-readme
  • master
  • mb/plugin-registry
  • mk/benchmark-stores
  • mpsd-at-vgu
  • neil/cobra-tests
  • new-integration-test-setup-v1
  • profile
  • proto-getters
  • recursive-read-only-try-1337
  • registry-used-by-app
  • remove-stuff
  • renovate/babel-runtime-7.x-lockfile
  • renovate/buf.build-gen-go-bufbuild-protovalidate-protocolbuffers-go-1.x
  • renovate/dompurify-3.x-lockfile
  • renovate/eslint-9.x-lockfile
  • renovate/eslint-plugin-prettier-5.x-lockfile
  • renovate/eslint-plugin-react-7.x-lockfile
  • renovate/eslint-plugin-react-hooks-5.x-lockfile
  • renovate/eslint-plugin-react-refresh-0.x-lockfile
  • renovate/fortawesome-fontawesome-svg-core-6.x-lockfile
  • renovate/fortawesome-free-regular-svg-icons-6.x-lockfile
  • renovate/fortawesome-free-solid-svg-icons-6.x-lockfile
  • renovate/github.com-aristanetworks-goarista-digest
  • renovate/github.com-bufbuild-protovalidate-go-0.x
  • renovate/github.com-docker-docker-27.x
  • renovate/github.com-docker-docker-28.x
  • renovate/github.com-grpc-ecosystem-grpc-gateway-v2-2.x
  • renovate/github.com-hashicorp-go-plugin-1.x
  • renovate/github.com-lesismal-nbio-1.x
  • renovate/github.com-openconfig-gnmi-0.x
  • renovate/github.com-prometheus-client_golang-1.x
  • renovate/go.mongodb.org-mongo-driver-2.x
  • renovate/golangci-golangci-lint-1.x
  • renovate/google.golang.org-genproto-googleapis-api-digest
  • renovate/react-18.x-lockfile
  • renovate/react-bootstrap-2.x-lockfile
  • 0.1.0
101 results
Show changes
Commits on Source (4)
build-mkdocs:
image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/python:3.11.5-slim-bullseye
image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/python:3.11.5-slim-bookworm
stage: build
before_script:
- pip install mkdocs-material
......@@ -13,7 +13,7 @@ build-mkdocs:
- if: $CI_COMMIT_REF_PROTECTED == "true"
.pages-options: &pages-options
image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/python:3.11.5-slim-bullseye
image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/python:3.11.5-slim-bookworm
stage: deploy
script:
- mv mkdocs-built public
......
......@@ -2,7 +2,7 @@ ARG GOLANG_VERSION=1.21
ARG BUILDARGS
ARG $GITLAB_PROXY=code.fbi.h-da.de:443/danet/dependency_proxy/containers
FROM ${GITLAB_PROXY}golang:$GOLANG_VERSION-bullseye AS builder
FROM ${GITLAB_PROXY}golang:$GOLANG_VERSION-bookworm AS builder
WORKDIR /gosdn
......
......@@ -2,14 +2,14 @@ ARG GOLANG_VERSION=1.21
ARG BUILDARGS
ARG $GITLAB_PROXY
FROM ${GITLAB_PROXY}golang:$GOLANG_VERSION-bullseye as builder
FROM ${GITLAB_PROXY}golang:$GOLANG_VERSION-bookworm as builder
WORKDIR /gosdn/
COPY . .
RUN --mount=type=cache,target=/root/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
make build-gosdn
FROM ${GITLAB_PROXY}golang:$GOLANG_VERSION-bullseye
FROM ${GITLAB_PROXY}golang:$GOLANG_VERSION-bookworm
WORKDIR /app/
COPY --from=builder /gosdn/controller/configs/development-gosdn.toml.example ./configs/development-gosdn.toml
COPY --from=builder /gosdn/controller/configs/containerlab-gosdn.toml.example ./configs/containerlab-gosdn.toml
......
......@@ -2,6 +2,7 @@ package server
import (
"context"
"errors"
"fmt"
"time"
......@@ -16,6 +17,7 @@ import (
log "github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/reflect/protoreflect"
)
// RoleServer holds a JWTManager and represents a RoleServiceServer.
......@@ -39,14 +41,33 @@ func NewRoleServer(
}
}
func (r RoleServer) checkForValidationErrors(request protoreflect.ProtoMessage) error {
err := r.protoValidator.Validate(request)
if err != nil {
var valErr *protovalidate.ValidationError
if ok := errors.As(err, &valErr); ok {
protoErr := valErr.ToProto()
grpcError, _ := status.New(codes.Aborted, "Validation failed").WithDetails(protoErr)
return grpcError.Err()
}
return status.Errorf(codes.Aborted, "%v", err)
}
return nil
}
// CreateRoles creates one are multiple new roles.
func (r RoleServer) CreateRoles(ctx context.Context, request *apb.CreateRolesRequest) (*apb.CreateRolesResponse, error) {
labels := prometheus.Labels{"service": "auth", "rpc": "post"}
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
if err := r.protoValidator.Validate(request); err != nil {
return nil, status.Errorf(codes.Aborted, "%v", err)
err := r.checkForValidationErrors(request)
if err != nil {
return nil, err
}
for _, rrole := range request.Roles {
......@@ -70,8 +91,9 @@ func (r RoleServer) GetRole(ctx context.Context, request *apb.GetRoleRequest) (*
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
if err := r.protoValidator.Validate(request); err != nil {
return nil, status.Errorf(codes.Aborted, "%v", err)
err := r.checkForValidationErrors(request)
if err != nil {
return nil, err
}
roleID, err := uuid.Parse(request.Id)
......@@ -103,8 +125,9 @@ func (r RoleServer) GetRoles(ctx context.Context, request *apb.GetRolesRequest)
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
if err := r.protoValidator.Validate(request); err != nil {
return nil, status.Errorf(codes.Aborted, "%v", err)
err := r.checkForValidationErrors(request)
if err != nil {
return nil, err
}
roleList, err := r.roleService.GetAll()
......@@ -134,8 +157,9 @@ func (r RoleServer) UpdateRoles(ctx context.Context, request *apb.UpdateRolesReq
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
if err := r.protoValidator.Validate(request); err != nil {
return nil, status.Errorf(codes.Aborted, "%v", err)
err := r.checkForValidationErrors(request)
if err != nil {
return nil, err
}
for _, role := range request.Roles {
......@@ -166,8 +190,9 @@ func (r RoleServer) DeletePermissionsForRole(ctx context.Context, request *apb.D
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
if err := r.protoValidator.Validate(request); err != nil {
return nil, status.Errorf(codes.Aborted, "%v", err)
err := r.checkForValidationErrors(request)
if err != nil {
return nil, err
}
roleToUpdate, err := r.roleService.Get(store.Query{Name: request.RoleName})
......@@ -211,8 +236,9 @@ func (r RoleServer) DeleteRoles(ctx context.Context, request *apb.DeleteRolesReq
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
if err := r.protoValidator.Validate(request); err != nil {
return nil, status.Errorf(codes.Aborted, "%v", err)
err := r.checkForValidationErrors(request)
if err != nil {
return nil, err
}
for _, role := range request.RoleName {
......
......@@ -6,6 +6,7 @@ import (
"testing"
"time"
"buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate"
apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
"code.fbi.h-da.de/danet/gosdn/controller/rbac"
"github.com/bufbuild/protovalidate-go"
......@@ -44,10 +45,11 @@ func TestRole_CreateRoles(t *testing.T) {
request *apb.CreateRolesRequest
}
tests := []struct {
name string
args args
want *apb.CreateRolesResponse
wantErr bool
name string
args args
want *apb.CreateRolesResponse
wantErr bool
validationErrors []*validate.Violation
}{
{
name: "default create roles",
......@@ -65,6 +67,49 @@ func TestRole_CreateRoles(t *testing.T) {
want: &apb.CreateRolesResponse{},
wantErr: false,
},
{
name: "role with too short name should fail",
args: args{ctx: context.TODO(),
request: &apb.CreateRolesRequest{
Roles: []*apb.Role{
{
Name: "r1",
Description: "Role 1",
Permissions: []string{"permission 1", "permission 2"},
},
},
},
},
want: &apb.CreateRolesResponse{},
wantErr: true,
validationErrors: []*validate.Violation{
{
FieldPath: "roles[0].name",
ConstraintId: "string.min_len",
Message: "value length must be at least 3 characters",
}},
},
{
name: "role with too short description should fail",
args: args{ctx: context.TODO(),
request: &apb.CreateRolesRequest{
Roles: []*apb.Role{
{
Name: "new role 1",
Description: "r1",
Permissions: []string{"permission 1", "permission 2"},
},
},
},
},
want: &apb.CreateRolesResponse{},
wantErr: true,
validationErrors: []*validate.Violation{{
FieldPath: "roles[0].description",
ConstraintId: "string.min_len",
Message: "value length must be at least 3 characters",
}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
......@@ -74,6 +119,10 @@ func TestRole_CreateRoles(t *testing.T) {
t.Errorf("Role.CreateRoles() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.wantErr {
assertValidationErrors(t, err, tt.validationErrors)
}
})
}
}
......@@ -84,10 +133,11 @@ func TestRole_GetRole(t *testing.T) {
request *apb.GetRoleRequest
}
tests := []struct {
name string
args args
want *apb.GetRoleResponse
wantErr bool
name string
args args
want *apb.GetRoleResponse
wantErr bool
validationErrors []*validate.Violation
}{
{
name: "default get role",
......@@ -118,6 +168,25 @@ func TestRole_GetRole(t *testing.T) {
want: nil,
wantErr: true,
},
{
name: "error get role with missing name",
args: args{
ctx: context.TODO(),
request: &apb.GetRoleRequest{
RoleName: "",
Id: uuid.Nil.String(),
},
},
want: nil,
wantErr: true,
validationErrors: []*validate.Violation{
{
FieldPath: "role_name",
ConstraintId: "required",
Message: "value is required",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
......@@ -133,8 +202,8 @@ func TestRole_GetRole(t *testing.T) {
t.Errorf("Role.GetRole() = %v, want %v", got, tt.want)
}
} else {
if got != nil {
t.Errorf("Role.GetRole() = %v, want %v", got, tt.want)
if tt.wantErr {
assertValidationErrors(t, err, tt.validationErrors)
}
}
})
......@@ -199,7 +268,7 @@ func TestRole_GetRoles(t *testing.T) {
}
if got != nil {
if len(got.Roles) != 3 {
if len(got.Roles) != tt.wantLen {
t.Errorf("Role.GetRoles() = %v, want %v", got, tt.want)
}
for _, gotR := range got.Roles {
......@@ -228,10 +297,11 @@ func TestRole_UpdateRoles(t *testing.T) {
request *apb.UpdateRolesRequest
}
tests := []struct {
name string
args args
want *apb.UpdateRolesResponse
wantErr bool
name string
args args
want *apb.UpdateRolesResponse
wantErr bool
validationErrors []*validate.Violation
}{
{
name: "default update roles",
......@@ -267,6 +337,54 @@ func TestRole_UpdateRoles(t *testing.T) {
want: nil,
wantErr: true,
},
{
name: "error update roles with too short name",
args: args{
ctx: context.TODO(),
request: &apb.UpdateRolesRequest{
Roles: []*apb.Role{
{
Id: uuid.NewString(),
Name: "a",
Description: "Test role",
},
},
},
},
want: nil,
wantErr: true,
validationErrors: []*validate.Violation{
{
FieldPath: "roles[0].name",
ConstraintId: "string.min_len",
Message: "value length must be at least 3 characters",
},
},
},
{
name: "error update roles with too short description",
args: args{
ctx: context.TODO(),
request: &apb.UpdateRolesRequest{
Roles: []*apb.Role{
{
Id: uuid.NewString(),
Name: "My role",
Description: "r",
},
},
},
},
want: nil,
wantErr: true,
validationErrors: []*validate.Violation{
{
FieldPath: "roles[0].description",
ConstraintId: "string.min_len",
Message: "value length must be at least 3 characters",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
......@@ -276,6 +394,10 @@ func TestRole_UpdateRoles(t *testing.T) {
t.Errorf("Role.UpdateRoles() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.wantErr {
assertValidationErrors(t, err, tt.validationErrors)
}
})
}
}
......@@ -286,10 +408,11 @@ func TestRole_DeletePermissionsForRole(t *testing.T) {
request *apb.DeletePermissionsForRoleRequest
}
tests := []struct {
name string
args args
want *apb.DeletePermissionsForRoleResponse
wantErr bool
name string
args args
want *apb.DeletePermissionsForRoleResponse
wantErr bool
validationErrors []*validate.Violation
}{
{
name: "default delete permissions for role",
......@@ -320,6 +443,30 @@ func TestRole_DeletePermissionsForRole(t *testing.T) {
want: nil,
wantErr: true,
},
{
name: "error delete permissions for role with no proper name and permissions provided",
args: args{
ctx: context.TODO(),
request: &apb.DeletePermissionsForRoleRequest{
RoleName: "",
PermissionsToDelete: []string{},
},
},
want: nil,
wantErr: true,
validationErrors: []*validate.Violation{
{
FieldPath: "role_name",
ConstraintId: "required",
Message: "value is required",
},
{
FieldPath: "permissions_to_delete",
ConstraintId: "required",
Message: "value is required",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
......@@ -329,6 +476,10 @@ func TestRole_DeletePermissionsForRole(t *testing.T) {
t.Errorf("Role.DeletePermissionsForRole() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.wantErr {
assertValidationErrors(t, err, tt.validationErrors)
}
})
}
}
......@@ -339,10 +490,11 @@ func TestRole_DeleteRoles(t *testing.T) {
request *apb.DeleteRolesRequest
}
tests := []struct {
name string
args args
want *apb.DeleteRolesResponse
wantErr bool
name string
args args
want *apb.DeleteRolesResponse
wantErr bool
validationErrors []*validate.Violation
}{
{
name: "default delete roles",
......@@ -371,6 +523,26 @@ func TestRole_DeleteRoles(t *testing.T) {
want: &apb.DeleteRolesResponse{},
wantErr: true,
},
{
name: "error delete roles with missing role name",
args: args{
ctx: context.TODO(),
request: &apb.DeleteRolesRequest{
RoleName: []string{
"",
},
},
},
want: &apb.DeleteRolesResponse{},
wantErr: true,
validationErrors: []*validate.Violation{
{
FieldPath: "role_name",
ConstraintId: "required",
Message: "value is required",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
......@@ -381,6 +553,10 @@ func TestRole_DeleteRoles(t *testing.T) {
t.Errorf("Role.DeleteRoles() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.wantErr {
assertValidationErrors(t, err, tt.validationErrors)
}
})
}
}
......@@ -3,6 +3,7 @@ package server
import (
"context"
"encoding/base64"
"errors"
"fmt"
"time"
......@@ -20,6 +21,7 @@ import (
log "github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/reflect/protoreflect"
"golang.org/x/crypto/argon2"
)
......@@ -41,14 +43,33 @@ func NewUserServer(jwtManager *rbac.JWTManager, userService rbacInterfaces.UserS
}
}
func (r UserServer) checkForValidationErrors(request protoreflect.ProtoMessage) error {
err := r.protoValidator.Validate(request)
if err != nil {
var valErr *protovalidate.ValidationError
if ok := errors.As(err, &valErr); ok {
protoErr := valErr.ToProto()
grpcError, _ := status.New(codes.Aborted, "Validation failed").WithDetails(protoErr)
return grpcError.Err()
}
return status.Errorf(codes.Aborted, "%v", err)
}
return nil
}
// CreateUsers creates new users, can be 1 or more.
func (u UserServer) CreateUsers(ctx context.Context, request *apb.CreateUsersRequest) (*apb.CreateUsersResponse, error) {
labels := prometheus.Labels{"service": "auth", "rpc": "post"}
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
if err := u.protoValidator.Validate(request); err != nil {
return nil, status.Errorf(codes.Aborted, "%v", err)
err := u.checkForValidationErrors(request)
if err != nil {
return nil, err
}
for _, user := range request.User {
......@@ -90,8 +111,9 @@ func (u UserServer) GetUser(ctx context.Context, request *apb.GetUserRequest) (*
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
if err := u.protoValidator.Validate(request); err != nil {
return nil, status.Errorf(codes.Aborted, "%v", err)
err := u.checkForValidationErrors(request)
if err != nil {
return nil, err
}
userID, err := uuid.Parse(request.Id)
......@@ -125,8 +147,9 @@ func (u UserServer) GetUsers(ctx context.Context, request *apb.GetUsersRequest)
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
if err := u.protoValidator.Validate(request); err != nil {
return nil, status.Errorf(codes.Aborted, "%v", err)
err := u.checkForValidationErrors(request)
if err != nil {
return nil, err
}
userList, err := u.userService.GetAll()
......@@ -158,8 +181,9 @@ func (u UserServer) UpdateUsers(ctx context.Context, request *apb.UpdateUsersReq
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
if err := u.protoValidator.Validate(request); err != nil {
return nil, status.Errorf(codes.Aborted, "%v", err)
err := u.checkForValidationErrors(request)
if err != nil {
return nil, err
}
for _, user := range request.User {
......@@ -198,8 +222,9 @@ func (u UserServer) DeleteUsers(ctx context.Context, request *apb.DeleteUsersReq
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
if err := u.protoValidator.Validate(request); err != nil {
return nil, status.Errorf(codes.Aborted, "%v", err)
err := u.checkForValidationErrors(request)
if err != nil {
return nil, err
}
for _, user := range request.Username {
......
......@@ -2,10 +2,10 @@ package server
import (
"context"
"fmt"
"testing"
"time"
"buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate"
"code.fbi.h-da.de/danet/gosdn/api/go/gosdn/conflict"
apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
eventservice "code.fbi.h-da.de/danet/gosdn/controller/eventService"
......@@ -44,9 +44,10 @@ func TestUser_CreateUsers(t *testing.T) {
request *apb.CreateUsersRequest
}
tests := []struct {
name string
args args
wantErr bool
name string
args args
wantErr bool
validationErrors []*validate.Violation
}{
{
name: "default create users",
......@@ -87,6 +88,38 @@ func TestUser_CreateUsers(t *testing.T) {
},
},
wantErr: true,
validationErrors: []*validate.Violation{
{
FieldPath: "user[0].password",
ConstraintId: "string.min_len",
Message: "value length must be at least 5 characters",
}},
},
{
name: "create users with too short username should fail",
args: args{
ctx: context.TODO(),
request: &apb.CreateUsersRequest{
User: []*apb.User{
{
Name: "a",
Roles: map[string]string{pndID: "userTestRole"},
Password: "password",
Token: "",
Metadata: &conflict.Metadata{
ResourceVersion: 0,
},
},
},
},
},
wantErr: true,
validationErrors: []*validate.Violation{
{
FieldPath: "user[0].name",
ConstraintId: "string.min_len",
Message: "value length must be at least 3 characters",
}},
},
}
for _, tt := range tests {
......@@ -97,7 +130,10 @@ func TestUser_CreateUsers(t *testing.T) {
t.Errorf("User.CreateUsers() error = %v, wantErr %v", err, tt.wantErr)
return
}
fmt.Printf("err %+v,want no error\n", err)
if tt.wantErr {
assertValidationErrors(t, err, tt.validationErrors)
}
})
}
}
......@@ -109,10 +145,11 @@ func TestUser_GetUser(t *testing.T) {
request *apb.GetUserRequest
}
tests := []struct {
name string
args args
want *apb.GetUserResponse
wantErr bool
name string
args args
want *apb.GetUserResponse
wantErr bool
validationErrors []*validate.Violation
}{
{
name: "default get user",
......@@ -140,6 +177,24 @@ func TestUser_GetUser(t *testing.T) {
want: nil,
wantErr: true,
},
{
name: "fail get user due to missing name",
args: args{
ctx: context.TODO(),
request: &apb.GetUserRequest{
Name: "",
Id: uuid.Nil.String(),
},
},
want: nil,
wantErr: true,
validationErrors: []*validate.Violation{
{
FieldPath: "name",
ConstraintId: "required",
Message: "value is required",
}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
......@@ -150,6 +205,10 @@ func TestUser_GetUser(t *testing.T) {
return
}
if tt.wantErr {
assertValidationErrors(t, err, tt.validationErrors)
}
if got != nil {
if got.User.Name != tt.want.User.Name || got.User.Id != tt.want.User.Id {
t.Errorf("User.GetUser() = %v, want %v", got, tt.want)
......@@ -230,10 +289,11 @@ func TestUser_UpdateUsers(t *testing.T) {
request *apb.UpdateUsersRequest
}
tests := []struct {
name string
args args
want *apb.UpdateUsersResponse
wantErr bool
name string
args args
want *apb.UpdateUsersResponse
wantErr bool
validationErrors []*validate.Violation
}{
{
name: "default update user",
......@@ -266,7 +326,7 @@ func TestUser_UpdateUsers(t *testing.T) {
wantErr: true,
},
{
name: "update user without name should fail",
name: "update user without name should fail validation",
args: args{ctx: context.TODO(),
request: &apb.UpdateUsersRequest{User: []*apb.UpdateUser{
{
......@@ -279,6 +339,13 @@ func TestUser_UpdateUsers(t *testing.T) {
},
want: nil,
wantErr: true,
validationErrors: []*validate.Violation{
{
FieldPath: "name",
ConstraintId: "required",
Message: "value is required",
},
},
},
}
......@@ -290,6 +357,10 @@ func TestUser_UpdateUsers(t *testing.T) {
t.Errorf("User.UpdateUsers() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.wantErr {
assertValidationErrors(t, err, tt.validationErrors)
}
})
}
}
......@@ -300,10 +371,11 @@ func TestUser_DeleteUsers(t *testing.T) {
request *apb.DeleteUsersRequest
}
tests := []struct {
name string
args args
want *apb.DeleteUsersResponse
wantErr bool
name string
args args
want *apb.DeleteUsersResponse
wantErr bool
validationErrors []*validate.Violation
}{
{
name: "default delete users",
......@@ -314,13 +386,28 @@ func TestUser_DeleteUsers(t *testing.T) {
wantErr: false,
},
{
name: "error delete users",
name: "error delete users for non existing user",
args: args{ctx: context.TODO(),
request: &apb.DeleteUsersRequest{Username: []string{"no user"}},
},
want: &apb.DeleteUsersResponse{},
wantErr: true,
},
{
name: "error delete users due to missing name",
args: args{ctx: context.TODO(),
request: &apb.DeleteUsersRequest{Username: []string{""}},
},
want: &apb.DeleteUsersResponse{},
wantErr: true,
validationErrors: []*validate.Violation{
{
FieldPath: "name",
ConstraintId: "required",
Message: "value is required",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
......@@ -330,6 +417,10 @@ func TestUser_DeleteUsers(t *testing.T) {
t.Errorf("User.DeleteUsers() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.wantErr {
assertValidationErrors(t, err, tt.validationErrors)
}
})
}
}
package server
import (
"testing"
"buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate"
"google.golang.org/grpc/status"
)
func contains(array []*validate.Violation, err *validate.Violation) bool {
for _, v := range array {
if v.FieldPath == err.FieldPath && v.ConstraintId == err.ConstraintId && v.Message == err.Message {
return true
}
}
return false
}
func assertValidationErrors(t *testing.T, err error, expectedValidationErrors []*validate.Violation) {
st := status.Convert(err)
errDetails := st.Details()
for _, detail := range errDetails {
switch errorType := detail.(type) {
case *validate.Violations:
for _, violation := range errorType.Violations {
ok := contains(expectedValidationErrors, violation)
if !ok {
t.Errorf("Received unexptected validation error: %v, expected %v", violation, expectedValidationErrors)
}
}
}
}
}
......@@ -89,12 +89,12 @@ require (
)
require (
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20230824200731-b9b8148056b9.1
github.com/bufbuild/protovalidate-go v0.3.1
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20230914171853-63dfe56cc2c4.1
github.com/bufbuild/protovalidate-go v0.3.3
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-plugin v1.4.10
github.com/lesismal/nbio v1.3.17
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb
)
require (
......@@ -104,7 +104,7 @@ require (
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 // indirect
github.com/containerd/console v1.0.3 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/google/cel-go v0.17.4 // indirect
github.com/google/cel-go v0.18.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-hclog v1.5.0 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
......@@ -115,6 +115,6 @@ require (
github.com/moby/sys/sequential v0.5.0 // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/stoewer/go-strcase v1.3.0 // indirect
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb // indirect
)
......@@ -10,6 +10,8 @@ bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxo
bazil.org/fuse v0.0.0-20200407214033-5883e5a4b512/go.mod h1:FbcW6z/2VytnFDhZfumh8Ss8zxHE6qpMP5sHTRe0EaM=
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20230824200731-b9b8148056b9.1 h1:9Ea7lsYYvoyqmq79GbCy6POXHrZbC+pHs+6lGNx9IBQ=
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20230824200731-b9b8148056b9.1/go.mod h1:xafc+XIsTxTy76GJQ1TKgvJWsSugFBqMaN27WhUblew=
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20230914171853-63dfe56cc2c4.1 h1:2gmp+PRca1fqQHf/WMKOgu9inVb0R0N07TucgY3QZCQ=
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20230914171853-63dfe56cc2c4.1/go.mod h1:xafc+XIsTxTy76GJQ1TKgvJWsSugFBqMaN27WhUblew=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
......@@ -152,6 +154,8 @@ github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dR
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
github.com/bufbuild/protovalidate-go v0.3.1 h1:+jbgQXo+7SzttLbGwVClpHowXKEgwK1QG/bK4xrmUy8=
github.com/bufbuild/protovalidate-go v0.3.1/go.mod h1:oD/fAR3ojBAunOmY3SGFJ4jhILpUtnuIalI4Id9rluY=
github.com/bufbuild/protovalidate-go v0.3.3 h1:H7tKyIhvQAbODKN0aoAxohaPOAnccG6wSS71e86zoLg=
github.com/bufbuild/protovalidate-go v0.3.3/go.mod h1:36yOYnOgeU1gtdIC/J+SKt+jww0gXMW5j/KZzgYuOJU=
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
......@@ -483,6 +487,8 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/cel-go v0.17.4 h1:9556LOjSyIZlgnT0oaCYGq2uk9BM6fzuTXhzYHskonk=
github.com/google/cel-go v0.17.4/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY=
github.com/google/cel-go v0.18.1 h1:V/lAXKq4C3BYLDy/ARzMtpkEEYfHQpZzVyzy69nEUjs=
github.com/google/cel-go v0.18.1/go.mod h1:PVAybmSnWkNMUZR/tEWFUiJ1Np4Hz0MHsZJcgC4zln4=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
......@@ -1125,6 +1131,8 @@ golang.org/x/exp v0.0.0-20230809094429-853ea248256d h1:wu5bD43Ana/nF1ZmaLr3lW/FQ
golang.org/x/exp v0.0.0-20230809094429-853ea248256d/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
......@@ -1551,8 +1559,12 @@ google.golang.org/genproto v0.0.0-20230807174057-1744710a1577 h1:Tyk/35yqszRCvar
google.golang.org/genproto v0.0.0-20230807174057-1744710a1577/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q=
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb h1:lK0oleSc7IQsUxO3U5TjL9DWlsxpEBemh+zpB7IqhWI=
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb h1:Isk1sSH7bovx8Rti2wZK0UZF6oraBDK74uoyLEEVFN0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
......
......@@ -2,7 +2,7 @@ ARG GOLANG_VERSION=1.21
ARG BUILDARGS
ARG $GITLAB_PROXY
FROM ${GITLAB_PROXY}golang:$GOLANG_VERSION-bullseye as builder
FROM ${GITLAB_PROXY}golang:$GOLANG_VERSION-bookworm as builder
WORKDIR /plugin-registry/
RUN apt-get update
RUN apt-get -y install --no-install-recommends zip
......
......@@ -2,7 +2,7 @@ ARG GOLANG_VERSION=1.21
ARG BUILDARGS
ARG $GITLAB_PROXY
FROM ${GITLAB_PROXY}golang:$GOLANG_VERSION-bullseye as builder
FROM ${GITLAB_PROXY}golang:$GOLANG_VERSION-bookworm as builder
WORKDIR /plugin-registry/
RUN apt-get update
RUN apt-get -y install --no-install-recommends zip
......