fix: add action v2 execution to features (#7597)

* fix: add action v2 execution to features

* fix: add action v2 execution to features

* fix: add action v2 execution to features

* fix: update internal/command/instance_features_model.go

Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>

* fix: merge back main

* fix: merge back main

* fix: rename feature and service

* fix: rename feature and service

* fix: review changes

* fix: review changes

---------

Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>
This commit is contained in:
Stefan Benz
2024-04-09 19:21:21 +02:00
committed by GitHub
parent 6a51c4b0f5
commit 6dcdef0268
52 changed files with 1069 additions and 737 deletions

View File

@@ -34,9 +34,9 @@ import (
"github.com/zitadel/zitadel/internal/api" "github.com/zitadel/zitadel/internal/api"
"github.com/zitadel/zitadel/internal/api/assets" "github.com/zitadel/zitadel/internal/api/assets"
internal_authz "github.com/zitadel/zitadel/internal/api/authz" internal_authz "github.com/zitadel/zitadel/internal/api/authz"
action_v3_alpha "github.com/zitadel/zitadel/internal/api/grpc/action/v3alpha"
"github.com/zitadel/zitadel/internal/api/grpc/admin" "github.com/zitadel/zitadel/internal/api/grpc/admin"
"github.com/zitadel/zitadel/internal/api/grpc/auth" "github.com/zitadel/zitadel/internal/api/grpc/auth"
execution_v3_alpha "github.com/zitadel/zitadel/internal/api/grpc/execution/v3alpha"
"github.com/zitadel/zitadel/internal/api/grpc/feature/v2" "github.com/zitadel/zitadel/internal/api/grpc/feature/v2"
"github.com/zitadel/zitadel/internal/api/grpc/management" "github.com/zitadel/zitadel/internal/api/grpc/management"
oidc_v2 "github.com/zitadel/zitadel/internal/api/grpc/oidc/v2" oidc_v2 "github.com/zitadel/zitadel/internal/api/grpc/oidc/v2"
@@ -408,7 +408,7 @@ func startAPIs(
if err := apis.RegisterService(ctx, feature.CreateServer(commands, queries)); err != nil { if err := apis.RegisterService(ctx, feature.CreateServer(commands, queries)); err != nil {
return nil, err return nil, err
} }
if err := apis.RegisterService(ctx, execution_v3_alpha.CreateServer(commands, queries, domain.AllFunctions, apis.ListGrpcMethods, apis.ListGrpcServices)); err != nil { if err := apis.RegisterService(ctx, action_v3_alpha.CreateServer(commands, queries, domain.AllFunctions, apis.ListGrpcMethods, apis.ListGrpcServices)); err != nil {
return nil, err return nil, err
} }
if err := apis.RegisterService(ctx, user_schema_v3_alpha.CreateServer(commands, queries)); err != nil { if err := apis.RegisterService(ctx, user_schema_v3_alpha.CreateServer(commands, queries)); err != nil {

View File

@@ -310,9 +310,9 @@ module.exports = {
groupPathsBy: "tag", groupPathsBy: "tag",
}, },
}, },
execution_v3: { action_v3: {
specPath: ".artifacts/openapi/zitadel/execution/v3alpha/execution_service.swagger.json", specPath: ".artifacts/openapi/zitadel/action/v3alpha/action_service.swagger.json",
outputDir: "docs/apis/resources/execution_service_v3", outputDir: "docs/apis/resources/action_service_v3",
sidebarOptions: { sidebarOptions: {
groupPathsBy: "tag", groupPathsBy: "tag",
}, },

View File

@@ -732,17 +732,17 @@ module.exports = {
}, },
{ {
type: "category", type: "category",
label: "Execution Lifecycle (Preview)", label: "Action Lifecycle (Preview)",
link: { link: {
type: "generated-index", type: "generated-index",
title: "Execution Service API (Preview)", title: "Action Service API (Preview)",
slug: "/apis/resources/execution_service_v3", slug: "/apis/resources/action_service_v3",
description: description:
"This API is intended to manage custom executions (previously known as actions) in a ZITADEL instance.\n" + "This API is intended to manage custom executions and targets (previously known as actions) in a ZITADEL instance.\n" +
"\n" + "\n" +
"This project is in Preview state. It can AND will continue breaking until the services provide the same functionality as the current actions.", "This project is in Preview state. It can AND will continue breaking until the services provide the same functionality as the current actions.",
}, },
items: require("./docs/apis/resources/execution_service_v3/sidebar.js"), items: require("./docs/apis/resources/action_service_v3/sidebar.js"),
}, },
], ],
}, },

View File

@@ -1,4 +1,4 @@
package execution package action
import ( import (
"context" "context"
@@ -7,28 +7,32 @@ import (
"github.com/zitadel/zitadel/internal/api/grpc/object/v2" "github.com/zitadel/zitadel/internal/api/grpc/object/v2"
"github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
execution "github.com/zitadel/zitadel/pkg/grpc/execution/v3alpha" action "github.com/zitadel/zitadel/pkg/grpc/action/v3alpha"
) )
func (s *Server) ListExecutionFunctions(_ context.Context, _ *execution.ListExecutionFunctionsRequest) (*execution.ListExecutionFunctionsResponse, error) { func (s *Server) ListExecutionFunctions(_ context.Context, _ *action.ListExecutionFunctionsRequest) (*action.ListExecutionFunctionsResponse, error) {
return &execution.ListExecutionFunctionsResponse{ return &action.ListExecutionFunctionsResponse{
Functions: s.ListActionFunctions(), Functions: s.ListActionFunctions(),
}, nil }, nil
} }
func (s *Server) ListExecutionMethods(_ context.Context, _ *execution.ListExecutionMethodsRequest) (*execution.ListExecutionMethodsResponse, error) { func (s *Server) ListExecutionMethods(_ context.Context, _ *action.ListExecutionMethodsRequest) (*action.ListExecutionMethodsResponse, error) {
return &execution.ListExecutionMethodsResponse{ return &action.ListExecutionMethodsResponse{
Methods: s.ListGRPCMethods(), Methods: s.ListGRPCMethods(),
}, nil }, nil
} }
func (s *Server) ListExecutionServices(_ context.Context, _ *execution.ListExecutionServicesRequest) (*execution.ListExecutionServicesResponse, error) { func (s *Server) ListExecutionServices(_ context.Context, _ *action.ListExecutionServicesRequest) (*action.ListExecutionServicesResponse, error) {
return &execution.ListExecutionServicesResponse{ return &action.ListExecutionServicesResponse{
Services: s.ListGRPCServices(), Services: s.ListGRPCServices(),
}, nil }, nil
} }
func (s *Server) SetExecution(ctx context.Context, req *execution.SetExecutionRequest) (*execution.SetExecutionResponse, error) { func (s *Server) SetExecution(ctx context.Context, req *action.SetExecutionRequest) (*action.SetExecutionResponse, error) {
if err := checkExecutionEnabled(ctx); err != nil {
return nil, err
}
set := &command.SetExecution{ set := &command.SetExecution{
Targets: req.GetTargets(), Targets: req.GetTargets(),
Includes: req.GetIncludes(), Includes: req.GetIncludes(),
@@ -37,7 +41,7 @@ func (s *Server) SetExecution(ctx context.Context, req *execution.SetExecutionRe
var err error var err error
var details *domain.ObjectDetails var details *domain.ObjectDetails
switch t := req.GetCondition().GetConditionType().(type) { switch t := req.GetCondition().GetConditionType().(type) {
case *execution.Condition_Request: case *action.Condition_Request:
cond := &command.ExecutionAPICondition{ cond := &command.ExecutionAPICondition{
Method: t.Request.GetMethod(), Method: t.Request.GetMethod(),
Service: t.Request.GetService(), Service: t.Request.GetService(),
@@ -47,7 +51,7 @@ func (s *Server) SetExecution(ctx context.Context, req *execution.SetExecutionRe
if err != nil { if err != nil {
return nil, err return nil, err
} }
case *execution.Condition_Response: case *action.Condition_Response:
cond := &command.ExecutionAPICondition{ cond := &command.ExecutionAPICondition{
Method: t.Response.GetMethod(), Method: t.Response.GetMethod(),
Service: t.Response.GetService(), Service: t.Response.GetService(),
@@ -57,7 +61,7 @@ func (s *Server) SetExecution(ctx context.Context, req *execution.SetExecutionRe
if err != nil { if err != nil {
return nil, err return nil, err
} }
case *execution.Condition_Event: case *action.Condition_Event:
cond := &command.ExecutionEventCondition{ cond := &command.ExecutionEventCondition{
Event: t.Event.GetEvent(), Event: t.Event.GetEvent(),
Group: t.Event.GetGroup(), Group: t.Event.GetGroup(),
@@ -67,22 +71,26 @@ func (s *Server) SetExecution(ctx context.Context, req *execution.SetExecutionRe
if err != nil { if err != nil {
return nil, err return nil, err
} }
case *execution.Condition_Function: case *action.Condition_Function:
details, err = s.command.SetExecutionFunction(ctx, command.ExecutionFunctionCondition(t.Function), set, authz.GetInstance(ctx).InstanceID()) details, err = s.command.SetExecutionFunction(ctx, command.ExecutionFunctionCondition(t.Function), set, authz.GetInstance(ctx).InstanceID())
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
return &execution.SetExecutionResponse{ return &action.SetExecutionResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
}, nil }, nil
} }
func (s *Server) DeleteExecution(ctx context.Context, req *execution.DeleteExecutionRequest) (*execution.DeleteExecutionResponse, error) { func (s *Server) DeleteExecution(ctx context.Context, req *action.DeleteExecutionRequest) (*action.DeleteExecutionResponse, error) {
if err := checkExecutionEnabled(ctx); err != nil {
return nil, err
}
var err error var err error
var details *domain.ObjectDetails var details *domain.ObjectDetails
switch t := req.GetCondition().GetConditionType().(type) { switch t := req.GetCondition().GetConditionType().(type) {
case *execution.Condition_Request: case *action.Condition_Request:
cond := &command.ExecutionAPICondition{ cond := &command.ExecutionAPICondition{
Method: t.Request.GetMethod(), Method: t.Request.GetMethod(),
Service: t.Request.GetService(), Service: t.Request.GetService(),
@@ -92,7 +100,7 @@ func (s *Server) DeleteExecution(ctx context.Context, req *execution.DeleteExecu
if err != nil { if err != nil {
return nil, err return nil, err
} }
case *execution.Condition_Response: case *action.Condition_Response:
cond := &command.ExecutionAPICondition{ cond := &command.ExecutionAPICondition{
Method: t.Response.GetMethod(), Method: t.Response.GetMethod(),
Service: t.Response.GetService(), Service: t.Response.GetService(),
@@ -102,7 +110,7 @@ func (s *Server) DeleteExecution(ctx context.Context, req *execution.DeleteExecu
if err != nil { if err != nil {
return nil, err return nil, err
} }
case *execution.Condition_Event: case *action.Condition_Event:
cond := &command.ExecutionEventCondition{ cond := &command.ExecutionEventCondition{
Event: t.Event.GetEvent(), Event: t.Event.GetEvent(),
Group: t.Event.GetGroup(), Group: t.Event.GetGroup(),
@@ -112,13 +120,13 @@ func (s *Server) DeleteExecution(ctx context.Context, req *execution.DeleteExecu
if err != nil { if err != nil {
return nil, err return nil, err
} }
case *execution.Condition_Function: case *action.Condition_Function:
details, err = s.command.DeleteExecutionFunction(ctx, command.ExecutionFunctionCondition(t.Function), authz.GetInstance(ctx).InstanceID()) details, err = s.command.DeleteExecutionFunction(ctx, command.ExecutionFunctionCondition(t.Function), authz.GetInstance(ctx).InstanceID())
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
return &execution.DeleteExecutionResponse{ return &action.DeleteExecutionResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
}, nil }, nil
} }

View File

@@ -1,4 +1,4 @@
package execution package action
import ( import (
"context" "context"
@@ -10,10 +10,14 @@ import (
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/internal/zerrors" "github.com/zitadel/zitadel/internal/zerrors"
execution "github.com/zitadel/zitadel/pkg/grpc/execution/v3alpha" action "github.com/zitadel/zitadel/pkg/grpc/action/v3alpha"
) )
func (s *Server) ListTargets(ctx context.Context, req *execution.ListTargetsRequest) (*execution.ListTargetsResponse, error) { func (s *Server) ListTargets(ctx context.Context, req *action.ListTargetsRequest) (*action.ListTargetsResponse, error) {
if err := checkExecutionEnabled(ctx); err != nil {
return nil, err
}
queries, err := listTargetsRequestToModel(req) queries, err := listTargetsRequestToModel(req)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -22,13 +26,13 @@ func (s *Server) ListTargets(ctx context.Context, req *execution.ListTargetsRequ
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &execution.ListTargetsResponse{ return &action.ListTargetsResponse{
Result: targetsToPb(resp.Targets), Result: targetsToPb(resp.Targets),
Details: object.ToListDetails(resp.SearchResponse), Details: object.ToListDetails(resp.SearchResponse),
}, nil }, nil
} }
func listTargetsRequestToModel(req *execution.ListTargetsRequest) (*query.TargetSearchQueries, error) { func listTargetsRequestToModel(req *action.ListTargetsRequest) (*query.TargetSearchQueries, error) {
offset, limit, asc := object.ListQueryToQuery(req.Query) offset, limit, asc := object.ListQueryToQuery(req.Query)
queries, err := targetQueriesToQuery(req.Queries) queries, err := targetQueriesToQuery(req.Queries)
if err != nil { if err != nil {
@@ -45,34 +49,34 @@ func listTargetsRequestToModel(req *execution.ListTargetsRequest) (*query.Target
}, nil }, nil
} }
func targetFieldNameToSortingColumn(field execution.TargetFieldName) query.Column { func targetFieldNameToSortingColumn(field action.TargetFieldName) query.Column {
switch field { switch field {
case execution.TargetFieldName_FIELD_NAME_UNSPECIFIED: case action.TargetFieldName_FIELD_NAME_UNSPECIFIED:
return query.TargetColumnID return query.TargetColumnID
case execution.TargetFieldName_FIELD_NAME_ID: case action.TargetFieldName_FIELD_NAME_ID:
return query.TargetColumnID return query.TargetColumnID
case execution.TargetFieldName_FIELD_NAME_CREATION_DATE: case action.TargetFieldName_FIELD_NAME_CREATION_DATE:
return query.TargetColumnCreationDate return query.TargetColumnCreationDate
case execution.TargetFieldName_FIELD_NAME_CHANGE_DATE: case action.TargetFieldName_FIELD_NAME_CHANGE_DATE:
return query.TargetColumnChangeDate return query.TargetColumnChangeDate
case execution.TargetFieldName_FIELD_NAME_NAME: case action.TargetFieldName_FIELD_NAME_NAME:
return query.TargetColumnName return query.TargetColumnName
case execution.TargetFieldName_FIELD_NAME_TARGET_TYPE: case action.TargetFieldName_FIELD_NAME_TARGET_TYPE:
return query.TargetColumnTargetType return query.TargetColumnTargetType
case execution.TargetFieldName_FIELD_NAME_URL: case action.TargetFieldName_FIELD_NAME_URL:
return query.TargetColumnURL return query.TargetColumnURL
case execution.TargetFieldName_FIELD_NAME_TIMEOUT: case action.TargetFieldName_FIELD_NAME_TIMEOUT:
return query.TargetColumnTimeout return query.TargetColumnTimeout
case execution.TargetFieldName_FIELD_NAME_ASYNC: case action.TargetFieldName_FIELD_NAME_ASYNC:
return query.TargetColumnAsync return query.TargetColumnAsync
case execution.TargetFieldName_FIELD_NAME_INTERRUPT_ON_ERROR: case action.TargetFieldName_FIELD_NAME_INTERRUPT_ON_ERROR:
return query.TargetColumnInterruptOnError return query.TargetColumnInterruptOnError
default: default:
return query.TargetColumnID return query.TargetColumnID
} }
} }
func targetQueriesToQuery(queries []*execution.TargetSearchQuery) (_ []query.SearchQuery, err error) { func targetQueriesToQuery(queries []*action.TargetSearchQuery) (_ []query.SearchQuery, err error) {
q := make([]query.SearchQuery, len(queries)) q := make([]query.SearchQuery, len(queries))
for i, query := range queries { for i, query := range queries {
q[i], err = targetQueryToQuery(query) q[i], err = targetQueryToQuery(query)
@@ -83,69 +87,77 @@ func targetQueriesToQuery(queries []*execution.TargetSearchQuery) (_ []query.Sea
return q, nil return q, nil
} }
func targetQueryToQuery(query *execution.TargetSearchQuery) (query.SearchQuery, error) { func targetQueryToQuery(query *action.TargetSearchQuery) (query.SearchQuery, error) {
switch q := query.Query.(type) { switch q := query.Query.(type) {
case *execution.TargetSearchQuery_TargetNameQuery: case *action.TargetSearchQuery_TargetNameQuery:
return targetNameQueryToQuery(q.TargetNameQuery) return targetNameQueryToQuery(q.TargetNameQuery)
case *execution.TargetSearchQuery_InTargetIdsQuery: case *action.TargetSearchQuery_InTargetIdsQuery:
return targetInTargetIdsQueryToQuery(q.InTargetIdsQuery) return targetInTargetIdsQueryToQuery(q.InTargetIdsQuery)
default: default:
return nil, zerrors.ThrowInvalidArgument(nil, "GRPC-vR9nC", "List.Query.Invalid") return nil, zerrors.ThrowInvalidArgument(nil, "GRPC-vR9nC", "List.Query.Invalid")
} }
} }
func targetNameQueryToQuery(q *execution.TargetNameQuery) (query.SearchQuery, error) { func targetNameQueryToQuery(q *action.TargetNameQuery) (query.SearchQuery, error) {
return query.NewTargetNameSearchQuery(object.TextMethodToQuery(q.Method), q.GetTargetName()) return query.NewTargetNameSearchQuery(object.TextMethodToQuery(q.Method), q.GetTargetName())
} }
func targetInTargetIdsQueryToQuery(q *execution.InTargetIDsQuery) (query.SearchQuery, error) { func targetInTargetIdsQueryToQuery(q *action.InTargetIDsQuery) (query.SearchQuery, error) {
return query.NewTargetInIDsSearchQuery(q.GetTargetIds()) return query.NewTargetInIDsSearchQuery(q.GetTargetIds())
} }
func (s *Server) GetTargetByID(ctx context.Context, req *execution.GetTargetByIDRequest) (_ *execution.GetTargetByIDResponse, err error) { func (s *Server) GetTargetByID(ctx context.Context, req *action.GetTargetByIDRequest) (_ *action.GetTargetByIDResponse, err error) {
if err := checkExecutionEnabled(ctx); err != nil {
return nil, err
}
resp, err := s.query.GetTargetByID(ctx, req.GetTargetId()) resp, err := s.query.GetTargetByID(ctx, req.GetTargetId())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &execution.GetTargetByIDResponse{ return &action.GetTargetByIDResponse{
Target: targetToPb(resp), Target: targetToPb(resp),
}, nil }, nil
} }
func targetsToPb(targets []*query.Target) []*execution.Target { func targetsToPb(targets []*query.Target) []*action.Target {
t := make([]*execution.Target, len(targets)) t := make([]*action.Target, len(targets))
for i, target := range targets { for i, target := range targets {
t[i] = targetToPb(target) t[i] = targetToPb(target)
} }
return t return t
} }
func targetToPb(t *query.Target) *execution.Target { func targetToPb(t *query.Target) *action.Target {
target := &execution.Target{ target := &action.Target{
Details: object.DomainToDetailsPb(&t.ObjectDetails), Details: object.DomainToDetailsPb(&t.ObjectDetails),
TargetId: t.ID, TargetId: t.ID,
Name: t.Name, Name: t.Name,
Timeout: durationpb.New(t.Timeout), Timeout: durationpb.New(t.Timeout),
} }
if t.Async { if t.Async {
target.ExecutionType = &execution.Target_IsAsync{IsAsync: t.Async} target.ExecutionType = &action.Target_IsAsync{IsAsync: t.Async}
} }
if t.InterruptOnError { if t.InterruptOnError {
target.ExecutionType = &execution.Target_InterruptOnError{InterruptOnError: t.InterruptOnError} target.ExecutionType = &action.Target_InterruptOnError{InterruptOnError: t.InterruptOnError}
} }
switch t.TargetType { switch t.TargetType {
case domain.TargetTypeWebhook: case domain.TargetTypeWebhook:
target.TargetType = &execution.Target_RestWebhook{RestWebhook: &execution.SetRESTWebhook{Url: t.URL}} target.TargetType = &action.Target_RestWebhook{RestWebhook: &action.SetRESTWebhook{Url: t.URL}}
case domain.TargetTypeRequestResponse: case domain.TargetTypeRequestResponse:
target.TargetType = &execution.Target_RestRequestResponse{RestRequestResponse: &execution.SetRESTRequestResponse{Url: t.URL}} target.TargetType = &action.Target_RestRequestResponse{RestRequestResponse: &action.SetRESTRequestResponse{Url: t.URL}}
default: default:
target.TargetType = nil target.TargetType = nil
} }
return target return target
} }
func (s *Server) ListExecutions(ctx context.Context, req *execution.ListExecutionsRequest) (*execution.ListExecutionsResponse, error) { func (s *Server) ListExecutions(ctx context.Context, req *action.ListExecutionsRequest) (*action.ListExecutionsResponse, error) {
if err := checkExecutionEnabled(ctx); err != nil {
return nil, err
}
queries, err := listExecutionsRequestToModel(req) queries, err := listExecutionsRequestToModel(req)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -154,13 +166,13 @@ func (s *Server) ListExecutions(ctx context.Context, req *execution.ListExecutio
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &execution.ListExecutionsResponse{ return &action.ListExecutionsResponse{
Result: executionsToPb(resp.Executions), Result: executionsToPb(resp.Executions),
Details: object.ToListDetails(resp.SearchResponse), Details: object.ToListDetails(resp.SearchResponse),
}, nil }, nil
} }
func listExecutionsRequestToModel(req *execution.ListExecutionsRequest) (*query.ExecutionSearchQueries, error) { func listExecutionsRequestToModel(req *action.ListExecutionsRequest) (*query.ExecutionSearchQueries, error) {
offset, limit, asc := object.ListQueryToQuery(req.Query) offset, limit, asc := object.ListQueryToQuery(req.Query)
queries, err := executionQueriesToQuery(req.Queries) queries, err := executionQueriesToQuery(req.Queries)
if err != nil { if err != nil {
@@ -176,7 +188,7 @@ func listExecutionsRequestToModel(req *execution.ListExecutionsRequest) (*query.
}, nil }, nil
} }
func executionQueriesToQuery(queries []*execution.SearchQuery) (_ []query.SearchQuery, err error) { func executionQueriesToQuery(queries []*action.SearchQuery) (_ []query.SearchQuery, err error) {
q := make([]query.SearchQuery, len(queries)) q := make([]query.SearchQuery, len(queries))
for i, query := range queries { for i, query := range queries {
q[i], err = executionQueryToQuery(query) q[i], err = executionQueryToQuery(query)
@@ -187,39 +199,39 @@ func executionQueriesToQuery(queries []*execution.SearchQuery) (_ []query.Search
return q, nil return q, nil
} }
func executionQueryToQuery(searchQuery *execution.SearchQuery) (query.SearchQuery, error) { func executionQueryToQuery(searchQuery *action.SearchQuery) (query.SearchQuery, error) {
switch q := searchQuery.Query.(type) { switch q := searchQuery.Query.(type) {
case *execution.SearchQuery_InConditionsQuery: case *action.SearchQuery_InConditionsQuery:
return inConditionsQueryToQuery(q.InConditionsQuery) return inConditionsQueryToQuery(q.InConditionsQuery)
case *execution.SearchQuery_ExecutionTypeQuery: case *action.SearchQuery_ExecutionTypeQuery:
return executionTypeToQuery(q.ExecutionTypeQuery) return executionTypeToQuery(q.ExecutionTypeQuery)
case *execution.SearchQuery_TargetQuery: case *action.SearchQuery_TargetQuery:
return query.NewExecutionTargetSearchQuery(q.TargetQuery.GetTargetId()) return query.NewExecutionTargetSearchQuery(q.TargetQuery.GetTargetId())
case *execution.SearchQuery_IncludeQuery: case *action.SearchQuery_IncludeQuery:
return query.NewExecutionIncludeSearchQuery(q.IncludeQuery.GetInclude()) return query.NewExecutionIncludeSearchQuery(q.IncludeQuery.GetInclude())
default: default:
return nil, zerrors.ThrowInvalidArgument(nil, "GRPC-vR9nC", "List.Query.Invalid") return nil, zerrors.ThrowInvalidArgument(nil, "GRPC-vR9nC", "List.Query.Invalid")
} }
} }
func executionTypeToQuery(q *execution.ExecutionTypeQuery) (query.SearchQuery, error) { func executionTypeToQuery(q *action.ExecutionTypeQuery) (query.SearchQuery, error) {
switch q.ExecutionType { switch q.ExecutionType {
case execution.ExecutionType_EXECUTION_TYPE_UNSPECIFIED: case action.ExecutionType_EXECUTION_TYPE_UNSPECIFIED:
return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeUnspecified) return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeUnspecified)
case execution.ExecutionType_EXECUTION_TYPE_REQUEST: case action.ExecutionType_EXECUTION_TYPE_REQUEST:
return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeRequest) return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeRequest)
case execution.ExecutionType_EXECUTION_TYPE_RESPONSE: case action.ExecutionType_EXECUTION_TYPE_RESPONSE:
return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeResponse) return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeResponse)
case execution.ExecutionType_EXECUTION_TYPE_EVENT: case action.ExecutionType_EXECUTION_TYPE_EVENT:
return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeEvent) return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeEvent)
case execution.ExecutionType_EXECUTION_TYPE_FUNCTION: case action.ExecutionType_EXECUTION_TYPE_FUNCTION:
return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeFunction) return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeFunction)
default: default:
return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeUnspecified) return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeUnspecified)
} }
} }
func inConditionsQueryToQuery(q *execution.InConditionsQuery) (query.SearchQuery, error) { func inConditionsQueryToQuery(q *action.InConditionsQuery) (query.SearchQuery, error) {
values := make([]string, len(q.GetConditions())) values := make([]string, len(q.GetConditions()))
for i, condition := range q.GetConditions() { for i, condition := range q.GetConditions() {
id, err := conditionToID(condition) id, err := conditionToID(condition)
@@ -231,45 +243,45 @@ func inConditionsQueryToQuery(q *execution.InConditionsQuery) (query.SearchQuery
return query.NewExecutionInIDsSearchQuery(values) return query.NewExecutionInIDsSearchQuery(values)
} }
func conditionToID(q *execution.Condition) (string, error) { func conditionToID(q *action.Condition) (string, error) {
switch t := q.GetConditionType().(type) { switch t := q.GetConditionType().(type) {
case *execution.Condition_Request: case *action.Condition_Request:
cond := &command.ExecutionAPICondition{ cond := &command.ExecutionAPICondition{
Method: t.Request.GetMethod(), Method: t.Request.GetMethod(),
Service: t.Request.GetService(), Service: t.Request.GetService(),
All: t.Request.GetAll(), All: t.Request.GetAll(),
} }
return cond.ID(domain.ExecutionTypeRequest), nil return cond.ID(domain.ExecutionTypeRequest), nil
case *execution.Condition_Response: case *action.Condition_Response:
cond := &command.ExecutionAPICondition{ cond := &command.ExecutionAPICondition{
Method: t.Response.GetMethod(), Method: t.Response.GetMethod(),
Service: t.Response.GetService(), Service: t.Response.GetService(),
All: t.Response.GetAll(), All: t.Response.GetAll(),
} }
return cond.ID(domain.ExecutionTypeResponse), nil return cond.ID(domain.ExecutionTypeResponse), nil
case *execution.Condition_Event: case *action.Condition_Event:
cond := &command.ExecutionEventCondition{ cond := &command.ExecutionEventCondition{
Event: t.Event.GetEvent(), Event: t.Event.GetEvent(),
Group: t.Event.GetGroup(), Group: t.Event.GetGroup(),
All: t.Event.GetAll(), All: t.Event.GetAll(),
} }
return cond.ID(), nil return cond.ID(), nil
case *execution.Condition_Function: case *action.Condition_Function:
return t.Function, nil return t.Function, nil
default: default:
return "", zerrors.ThrowInvalidArgument(nil, "GRPC-vR9nC", "List.Query.Invalid") return "", zerrors.ThrowInvalidArgument(nil, "GRPC-vR9nC", "List.Query.Invalid")
} }
} }
func executionsToPb(executions []*query.Execution) []*execution.Execution { func executionsToPb(executions []*query.Execution) []*action.Execution {
e := make([]*execution.Execution, len(executions)) e := make([]*action.Execution, len(executions))
for i, execution := range executions { for i, execution := range executions {
e[i] = executionToPb(execution) e[i] = executionToPb(execution)
} }
return e return e
} }
func executionToPb(e *query.Execution) *execution.Execution { func executionToPb(e *query.Execution) *action.Execution {
var targets, includes []string var targets, includes []string
if len(e.Targets) > 0 { if len(e.Targets) > 0 {
targets = e.Targets targets = e.Targets
@@ -277,7 +289,7 @@ func executionToPb(e *query.Execution) *execution.Execution {
if len(e.Includes) > 0 { if len(e.Includes) > 0 {
includes = e.Includes includes = e.Includes
} }
return &execution.Execution{ return &action.Execution{
Details: object.DomainToDetailsPb(&e.ObjectDetails), Details: object.DomainToDetailsPb(&e.ObjectDetails),
ExecutionId: e.ID, ExecutionId: e.ID,
Targets: targets, Targets: targets,

View File

@@ -1,6 +1,6 @@
//go:build integration //go:build integration
package execution_test package action_test
import ( import (
"context" "context"
@@ -13,27 +13,28 @@ import (
"google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/durationpb"
"github.com/zitadel/zitadel/internal/integration" "github.com/zitadel/zitadel/internal/integration"
execution "github.com/zitadel/zitadel/pkg/grpc/execution/v3alpha" action "github.com/zitadel/zitadel/pkg/grpc/action/v3alpha"
object "github.com/zitadel/zitadel/pkg/grpc/object/v2beta" object "github.com/zitadel/zitadel/pkg/grpc/object/v2beta"
) )
func TestServer_GetTargetByID(t *testing.T) { func TestServer_GetTargetByID(t *testing.T) {
ensureFeatureEnabled(t)
type args struct { type args struct {
ctx context.Context ctx context.Context
dep func(context.Context, *execution.GetTargetByIDRequest, *execution.GetTargetByIDResponse) error dep func(context.Context, *action.GetTargetByIDRequest, *action.GetTargetByIDResponse) error
req *execution.GetTargetByIDRequest req *action.GetTargetByIDRequest
} }
tests := []struct { tests := []struct {
name string name string
args args args args
want *execution.GetTargetByIDResponse want *action.GetTargetByIDResponse
wantErr bool wantErr bool
}{ }{
{ {
name: "missing permission", name: "missing permission",
args: args{ args: args{
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner), ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
req: &execution.GetTargetByIDRequest{}, req: &action.GetTargetByIDRequest{},
}, },
wantErr: true, wantErr: true,
}, },
@@ -41,7 +42,7 @@ func TestServer_GetTargetByID(t *testing.T) {
name: "not found", name: "not found",
args: args{ args: args{
ctx: CTX, ctx: CTX,
req: &execution.GetTargetByIDRequest{TargetId: "notexisting"}, req: &action.GetTargetByIDRequest{TargetId: "notexisting"},
}, },
wantErr: true, wantErr: true,
}, },
@@ -49,7 +50,7 @@ func TestServer_GetTargetByID(t *testing.T) {
name: "get, ok", name: "get, ok",
args: args{ args: args{
ctx: CTX, ctx: CTX,
dep: func(ctx context.Context, request *execution.GetTargetByIDRequest, response *execution.GetTargetByIDResponse) error { dep: func(ctx context.Context, request *action.GetTargetByIDRequest, response *action.GetTargetByIDResponse) error {
name := fmt.Sprint(time.Now().UnixNano() + 1) name := fmt.Sprint(time.Now().UnixNano() + 1)
resp := Tester.CreateTargetWithNameAndType(ctx, t, name, false, false) resp := Tester.CreateTargetWithNameAndType(ctx, t, name, false, false)
request.TargetId = resp.GetId() request.TargetId = resp.GetId()
@@ -61,15 +62,15 @@ func TestServer_GetTargetByID(t *testing.T) {
response.Target.Details.Sequence = resp.GetDetails().GetSequence() response.Target.Details.Sequence = resp.GetDetails().GetSequence()
return nil return nil
}, },
req: &execution.GetTargetByIDRequest{}, req: &action.GetTargetByIDRequest{},
}, },
want: &execution.GetTargetByIDResponse{ want: &action.GetTargetByIDResponse{
Target: &execution.Target{ Target: &action.Target{
Details: &object.Details{ Details: &object.Details{
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),
}, },
TargetType: &execution.Target_RestWebhook{ TargetType: &action.Target_RestWebhook{
RestWebhook: &execution.SetRESTWebhook{ RestWebhook: &action.SetRESTWebhook{
Url: "https://example.com", Url: "https://example.com",
}, },
}, },
@@ -81,7 +82,7 @@ func TestServer_GetTargetByID(t *testing.T) {
name: "get, async, ok", name: "get, async, ok",
args: args{ args: args{
ctx: CTX, ctx: CTX,
dep: func(ctx context.Context, request *execution.GetTargetByIDRequest, response *execution.GetTargetByIDResponse) error { dep: func(ctx context.Context, request *action.GetTargetByIDRequest, response *action.GetTargetByIDResponse) error {
name := fmt.Sprint(time.Now().UnixNano() + 1) name := fmt.Sprint(time.Now().UnixNano() + 1)
resp := Tester.CreateTargetWithNameAndType(ctx, t, name, true, false) resp := Tester.CreateTargetWithNameAndType(ctx, t, name, true, false)
request.TargetId = resp.GetId() request.TargetId = resp.GetId()
@@ -93,20 +94,20 @@ func TestServer_GetTargetByID(t *testing.T) {
response.Target.Details.Sequence = resp.GetDetails().GetSequence() response.Target.Details.Sequence = resp.GetDetails().GetSequence()
return nil return nil
}, },
req: &execution.GetTargetByIDRequest{}, req: &action.GetTargetByIDRequest{},
}, },
want: &execution.GetTargetByIDResponse{ want: &action.GetTargetByIDResponse{
Target: &execution.Target{ Target: &action.Target{
Details: &object.Details{ Details: &object.Details{
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),
}, },
TargetType: &execution.Target_RestWebhook{ TargetType: &action.Target_RestWebhook{
RestWebhook: &execution.SetRESTWebhook{ RestWebhook: &action.SetRESTWebhook{
Url: "https://example.com", Url: "https://example.com",
}, },
}, },
Timeout: durationpb.New(10 * time.Second), Timeout: durationpb.New(10 * time.Second),
ExecutionType: &execution.Target_IsAsync{IsAsync: true}, ExecutionType: &action.Target_IsAsync{IsAsync: true},
}, },
}, },
}, },
@@ -114,7 +115,7 @@ func TestServer_GetTargetByID(t *testing.T) {
name: "get, interruptOnError, ok", name: "get, interruptOnError, ok",
args: args{ args: args{
ctx: CTX, ctx: CTX,
dep: func(ctx context.Context, request *execution.GetTargetByIDRequest, response *execution.GetTargetByIDResponse) error { dep: func(ctx context.Context, request *action.GetTargetByIDRequest, response *action.GetTargetByIDResponse) error {
name := fmt.Sprint(time.Now().UnixNano() + 1) name := fmt.Sprint(time.Now().UnixNano() + 1)
resp := Tester.CreateTargetWithNameAndType(ctx, t, name, false, true) resp := Tester.CreateTargetWithNameAndType(ctx, t, name, false, true)
request.TargetId = resp.GetId() request.TargetId = resp.GetId()
@@ -126,20 +127,20 @@ func TestServer_GetTargetByID(t *testing.T) {
response.Target.Details.Sequence = resp.GetDetails().GetSequence() response.Target.Details.Sequence = resp.GetDetails().GetSequence()
return nil return nil
}, },
req: &execution.GetTargetByIDRequest{}, req: &action.GetTargetByIDRequest{},
}, },
want: &execution.GetTargetByIDResponse{ want: &action.GetTargetByIDResponse{
Target: &execution.Target{ Target: &action.Target{
Details: &object.Details{ Details: &object.Details{
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),
}, },
TargetType: &execution.Target_RestWebhook{ TargetType: &action.Target_RestWebhook{
RestWebhook: &execution.SetRESTWebhook{ RestWebhook: &action.SetRESTWebhook{
Url: "https://example.com", Url: "https://example.com",
}, },
}, },
Timeout: durationpb.New(10 * time.Second), Timeout: durationpb.New(10 * time.Second),
ExecutionType: &execution.Target_InterruptOnError{InterruptOnError: true}, ExecutionType: &action.Target_InterruptOnError{InterruptOnError: true},
}, },
}, },
}, },
@@ -178,22 +179,23 @@ func TestServer_GetTargetByID(t *testing.T) {
} }
func TestServer_ListTargets(t *testing.T) { func TestServer_ListTargets(t *testing.T) {
ensureFeatureEnabled(t)
type args struct { type args struct {
ctx context.Context ctx context.Context
dep func(context.Context, *execution.ListTargetsRequest, *execution.ListTargetsResponse) error dep func(context.Context, *action.ListTargetsRequest, *action.ListTargetsResponse) error
req *execution.ListTargetsRequest req *action.ListTargetsRequest
} }
tests := []struct { tests := []struct {
name string name string
args args args args
want *execution.ListTargetsResponse want *action.ListTargetsResponse
wantErr bool wantErr bool
}{ }{
{ {
name: "missing permission", name: "missing permission",
args: args{ args: args{
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner), ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
req: &execution.ListTargetsRequest{}, req: &action.ListTargetsRequest{},
}, },
wantErr: true, wantErr: true,
}, },
@@ -201,10 +203,10 @@ func TestServer_ListTargets(t *testing.T) {
name: "list, not found", name: "list, not found",
args: args{ args: args{
ctx: CTX, ctx: CTX,
req: &execution.ListTargetsRequest{ req: &action.ListTargetsRequest{
Queries: []*execution.TargetSearchQuery{ Queries: []*action.TargetSearchQuery{
{Query: &execution.TargetSearchQuery_InTargetIdsQuery{ {Query: &action.TargetSearchQuery_InTargetIdsQuery{
InTargetIdsQuery: &execution.InTargetIDsQuery{ InTargetIdsQuery: &action.InTargetIDsQuery{
TargetIds: []string{"notfound"}, TargetIds: []string{"notfound"},
}, },
}, },
@@ -212,22 +214,22 @@ func TestServer_ListTargets(t *testing.T) {
}, },
}, },
}, },
want: &execution.ListTargetsResponse{ want: &action.ListTargetsResponse{
Details: &object.ListDetails{ Details: &object.ListDetails{
TotalResult: 0, TotalResult: 0,
}, },
Result: []*execution.Target{}, Result: []*action.Target{},
}, },
}, },
{ {
name: "list single id", name: "list single id",
args: args{ args: args{
ctx: CTX, ctx: CTX,
dep: func(ctx context.Context, request *execution.ListTargetsRequest, response *execution.ListTargetsResponse) error { dep: func(ctx context.Context, request *action.ListTargetsRequest, response *action.ListTargetsResponse) error {
name := fmt.Sprint(time.Now().UnixNano() + 1) name := fmt.Sprint(time.Now().UnixNano() + 1)
resp := Tester.CreateTargetWithNameAndType(ctx, t, name, false, false) resp := Tester.CreateTargetWithNameAndType(ctx, t, name, false, false)
request.Queries[0].Query = &execution.TargetSearchQuery_InTargetIdsQuery{ request.Queries[0].Query = &action.TargetSearchQuery_InTargetIdsQuery{
InTargetIdsQuery: &execution.InTargetIDsQuery{ InTargetIdsQuery: &action.InTargetIDsQuery{
TargetIds: []string{resp.GetId()}, TargetIds: []string{resp.GetId()},
}, },
} }
@@ -240,21 +242,21 @@ func TestServer_ListTargets(t *testing.T) {
response.Result[0].Name = name response.Result[0].Name = name
return nil return nil
}, },
req: &execution.ListTargetsRequest{ req: &action.ListTargetsRequest{
Queries: []*execution.TargetSearchQuery{{}}, Queries: []*action.TargetSearchQuery{{}},
}, },
}, },
want: &execution.ListTargetsResponse{ want: &action.ListTargetsResponse{
Details: &object.ListDetails{ Details: &object.ListDetails{
TotalResult: 1, TotalResult: 1,
}, },
Result: []*execution.Target{ Result: []*action.Target{
{ {
Details: &object.Details{ Details: &object.Details{
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),
}, },
TargetType: &execution.Target_RestWebhook{ TargetType: &action.Target_RestWebhook{
RestWebhook: &execution.SetRESTWebhook{ RestWebhook: &action.SetRESTWebhook{
Url: "https://example.com", Url: "https://example.com",
}, },
}, },
@@ -266,11 +268,11 @@ func TestServer_ListTargets(t *testing.T) {
name: "list single name", name: "list single name",
args: args{ args: args{
ctx: CTX, ctx: CTX,
dep: func(ctx context.Context, request *execution.ListTargetsRequest, response *execution.ListTargetsResponse) error { dep: func(ctx context.Context, request *action.ListTargetsRequest, response *action.ListTargetsResponse) error {
name := fmt.Sprint(time.Now().UnixNano() + 1) name := fmt.Sprint(time.Now().UnixNano() + 1)
resp := Tester.CreateTargetWithNameAndType(ctx, t, name, false, false) resp := Tester.CreateTargetWithNameAndType(ctx, t, name, false, false)
request.Queries[0].Query = &execution.TargetSearchQuery_TargetNameQuery{ request.Queries[0].Query = &action.TargetSearchQuery_TargetNameQuery{
TargetNameQuery: &execution.TargetNameQuery{ TargetNameQuery: &action.TargetNameQuery{
TargetName: name, TargetName: name,
}, },
} }
@@ -283,21 +285,21 @@ func TestServer_ListTargets(t *testing.T) {
response.Result[0].Name = name response.Result[0].Name = name
return nil return nil
}, },
req: &execution.ListTargetsRequest{ req: &action.ListTargetsRequest{
Queries: []*execution.TargetSearchQuery{{}}, Queries: []*action.TargetSearchQuery{{}},
}, },
}, },
want: &execution.ListTargetsResponse{ want: &action.ListTargetsResponse{
Details: &object.ListDetails{ Details: &object.ListDetails{
TotalResult: 1, TotalResult: 1,
}, },
Result: []*execution.Target{ Result: []*action.Target{
{ {
Details: &object.Details{ Details: &object.Details{
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),
}, },
TargetType: &execution.Target_RestWebhook{ TargetType: &action.Target_RestWebhook{
RestWebhook: &execution.SetRESTWebhook{ RestWebhook: &action.SetRESTWebhook{
Url: "https://example.com", Url: "https://example.com",
}, },
}, },
@@ -310,15 +312,15 @@ func TestServer_ListTargets(t *testing.T) {
name: "list multiple id", name: "list multiple id",
args: args{ args: args{
ctx: CTX, ctx: CTX,
dep: func(ctx context.Context, request *execution.ListTargetsRequest, response *execution.ListTargetsResponse) error { dep: func(ctx context.Context, request *action.ListTargetsRequest, response *action.ListTargetsResponse) error {
name1 := fmt.Sprint(time.Now().UnixNano() + 1) name1 := fmt.Sprint(time.Now().UnixNano() + 1)
name2 := fmt.Sprint(time.Now().UnixNano() + 3) name2 := fmt.Sprint(time.Now().UnixNano() + 3)
name3 := fmt.Sprint(time.Now().UnixNano() + 5) name3 := fmt.Sprint(time.Now().UnixNano() + 5)
resp1 := Tester.CreateTargetWithNameAndType(ctx, t, name1, false, false) resp1 := Tester.CreateTargetWithNameAndType(ctx, t, name1, false, false)
resp2 := Tester.CreateTargetWithNameAndType(ctx, t, name2, true, false) resp2 := Tester.CreateTargetWithNameAndType(ctx, t, name2, true, false)
resp3 := Tester.CreateTargetWithNameAndType(ctx, t, name3, false, true) resp3 := Tester.CreateTargetWithNameAndType(ctx, t, name3, false, true)
request.Queries[0].Query = &execution.TargetSearchQuery_InTargetIdsQuery{ request.Queries[0].Query = &action.TargetSearchQuery_InTargetIdsQuery{
InTargetIdsQuery: &execution.InTargetIDsQuery{ InTargetIdsQuery: &action.InTargetIDsQuery{
TargetIds: []string{resp1.GetId(), resp2.GetId(), resp3.GetId()}, TargetIds: []string{resp1.GetId(), resp2.GetId(), resp3.GetId()},
}, },
} }
@@ -339,21 +341,21 @@ func TestServer_ListTargets(t *testing.T) {
response.Result[2].Name = name3 response.Result[2].Name = name3
return nil return nil
}, },
req: &execution.ListTargetsRequest{ req: &action.ListTargetsRequest{
Queries: []*execution.TargetSearchQuery{{}}, Queries: []*action.TargetSearchQuery{{}},
}, },
}, },
want: &execution.ListTargetsResponse{ want: &action.ListTargetsResponse{
Details: &object.ListDetails{ Details: &object.ListDetails{
TotalResult: 3, TotalResult: 3,
}, },
Result: []*execution.Target{ Result: []*action.Target{
{ {
Details: &object.Details{ Details: &object.Details{
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),
}, },
TargetType: &execution.Target_RestWebhook{ TargetType: &action.Target_RestWebhook{
RestWebhook: &execution.SetRESTWebhook{ RestWebhook: &action.SetRESTWebhook{
Url: "https://example.com", Url: "https://example.com",
}, },
}, },
@@ -363,25 +365,25 @@ func TestServer_ListTargets(t *testing.T) {
Details: &object.Details{ Details: &object.Details{
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),
}, },
TargetType: &execution.Target_RestWebhook{ TargetType: &action.Target_RestWebhook{
RestWebhook: &execution.SetRESTWebhook{ RestWebhook: &action.SetRESTWebhook{
Url: "https://example.com", Url: "https://example.com",
}, },
}, },
Timeout: durationpb.New(10 * time.Second), Timeout: durationpb.New(10 * time.Second),
ExecutionType: &execution.Target_IsAsync{IsAsync: true}, ExecutionType: &action.Target_IsAsync{IsAsync: true},
}, },
{ {
Details: &object.Details{ Details: &object.Details{
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),
}, },
TargetType: &execution.Target_RestWebhook{ TargetType: &action.Target_RestWebhook{
RestWebhook: &execution.SetRESTWebhook{ RestWebhook: &action.SetRESTWebhook{
Url: "https://example.com", Url: "https://example.com",
}, },
}, },
Timeout: durationpb.New(10 * time.Second), Timeout: durationpb.New(10 * time.Second),
ExecutionType: &execution.Target_InterruptOnError{InterruptOnError: true}, ExecutionType: &action.Target_InterruptOnError{InterruptOnError: true},
}, },
}, },
}, },
@@ -421,24 +423,25 @@ func TestServer_ListTargets(t *testing.T) {
} }
func TestServer_ListExecutions_Request(t *testing.T) { func TestServer_ListExecutions_Request(t *testing.T) {
ensureFeatureEnabled(t)
targetResp := Tester.CreateTarget(CTX, t) targetResp := Tester.CreateTarget(CTX, t)
type args struct { type args struct {
ctx context.Context ctx context.Context
dep func(context.Context, *execution.ListExecutionsRequest, *execution.ListExecutionsResponse) error dep func(context.Context, *action.ListExecutionsRequest, *action.ListExecutionsResponse) error
req *execution.ListExecutionsRequest req *action.ListExecutionsRequest
} }
tests := []struct { tests := []struct {
name string name string
args args args args
want *execution.ListExecutionsResponse want *action.ListExecutionsResponse
wantErr bool wantErr bool
}{ }{
{ {
name: "missing permission", name: "missing permission",
args: args{ args: args{
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner), ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
req: &execution.ListExecutionsRequest{}, req: &action.ListExecutionsRequest{},
}, },
wantErr: true, wantErr: true,
}, },
@@ -446,7 +449,7 @@ func TestServer_ListExecutions_Request(t *testing.T) {
name: "list single condition", name: "list single condition",
args: args{ args: args{
ctx: CTX, ctx: CTX,
dep: func(ctx context.Context, request *execution.ListExecutionsRequest, response *execution.ListExecutionsResponse) error { dep: func(ctx context.Context, request *action.ListExecutionsRequest, response *action.ListExecutionsResponse) error {
resp := Tester.SetExecution(ctx, t, request.Queries[0].GetInConditionsQuery().GetConditions()[0], []string{targetResp.GetId()}, []string{}) resp := Tester.SetExecution(ctx, t, request.Queries[0].GetInConditionsQuery().GetConditions()[0], []string{targetResp.GetId()}, []string{})
response.Details.Timestamp = resp.GetDetails().GetChangeDate() response.Details.Timestamp = resp.GetDetails().GetChangeDate()
@@ -456,14 +459,14 @@ func TestServer_ListExecutions_Request(t *testing.T) {
response.Result[0].Details.Sequence = resp.GetDetails().GetSequence() response.Result[0].Details.Sequence = resp.GetDetails().GetSequence()
return nil return nil
}, },
req: &execution.ListExecutionsRequest{ req: &action.ListExecutionsRequest{
Queries: []*execution.SearchQuery{{ Queries: []*action.SearchQuery{{
Query: &execution.SearchQuery_InConditionsQuery{ Query: &action.SearchQuery_InConditionsQuery{
InConditionsQuery: &execution.InConditionsQuery{ InConditionsQuery: &action.InConditionsQuery{
Conditions: []*execution.Condition{{ Conditions: []*action.Condition{{
ConditionType: &execution.Condition_Request{ ConditionType: &action.Condition_Request{
Request: &execution.RequestExecution{ Request: &action.RequestExecution{
Condition: &execution.RequestExecution_Method{ Condition: &action.RequestExecution_Method{
Method: "/zitadel.session.v2beta.SessionService/GetSession", Method: "/zitadel.session.v2beta.SessionService/GetSession",
}, },
}, },
@@ -475,11 +478,11 @@ func TestServer_ListExecutions_Request(t *testing.T) {
}}, }},
}, },
}, },
want: &execution.ListExecutionsResponse{ want: &action.ListExecutionsResponse{
Details: &object.ListDetails{ Details: &object.ListDetails{
TotalResult: 1, TotalResult: 1,
}, },
Result: []*execution.Execution{ Result: []*action.Execution{
{ {
Details: &object.Details{ Details: &object.Details{
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),
@@ -494,20 +497,20 @@ func TestServer_ListExecutions_Request(t *testing.T) {
name: "list single target", name: "list single target",
args: args{ args: args{
ctx: CTX, ctx: CTX,
dep: func(ctx context.Context, request *execution.ListExecutionsRequest, response *execution.ListExecutionsResponse) error { dep: func(ctx context.Context, request *action.ListExecutionsRequest, response *action.ListExecutionsResponse) error {
target := Tester.CreateTarget(ctx, t) target := Tester.CreateTarget(ctx, t)
// add target as query to the request // add target as query to the request
request.Queries[0] = &execution.SearchQuery{ request.Queries[0] = &action.SearchQuery{
Query: &execution.SearchQuery_TargetQuery{ Query: &action.SearchQuery_TargetQuery{
TargetQuery: &execution.TargetQuery{ TargetQuery: &action.TargetQuery{
TargetId: target.GetId(), TargetId: target.GetId(),
}, },
}, },
} }
resp := Tester.SetExecution(ctx, t, &execution.Condition{ resp := Tester.SetExecution(ctx, t, &action.Condition{
ConditionType: &execution.Condition_Request{ ConditionType: &action.Condition_Request{
Request: &execution.RequestExecution{ Request: &action.RequestExecution{
Condition: &execution.RequestExecution_Method{ Condition: &action.RequestExecution_Method{
Method: "/zitadel.management.v1.ManagementService/UpdateAction", Method: "/zitadel.management.v1.ManagementService/UpdateAction",
}, },
}, },
@@ -522,15 +525,15 @@ func TestServer_ListExecutions_Request(t *testing.T) {
response.Result[0].Targets[0] = target.GetId() response.Result[0].Targets[0] = target.GetId()
return nil return nil
}, },
req: &execution.ListExecutionsRequest{ req: &action.ListExecutionsRequest{
Queries: []*execution.SearchQuery{{}}, Queries: []*action.SearchQuery{{}},
}, },
}, },
want: &execution.ListExecutionsResponse{ want: &action.ListExecutionsResponse{
Details: &object.ListDetails{ Details: &object.ListDetails{
TotalResult: 1, TotalResult: 1,
}, },
Result: []*execution.Execution{ Result: []*action.Execution{
{ {
Details: &object.Details{ Details: &object.Details{
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),
@@ -544,20 +547,20 @@ func TestServer_ListExecutions_Request(t *testing.T) {
name: "list single include", name: "list single include",
args: args{ args: args{
ctx: CTX, ctx: CTX,
dep: func(ctx context.Context, request *execution.ListExecutionsRequest, response *execution.ListExecutionsResponse) error { dep: func(ctx context.Context, request *action.ListExecutionsRequest, response *action.ListExecutionsResponse) error {
Tester.SetExecution(ctx, t, &execution.Condition{ Tester.SetExecution(ctx, t, &action.Condition{
ConditionType: &execution.Condition_Request{ ConditionType: &action.Condition_Request{
Request: &execution.RequestExecution{ Request: &action.RequestExecution{
Condition: &execution.RequestExecution_Method{ Condition: &action.RequestExecution_Method{
Method: "/zitadel.management.v1.ManagementService/GetAction", Method: "/zitadel.management.v1.ManagementService/GetAction",
}, },
}, },
}, },
}, []string{targetResp.GetId()}, []string{}) }, []string{targetResp.GetId()}, []string{})
resp2 := Tester.SetExecution(ctx, t, &execution.Condition{ resp2 := Tester.SetExecution(ctx, t, &action.Condition{
ConditionType: &execution.Condition_Request{ ConditionType: &action.Condition_Request{
Request: &execution.RequestExecution{ Request: &action.RequestExecution{
Condition: &execution.RequestExecution_Method{ Condition: &action.RequestExecution_Method{
Method: "/zitadel.management.v1.ManagementService/ListActions", Method: "/zitadel.management.v1.ManagementService/ListActions",
}, },
}, },
@@ -571,19 +574,19 @@ func TestServer_ListExecutions_Request(t *testing.T) {
response.Result[0].Details.Sequence = resp2.GetDetails().GetSequence() response.Result[0].Details.Sequence = resp2.GetDetails().GetSequence()
return nil return nil
}, },
req: &execution.ListExecutionsRequest{ req: &action.ListExecutionsRequest{
Queries: []*execution.SearchQuery{{ Queries: []*action.SearchQuery{{
Query: &execution.SearchQuery_IncludeQuery{ Query: &action.SearchQuery_IncludeQuery{
IncludeQuery: &execution.IncludeQuery{Include: "request./zitadel.management.v1.ManagementService/GetAction"}, IncludeQuery: &action.IncludeQuery{Include: "request./zitadel.management.v1.ManagementService/GetAction"},
}, },
}}, }},
}, },
}, },
want: &execution.ListExecutionsResponse{ want: &action.ListExecutionsResponse{
Details: &object.ListDetails{ Details: &object.ListDetails{
TotalResult: 1, TotalResult: 1,
}, },
Result: []*execution.Execution{ Result: []*action.Execution{
{ {
Details: &object.Details{ Details: &object.Details{
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),
@@ -598,7 +601,7 @@ func TestServer_ListExecutions_Request(t *testing.T) {
name: "list multiple conditions", name: "list multiple conditions",
args: args{ args: args{
ctx: CTX, ctx: CTX,
dep: func(ctx context.Context, request *execution.ListExecutionsRequest, response *execution.ListExecutionsResponse) error { dep: func(ctx context.Context, request *action.ListExecutionsRequest, response *action.ListExecutionsResponse) error {
resp1 := Tester.SetExecution(ctx, t, request.Queries[0].GetInConditionsQuery().GetConditions()[0], []string{targetResp.GetId()}, []string{}) resp1 := Tester.SetExecution(ctx, t, request.Queries[0].GetInConditionsQuery().GetConditions()[0], []string{targetResp.GetId()}, []string{})
response.Result[0].Details.ChangeDate = resp1.GetDetails().GetChangeDate() response.Result[0].Details.ChangeDate = resp1.GetDetails().GetChangeDate()
@@ -615,33 +618,33 @@ func TestServer_ListExecutions_Request(t *testing.T) {
response.Result[2].Details.Sequence = resp3.GetDetails().GetSequence() response.Result[2].Details.Sequence = resp3.GetDetails().GetSequence()
return nil return nil
}, },
req: &execution.ListExecutionsRequest{ req: &action.ListExecutionsRequest{
Queries: []*execution.SearchQuery{{ Queries: []*action.SearchQuery{{
Query: &execution.SearchQuery_InConditionsQuery{ Query: &action.SearchQuery_InConditionsQuery{
InConditionsQuery: &execution.InConditionsQuery{ InConditionsQuery: &action.InConditionsQuery{
Conditions: []*execution.Condition{ Conditions: []*action.Condition{
{ {
ConditionType: &execution.Condition_Request{ ConditionType: &action.Condition_Request{
Request: &execution.RequestExecution{ Request: &action.RequestExecution{
Condition: &execution.RequestExecution_Method{ Condition: &action.RequestExecution_Method{
Method: "/zitadel.session.v2beta.SessionService/GetSession", Method: "/zitadel.session.v2beta.SessionService/GetSession",
}, },
}, },
}, },
}, },
{ {
ConditionType: &execution.Condition_Request{ ConditionType: &action.Condition_Request{
Request: &execution.RequestExecution{ Request: &action.RequestExecution{
Condition: &execution.RequestExecution_Method{ Condition: &action.RequestExecution_Method{
Method: "/zitadel.session.v2beta.SessionService/CreateSession", Method: "/zitadel.session.v2beta.SessionService/CreateSession",
}, },
}, },
}, },
}, },
{ {
ConditionType: &execution.Condition_Request{ ConditionType: &action.Condition_Request{
Request: &execution.RequestExecution{ Request: &action.RequestExecution{
Condition: &execution.RequestExecution_Method{ Condition: &action.RequestExecution_Method{
Method: "/zitadel.session.v2beta.SessionService/SetSession", Method: "/zitadel.session.v2beta.SessionService/SetSession",
}, },
}, },
@@ -653,11 +656,11 @@ func TestServer_ListExecutions_Request(t *testing.T) {
}}, }},
}, },
}, },
want: &execution.ListExecutionsResponse{ want: &action.ListExecutionsResponse{
Details: &object.ListDetails{ Details: &object.ListDetails{
TotalResult: 3, TotalResult: 3,
}, },
Result: []*execution.Execution{ Result: []*action.Execution{
{ {
Details: &object.Details{ Details: &object.Details{
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),

View File

@@ -1,19 +1,22 @@
package execution package action
import ( import (
"context"
"google.golang.org/grpc" "google.golang.org/grpc"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/server" "github.com/zitadel/zitadel/internal/api/grpc/server"
"github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/query"
execution "github.com/zitadel/zitadel/pkg/grpc/execution/v3alpha" "github.com/zitadel/zitadel/internal/zerrors"
action "github.com/zitadel/zitadel/pkg/grpc/action/v3alpha"
) )
var _ execution.ExecutionServiceServer = (*Server)(nil) var _ action.ActionServiceServer = (*Server)(nil)
type Server struct { type Server struct {
execution.UnimplementedExecutionServiceServer action.UnimplementedActionServiceServer
command *command.Commands command *command.Commands
query *query.Queries query *query.Queries
ListActionFunctions func() []string ListActionFunctions func() []string
@@ -40,21 +43,28 @@ func CreateServer(
} }
func (s *Server) RegisterServer(grpcServer *grpc.Server) { func (s *Server) RegisterServer(grpcServer *grpc.Server) {
execution.RegisterExecutionServiceServer(grpcServer, s) action.RegisterActionServiceServer(grpcServer, s)
} }
func (s *Server) AppName() string { func (s *Server) AppName() string {
return execution.ExecutionService_ServiceDesc.ServiceName return action.ActionService_ServiceDesc.ServiceName
} }
func (s *Server) MethodPrefix() string { func (s *Server) MethodPrefix() string {
return execution.ExecutionService_ServiceDesc.ServiceName return action.ActionService_ServiceDesc.ServiceName
} }
func (s *Server) AuthMethods() authz.MethodMapping { func (s *Server) AuthMethods() authz.MethodMapping {
return execution.ExecutionService_AuthMethods return action.ActionService_AuthMethods
} }
func (s *Server) RegisterGateway() server.RegisterGatewayFunc { func (s *Server) RegisterGateway() server.RegisterGatewayFunc {
return execution.RegisterExecutionServiceHandler return action.RegisterActionServiceHandler
}
func checkExecutionEnabled(ctx context.Context) error {
if authz.GetInstance(ctx).Features().Actions {
return nil
}
return zerrors.ThrowPreconditionFailed(nil, "SCHEMA-141bwx3lef", "Errors.action.NotEnabled")
} }

View File

@@ -0,0 +1,69 @@
//go:build integration
package action_test
import (
"context"
"os"
"testing"
"time"
"github.com/muhlemmer/gu"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zitadel/zitadel/internal/integration"
action "github.com/zitadel/zitadel/pkg/grpc/action/v3alpha"
feature "github.com/zitadel/zitadel/pkg/grpc/feature/v2beta"
)
var (
CTX context.Context
Tester *integration.Tester
Client action.ActionServiceClient
)
func TestMain(m *testing.M) {
os.Exit(func() int {
ctx, errCtx, cancel := integration.Contexts(5 * time.Minute)
defer cancel()
Tester = integration.NewTester(ctx)
defer Tester.Done()
Client = Tester.Client.ActionV3
CTX, _ = Tester.WithAuthorization(ctx, integration.IAMOwner), errCtx
return m.Run()
}())
}
func ensureFeatureEnabled(t *testing.T) {
f, err := Tester.Client.FeatureV2.GetInstanceFeatures(CTX, &feature.GetInstanceFeaturesRequest{
Inheritance: true,
})
require.NoError(t, err)
if f.Actions.GetEnabled() {
return
}
_, err = Tester.Client.FeatureV2.SetInstanceFeatures(CTX, &feature.SetInstanceFeaturesRequest{
Actions: gu.Ptr(true),
})
require.NoError(t, err)
retryDuration := time.Minute
if ctxDeadline, ok := CTX.Deadline(); ok {
retryDuration = time.Until(ctxDeadline)
}
require.EventuallyWithT(t,
func(ttt *assert.CollectT) {
f, err := Tester.Client.FeatureV2.GetInstanceFeatures(CTX, &feature.GetInstanceFeaturesRequest{
Inheritance: true,
})
require.NoError(ttt, err)
if f.Actions.GetEnabled() {
return
}
},
retryDuration,
100*time.Millisecond,
"timed out waiting for ensuring instance feature")
}

View File

@@ -1,4 +1,4 @@
package execution package action
import ( import (
"context" "context"
@@ -10,49 +10,61 @@ import (
"github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore/v1/models" "github.com/zitadel/zitadel/internal/eventstore/v1/models"
execution "github.com/zitadel/zitadel/pkg/grpc/execution/v3alpha" action "github.com/zitadel/zitadel/pkg/grpc/action/v3alpha"
) )
func (s *Server) CreateTarget(ctx context.Context, req *execution.CreateTargetRequest) (*execution.CreateTargetResponse, error) { func (s *Server) CreateTarget(ctx context.Context, req *action.CreateTargetRequest) (*action.CreateTargetResponse, error) {
if err := checkExecutionEnabled(ctx); err != nil {
return nil, err
}
add := createTargetToCommand(req) add := createTargetToCommand(req)
details, err := s.command.AddTarget(ctx, add, authz.GetInstance(ctx).InstanceID()) details, err := s.command.AddTarget(ctx, add, authz.GetInstance(ctx).InstanceID())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &execution.CreateTargetResponse{ return &action.CreateTargetResponse{
Id: add.AggregateID, Id: add.AggregateID,
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
}, nil }, nil
} }
func (s *Server) UpdateTarget(ctx context.Context, req *execution.UpdateTargetRequest) (*execution.UpdateTargetResponse, error) { func (s *Server) UpdateTarget(ctx context.Context, req *action.UpdateTargetRequest) (*action.UpdateTargetResponse, error) {
if err := checkExecutionEnabled(ctx); err != nil {
return nil, err
}
details, err := s.command.ChangeTarget(ctx, updateTargetToCommand(req), authz.GetInstance(ctx).InstanceID()) details, err := s.command.ChangeTarget(ctx, updateTargetToCommand(req), authz.GetInstance(ctx).InstanceID())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &execution.UpdateTargetResponse{ return &action.UpdateTargetResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
}, nil }, nil
} }
func (s *Server) DeleteTarget(ctx context.Context, req *execution.DeleteTargetRequest) (*execution.DeleteTargetResponse, error) { func (s *Server) DeleteTarget(ctx context.Context, req *action.DeleteTargetRequest) (*action.DeleteTargetResponse, error) {
if err := checkExecutionEnabled(ctx); err != nil {
return nil, err
}
details, err := s.command.DeleteTarget(ctx, req.GetTargetId(), authz.GetInstance(ctx).InstanceID()) details, err := s.command.DeleteTarget(ctx, req.GetTargetId(), authz.GetInstance(ctx).InstanceID())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &execution.DeleteTargetResponse{ return &action.DeleteTargetResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
}, nil }, nil
} }
func createTargetToCommand(req *execution.CreateTargetRequest) *command.AddTarget { func createTargetToCommand(req *action.CreateTargetRequest) *command.AddTarget {
var targetType domain.TargetType var targetType domain.TargetType
var url string var url string
switch t := req.GetTargetType().(type) { switch t := req.GetTargetType().(type) {
case *execution.CreateTargetRequest_RestWebhook: case *action.CreateTargetRequest_RestWebhook:
targetType = domain.TargetTypeWebhook targetType = domain.TargetTypeWebhook
url = t.RestWebhook.GetUrl() url = t.RestWebhook.GetUrl()
case *execution.CreateTargetRequest_RestRequestResponse: case *action.CreateTargetRequest_RestRequestResponse:
targetType = domain.TargetTypeRequestResponse targetType = domain.TargetTypeRequestResponse
url = t.RestRequestResponse.GetUrl() url = t.RestRequestResponse.GetUrl()
} }
@@ -66,7 +78,7 @@ func createTargetToCommand(req *execution.CreateTargetRequest) *command.AddTarge
} }
} }
func updateTargetToCommand(req *execution.UpdateTargetRequest) *command.ChangeTarget { func updateTargetToCommand(req *action.UpdateTargetRequest) *command.ChangeTarget {
if req == nil { if req == nil {
return nil return nil
} }
@@ -77,10 +89,10 @@ func updateTargetToCommand(req *execution.UpdateTargetRequest) *command.ChangeTa
Name: req.Name, Name: req.Name,
} }
switch t := req.GetTargetType().(type) { switch t := req.GetTargetType().(type) {
case *execution.UpdateTargetRequest_RestWebhook: case *action.UpdateTargetRequest_RestWebhook:
target.TargetType = gu.Ptr(domain.TargetTypeWebhook) target.TargetType = gu.Ptr(domain.TargetTypeWebhook)
target.URL = gu.Ptr(t.RestWebhook.GetUrl()) target.URL = gu.Ptr(t.RestWebhook.GetUrl())
case *execution.UpdateTargetRequest_RestRequestResponse: case *action.UpdateTargetRequest_RestRequestResponse:
target.TargetType = gu.Ptr(domain.TargetTypeRequestResponse) target.TargetType = gu.Ptr(domain.TargetTypeRequestResponse)
target.URL = gu.Ptr(t.RestRequestResponse.GetUrl()) target.URL = gu.Ptr(t.RestRequestResponse.GetUrl())
} }

View File

@@ -1,6 +1,6 @@
//go:build integration //go:build integration
package execution_test package action_test
import ( import (
"context" "context"
@@ -15,22 +15,23 @@ import (
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/integration" "github.com/zitadel/zitadel/internal/integration"
execution "github.com/zitadel/zitadel/pkg/grpc/execution/v3alpha" action "github.com/zitadel/zitadel/pkg/grpc/action/v3alpha"
object "github.com/zitadel/zitadel/pkg/grpc/object/v2beta" object "github.com/zitadel/zitadel/pkg/grpc/object/v2beta"
) )
func TestServer_CreateTarget(t *testing.T) { func TestServer_CreateTarget(t *testing.T) {
ensureFeatureEnabled(t)
tests := []struct { tests := []struct {
name string name string
ctx context.Context ctx context.Context
req *execution.CreateTargetRequest req *action.CreateTargetRequest
want *execution.CreateTargetResponse want *action.CreateTargetResponse
wantErr bool wantErr bool
}{ }{
{ {
name: "missing permission", name: "missing permission",
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner), ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
req: &execution.CreateTargetRequest{ req: &action.CreateTargetRequest{
Name: fmt.Sprint(time.Now().UnixNano() + 1), Name: fmt.Sprint(time.Now().UnixNano() + 1),
}, },
wantErr: true, wantErr: true,
@@ -38,7 +39,7 @@ func TestServer_CreateTarget(t *testing.T) {
{ {
name: "empty name", name: "empty name",
ctx: CTX, ctx: CTX,
req: &execution.CreateTargetRequest{ req: &action.CreateTargetRequest{
Name: "", Name: "",
}, },
wantErr: true, wantErr: true,
@@ -46,7 +47,7 @@ func TestServer_CreateTarget(t *testing.T) {
{ {
name: "empty type", name: "empty type",
ctx: CTX, ctx: CTX,
req: &execution.CreateTargetRequest{ req: &action.CreateTargetRequest{
Name: fmt.Sprint(time.Now().UnixNano() + 1), Name: fmt.Sprint(time.Now().UnixNano() + 1),
TargetType: nil, TargetType: nil,
}, },
@@ -55,10 +56,10 @@ func TestServer_CreateTarget(t *testing.T) {
{ {
name: "empty webhook url", name: "empty webhook url",
ctx: CTX, ctx: CTX,
req: &execution.CreateTargetRequest{ req: &action.CreateTargetRequest{
Name: fmt.Sprint(time.Now().UnixNano() + 1), Name: fmt.Sprint(time.Now().UnixNano() + 1),
TargetType: &execution.CreateTargetRequest_RestWebhook{ TargetType: &action.CreateTargetRequest_RestWebhook{
RestWebhook: &execution.SetRESTWebhook{}, RestWebhook: &action.SetRESTWebhook{},
}, },
}, },
wantErr: true, wantErr: true,
@@ -66,10 +67,10 @@ func TestServer_CreateTarget(t *testing.T) {
{ {
name: "empty request response url", name: "empty request response url",
ctx: CTX, ctx: CTX,
req: &execution.CreateTargetRequest{ req: &action.CreateTargetRequest{
Name: fmt.Sprint(time.Now().UnixNano() + 1), Name: fmt.Sprint(time.Now().UnixNano() + 1),
TargetType: &execution.CreateTargetRequest_RestRequestResponse{ TargetType: &action.CreateTargetRequest_RestRequestResponse{
RestRequestResponse: &execution.SetRESTRequestResponse{}, RestRequestResponse: &action.SetRESTRequestResponse{},
}, },
}, },
wantErr: true, wantErr: true,
@@ -77,10 +78,10 @@ func TestServer_CreateTarget(t *testing.T) {
{ {
name: "empty timeout", name: "empty timeout",
ctx: CTX, ctx: CTX,
req: &execution.CreateTargetRequest{ req: &action.CreateTargetRequest{
Name: fmt.Sprint(time.Now().UnixNano() + 1), Name: fmt.Sprint(time.Now().UnixNano() + 1),
TargetType: &execution.CreateTargetRequest_RestWebhook{ TargetType: &action.CreateTargetRequest_RestWebhook{
RestWebhook: &execution.SetRESTWebhook{ RestWebhook: &action.SetRESTWebhook{
Url: "https://example.com", Url: "https://example.com",
}, },
}, },
@@ -92,17 +93,17 @@ func TestServer_CreateTarget(t *testing.T) {
{ {
name: "empty execution type, ok", name: "empty execution type, ok",
ctx: CTX, ctx: CTX,
req: &execution.CreateTargetRequest{ req: &action.CreateTargetRequest{
Name: fmt.Sprint(time.Now().UnixNano() + 1), Name: fmt.Sprint(time.Now().UnixNano() + 1),
TargetType: &execution.CreateTargetRequest_RestWebhook{ TargetType: &action.CreateTargetRequest_RestWebhook{
RestWebhook: &execution.SetRESTWebhook{ RestWebhook: &action.SetRESTWebhook{
Url: "https://example.com", Url: "https://example.com",
}, },
}, },
Timeout: durationpb.New(10 * time.Second), Timeout: durationpb.New(10 * time.Second),
ExecutionType: nil, ExecutionType: nil,
}, },
want: &execution.CreateTargetResponse{ want: &action.CreateTargetResponse{
Details: &object.Details{ Details: &object.Details{
ChangeDate: timestamppb.Now(), ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),
@@ -112,19 +113,19 @@ func TestServer_CreateTarget(t *testing.T) {
{ {
name: "async execution, ok", name: "async execution, ok",
ctx: CTX, ctx: CTX,
req: &execution.CreateTargetRequest{ req: &action.CreateTargetRequest{
Name: fmt.Sprint(time.Now().UnixNano() + 1), Name: fmt.Sprint(time.Now().UnixNano() + 1),
TargetType: &execution.CreateTargetRequest_RestWebhook{ TargetType: &action.CreateTargetRequest_RestWebhook{
RestWebhook: &execution.SetRESTWebhook{ RestWebhook: &action.SetRESTWebhook{
Url: "https://example.com", Url: "https://example.com",
}, },
}, },
Timeout: durationpb.New(10 * time.Second), Timeout: durationpb.New(10 * time.Second),
ExecutionType: &execution.CreateTargetRequest_IsAsync{ ExecutionType: &action.CreateTargetRequest_IsAsync{
IsAsync: true, IsAsync: true,
}, },
}, },
want: &execution.CreateTargetResponse{ want: &action.CreateTargetResponse{
Details: &object.Details{ Details: &object.Details{
ChangeDate: timestamppb.Now(), ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),
@@ -134,19 +135,19 @@ func TestServer_CreateTarget(t *testing.T) {
{ {
name: "interrupt on error execution, ok", name: "interrupt on error execution, ok",
ctx: CTX, ctx: CTX,
req: &execution.CreateTargetRequest{ req: &action.CreateTargetRequest{
Name: fmt.Sprint(time.Now().UnixNano() + 1), Name: fmt.Sprint(time.Now().UnixNano() + 1),
TargetType: &execution.CreateTargetRequest_RestWebhook{ TargetType: &action.CreateTargetRequest_RestWebhook{
RestWebhook: &execution.SetRESTWebhook{ RestWebhook: &action.SetRESTWebhook{
Url: "https://example.com", Url: "https://example.com",
}, },
}, },
Timeout: durationpb.New(10 * time.Second), Timeout: durationpb.New(10 * time.Second),
ExecutionType: &execution.CreateTargetRequest_InterruptOnError{ ExecutionType: &action.CreateTargetRequest_InterruptOnError{
InterruptOnError: true, InterruptOnError: true,
}, },
}, },
want: &execution.CreateTargetResponse{ want: &action.CreateTargetResponse{
Details: &object.Details{ Details: &object.Details{
ChangeDate: timestamppb.Now(), ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),
@@ -170,27 +171,28 @@ func TestServer_CreateTarget(t *testing.T) {
} }
func TestServer_UpdateTarget(t *testing.T) { func TestServer_UpdateTarget(t *testing.T) {
ensureFeatureEnabled(t)
type args struct { type args struct {
ctx context.Context ctx context.Context
req *execution.UpdateTargetRequest req *action.UpdateTargetRequest
} }
tests := []struct { tests := []struct {
name string name string
prepare func(request *execution.UpdateTargetRequest) error prepare func(request *action.UpdateTargetRequest) error
args args args args
want *execution.UpdateTargetResponse want *action.UpdateTargetResponse
wantErr bool wantErr bool
}{ }{
{ {
name: "missing permission", name: "missing permission",
prepare: func(request *execution.UpdateTargetRequest) error { prepare: func(request *action.UpdateTargetRequest) error {
targetID := Tester.CreateTarget(CTX, t).GetId() targetID := Tester.CreateTarget(CTX, t).GetId()
request.TargetId = targetID request.TargetId = targetID
return nil return nil
}, },
args: args{ args: args{
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner), ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
req: &execution.UpdateTargetRequest{ req: &action.UpdateTargetRequest{
Name: gu.Ptr(fmt.Sprint(time.Now().UnixNano() + 1)), Name: gu.Ptr(fmt.Sprint(time.Now().UnixNano() + 1)),
}, },
}, },
@@ -198,13 +200,13 @@ func TestServer_UpdateTarget(t *testing.T) {
}, },
{ {
name: "not existing", name: "not existing",
prepare: func(request *execution.UpdateTargetRequest) error { prepare: func(request *action.UpdateTargetRequest) error {
request.TargetId = "notexisting" request.TargetId = "notexisting"
return nil return nil
}, },
args: args{ args: args{
ctx: CTX, ctx: CTX,
req: &execution.UpdateTargetRequest{ req: &action.UpdateTargetRequest{
Name: gu.Ptr(fmt.Sprint(time.Now().UnixNano() + 1)), Name: gu.Ptr(fmt.Sprint(time.Now().UnixNano() + 1)),
}, },
}, },
@@ -212,18 +214,18 @@ func TestServer_UpdateTarget(t *testing.T) {
}, },
{ {
name: "change name, ok", name: "change name, ok",
prepare: func(request *execution.UpdateTargetRequest) error { prepare: func(request *action.UpdateTargetRequest) error {
targetID := Tester.CreateTarget(CTX, t).GetId() targetID := Tester.CreateTarget(CTX, t).GetId()
request.TargetId = targetID request.TargetId = targetID
return nil return nil
}, },
args: args{ args: args{
ctx: CTX, ctx: CTX,
req: &execution.UpdateTargetRequest{ req: &action.UpdateTargetRequest{
Name: gu.Ptr(fmt.Sprint(time.Now().UnixNano() + 1)), Name: gu.Ptr(fmt.Sprint(time.Now().UnixNano() + 1)),
}, },
}, },
want: &execution.UpdateTargetResponse{ want: &action.UpdateTargetResponse{
Details: &object.Details{ Details: &object.Details{
ChangeDate: timestamppb.Now(), ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),
@@ -232,22 +234,22 @@ func TestServer_UpdateTarget(t *testing.T) {
}, },
{ {
name: "change type, ok", name: "change type, ok",
prepare: func(request *execution.UpdateTargetRequest) error { prepare: func(request *action.UpdateTargetRequest) error {
targetID := Tester.CreateTarget(CTX, t).GetId() targetID := Tester.CreateTarget(CTX, t).GetId()
request.TargetId = targetID request.TargetId = targetID
return nil return nil
}, },
args: args{ args: args{
ctx: CTX, ctx: CTX,
req: &execution.UpdateTargetRequest{ req: &action.UpdateTargetRequest{
TargetType: &execution.UpdateTargetRequest_RestRequestResponse{ TargetType: &action.UpdateTargetRequest_RestRequestResponse{
RestRequestResponse: &execution.SetRESTRequestResponse{ RestRequestResponse: &action.SetRESTRequestResponse{
Url: "https://example.com", Url: "https://example.com",
}, },
}, },
}, },
}, },
want: &execution.UpdateTargetResponse{ want: &action.UpdateTargetResponse{
Details: &object.Details{ Details: &object.Details{
ChangeDate: timestamppb.Now(), ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),
@@ -256,22 +258,22 @@ func TestServer_UpdateTarget(t *testing.T) {
}, },
{ {
name: "change url, ok", name: "change url, ok",
prepare: func(request *execution.UpdateTargetRequest) error { prepare: func(request *action.UpdateTargetRequest) error {
targetID := Tester.CreateTarget(CTX, t).GetId() targetID := Tester.CreateTarget(CTX, t).GetId()
request.TargetId = targetID request.TargetId = targetID
return nil return nil
}, },
args: args{ args: args{
ctx: CTX, ctx: CTX,
req: &execution.UpdateTargetRequest{ req: &action.UpdateTargetRequest{
TargetType: &execution.UpdateTargetRequest_RestWebhook{ TargetType: &action.UpdateTargetRequest_RestWebhook{
RestWebhook: &execution.SetRESTWebhook{ RestWebhook: &action.SetRESTWebhook{
Url: "https://example.com/hooks/new", Url: "https://example.com/hooks/new",
}, },
}, },
}, },
}, },
want: &execution.UpdateTargetResponse{ want: &action.UpdateTargetResponse{
Details: &object.Details{ Details: &object.Details{
ChangeDate: timestamppb.Now(), ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),
@@ -280,18 +282,18 @@ func TestServer_UpdateTarget(t *testing.T) {
}, },
{ {
name: "change timeout, ok", name: "change timeout, ok",
prepare: func(request *execution.UpdateTargetRequest) error { prepare: func(request *action.UpdateTargetRequest) error {
targetID := Tester.CreateTarget(CTX, t).GetId() targetID := Tester.CreateTarget(CTX, t).GetId()
request.TargetId = targetID request.TargetId = targetID
return nil return nil
}, },
args: args{ args: args{
ctx: CTX, ctx: CTX,
req: &execution.UpdateTargetRequest{ req: &action.UpdateTargetRequest{
Timeout: durationpb.New(20 * time.Second), Timeout: durationpb.New(20 * time.Second),
}, },
}, },
want: &execution.UpdateTargetResponse{ want: &action.UpdateTargetResponse{
Details: &object.Details{ Details: &object.Details{
ChangeDate: timestamppb.Now(), ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),
@@ -300,20 +302,20 @@ func TestServer_UpdateTarget(t *testing.T) {
}, },
{ {
name: "change execution type, ok", name: "change execution type, ok",
prepare: func(request *execution.UpdateTargetRequest) error { prepare: func(request *action.UpdateTargetRequest) error {
targetID := Tester.CreateTarget(CTX, t).GetId() targetID := Tester.CreateTarget(CTX, t).GetId()
request.TargetId = targetID request.TargetId = targetID
return nil return nil
}, },
args: args{ args: args{
ctx: CTX, ctx: CTX,
req: &execution.UpdateTargetRequest{ req: &action.UpdateTargetRequest{
ExecutionType: &execution.UpdateTargetRequest_IsAsync{ ExecutionType: &action.UpdateTargetRequest_IsAsync{
IsAsync: true, IsAsync: true,
}, },
}, },
}, },
want: &execution.UpdateTargetResponse{ want: &action.UpdateTargetResponse{
Details: &object.Details{ Details: &object.Details{
ChangeDate: timestamppb.Now(), ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),
@@ -338,18 +340,19 @@ func TestServer_UpdateTarget(t *testing.T) {
} }
func TestServer_DeleteTarget(t *testing.T) { func TestServer_DeleteTarget(t *testing.T) {
ensureFeatureEnabled(t)
target := Tester.CreateTarget(CTX, t) target := Tester.CreateTarget(CTX, t)
tests := []struct { tests := []struct {
name string name string
ctx context.Context ctx context.Context
req *execution.DeleteTargetRequest req *action.DeleteTargetRequest
want *execution.DeleteTargetResponse want *action.DeleteTargetResponse
wantErr bool wantErr bool
}{ }{
{ {
name: "missing permission", name: "missing permission",
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner), ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
req: &execution.DeleteTargetRequest{ req: &action.DeleteTargetRequest{
TargetId: target.GetId(), TargetId: target.GetId(),
}, },
wantErr: true, wantErr: true,
@@ -357,7 +360,7 @@ func TestServer_DeleteTarget(t *testing.T) {
{ {
name: "empty id", name: "empty id",
ctx: CTX, ctx: CTX,
req: &execution.DeleteTargetRequest{ req: &action.DeleteTargetRequest{
TargetId: "", TargetId: "",
}, },
wantErr: true, wantErr: true,
@@ -365,10 +368,10 @@ func TestServer_DeleteTarget(t *testing.T) {
{ {
name: "delete target", name: "delete target",
ctx: CTX, ctx: CTX,
req: &execution.DeleteTargetRequest{ req: &action.DeleteTargetRequest{
TargetId: target.GetId(), TargetId: target.GetId(),
}, },
want: &execution.DeleteTargetResponse{ want: &action.DeleteTargetResponse{
Details: &object.Details{ Details: &object.Details{
ChangeDate: timestamppb.Now(), ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Instance.InstanceID(), ResourceOwner: Tester.Instance.InstanceID(),

View File

@@ -1,4 +1,4 @@
package execution package action
import ( import (
"testing" "testing"
@@ -10,12 +10,12 @@ import (
"github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
execution "github.com/zitadel/zitadel/pkg/grpc/execution/v3alpha" action "github.com/zitadel/zitadel/pkg/grpc/action/v3alpha"
) )
func Test_createTargetToCommand(t *testing.T) { func Test_createTargetToCommand(t *testing.T) {
type args struct { type args struct {
req *execution.CreateTargetRequest req *action.CreateTargetRequest
} }
tests := []struct { tests := []struct {
name string name string
@@ -35,15 +35,15 @@ func Test_createTargetToCommand(t *testing.T) {
}, },
{ {
name: "all fields (async webhook)", name: "all fields (async webhook)",
args: args{&execution.CreateTargetRequest{ args: args{&action.CreateTargetRequest{
Name: "target 1", Name: "target 1",
TargetType: &execution.CreateTargetRequest_RestWebhook{ TargetType: &action.CreateTargetRequest_RestWebhook{
RestWebhook: &execution.SetRESTWebhook{ RestWebhook: &action.SetRESTWebhook{
Url: "https://example.com/hooks/1", Url: "https://example.com/hooks/1",
}, },
}, },
Timeout: durationpb.New(10 * time.Second), Timeout: durationpb.New(10 * time.Second),
ExecutionType: &execution.CreateTargetRequest_IsAsync{ ExecutionType: &action.CreateTargetRequest_IsAsync{
IsAsync: true, IsAsync: true,
}, },
}}, }},
@@ -58,15 +58,15 @@ func Test_createTargetToCommand(t *testing.T) {
}, },
{ {
name: "all fields (interrupting response)", name: "all fields (interrupting response)",
args: args{&execution.CreateTargetRequest{ args: args{&action.CreateTargetRequest{
Name: "target 1", Name: "target 1",
TargetType: &execution.CreateTargetRequest_RestRequestResponse{ TargetType: &action.CreateTargetRequest_RestRequestResponse{
RestRequestResponse: &execution.SetRESTRequestResponse{ RestRequestResponse: &action.SetRESTRequestResponse{
Url: "https://example.com/hooks/1", Url: "https://example.com/hooks/1",
}, },
}, },
Timeout: durationpb.New(10 * time.Second), Timeout: durationpb.New(10 * time.Second),
ExecutionType: &execution.CreateTargetRequest_InterruptOnError{ ExecutionType: &action.CreateTargetRequest_InterruptOnError{
InterruptOnError: true, InterruptOnError: true,
}, },
}}, }},
@@ -90,7 +90,7 @@ func Test_createTargetToCommand(t *testing.T) {
func Test_updateTargetToCommand(t *testing.T) { func Test_updateTargetToCommand(t *testing.T) {
type args struct { type args struct {
req *execution.UpdateTargetRequest req *action.UpdateTargetRequest
} }
tests := []struct { tests := []struct {
name string name string
@@ -104,7 +104,7 @@ func Test_updateTargetToCommand(t *testing.T) {
}, },
{ {
name: "all fields nil", name: "all fields nil",
args: args{&execution.UpdateTargetRequest{ args: args{&action.UpdateTargetRequest{
Name: nil, Name: nil,
TargetType: nil, TargetType: nil,
Timeout: nil, Timeout: nil,
@@ -121,7 +121,7 @@ func Test_updateTargetToCommand(t *testing.T) {
}, },
{ {
name: "all fields empty", name: "all fields empty",
args: args{&execution.UpdateTargetRequest{ args: args{&action.UpdateTargetRequest{
Name: gu.Ptr(""), Name: gu.Ptr(""),
TargetType: nil, TargetType: nil,
Timeout: durationpb.New(0), Timeout: durationpb.New(0),
@@ -138,15 +138,15 @@ func Test_updateTargetToCommand(t *testing.T) {
}, },
{ {
name: "all fields (async webhook)", name: "all fields (async webhook)",
args: args{&execution.UpdateTargetRequest{ args: args{&action.UpdateTargetRequest{
Name: gu.Ptr("target 1"), Name: gu.Ptr("target 1"),
TargetType: &execution.UpdateTargetRequest_RestWebhook{ TargetType: &action.UpdateTargetRequest_RestWebhook{
RestWebhook: &execution.SetRESTWebhook{ RestWebhook: &action.SetRESTWebhook{
Url: "https://example.com/hooks/1", Url: "https://example.com/hooks/1",
}, },
}, },
Timeout: durationpb.New(10 * time.Second), Timeout: durationpb.New(10 * time.Second),
ExecutionType: &execution.UpdateTargetRequest_IsAsync{ ExecutionType: &action.UpdateTargetRequest_IsAsync{
IsAsync: true, IsAsync: true,
}, },
}}, }},
@@ -161,15 +161,15 @@ func Test_updateTargetToCommand(t *testing.T) {
}, },
{ {
name: "all fields (interrupting response)", name: "all fields (interrupting response)",
args: args{&execution.UpdateTargetRequest{ args: args{&action.UpdateTargetRequest{
Name: gu.Ptr("target 1"), Name: gu.Ptr("target 1"),
TargetType: &execution.UpdateTargetRequest_RestRequestResponse{ TargetType: &action.UpdateTargetRequest_RestRequestResponse{
RestRequestResponse: &execution.SetRESTRequestResponse{ RestRequestResponse: &action.SetRESTRequestResponse{
Url: "https://example.com/hooks/1", Url: "https://example.com/hooks/1",
}, },
}, },
Timeout: durationpb.New(10 * time.Second), Timeout: durationpb.New(10 * time.Second),
ExecutionType: &execution.UpdateTargetRequest_InterruptOnError{ ExecutionType: &action.UpdateTargetRequest_InterruptOnError{
InterruptOnError: true, InterruptOnError: true,
}, },
}}, }},

View File

@@ -1,33 +0,0 @@
//go:build integration
package execution_test
import (
"context"
"os"
"testing"
"time"
"github.com/zitadel/zitadel/internal/integration"
execution "github.com/zitadel/zitadel/pkg/grpc/execution/v3alpha"
)
var (
CTX context.Context
Tester *integration.Tester
Client execution.ExecutionServiceClient
)
func TestMain(m *testing.M) {
os.Exit(func() int {
ctx, errCtx, cancel := integration.Contexts(5 * time.Minute)
defer cancel()
Tester = integration.NewTester(ctx)
defer Tester.Done()
Client = Tester.Client.ExecutionV3
CTX, _ = Tester.WithAuthorization(ctx, integration.IAMOwner), errCtx
return m.Run()
}())
}

View File

@@ -14,6 +14,7 @@ func systemFeaturesToCommand(req *feature_pb.SetSystemFeaturesRequest) *command.
TriggerIntrospectionProjections: req.OidcTriggerIntrospectionProjections, TriggerIntrospectionProjections: req.OidcTriggerIntrospectionProjections,
LegacyIntrospection: req.OidcLegacyIntrospection, LegacyIntrospection: req.OidcLegacyIntrospection,
UserSchema: req.UserSchema, UserSchema: req.UserSchema,
Actions: req.Actions,
TokenExchange: req.OidcTokenExchange, TokenExchange: req.OidcTokenExchange,
} }
} }
@@ -26,6 +27,7 @@ func systemFeaturesToPb(f *query.SystemFeatures) *feature_pb.GetSystemFeaturesRe
OidcLegacyIntrospection: featureSourceToFlagPb(&f.LegacyIntrospection), OidcLegacyIntrospection: featureSourceToFlagPb(&f.LegacyIntrospection),
UserSchema: featureSourceToFlagPb(&f.UserSchema), UserSchema: featureSourceToFlagPb(&f.UserSchema),
OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange), OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange),
Actions: featureSourceToFlagPb(&f.Actions),
} }
} }
@@ -36,6 +38,7 @@ func instanceFeaturesToCommand(req *feature_pb.SetInstanceFeaturesRequest) *comm
LegacyIntrospection: req.OidcLegacyIntrospection, LegacyIntrospection: req.OidcLegacyIntrospection,
UserSchema: req.UserSchema, UserSchema: req.UserSchema,
TokenExchange: req.OidcTokenExchange, TokenExchange: req.OidcTokenExchange,
Actions: req.Actions,
} }
} }
@@ -47,6 +50,7 @@ func instanceFeaturesToPb(f *query.InstanceFeatures) *feature_pb.GetInstanceFeat
OidcLegacyIntrospection: featureSourceToFlagPb(&f.LegacyIntrospection), OidcLegacyIntrospection: featureSourceToFlagPb(&f.LegacyIntrospection),
UserSchema: featureSourceToFlagPb(&f.UserSchema), UserSchema: featureSourceToFlagPb(&f.UserSchema),
OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange), OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange),
Actions: featureSourceToFlagPb(&f.Actions),
} }
} }

View File

@@ -22,6 +22,7 @@ func Test_systemFeaturesToCommand(t *testing.T) {
OidcTriggerIntrospectionProjections: gu.Ptr(false), OidcTriggerIntrospectionProjections: gu.Ptr(false),
OidcLegacyIntrospection: nil, OidcLegacyIntrospection: nil,
UserSchema: gu.Ptr(true), UserSchema: gu.Ptr(true),
Actions: gu.Ptr(true),
OidcTokenExchange: gu.Ptr(true), OidcTokenExchange: gu.Ptr(true),
} }
want := &command.SystemFeatures{ want := &command.SystemFeatures{
@@ -29,6 +30,7 @@ func Test_systemFeaturesToCommand(t *testing.T) {
TriggerIntrospectionProjections: gu.Ptr(false), TriggerIntrospectionProjections: gu.Ptr(false),
LegacyIntrospection: nil, LegacyIntrospection: nil,
UserSchema: gu.Ptr(true), UserSchema: gu.Ptr(true),
Actions: gu.Ptr(true),
TokenExchange: gu.Ptr(true), TokenExchange: gu.Ptr(true),
} }
got := systemFeaturesToCommand(arg) got := systemFeaturesToCommand(arg)
@@ -58,6 +60,10 @@ func Test_systemFeaturesToPb(t *testing.T) {
Level: feature.LevelSystem, Level: feature.LevelSystem,
Value: true, Value: true,
}, },
Actions: query.FeatureSource[bool]{
Level: feature.LevelSystem,
Value: true,
},
TokenExchange: query.FeatureSource[bool]{ TokenExchange: query.FeatureSource[bool]{
Level: feature.LevelSystem, Level: feature.LevelSystem,
Value: false, Value: false,
@@ -89,6 +95,10 @@ func Test_systemFeaturesToPb(t *testing.T) {
Enabled: false, Enabled: false,
Source: feature_pb.Source_SOURCE_SYSTEM, Source: feature_pb.Source_SOURCE_SYSTEM,
}, },
Actions: &feature_pb.FeatureFlag{
Enabled: true,
Source: feature_pb.Source_SOURCE_SYSTEM,
},
} }
got := systemFeaturesToPb(arg) got := systemFeaturesToPb(arg)
assert.Equal(t, want, got) assert.Equal(t, want, got)
@@ -101,6 +111,7 @@ func Test_instanceFeaturesToCommand(t *testing.T) {
OidcLegacyIntrospection: nil, OidcLegacyIntrospection: nil,
UserSchema: gu.Ptr(true), UserSchema: gu.Ptr(true),
OidcTokenExchange: gu.Ptr(true), OidcTokenExchange: gu.Ptr(true),
Actions: gu.Ptr(true),
} }
want := &command.InstanceFeatures{ want := &command.InstanceFeatures{
LoginDefaultOrg: gu.Ptr(true), LoginDefaultOrg: gu.Ptr(true),
@@ -108,6 +119,7 @@ func Test_instanceFeaturesToCommand(t *testing.T) {
LegacyIntrospection: nil, LegacyIntrospection: nil,
UserSchema: gu.Ptr(true), UserSchema: gu.Ptr(true),
TokenExchange: gu.Ptr(true), TokenExchange: gu.Ptr(true),
Actions: gu.Ptr(true),
} }
got := instanceFeaturesToCommand(arg) got := instanceFeaturesToCommand(arg)
assert.Equal(t, want, got) assert.Equal(t, want, got)
@@ -136,6 +148,10 @@ func Test_instanceFeaturesToPb(t *testing.T) {
Level: feature.LevelInstance, Level: feature.LevelInstance,
Value: true, Value: true,
}, },
Actions: query.FeatureSource[bool]{
Level: feature.LevelInstance,
Value: true,
},
TokenExchange: query.FeatureSource[bool]{ TokenExchange: query.FeatureSource[bool]{
Level: feature.LevelSystem, Level: feature.LevelSystem,
Value: false, Value: false,
@@ -163,6 +179,10 @@ func Test_instanceFeaturesToPb(t *testing.T) {
Enabled: true, Enabled: true,
Source: feature_pb.Source_SOURCE_INSTANCE, Source: feature_pb.Source_SOURCE_INSTANCE,
}, },
Actions: &feature_pb.FeatureFlag{
Enabled: true,
Source: feature_pb.Source_SOURCE_INSTANCE,
},
OidcTokenExchange: &feature_pb.FeatureFlag{ OidcTokenExchange: &feature_pb.FeatureFlag{
Enabled: false, Enabled: false,
Source: feature_pb.Source_SOURCE_SYSTEM, Source: feature_pb.Source_SOURCE_SYSTEM,

View File

@@ -219,6 +219,7 @@ func TestServer_GetSystemFeatures(t *testing.T) {
assertFeatureFlag(t, tt.want.OidcTriggerIntrospectionProjections, got.OidcTriggerIntrospectionProjections) assertFeatureFlag(t, tt.want.OidcTriggerIntrospectionProjections, got.OidcTriggerIntrospectionProjections)
assertFeatureFlag(t, tt.want.OidcLegacyIntrospection, got.OidcLegacyIntrospection) assertFeatureFlag(t, tt.want.OidcLegacyIntrospection, got.OidcLegacyIntrospection)
assertFeatureFlag(t, tt.want.UserSchema, got.UserSchema) assertFeatureFlag(t, tt.want.UserSchema, got.UserSchema)
assertFeatureFlag(t, tt.want.Actions, got.Actions)
}) })
} }
} }
@@ -389,6 +390,10 @@ func TestServer_GetInstanceFeatures(t *testing.T) {
Enabled: false, Enabled: false,
Source: feature.Source_SOURCE_UNSPECIFIED, Source: feature.Source_SOURCE_UNSPECIFIED,
}, },
Actions: &feature.FeatureFlag{
Enabled: false,
Source: feature.Source_SOURCE_UNSPECIFIED,
},
}, },
}, },
{ {
@@ -398,6 +403,7 @@ func TestServer_GetInstanceFeatures(t *testing.T) {
LoginDefaultOrg: gu.Ptr(true), LoginDefaultOrg: gu.Ptr(true),
OidcTriggerIntrospectionProjections: gu.Ptr(false), OidcTriggerIntrospectionProjections: gu.Ptr(false),
UserSchema: gu.Ptr(true), UserSchema: gu.Ptr(true),
Actions: gu.Ptr(true),
}) })
require.NoError(t, err) require.NoError(t, err)
}, },
@@ -418,6 +424,10 @@ func TestServer_GetInstanceFeatures(t *testing.T) {
Enabled: true, Enabled: true,
Source: feature.Source_SOURCE_INSTANCE, Source: feature.Source_SOURCE_INSTANCE,
}, },
Actions: &feature.FeatureFlag{
Enabled: true,
Source: feature.Source_SOURCE_INSTANCE,
},
}, },
}, },
{ {
@@ -451,6 +461,10 @@ func TestServer_GetInstanceFeatures(t *testing.T) {
Enabled: false, Enabled: false,
Source: feature.Source_SOURCE_UNSPECIFIED, Source: feature.Source_SOURCE_UNSPECIFIED,
}, },
Actions: &feature.FeatureFlag{
Enabled: false,
Source: feature.Source_SOURCE_UNSPECIFIED,
},
}, },
}, },
} }

View File

@@ -390,6 +390,27 @@ func TestServer_CreateSession_successfulIntent(t *testing.T) {
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor, wantIntentFactor) verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor, wantIntentFactor)
} }
func TestServer_CreateSession_successfulIntent_instant(t *testing.T) {
idpID := Tester.AddGenericOAuthProvider(t)
intentID, token, _, _ := Tester.CreateSuccessfulOAuthIntent(t, idpID, User.GetUserId(), "id")
createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{
Checks: &session.Checks{
User: &session.CheckUser{
Search: &session.CheckUser_UserId{
UserId: User.GetUserId(),
},
},
IdpIntent: &session.CheckIDPIntent{
IdpIntentId: intentID,
IdpIntentToken: token,
},
},
})
require.NoError(t, err)
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor, wantIntentFactor)
}
func TestServer_CreateSession_successfulIntentUnknownUserID(t *testing.T) { func TestServer_CreateSession_successfulIntentUnknownUserID(t *testing.T) {
idpID := Tester.AddGenericOAuthProvider(t) idpID := Tester.AddGenericOAuthProvider(t)

View File

@@ -75,6 +75,8 @@ func ensureFeatureEnabled(t *testing.T) {
} }
func TestServer_CreateUserSchema(t *testing.T) { func TestServer_CreateUserSchema(t *testing.T) {
ensureFeatureEnabled(t)
tests := []struct { tests := []struct {
name string name string
ctx context.Context ctx context.Context
@@ -315,7 +317,6 @@ func TestServer_CreateUserSchema(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
ensureFeatureEnabled(t)
got, err := Client.CreateUserSchema(tt.ctx, tt.req) got, err := Client.CreateUserSchema(tt.ctx, tt.req)
if tt.wantErr { if tt.wantErr {
require.Error(t, err) require.Error(t, err)
@@ -330,6 +331,8 @@ func TestServer_CreateUserSchema(t *testing.T) {
} }
func TestServer_UpdateUserSchema(t *testing.T) { func TestServer_UpdateUserSchema(t *testing.T) {
ensureFeatureEnabled(t)
type args struct { type args struct {
ctx context.Context ctx context.Context
req *schema.UpdateUserSchemaRequest req *schema.UpdateUserSchemaRequest
@@ -572,7 +575,6 @@ func TestServer_UpdateUserSchema(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
ensureFeatureEnabled(t)
err := tt.prepare(tt.args.req) err := tt.prepare(tt.args.req)
require.NoError(t, err) require.NoError(t, err)
@@ -588,6 +590,8 @@ func TestServer_UpdateUserSchema(t *testing.T) {
} }
func TestServer_DeactivateUserSchema(t *testing.T) { func TestServer_DeactivateUserSchema(t *testing.T) {
ensureFeatureEnabled(t)
type args struct { type args struct {
ctx context.Context ctx context.Context
req *schema.DeactivateUserSchemaRequest req *schema.DeactivateUserSchemaRequest
@@ -647,7 +651,6 @@ func TestServer_DeactivateUserSchema(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
ensureFeatureEnabled(t)
err := tt.args.prepare(tt.args.req) err := tt.args.prepare(tt.args.req)
require.NoError(t, err) require.NoError(t, err)
@@ -663,6 +666,8 @@ func TestServer_DeactivateUserSchema(t *testing.T) {
} }
func TestServer_ReactivateUserSchema(t *testing.T) { func TestServer_ReactivateUserSchema(t *testing.T) {
ensureFeatureEnabled(t)
type args struct { type args struct {
ctx context.Context ctx context.Context
req *schema.ReactivateUserSchemaRequest req *schema.ReactivateUserSchemaRequest
@@ -722,7 +727,6 @@ func TestServer_ReactivateUserSchema(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
ensureFeatureEnabled(t)
err := tt.args.prepare(tt.args.req) err := tt.args.prepare(tt.args.req)
require.NoError(t, err) require.NoError(t, err)
@@ -738,6 +742,8 @@ func TestServer_ReactivateUserSchema(t *testing.T) {
} }
func TestServer_DeleteUserSchema(t *testing.T) { func TestServer_DeleteUserSchema(t *testing.T) {
ensureFeatureEnabled(t)
type args struct { type args struct {
ctx context.Context ctx context.Context
req *schema.DeleteUserSchemaRequest req *schema.DeleteUserSchemaRequest
@@ -797,7 +803,6 @@ func TestServer_DeleteUserSchema(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
ensureFeatureEnabled(t)
err := tt.args.prepare(tt.args.req) err := tt.args.prepare(tt.args.req)
require.NoError(t, err) require.NoError(t, err)

View File

@@ -5,6 +5,7 @@
// //
// mockgen -package mock -destination ./mock/repository.mock.go github.com/zitadel/zitadel/internal/auth_request/repository AuthRequestCache // mockgen -package mock -destination ./mock/repository.mock.go github.com/zitadel/zitadel/internal/auth_request/repository AuthRequestCache
// //
// Package mock is a generated GoMock package. // Package mock is a generated GoMock package.
package mock package mock

View File

@@ -17,6 +17,7 @@ type InstanceFeatures struct {
LegacyIntrospection *bool LegacyIntrospection *bool
UserSchema *bool UserSchema *bool
TokenExchange *bool TokenExchange *bool
Actions *bool
} }
func (m *InstanceFeatures) isEmpty() bool { func (m *InstanceFeatures) isEmpty() bool {
@@ -24,7 +25,8 @@ func (m *InstanceFeatures) isEmpty() bool {
m.TriggerIntrospectionProjections == nil && m.TriggerIntrospectionProjections == nil &&
m.LegacyIntrospection == nil && m.LegacyIntrospection == nil &&
m.UserSchema == nil && m.UserSchema == nil &&
m.TokenExchange == nil m.TokenExchange == nil &&
m.Actions == nil
} }
func (c *Commands) SetInstanceFeatures(ctx context.Context, f *InstanceFeatures) (*domain.ObjectDetails, error) { func (c *Commands) SetInstanceFeatures(ctx context.Context, f *InstanceFeatures) (*domain.ObjectDetails, error) {

View File

@@ -56,6 +56,7 @@ func (m *InstanceFeaturesWriteModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.InstanceLegacyIntrospectionEventType, feature_v2.InstanceLegacyIntrospectionEventType,
feature_v2.InstanceUserSchemaEventType, feature_v2.InstanceUserSchemaEventType,
feature_v2.InstanceTokenExchangeEventType, feature_v2.InstanceTokenExchangeEventType,
feature_v2.InstanceActionsEventType,
). ).
Builder().ResourceOwner(m.ResourceOwner) Builder().ResourceOwner(m.ResourceOwner)
} }
@@ -66,6 +67,7 @@ func (m *InstanceFeaturesWriteModel) reduceReset() {
m.LegacyIntrospection = nil m.LegacyIntrospection = nil
m.UserSchema = nil m.UserSchema = nil
m.TokenExchange = nil m.TokenExchange = nil
m.Actions = nil
} }
func (m *InstanceFeaturesWriteModel) reduceBoolFeature(event *feature_v2.SetEvent[bool]) error { func (m *InstanceFeaturesWriteModel) reduceBoolFeature(event *feature_v2.SetEvent[bool]) error {
@@ -86,6 +88,8 @@ func (m *InstanceFeaturesWriteModel) reduceBoolFeature(event *feature_v2.SetEven
m.TokenExchange = &event.Value m.TokenExchange = &event.Value
case feature.KeyUserSchema: case feature.KeyUserSchema:
m.UserSchema = &event.Value m.UserSchema = &event.Value
case feature.KeyActions:
m.Actions = &event.Value
} }
return nil return nil
} }
@@ -98,5 +102,6 @@ func (wm *InstanceFeaturesWriteModel) setCommands(ctx context.Context, f *Instan
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.LegacyIntrospection, f.LegacyIntrospection, feature_v2.InstanceLegacyIntrospectionEventType) cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.LegacyIntrospection, f.LegacyIntrospection, feature_v2.InstanceLegacyIntrospectionEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.TokenExchange, f.TokenExchange, feature_v2.InstanceTokenExchangeEventType) cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.TokenExchange, f.TokenExchange, feature_v2.InstanceTokenExchangeEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.UserSchema, f.UserSchema, feature_v2.InstanceUserSchemaEventType) cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.UserSchema, f.UserSchema, feature_v2.InstanceUserSchemaEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.Actions, f.Actions, feature_v2.InstanceActionsEventType)
return cmds return cmds
} }

View File

@@ -149,6 +149,24 @@ func TestCommands_SetInstanceFeatures(t *testing.T) {
ResourceOwner: "instance1", ResourceOwner: "instance1",
}, },
}, },
{
name: "set Actions",
eventstore: expectEventstore(
expectFilter(),
expectPush(
feature_v2.NewSetEvent[bool](
ctx, aggregate,
feature_v2.InstanceActionsEventType, true,
),
),
),
args: args{ctx, &InstanceFeatures{
Actions: gu.Ptr(true),
}},
want: &domain.ObjectDetails{
ResourceOwner: "instance1",
},
},
{ {
name: "push error", name: "push error",
eventstore: expectEventstore( eventstore: expectEventstore(
@@ -186,6 +204,10 @@ func TestCommands_SetInstanceFeatures(t *testing.T) {
ctx, aggregate, ctx, aggregate,
feature_v2.InstanceUserSchemaEventType, true, feature_v2.InstanceUserSchemaEventType, true,
), ),
feature_v2.NewSetEvent[bool](
ctx, aggregate,
feature_v2.InstanceActionsEventType, true,
),
), ),
), ),
args: args{ctx, &InstanceFeatures{ args: args{ctx, &InstanceFeatures{
@@ -193,6 +215,7 @@ func TestCommands_SetInstanceFeatures(t *testing.T) {
TriggerIntrospectionProjections: gu.Ptr(false), TriggerIntrospectionProjections: gu.Ptr(false),
LegacyIntrospection: gu.Ptr(true), LegacyIntrospection: gu.Ptr(true),
UserSchema: gu.Ptr(true), UserSchema: gu.Ptr(true),
Actions: gu.Ptr(true),
}}, }},
want: &domain.ObjectDetails{ want: &domain.ObjectDetails{
ResourceOwner: "instance1", ResourceOwner: "instance1",

View File

@@ -14,6 +14,7 @@ type SystemFeatures struct {
LegacyIntrospection *bool LegacyIntrospection *bool
TokenExchange *bool TokenExchange *bool
UserSchema *bool UserSchema *bool
Actions *bool
} }
func (m *SystemFeatures) isEmpty() bool { func (m *SystemFeatures) isEmpty() bool {
@@ -21,7 +22,8 @@ func (m *SystemFeatures) isEmpty() bool {
m.TriggerIntrospectionProjections == nil && m.TriggerIntrospectionProjections == nil &&
m.LegacyIntrospection == nil && m.LegacyIntrospection == nil &&
m.UserSchema == nil && m.UserSchema == nil &&
m.TokenExchange == nil m.TokenExchange == nil &&
m.Actions == nil
} }
func (c *Commands) SetSystemFeatures(ctx context.Context, f *SystemFeatures) (*domain.ObjectDetails, error) { func (c *Commands) SetSystemFeatures(ctx context.Context, f *SystemFeatures) (*domain.ObjectDetails, error) {

View File

@@ -51,6 +51,7 @@ func (m *SystemFeaturesWriteModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.SystemLegacyIntrospectionEventType, feature_v2.SystemLegacyIntrospectionEventType,
feature_v2.SystemUserSchemaEventType, feature_v2.SystemUserSchemaEventType,
feature_v2.SystemTokenExchangeEventType, feature_v2.SystemTokenExchangeEventType,
feature_v2.SystemActionsEventType,
). ).
Builder().ResourceOwner(m.ResourceOwner) Builder().ResourceOwner(m.ResourceOwner)
} }
@@ -61,6 +62,7 @@ func (m *SystemFeaturesWriteModel) reduceReset() {
m.LegacyIntrospection = nil m.LegacyIntrospection = nil
m.TokenExchange = nil m.TokenExchange = nil
m.UserSchema = nil m.UserSchema = nil
m.Actions = nil
} }
func (m *SystemFeaturesWriteModel) reduceBoolFeature(event *feature_v2.SetEvent[bool]) error { func (m *SystemFeaturesWriteModel) reduceBoolFeature(event *feature_v2.SetEvent[bool]) error {
@@ -81,6 +83,8 @@ func (m *SystemFeaturesWriteModel) reduceBoolFeature(event *feature_v2.SetEvent[
m.UserSchema = &event.Value m.UserSchema = &event.Value
case feature.KeyTokenExchange: case feature.KeyTokenExchange:
m.TokenExchange = &event.Value m.TokenExchange = &event.Value
case feature.KeyActions:
m.Actions = &event.Value
} }
return nil return nil
} }
@@ -93,6 +97,7 @@ func (wm *SystemFeaturesWriteModel) setCommands(ctx context.Context, f *SystemFe
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.LegacyIntrospection, f.LegacyIntrospection, feature_v2.SystemLegacyIntrospectionEventType) cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.LegacyIntrospection, f.LegacyIntrospection, feature_v2.SystemLegacyIntrospectionEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.UserSchema, f.UserSchema, feature_v2.SystemUserSchemaEventType) cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.UserSchema, f.UserSchema, feature_v2.SystemUserSchemaEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.TokenExchange, f.TokenExchange, feature_v2.SystemTokenExchangeEventType) cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.TokenExchange, f.TokenExchange, feature_v2.SystemTokenExchangeEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.Actions, f.Actions, feature_v2.SystemActionsEventType)
return cmds return cmds
} }

View File

@@ -117,6 +117,24 @@ func TestCommands_SetSystemFeatures(t *testing.T) {
ResourceOwner: "SYSTEM", ResourceOwner: "SYSTEM",
}, },
}, },
{
name: "set Actions",
eventstore: expectEventstore(
expectFilter(),
expectPush(
feature_v2.NewSetEvent[bool](
context.Background(), aggregate,
feature_v2.SystemActionsEventType, true,
),
),
),
args: args{context.Background(), &SystemFeatures{
Actions: gu.Ptr(true),
}},
want: &domain.ObjectDetails{
ResourceOwner: "SYSTEM",
},
},
{ {
name: "push error", name: "push error",
eventstore: expectEventstore( eventstore: expectEventstore(
@@ -154,6 +172,10 @@ func TestCommands_SetSystemFeatures(t *testing.T) {
context.Background(), aggregate, context.Background(), aggregate,
feature_v2.SystemUserSchemaEventType, true, feature_v2.SystemUserSchemaEventType, true,
), ),
feature_v2.NewSetEvent[bool](
context.Background(), aggregate,
feature_v2.SystemActionsEventType, true,
),
), ),
), ),
args: args{context.Background(), &SystemFeatures{ args: args{context.Background(), &SystemFeatures{
@@ -161,6 +183,7 @@ func TestCommands_SetSystemFeatures(t *testing.T) {
TriggerIntrospectionProjections: gu.Ptr(false), TriggerIntrospectionProjections: gu.Ptr(false),
LegacyIntrospection: gu.Ptr(true), LegacyIntrospection: gu.Ptr(true),
UserSchema: gu.Ptr(true), UserSchema: gu.Ptr(true),
Actions: gu.Ptr(true),
}}, }},
want: &domain.ObjectDetails{ want: &domain.ObjectDetails{
ResourceOwner: "SYSTEM", ResourceOwner: "SYSTEM",
@@ -205,6 +228,10 @@ func TestCommands_SetSystemFeatures(t *testing.T) {
context.Background(), aggregate, context.Background(), aggregate,
feature_v2.SystemUserSchemaEventType, true, feature_v2.SystemUserSchemaEventType, true,
), ),
feature_v2.NewSetEvent[bool](
context.Background(), aggregate,
feature_v2.SystemActionsEventType, false,
),
), ),
), ),
args: args{context.Background(), &SystemFeatures{ args: args{context.Background(), &SystemFeatures{
@@ -212,6 +239,7 @@ func TestCommands_SetSystemFeatures(t *testing.T) {
TriggerIntrospectionProjections: gu.Ptr(false), TriggerIntrospectionProjections: gu.Ptr(false),
LegacyIntrospection: gu.Ptr(true), LegacyIntrospection: gu.Ptr(true),
UserSchema: gu.Ptr(true), UserSchema: gu.Ptr(true),
Actions: gu.Ptr(false),
}}, }},
want: &domain.ObjectDetails{ want: &domain.ObjectDetails{
ResourceOwner: "SYSTEM", ResourceOwner: "SYSTEM",

View File

@@ -1,5 +1,3 @@
//go:generate enumer -type Feature
package domain package domain
type Feature int type Feature int

View File

@@ -5,6 +5,7 @@
// //
// mockgen -package mock -destination ./repository.mock.go github.com/zitadel/zitadel/internal/eventstore Querier,Pusher // mockgen -package mock -destination ./repository.mock.go github.com/zitadel/zitadel/internal/eventstore Querier,Pusher
// //
// Package mock is a generated GoMock package. // Package mock is a generated GoMock package.
package mock package mock

View File

@@ -10,6 +10,7 @@ const (
KeyLegacyIntrospection KeyLegacyIntrospection
KeyUserSchema KeyUserSchema
KeyTokenExchange KeyTokenExchange
KeyActions
) )
//go:generate enumer -type Level -transform snake -trimprefix Level //go:generate enumer -type Level -transform snake -trimprefix Level
@@ -31,4 +32,5 @@ type Features struct {
LegacyIntrospection bool `json:"legacy_introspection,omitempty"` LegacyIntrospection bool `json:"legacy_introspection,omitempty"`
UserSchema bool `json:"user_schema,omitempty"` UserSchema bool `json:"user_schema,omitempty"`
TokenExchange bool `json:"token_exchange,omitempty"` TokenExchange bool `json:"token_exchange,omitempty"`
Actions bool `json:"actions,omitempty"`
} }

View File

@@ -7,11 +7,11 @@ import (
"strings" "strings"
) )
const _KeyName = "unspecifiedlogin_default_orgtrigger_introspection_projectionslegacy_introspectionuser_schematoken_exchange" const _KeyName = "unspecifiedlogin_default_orgtrigger_introspection_projectionslegacy_introspectionuser_schematoken_exchangeactions"
var _KeyIndex = [...]uint8{0, 11, 28, 61, 81, 92, 106} var _KeyIndex = [...]uint8{0, 11, 28, 61, 81, 92, 106, 113}
const _KeyLowerName = "unspecifiedlogin_default_orgtrigger_introspection_projectionslegacy_introspectionuser_schematoken_exchange" const _KeyLowerName = "unspecifiedlogin_default_orgtrigger_introspection_projectionslegacy_introspectionuser_schematoken_exchangeactions"
func (i Key) String() string { func (i Key) String() string {
if i < 0 || i >= Key(len(_KeyIndex)-1) { if i < 0 || i >= Key(len(_KeyIndex)-1) {
@@ -30,23 +30,26 @@ func _KeyNoOp() {
_ = x[KeyLegacyIntrospection-(3)] _ = x[KeyLegacyIntrospection-(3)]
_ = x[KeyUserSchema-(4)] _ = x[KeyUserSchema-(4)]
_ = x[KeyTokenExchange-(5)] _ = x[KeyTokenExchange-(5)]
_ = x[KeyActions-(6)]
} }
var _KeyValues = []Key{KeyUnspecified, KeyLoginDefaultOrg, KeyTriggerIntrospectionProjections, KeyLegacyIntrospection, KeyUserSchema, KeyTokenExchange} var _KeyValues = []Key{KeyUnspecified, KeyLoginDefaultOrg, KeyTriggerIntrospectionProjections, KeyLegacyIntrospection, KeyUserSchema, KeyTokenExchange, KeyActions}
var _KeyNameToValueMap = map[string]Key{ var _KeyNameToValueMap = map[string]Key{
_KeyName[0:11]: KeyUnspecified, _KeyName[0:11]: KeyUnspecified,
_KeyLowerName[0:11]: KeyUnspecified, _KeyLowerName[0:11]: KeyUnspecified,
_KeyName[11:28]: KeyLoginDefaultOrg, _KeyName[11:28]: KeyLoginDefaultOrg,
_KeyLowerName[11:28]: KeyLoginDefaultOrg, _KeyLowerName[11:28]: KeyLoginDefaultOrg,
_KeyName[28:61]: KeyTriggerIntrospectionProjections, _KeyName[28:61]: KeyTriggerIntrospectionProjections,
_KeyLowerName[28:61]: KeyTriggerIntrospectionProjections, _KeyLowerName[28:61]: KeyTriggerIntrospectionProjections,
_KeyName[61:81]: KeyLegacyIntrospection, _KeyName[61:81]: KeyLegacyIntrospection,
_KeyLowerName[61:81]: KeyLegacyIntrospection, _KeyLowerName[61:81]: KeyLegacyIntrospection,
_KeyName[81:92]: KeyUserSchema, _KeyName[81:92]: KeyUserSchema,
_KeyLowerName[81:92]: KeyUserSchema, _KeyLowerName[81:92]: KeyUserSchema,
_KeyName[92:106]: KeyTokenExchange, _KeyName[92:106]: KeyTokenExchange,
_KeyLowerName[92:106]: KeyTokenExchange, _KeyLowerName[92:106]: KeyTokenExchange,
_KeyName[106:113]: KeyActions,
_KeyLowerName[106:113]: KeyActions,
} }
var _KeyNames = []string{ var _KeyNames = []string{
@@ -56,6 +59,7 @@ var _KeyNames = []string{
_KeyName[61:81], _KeyName[61:81],
_KeyName[81:92], _KeyName[81:92],
_KeyName[92:106], _KeyName[92:106],
_KeyName[106:113],
} }
// KeyString retrieves an enum value from the enum constants string name. // KeyString retrieves an enum value from the enum constants string name.

View File

@@ -5,6 +5,7 @@
// //
// mockgen -package mock -destination ./mock/generator.mock.go github.com/zitadel/zitadel/internal/id Generator // mockgen -package mock -destination ./mock/generator.mock.go github.com/zitadel/zitadel/internal/id Generator
// //
// Package mock is a generated GoMock package. // Package mock is a generated GoMock package.
package mock package mock

View File

@@ -25,9 +25,9 @@ import (
openid "github.com/zitadel/zitadel/internal/idp/providers/oidc" openid "github.com/zitadel/zitadel/internal/idp/providers/oidc"
"github.com/zitadel/zitadel/internal/idp/providers/saml" "github.com/zitadel/zitadel/internal/idp/providers/saml"
"github.com/zitadel/zitadel/internal/repository/idp" "github.com/zitadel/zitadel/internal/repository/idp"
action "github.com/zitadel/zitadel/pkg/grpc/action/v3alpha"
"github.com/zitadel/zitadel/pkg/grpc/admin" "github.com/zitadel/zitadel/pkg/grpc/admin"
"github.com/zitadel/zitadel/pkg/grpc/auth" "github.com/zitadel/zitadel/pkg/grpc/auth"
execution "github.com/zitadel/zitadel/pkg/grpc/execution/v3alpha"
feature "github.com/zitadel/zitadel/pkg/grpc/feature/v2beta" feature "github.com/zitadel/zitadel/pkg/grpc/feature/v2beta"
mgmt "github.com/zitadel/zitadel/pkg/grpc/management" mgmt "github.com/zitadel/zitadel/pkg/grpc/management"
object "github.com/zitadel/zitadel/pkg/grpc/object/v2beta" object "github.com/zitadel/zitadel/pkg/grpc/object/v2beta"
@@ -53,7 +53,7 @@ type Client struct {
OIDCv2 oidc_pb.OIDCServiceClient OIDCv2 oidc_pb.OIDCServiceClient
OrgV2 organisation.OrganizationServiceClient OrgV2 organisation.OrganizationServiceClient
System system.SystemServiceClient System system.SystemServiceClient
ExecutionV3 execution.ExecutionServiceClient ActionV3 action.ActionServiceClient
FeatureV2 feature.FeatureServiceClient FeatureV2 feature.FeatureServiceClient
UserSchemaV3 schema.UserSchemaServiceClient UserSchemaV3 schema.UserSchemaServiceClient
} }
@@ -70,7 +70,7 @@ func newClient(cc *grpc.ClientConn) Client {
OIDCv2: oidc_pb.NewOIDCServiceClient(cc), OIDCv2: oidc_pb.NewOIDCServiceClient(cc),
OrgV2: organisation.NewOrganizationServiceClient(cc), OrgV2: organisation.NewOrganizationServiceClient(cc),
System: system.NewSystemServiceClient(cc), System: system.NewSystemServiceClient(cc),
ExecutionV3: execution.NewExecutionServiceClient(cc), ActionV3: action.NewActionServiceClient(cc),
FeatureV2: feature.NewFeatureServiceClient(cc), FeatureV2: feature.NewFeatureServiceClient(cc),
UserSchemaV3: schema.NewUserSchemaServiceClient(cc), UserSchemaV3: schema.NewUserSchemaServiceClient(cc),
} }
@@ -522,48 +522,48 @@ func (s *Tester) CreateProjectMembership(t *testing.T, ctx context.Context, proj
require.NoError(t, err) require.NoError(t, err)
} }
func (s *Tester) CreateTarget(ctx context.Context, t *testing.T) *execution.CreateTargetResponse { func (s *Tester) CreateTarget(ctx context.Context, t *testing.T) *action.CreateTargetResponse {
req := &execution.CreateTargetRequest{ req := &action.CreateTargetRequest{
Name: fmt.Sprint(time.Now().UnixNano() + 1), Name: fmt.Sprint(time.Now().UnixNano() + 1),
TargetType: &execution.CreateTargetRequest_RestWebhook{ TargetType: &action.CreateTargetRequest_RestWebhook{
RestWebhook: &execution.SetRESTWebhook{ RestWebhook: &action.SetRESTWebhook{
Url: "https://example.com", Url: "https://example.com",
}, },
}, },
Timeout: durationpb.New(10 * time.Second), Timeout: durationpb.New(10 * time.Second),
} }
target, err := s.Client.ExecutionV3.CreateTarget(ctx, req) target, err := s.Client.ActionV3.CreateTarget(ctx, req)
require.NoError(t, err) require.NoError(t, err)
return target return target
} }
func (s *Tester) CreateTargetWithNameAndType(ctx context.Context, t *testing.T, name string, async bool, interrupt bool) *execution.CreateTargetResponse { func (s *Tester) CreateTargetWithNameAndType(ctx context.Context, t *testing.T, name string, async bool, interrupt bool) *action.CreateTargetResponse {
req := &execution.CreateTargetRequest{ req := &action.CreateTargetRequest{
Name: name, Name: name,
TargetType: &execution.CreateTargetRequest_RestWebhook{ TargetType: &action.CreateTargetRequest_RestWebhook{
RestWebhook: &execution.SetRESTWebhook{ RestWebhook: &action.SetRESTWebhook{
Url: "https://example.com", Url: "https://example.com",
}, },
}, },
Timeout: durationpb.New(10 * time.Second), Timeout: durationpb.New(10 * time.Second),
} }
if async { if async {
req.ExecutionType = &execution.CreateTargetRequest_IsAsync{ req.ExecutionType = &action.CreateTargetRequest_IsAsync{
IsAsync: true, IsAsync: true,
} }
} }
if interrupt { if interrupt {
req.ExecutionType = &execution.CreateTargetRequest_InterruptOnError{ req.ExecutionType = &action.CreateTargetRequest_InterruptOnError{
InterruptOnError: true, InterruptOnError: true,
} }
} }
target, err := s.Client.ExecutionV3.CreateTarget(ctx, req) target, err := s.Client.ActionV3.CreateTarget(ctx, req)
require.NoError(t, err) require.NoError(t, err)
return target return target
} }
func (s *Tester) SetExecution(ctx context.Context, t *testing.T, cond *execution.Condition, targets []string, includes []string) *execution.SetExecutionResponse { func (s *Tester) SetExecution(ctx context.Context, t *testing.T, cond *action.Condition, targets []string, includes []string) *action.SetExecutionResponse {
target, err := s.Client.ExecutionV3.SetExecution(ctx, &execution.SetExecutionRequest{ target, err := s.Client.ActionV3.SetExecution(ctx, &action.SetExecutionRequest{
Condition: cond, Condition: cond,
Targets: targets, Targets: targets,
Includes: includes, Includes: includes,

View File

@@ -5,6 +5,7 @@
// //
// mockgen -package mock -destination ./mock/channel.mock.go github.com/zitadel/zitadel/internal/notification/channels NotificationChannel // mockgen -package mock -destination ./mock/channel.mock.go github.com/zitadel/zitadel/internal/notification/channels NotificationChannel
// //
// Package mock is a generated GoMock package. // Package mock is a generated GoMock package.
package mock package mock

View File

@@ -5,6 +5,7 @@
// //
// mockgen -package mock -destination ./mock/message.mock.go github.com/zitadel/zitadel/internal/notification/channels Message // mockgen -package mock -destination ./mock/message.mock.go github.com/zitadel/zitadel/internal/notification/channels Message
// //
// Package mock is a generated GoMock package. // Package mock is a generated GoMock package.
package mock package mock

View File

@@ -5,6 +5,7 @@
// //
// mockgen -package mock -destination ./mock/commands.mock.go github.com/zitadel/zitadel/internal/notification/handlers Commands // mockgen -package mock -destination ./mock/commands.mock.go github.com/zitadel/zitadel/internal/notification/handlers Commands
// //
// Package mock is a generated GoMock package. // Package mock is a generated GoMock package.
package mock package mock

View File

@@ -5,6 +5,7 @@
// //
// mockgen -package mock -destination ./mock/queries.mock.go github.com/zitadel/zitadel/internal/notification/handlers Queries // mockgen -package mock -destination ./mock/queries.mock.go github.com/zitadel/zitadel/internal/notification/handlers Queries
// //
// Package mock is a generated GoMock package. // Package mock is a generated GoMock package.
package mock package mock

View File

@@ -13,6 +13,7 @@ type InstanceFeatures struct {
LegacyIntrospection FeatureSource[bool] LegacyIntrospection FeatureSource[bool]
UserSchema FeatureSource[bool] UserSchema FeatureSource[bool]
TokenExchange FeatureSource[bool] TokenExchange FeatureSource[bool]
Actions FeatureSource[bool]
} }
func (q *Queries) GetInstanceFeatures(ctx context.Context, cascade bool) (_ *InstanceFeatures, err error) { func (q *Queries) GetInstanceFeatures(ctx context.Context, cascade bool) (_ *InstanceFeatures, err error) {

View File

@@ -62,6 +62,7 @@ func (m *InstanceFeaturesReadModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.InstanceLegacyIntrospectionEventType, feature_v2.InstanceLegacyIntrospectionEventType,
feature_v2.InstanceUserSchemaEventType, feature_v2.InstanceUserSchemaEventType,
feature_v2.InstanceTokenExchangeEventType, feature_v2.InstanceTokenExchangeEventType,
feature_v2.InstanceActionsEventType,
). ).
Builder().ResourceOwner(m.ResourceOwner) Builder().ResourceOwner(m.ResourceOwner)
} }
@@ -75,6 +76,7 @@ func (m *InstanceFeaturesReadModel) reduceReset() {
m.instance.LegacyIntrospection = FeatureSource[bool]{} m.instance.LegacyIntrospection = FeatureSource[bool]{}
m.instance.UserSchema = FeatureSource[bool]{} m.instance.UserSchema = FeatureSource[bool]{}
m.instance.TokenExchange = FeatureSource[bool]{} m.instance.TokenExchange = FeatureSource[bool]{}
m.instance.Actions = FeatureSource[bool]{}
} }
func (m *InstanceFeaturesReadModel) populateFromSystem() bool { func (m *InstanceFeaturesReadModel) populateFromSystem() bool {
@@ -86,6 +88,7 @@ func (m *InstanceFeaturesReadModel) populateFromSystem() bool {
m.instance.LegacyIntrospection = m.system.LegacyIntrospection m.instance.LegacyIntrospection = m.system.LegacyIntrospection
m.instance.UserSchema = m.system.UserSchema m.instance.UserSchema = m.system.UserSchema
m.instance.TokenExchange = m.system.TokenExchange m.instance.TokenExchange = m.system.TokenExchange
m.instance.Actions = m.system.Actions
return true return true
} }
@@ -109,6 +112,8 @@ func (m *InstanceFeaturesReadModel) reduceBoolFeature(event *feature_v2.SetEvent
dst = &m.instance.UserSchema dst = &m.instance.UserSchema
case feature.KeyTokenExchange: case feature.KeyTokenExchange:
dst = &m.instance.TokenExchange dst = &m.instance.TokenExchange
case feature.KeyActions:
dst = &m.instance.Actions
} }
*dst = FeatureSource[bool]{ *dst = FeatureSource[bool]{
Level: level, Level: level,

View File

@@ -105,6 +105,10 @@ func TestQueries_GetInstanceFeatures(t *testing.T) {
ctx, aggregate, ctx, aggregate,
feature_v2.InstanceUserSchemaEventType, false, feature_v2.InstanceUserSchemaEventType, false,
)), )),
eventFromEventPusher(feature_v2.NewSetEvent[bool](
ctx, aggregate,
feature_v2.InstanceActionsEventType, false,
)),
), ),
), ),
args: args{true}, args: args{true},
@@ -128,6 +132,10 @@ func TestQueries_GetInstanceFeatures(t *testing.T) {
Level: feature.LevelInstance, Level: feature.LevelInstance,
Value: false, Value: false,
}, },
Actions: FeatureSource[bool]{
Level: feature.LevelInstance,
Value: false,
},
}, },
}, },
{ {
@@ -154,6 +162,10 @@ func TestQueries_GetInstanceFeatures(t *testing.T) {
ctx, aggregate, ctx, aggregate,
feature_v2.InstanceUserSchemaEventType, false, feature_v2.InstanceUserSchemaEventType, false,
)), )),
eventFromEventPusher(feature_v2.NewSetEvent[bool](
ctx, aggregate,
feature_v2.InstanceActionsEventType, false,
)),
eventFromEventPusher(feature_v2.NewResetEvent( eventFromEventPusher(feature_v2.NewResetEvent(
ctx, aggregate, ctx, aggregate,
feature_v2.InstanceResetEventType, feature_v2.InstanceResetEventType,
@@ -185,6 +197,10 @@ func TestQueries_GetInstanceFeatures(t *testing.T) {
Level: feature.LevelUnspecified, Level: feature.LevelUnspecified,
Value: false, Value: false,
}, },
Actions: FeatureSource[bool]{
Level: feature.LevelUnspecified,
Value: false,
},
}, },
}, },
{ {
@@ -207,6 +223,10 @@ func TestQueries_GetInstanceFeatures(t *testing.T) {
ctx, aggregate, ctx, aggregate,
feature_v2.InstanceUserSchemaEventType, false, feature_v2.InstanceUserSchemaEventType, false,
)), )),
eventFromEventPusher(feature_v2.NewSetEvent[bool](
ctx, aggregate,
feature_v2.InstanceActionsEventType, false,
)),
eventFromEventPusher(feature_v2.NewResetEvent( eventFromEventPusher(feature_v2.NewResetEvent(
ctx, aggregate, ctx, aggregate,
feature_v2.InstanceResetEventType, feature_v2.InstanceResetEventType,
@@ -238,6 +258,10 @@ func TestQueries_GetInstanceFeatures(t *testing.T) {
Level: feature.LevelUnspecified, Level: feature.LevelUnspecified,
Value: false, Value: false,
}, },
Actions: FeatureSource[bool]{
Level: feature.LevelUnspecified,
Value: false,
},
}, },
}, },
} }

View File

@@ -79,6 +79,10 @@ func (*instanceFeatureProjection) Reducers() []handler.AggregateReducer {
Event: feature_v2.InstanceTokenExchangeEventType, Event: feature_v2.InstanceTokenExchangeEventType,
Reduce: reduceInstanceSetFeature[bool], Reduce: reduceInstanceSetFeature[bool],
}, },
{
Event: feature_v2.InstanceActionsEventType,
Reduce: reduceInstanceSetFeature[bool],
},
{ {
Event: instance.InstanceRemovedEventType, Event: instance.InstanceRemovedEventType,
Reduce: reduceInstanceRemovedHelper(InstanceDomainInstanceIDCol), Reduce: reduceInstanceRemovedHelper(InstanceDomainInstanceIDCol),

View File

@@ -71,6 +71,10 @@ func (*systemFeatureProjection) Reducers() []handler.AggregateReducer {
Event: feature_v2.SystemTokenExchangeEventType, Event: feature_v2.SystemTokenExchangeEventType,
Reduce: reduceSystemSetFeature[bool], Reduce: reduceSystemSetFeature[bool],
}, },
{
Event: feature_v2.SystemActionsEventType,
Reduce: reduceSystemSetFeature[bool],
},
}, },
}} }}
} }

View File

@@ -20,6 +20,7 @@ type SystemFeatures struct {
LegacyIntrospection FeatureSource[bool] LegacyIntrospection FeatureSource[bool]
UserSchema FeatureSource[bool] UserSchema FeatureSource[bool]
TokenExchange FeatureSource[bool] TokenExchange FeatureSource[bool]
Actions FeatureSource[bool]
} }
func (q *Queries) GetSystemFeatures(ctx context.Context) (_ *SystemFeatures, err error) { func (q *Queries) GetSystemFeatures(ctx context.Context) (_ *SystemFeatures, err error) {

View File

@@ -50,6 +50,7 @@ func (m *SystemFeaturesReadModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.SystemLegacyIntrospectionEventType, feature_v2.SystemLegacyIntrospectionEventType,
feature_v2.SystemUserSchemaEventType, feature_v2.SystemUserSchemaEventType,
feature_v2.SystemTokenExchangeEventType, feature_v2.SystemTokenExchangeEventType,
feature_v2.SystemActionsEventType,
). ).
Builder().ResourceOwner(m.ResourceOwner) Builder().ResourceOwner(m.ResourceOwner)
} }
@@ -78,6 +79,8 @@ func (m *SystemFeaturesReadModel) reduceBoolFeature(event *feature_v2.SetEvent[b
dst = &m.system.UserSchema dst = &m.system.UserSchema
case feature.KeyTokenExchange: case feature.KeyTokenExchange:
dst = &m.system.TokenExchange dst = &m.system.TokenExchange
case feature.KeyActions:
dst = &m.system.Actions
} }
*dst = FeatureSource[bool]{ *dst = FeatureSource[bool]{

View File

@@ -61,6 +61,10 @@ func TestQueries_GetSystemFeatures(t *testing.T) {
context.Background(), aggregate, context.Background(), aggregate,
feature_v2.SystemUserSchemaEventType, false, feature_v2.SystemUserSchemaEventType, false,
)), )),
eventFromEventPusher(feature_v2.NewSetEvent[bool](
context.Background(), aggregate,
feature_v2.SystemActionsEventType, true,
)),
), ),
), ),
want: &SystemFeatures{ want: &SystemFeatures{
@@ -83,6 +87,10 @@ func TestQueries_GetSystemFeatures(t *testing.T) {
Level: feature.LevelSystem, Level: feature.LevelSystem,
Value: false, Value: false,
}, },
Actions: FeatureSource[bool]{
Level: feature.LevelSystem,
Value: true,
},
}, },
}, },
{ {
@@ -105,6 +113,10 @@ func TestQueries_GetSystemFeatures(t *testing.T) {
context.Background(), aggregate, context.Background(), aggregate,
feature_v2.SystemUserSchemaEventType, false, feature_v2.SystemUserSchemaEventType, false,
)), )),
eventFromEventPusher(feature_v2.NewSetEvent[bool](
context.Background(), aggregate,
feature_v2.SystemActionsEventType, false,
)),
eventFromEventPusher(feature_v2.NewResetEvent( eventFromEventPusher(feature_v2.NewResetEvent(
context.Background(), aggregate, context.Background(), aggregate,
feature_v2.SystemResetEventType, feature_v2.SystemResetEventType,
@@ -135,6 +147,10 @@ func TestQueries_GetSystemFeatures(t *testing.T) {
Level: feature.LevelUnspecified, Level: feature.LevelUnspecified,
Value: false, Value: false,
}, },
Actions: FeatureSource[bool]{
Level: feature.LevelUnspecified,
Value: false,
},
}, },
}, },
{ {
@@ -157,6 +173,10 @@ func TestQueries_GetSystemFeatures(t *testing.T) {
context.Background(), aggregate, context.Background(), aggregate,
feature_v2.SystemUserSchemaEventType, false, feature_v2.SystemUserSchemaEventType, false,
)), )),
eventFromEventPusher(feature_v2.NewSetEvent[bool](
context.Background(), aggregate,
feature_v2.SystemActionsEventType, false,
)),
eventFromEventPusher(feature_v2.NewResetEvent( eventFromEventPusher(feature_v2.NewResetEvent(
context.Background(), aggregate, context.Background(), aggregate,
feature_v2.SystemResetEventType, feature_v2.SystemResetEventType,
@@ -187,6 +207,10 @@ func TestQueries_GetSystemFeatures(t *testing.T) {
Level: feature.LevelUnspecified, Level: feature.LevelUnspecified,
Value: false, Value: false,
}, },
Actions: FeatureSource[bool]{
Level: feature.LevelUnspecified,
Value: false,
},
}, },
}, },
} }

View File

@@ -11,10 +11,12 @@ func init() {
eventstore.RegisterFilterEventMapper(AggregateType, SystemLegacyIntrospectionEventType, eventstore.GenericEventMapper[SetEvent[bool]]) eventstore.RegisterFilterEventMapper(AggregateType, SystemLegacyIntrospectionEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, SystemUserSchemaEventType, eventstore.GenericEventMapper[SetEvent[bool]]) eventstore.RegisterFilterEventMapper(AggregateType, SystemUserSchemaEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, SystemTokenExchangeEventType, eventstore.GenericEventMapper[SetEvent[bool]]) eventstore.RegisterFilterEventMapper(AggregateType, SystemTokenExchangeEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, SystemActionsEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceResetEventType, eventstore.GenericEventMapper[ResetEvent]) eventstore.RegisterFilterEventMapper(AggregateType, InstanceResetEventType, eventstore.GenericEventMapper[ResetEvent])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceLoginDefaultOrgEventType, eventstore.GenericEventMapper[SetEvent[bool]]) eventstore.RegisterFilterEventMapper(AggregateType, InstanceLoginDefaultOrgEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceTriggerIntrospectionProjectionsEventType, eventstore.GenericEventMapper[SetEvent[bool]]) eventstore.RegisterFilterEventMapper(AggregateType, InstanceTriggerIntrospectionProjectionsEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceLegacyIntrospectionEventType, eventstore.GenericEventMapper[SetEvent[bool]]) eventstore.RegisterFilterEventMapper(AggregateType, InstanceLegacyIntrospectionEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceUserSchemaEventType, eventstore.GenericEventMapper[SetEvent[bool]]) eventstore.RegisterFilterEventMapper(AggregateType, InstanceUserSchemaEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceTokenExchangeEventType, eventstore.GenericEventMapper[SetEvent[bool]]) eventstore.RegisterFilterEventMapper(AggregateType, InstanceTokenExchangeEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceActionsEventType, eventstore.GenericEventMapper[SetEvent[bool]])
} }

View File

@@ -17,6 +17,7 @@ var (
SystemLegacyIntrospectionEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyLegacyIntrospection) SystemLegacyIntrospectionEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyLegacyIntrospection)
SystemUserSchemaEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyUserSchema) SystemUserSchemaEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyUserSchema)
SystemTokenExchangeEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyTokenExchange) SystemTokenExchangeEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyTokenExchange)
SystemActionsEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyActions)
InstanceResetEventType = resetEventTypeFromFeature(feature.LevelInstance) InstanceResetEventType = resetEventTypeFromFeature(feature.LevelInstance)
InstanceLoginDefaultOrgEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyLoginDefaultOrg) InstanceLoginDefaultOrgEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyLoginDefaultOrg)
@@ -24,6 +25,7 @@ var (
InstanceLegacyIntrospectionEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyLegacyIntrospection) InstanceLegacyIntrospectionEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyLegacyIntrospection)
InstanceUserSchemaEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyUserSchema) InstanceUserSchemaEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyUserSchema)
InstanceTokenExchangeEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyTokenExchange) InstanceTokenExchangeEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyTokenExchange)
InstanceActionsEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyActions)
) )
const ( const (

View File

@@ -5,6 +5,7 @@
// //
// mockgen -source storage.go -destination ./mock/storage_mock.go -package mock // mockgen -source storage.go -destination ./mock/storage_mock.go -package mock
// //
// Package mock is a generated GoMock package. // Package mock is a generated GoMock package.
package mock package mock

View File

@@ -1,6 +1,6 @@
syntax = "proto3"; syntax = "proto3";
package zitadel.execution.v3alpha; package zitadel.action.v3alpha;
import "google/api/annotations.proto"; import "google/api/annotations.proto";
import "google/api/field_behavior.proto"; import "google/api/field_behavior.proto";
@@ -8,17 +8,17 @@ import "google/protobuf/duration.proto";
import "google/protobuf/struct.proto"; import "google/protobuf/struct.proto";
import "protoc-gen-openapiv2/options/annotations.proto"; import "protoc-gen-openapiv2/options/annotations.proto";
import "validate/validate.proto"; import "validate/validate.proto";
import "zitadel/execution/v3alpha/target.proto"; import "zitadel/action/v3alpha/target.proto";
import "zitadel/execution/v3alpha/execution.proto"; import "zitadel/action/v3alpha/execution.proto";
import "zitadel/execution/v3alpha/query.proto"; import "zitadel/action/v3alpha/query.proto";
import "zitadel/object/v2beta/object.proto"; import "zitadel/object/v2beta/object.proto";
import "zitadel/protoc_gen_zitadel/v2/options.proto"; import "zitadel/protoc_gen_zitadel/v2/options.proto";
option go_package = "github.com/zitadel/zitadel/pkg/grpc/execution/v3alpha;execution"; option go_package = "github.com/zitadel/zitadel/pkg/grpc/action/v3alpha;action";
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
info: { info: {
title: "Execution Service"; title: "Action Service";
version: "3.0-preview"; version: "3.0-preview";
description: "This API is intended to manage custom executions (previously known as actions) in a ZITADEL instance. This project is in preview state. It can AND will continue breaking until the services provide the same functionality as the current actions."; description: "This API is intended to manage custom executions (previously known as actions) in a ZITADEL instance. This project is in preview state. It can AND will continue breaking until the services provide the same functionality as the current actions.";
contact:{ contact:{
@@ -104,7 +104,7 @@ option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
} }
}; };
service ExecutionService { service ActionService {
// Create a target // Create a target
// //
@@ -516,22 +516,22 @@ message ListTargetsRequest {
// list limitations and ordering. // list limitations and ordering.
zitadel.object.v2beta.ListQuery query = 1; zitadel.object.v2beta.ListQuery query = 1;
// the field the result is sorted. // the field the result is sorted.
zitadel.execution.v3alpha.TargetFieldName sorting_column = 2 [ zitadel.action.v3alpha.TargetFieldName sorting_column = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"FIELD_NAME_SCHEMA_TYPE\"" example: "\"FIELD_NAME_SCHEMA_TYPE\""
} }
]; ];
// Define the criteria to query for. // Define the criteria to query for.
repeated zitadel.execution.v3alpha.TargetSearchQuery queries = 3; repeated zitadel.action.v3alpha.TargetSearchQuery queries = 3;
} }
message ListTargetsResponse { message ListTargetsResponse {
// Details provides information about the returned result including total amount found. // Details provides information about the returned result including total amount found.
zitadel.object.v2beta.ListDetails details = 1; zitadel.object.v2beta.ListDetails details = 1;
// States by which field the results are sorted. // States by which field the results are sorted.
zitadel.execution.v3alpha.TargetFieldName sorting_column = 2; zitadel.action.v3alpha.TargetFieldName sorting_column = 2;
// The result contains the user schemas, which matched the queries. // The result contains the user schemas, which matched the queries.
repeated zitadel.execution.v3alpha.Target result = 3; repeated zitadel.action.v3alpha.Target result = 3;
} }
message GetTargetByIDRequest { message GetTargetByIDRequest {
@@ -548,7 +548,7 @@ message GetTargetByIDRequest {
} }
message GetTargetByIDResponse { message GetTargetByIDResponse {
zitadel.execution.v3alpha.Target target = 1; zitadel.action.v3alpha.Target target = 1;
} }
message SetExecutionRequest { message SetExecutionRequest {
@@ -579,14 +579,14 @@ message ListExecutionsRequest {
// list limitations and ordering. // list limitations and ordering.
zitadel.object.v2beta.ListQuery query = 1; zitadel.object.v2beta.ListQuery query = 1;
// Define the criteria to query for. // Define the criteria to query for.
repeated zitadel.execution.v3alpha.SearchQuery queries = 2; repeated zitadel.action.v3alpha.SearchQuery queries = 2;
} }
message ListExecutionsResponse { message ListExecutionsResponse {
// Details provides information about the returned result including total amount found. // Details provides information about the returned result including total amount found.
zitadel.object.v2beta.ListDetails details = 1; zitadel.object.v2beta.ListDetails details = 1;
// The result contains the executions, which matched the queries. // The result contains the executions, which matched the queries.
repeated zitadel.execution.v3alpha.Execution result = 2; repeated zitadel.action.v3alpha.Execution result = 2;
} }
message ListExecutionFunctionsRequest{} message ListExecutionFunctionsRequest{}

View File

@@ -1,6 +1,6 @@
syntax = "proto3"; syntax = "proto3";
package zitadel.execution.v3alpha; package zitadel.action.v3alpha;
import "google/api/annotations.proto"; import "google/api/annotations.proto";
import "google/api/field_behavior.proto"; import "google/api/field_behavior.proto";
@@ -11,7 +11,7 @@ import "validate/validate.proto";
import "zitadel/object/v2beta/object.proto"; import "zitadel/object/v2beta/object.proto";
import "zitadel/protoc_gen_zitadel/v2/options.proto"; import "zitadel/protoc_gen_zitadel/v2/options.proto";
option go_package = "github.com/zitadel/zitadel/pkg/grpc/execution/v3alpha;execution"; option go_package = "github.com/zitadel/zitadel/pkg/grpc/action/v3alpha;action";
message Execution { message Execution {
string execution_id = 1 [ string execution_id = 1 [

View File

@@ -1,14 +1,14 @@
syntax = "proto3"; syntax = "proto3";
package zitadel.execution.v3alpha; package zitadel.action.v3alpha;
option go_package = "github.com/zitadel/zitadel/pkg/grpc/execution/v3alpha;execution"; option go_package = "github.com/zitadel/zitadel/pkg/grpc/action/v3alpha;action";
import "google/api/field_behavior.proto"; import "google/api/field_behavior.proto";
import "protoc-gen-openapiv2/options/annotations.proto"; import "protoc-gen-openapiv2/options/annotations.proto";
import "validate/validate.proto"; import "validate/validate.proto";
import "zitadel/object/v2beta/object.proto"; import "zitadel/object/v2beta/object.proto";
import "zitadel/execution/v3alpha/execution.proto"; import "zitadel/action/v3alpha/execution.proto";
message SearchQuery { message SearchQuery {
oneof query { oneof query {

View File

@@ -1,6 +1,6 @@
syntax = "proto3"; syntax = "proto3";
package zitadel.execution.v3alpha; package zitadel.action.v3alpha;
import "google/api/annotations.proto"; import "google/api/annotations.proto";
import "google/api/field_behavior.proto"; import "google/api/field_behavior.proto";
@@ -11,7 +11,7 @@ import "validate/validate.proto";
import "zitadel/object/v2beta/object.proto"; import "zitadel/object/v2beta/object.proto";
import "zitadel/protoc_gen_zitadel/v2/options.proto"; import "zitadel/protoc_gen_zitadel/v2/options.proto";
option go_package = "github.com/zitadel/zitadel/pkg/grpc/execution/v3alpha;execution"; option go_package = "github.com/zitadel/zitadel/pkg/grpc/action/v3alpha;action";
message SetRESTWebhook { message SetRESTWebhook {
string url = 1 [ string url = 1 [

View File

@@ -43,6 +43,12 @@ message SetInstanceFeaturesRequest{
description: "Enable the experimental `urn:ietf:params:oauth:grant-type:token-exchange` grant type for the OIDC token endpoint. Token exchange can be used to request tokens with a lesser scope or impersonate other users. See the security policy to allow impersonation on an instance."; description: "Enable the experimental `urn:ietf:params:oauth:grant-type:token-exchange` grant type for the OIDC token endpoint. Token exchange can be used to request tokens with a lesser scope or impersonate other users. See the security policy to allow impersonation on an instance.";
} }
]; ];
optional bool actions = 6 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "Actions allow to manage data executions and targets. If the flag is enabled, you'll be able to use the new API and its features. Note that it is still in an early stage.";
}
];
} }
message SetInstanceFeaturesResponse { message SetInstanceFeaturesResponse {
@@ -100,4 +106,11 @@ message GetInstanceFeaturesResponse {
description: "Enable the experimental `urn:ietf:params:oauth:grant-type:token-exchange` grant type for the OIDC token endpoint. Token exchange can be used to request tokens with a lesser scope or impersonate other users. See the security policy to allow impersonation on an instance."; description: "Enable the experimental `urn:ietf:params:oauth:grant-type:token-exchange` grant type for the OIDC token endpoint. Token exchange can be used to request tokens with a lesser scope or impersonate other users. See the security policy to allow impersonation on an instance.";
} }
]; ];
FeatureFlag actions = 7 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "Actions v2 allow to manage data executions and targets. If the flag is enabled, you'll be able to use the new API and its features. Note that it is still in an early stage.";
}
];
} }

View File

@@ -45,7 +45,14 @@ message SetSystemFeaturesRequest{
description: "Enable the experimental `urn:ietf:params:oauth:grant-type:token-exchange` grant type for the OIDC token endpoint. Token exchange can be used to request tokens with a lesser scope or impersonate other users. See the security policy to allow impersonation on an instance."; description: "Enable the experimental `urn:ietf:params:oauth:grant-type:token-exchange` grant type for the OIDC token endpoint. Token exchange can be used to request tokens with a lesser scope or impersonate other users. See the security policy to allow impersonation on an instance.";
} }
]; ];
optional bool actions = 6 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "Actions allow to manage data executions and targets. If the flag is enabled, you'll be able to use the new API and its features. Note that it is still in an early stage.";
}
];
} }
message SetSystemFeaturesResponse { message SetSystemFeaturesResponse {
@@ -96,4 +103,11 @@ message GetSystemFeaturesResponse {
description: "Enable the experimental `urn:ietf:params:oauth:grant-type:token-exchange` grant type for the OIDC token endpoint. Token exchange can be used to request tokens with a lesser scope or impersonate other users. See the security policy to allow impersonation on an instance."; description: "Enable the experimental `urn:ietf:params:oauth:grant-type:token-exchange` grant type for the OIDC token endpoint. Token exchange can be used to request tokens with a lesser scope or impersonate other users. See the security policy to allow impersonation on an instance.";
} }
]; ];
FeatureFlag actions = 7 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "Actions v2 allow to manage data executions and targets. If the flag is enabled, you'll be able to use the new API and its features. Note that it is still in an early stage.";
}
];
} }