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
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
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/assets"
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/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/management"
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 {
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
}
if err := apis.RegisterService(ctx, user_schema_v3_alpha.CreateServer(commands, queries)); err != nil {

View File

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

View File

@ -732,17 +732,17 @@ module.exports = {
},
{
type: "category",
label: "Execution Lifecycle (Preview)",
label: "Action Lifecycle (Preview)",
link: {
type: "generated-index",
title: "Execution Service API (Preview)",
slug: "/apis/resources/execution_service_v3",
title: "Action Service API (Preview)",
slug: "/apis/resources/action_service_v3",
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" +
"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 (
"context"
@ -7,28 +7,32 @@ import (
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
"github.com/zitadel/zitadel/internal/command"
"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) {
return &execution.ListExecutionFunctionsResponse{
func (s *Server) ListExecutionFunctions(_ context.Context, _ *action.ListExecutionFunctionsRequest) (*action.ListExecutionFunctionsResponse, error) {
return &action.ListExecutionFunctionsResponse{
Functions: s.ListActionFunctions(),
}, nil
}
func (s *Server) ListExecutionMethods(_ context.Context, _ *execution.ListExecutionMethodsRequest) (*execution.ListExecutionMethodsResponse, error) {
return &execution.ListExecutionMethodsResponse{
func (s *Server) ListExecutionMethods(_ context.Context, _ *action.ListExecutionMethodsRequest) (*action.ListExecutionMethodsResponse, error) {
return &action.ListExecutionMethodsResponse{
Methods: s.ListGRPCMethods(),
}, nil
}
func (s *Server) ListExecutionServices(_ context.Context, _ *execution.ListExecutionServicesRequest) (*execution.ListExecutionServicesResponse, error) {
return &execution.ListExecutionServicesResponse{
func (s *Server) ListExecutionServices(_ context.Context, _ *action.ListExecutionServicesRequest) (*action.ListExecutionServicesResponse, error) {
return &action.ListExecutionServicesResponse{
Services: s.ListGRPCServices(),
}, 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{
Targets: req.GetTargets(),
Includes: req.GetIncludes(),
@ -37,7 +41,7 @@ func (s *Server) SetExecution(ctx context.Context, req *execution.SetExecutionRe
var err error
var details *domain.ObjectDetails
switch t := req.GetCondition().GetConditionType().(type) {
case *execution.Condition_Request:
case *action.Condition_Request:
cond := &command.ExecutionAPICondition{
Method: t.Request.GetMethod(),
Service: t.Request.GetService(),
@ -47,7 +51,7 @@ func (s *Server) SetExecution(ctx context.Context, req *execution.SetExecutionRe
if err != nil {
return nil, err
}
case *execution.Condition_Response:
case *action.Condition_Response:
cond := &command.ExecutionAPICondition{
Method: t.Response.GetMethod(),
Service: t.Response.GetService(),
@ -57,7 +61,7 @@ func (s *Server) SetExecution(ctx context.Context, req *execution.SetExecutionRe
if err != nil {
return nil, err
}
case *execution.Condition_Event:
case *action.Condition_Event:
cond := &command.ExecutionEventCondition{
Event: t.Event.GetEvent(),
Group: t.Event.GetGroup(),
@ -67,22 +71,26 @@ func (s *Server) SetExecution(ctx context.Context, req *execution.SetExecutionRe
if err != nil {
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())
if err != nil {
return nil, err
}
}
return &execution.SetExecutionResponse{
return &action.SetExecutionResponse{
Details: object.DomainToDetailsPb(details),
}, 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 details *domain.ObjectDetails
switch t := req.GetCondition().GetConditionType().(type) {
case *execution.Condition_Request:
case *action.Condition_Request:
cond := &command.ExecutionAPICondition{
Method: t.Request.GetMethod(),
Service: t.Request.GetService(),
@ -92,7 +100,7 @@ func (s *Server) DeleteExecution(ctx context.Context, req *execution.DeleteExecu
if err != nil {
return nil, err
}
case *execution.Condition_Response:
case *action.Condition_Response:
cond := &command.ExecutionAPICondition{
Method: t.Response.GetMethod(),
Service: t.Response.GetService(),
@ -102,7 +110,7 @@ func (s *Server) DeleteExecution(ctx context.Context, req *execution.DeleteExecu
if err != nil {
return nil, err
}
case *execution.Condition_Event:
case *action.Condition_Event:
cond := &command.ExecutionEventCondition{
Event: t.Event.GetEvent(),
Group: t.Event.GetGroup(),
@ -112,13 +120,13 @@ func (s *Server) DeleteExecution(ctx context.Context, req *execution.DeleteExecu
if err != nil {
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())
if err != nil {
return nil, err
}
}
return &execution.DeleteExecutionResponse{
return &action.DeleteExecutionResponse{
Details: object.DomainToDetailsPb(details),
}, nil
}

View File

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

View File

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

View File

@ -1,19 +1,22 @@
package execution
package action
import (
"context"
"google.golang.org/grpc"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/server"
"github.com/zitadel/zitadel/internal/command"
"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 {
execution.UnimplementedExecutionServiceServer
action.UnimplementedActionServiceServer
command *command.Commands
query *query.Queries
ListActionFunctions func() []string
@ -40,21 +43,28 @@ func CreateServer(
}
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
execution.RegisterExecutionServiceServer(grpcServer, s)
action.RegisterActionServiceServer(grpcServer, s)
}
func (s *Server) AppName() string {
return execution.ExecutionService_ServiceDesc.ServiceName
return action.ActionService_ServiceDesc.ServiceName
}
func (s *Server) MethodPrefix() string {
return execution.ExecutionService_ServiceDesc.ServiceName
return action.ActionService_ServiceDesc.ServiceName
}
func (s *Server) AuthMethods() authz.MethodMapping {
return execution.ExecutionService_AuthMethods
return action.ActionService_AuthMethods
}
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 (
"context"
@ -10,49 +10,61 @@ import (
"github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/domain"
"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)
details, err := s.command.AddTarget(ctx, add, authz.GetInstance(ctx).InstanceID())
if err != nil {
return nil, err
}
return &execution.CreateTargetResponse{
return &action.CreateTargetResponse{
Id: add.AggregateID,
Details: object.DomainToDetailsPb(details),
}, 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())
if err != nil {
return nil, err
}
return &execution.UpdateTargetResponse{
return &action.UpdateTargetResponse{
Details: object.DomainToDetailsPb(details),
}, 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())
if err != nil {
return nil, err
}
return &execution.DeleteTargetResponse{
return &action.DeleteTargetResponse{
Details: object.DomainToDetailsPb(details),
}, nil
}
func createTargetToCommand(req *execution.CreateTargetRequest) *command.AddTarget {
func createTargetToCommand(req *action.CreateTargetRequest) *command.AddTarget {
var targetType domain.TargetType
var url string
switch t := req.GetTargetType().(type) {
case *execution.CreateTargetRequest_RestWebhook:
case *action.CreateTargetRequest_RestWebhook:
targetType = domain.TargetTypeWebhook
url = t.RestWebhook.GetUrl()
case *execution.CreateTargetRequest_RestRequestResponse:
case *action.CreateTargetRequest_RestRequestResponse:
targetType = domain.TargetTypeRequestResponse
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 {
return nil
}
@ -77,10 +89,10 @@ func updateTargetToCommand(req *execution.UpdateTargetRequest) *command.ChangeTa
Name: req.Name,
}
switch t := req.GetTargetType().(type) {
case *execution.UpdateTargetRequest_RestWebhook:
case *action.UpdateTargetRequest_RestWebhook:
target.TargetType = gu.Ptr(domain.TargetTypeWebhook)
target.URL = gu.Ptr(t.RestWebhook.GetUrl())
case *execution.UpdateTargetRequest_RestRequestResponse:
case *action.UpdateTargetRequest_RestRequestResponse:
target.TargetType = gu.Ptr(domain.TargetTypeRequestResponse)
target.URL = gu.Ptr(t.RestRequestResponse.GetUrl())
}

View File

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

View File

@ -1,4 +1,4 @@
package execution
package action
import (
"testing"
@ -10,12 +10,12 @@ import (
"github.com/zitadel/zitadel/internal/command"
"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) {
type args struct {
req *execution.CreateTargetRequest
req *action.CreateTargetRequest
}
tests := []struct {
name string
@ -35,15 +35,15 @@ func Test_createTargetToCommand(t *testing.T) {
},
{
name: "all fields (async webhook)",
args: args{&execution.CreateTargetRequest{
args: args{&action.CreateTargetRequest{
Name: "target 1",
TargetType: &execution.CreateTargetRequest_RestWebhook{
RestWebhook: &execution.SetRESTWebhook{
TargetType: &action.CreateTargetRequest_RestWebhook{
RestWebhook: &action.SetRESTWebhook{
Url: "https://example.com/hooks/1",
},
},
Timeout: durationpb.New(10 * time.Second),
ExecutionType: &execution.CreateTargetRequest_IsAsync{
ExecutionType: &action.CreateTargetRequest_IsAsync{
IsAsync: true,
},
}},
@ -58,15 +58,15 @@ func Test_createTargetToCommand(t *testing.T) {
},
{
name: "all fields (interrupting response)",
args: args{&execution.CreateTargetRequest{
args: args{&action.CreateTargetRequest{
Name: "target 1",
TargetType: &execution.CreateTargetRequest_RestRequestResponse{
RestRequestResponse: &execution.SetRESTRequestResponse{
TargetType: &action.CreateTargetRequest_RestRequestResponse{
RestRequestResponse: &action.SetRESTRequestResponse{
Url: "https://example.com/hooks/1",
},
},
Timeout: durationpb.New(10 * time.Second),
ExecutionType: &execution.CreateTargetRequest_InterruptOnError{
ExecutionType: &action.CreateTargetRequest_InterruptOnError{
InterruptOnError: true,
},
}},
@ -90,7 +90,7 @@ func Test_createTargetToCommand(t *testing.T) {
func Test_updateTargetToCommand(t *testing.T) {
type args struct {
req *execution.UpdateTargetRequest
req *action.UpdateTargetRequest
}
tests := []struct {
name string
@ -104,7 +104,7 @@ func Test_updateTargetToCommand(t *testing.T) {
},
{
name: "all fields nil",
args: args{&execution.UpdateTargetRequest{
args: args{&action.UpdateTargetRequest{
Name: nil,
TargetType: nil,
Timeout: nil,
@ -121,7 +121,7 @@ func Test_updateTargetToCommand(t *testing.T) {
},
{
name: "all fields empty",
args: args{&execution.UpdateTargetRequest{
args: args{&action.UpdateTargetRequest{
Name: gu.Ptr(""),
TargetType: nil,
Timeout: durationpb.New(0),
@ -138,15 +138,15 @@ func Test_updateTargetToCommand(t *testing.T) {
},
{
name: "all fields (async webhook)",
args: args{&execution.UpdateTargetRequest{
args: args{&action.UpdateTargetRequest{
Name: gu.Ptr("target 1"),
TargetType: &execution.UpdateTargetRequest_RestWebhook{
RestWebhook: &execution.SetRESTWebhook{
TargetType: &action.UpdateTargetRequest_RestWebhook{
RestWebhook: &action.SetRESTWebhook{
Url: "https://example.com/hooks/1",
},
},
Timeout: durationpb.New(10 * time.Second),
ExecutionType: &execution.UpdateTargetRequest_IsAsync{
ExecutionType: &action.UpdateTargetRequest_IsAsync{
IsAsync: true,
},
}},
@ -161,15 +161,15 @@ func Test_updateTargetToCommand(t *testing.T) {
},
{
name: "all fields (interrupting response)",
args: args{&execution.UpdateTargetRequest{
args: args{&action.UpdateTargetRequest{
Name: gu.Ptr("target 1"),
TargetType: &execution.UpdateTargetRequest_RestRequestResponse{
RestRequestResponse: &execution.SetRESTRequestResponse{
TargetType: &action.UpdateTargetRequest_RestRequestResponse{
RestRequestResponse: &action.SetRESTRequestResponse{
Url: "https://example.com/hooks/1",
},
},
Timeout: durationpb.New(10 * time.Second),
ExecutionType: &execution.UpdateTargetRequest_InterruptOnError{
ExecutionType: &action.UpdateTargetRequest_InterruptOnError{
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,
LegacyIntrospection: req.OidcLegacyIntrospection,
UserSchema: req.UserSchema,
Actions: req.Actions,
TokenExchange: req.OidcTokenExchange,
}
}
@ -26,6 +27,7 @@ func systemFeaturesToPb(f *query.SystemFeatures) *feature_pb.GetSystemFeaturesRe
OidcLegacyIntrospection: featureSourceToFlagPb(&f.LegacyIntrospection),
UserSchema: featureSourceToFlagPb(&f.UserSchema),
OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange),
Actions: featureSourceToFlagPb(&f.Actions),
}
}
@ -36,6 +38,7 @@ func instanceFeaturesToCommand(req *feature_pb.SetInstanceFeaturesRequest) *comm
LegacyIntrospection: req.OidcLegacyIntrospection,
UserSchema: req.UserSchema,
TokenExchange: req.OidcTokenExchange,
Actions: req.Actions,
}
}
@ -47,6 +50,7 @@ func instanceFeaturesToPb(f *query.InstanceFeatures) *feature_pb.GetInstanceFeat
OidcLegacyIntrospection: featureSourceToFlagPb(&f.LegacyIntrospection),
UserSchema: featureSourceToFlagPb(&f.UserSchema),
OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange),
Actions: featureSourceToFlagPb(&f.Actions),
}
}

View File

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

View File

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

View File

@ -17,6 +17,7 @@ type InstanceFeatures struct {
LegacyIntrospection *bool
UserSchema *bool
TokenExchange *bool
Actions *bool
}
func (m *InstanceFeatures) isEmpty() bool {
@ -24,7 +25,8 @@ func (m *InstanceFeatures) isEmpty() bool {
m.TriggerIntrospectionProjections == nil &&
m.LegacyIntrospection == 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) {

View File

@ -56,6 +56,7 @@ func (m *InstanceFeaturesWriteModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.InstanceLegacyIntrospectionEventType,
feature_v2.InstanceUserSchemaEventType,
feature_v2.InstanceTokenExchangeEventType,
feature_v2.InstanceActionsEventType,
).
Builder().ResourceOwner(m.ResourceOwner)
}
@ -66,6 +67,7 @@ func (m *InstanceFeaturesWriteModel) reduceReset() {
m.LegacyIntrospection = nil
m.UserSchema = nil
m.TokenExchange = nil
m.Actions = nil
}
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
case feature.KeyUserSchema:
m.UserSchema = &event.Value
case feature.KeyActions:
m.Actions = &event.Value
}
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.TokenExchange, f.TokenExchange, feature_v2.InstanceTokenExchangeEventType)
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
}

View File

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

View File

@ -14,6 +14,7 @@ type SystemFeatures struct {
LegacyIntrospection *bool
TokenExchange *bool
UserSchema *bool
Actions *bool
}
func (m *SystemFeatures) isEmpty() bool {
@ -21,7 +22,8 @@ func (m *SystemFeatures) isEmpty() bool {
m.TriggerIntrospectionProjections == nil &&
m.LegacyIntrospection == 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) {

View File

@ -51,6 +51,7 @@ func (m *SystemFeaturesWriteModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.SystemLegacyIntrospectionEventType,
feature_v2.SystemUserSchemaEventType,
feature_v2.SystemTokenExchangeEventType,
feature_v2.SystemActionsEventType,
).
Builder().ResourceOwner(m.ResourceOwner)
}
@ -61,6 +62,7 @@ func (m *SystemFeaturesWriteModel) reduceReset() {
m.LegacyIntrospection = nil
m.TokenExchange = nil
m.UserSchema = nil
m.Actions = nil
}
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
case feature.KeyTokenExchange:
m.TokenExchange = &event.Value
case feature.KeyActions:
m.Actions = &event.Value
}
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.UserSchema, f.UserSchema, feature_v2.SystemUserSchemaEventType)
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
}

View File

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

View File

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

View File

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

View File

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

View File

@ -7,11 +7,11 @@ import (
"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 {
if i < 0 || i >= Key(len(_KeyIndex)-1) {
@ -30,23 +30,26 @@ func _KeyNoOp() {
_ = x[KeyLegacyIntrospection-(3)]
_ = x[KeyUserSchema-(4)]
_ = 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{
_KeyName[0:11]: KeyUnspecified,
_KeyLowerName[0:11]: KeyUnspecified,
_KeyName[11:28]: KeyLoginDefaultOrg,
_KeyLowerName[11:28]: KeyLoginDefaultOrg,
_KeyName[28:61]: KeyTriggerIntrospectionProjections,
_KeyLowerName[28:61]: KeyTriggerIntrospectionProjections,
_KeyName[61:81]: KeyLegacyIntrospection,
_KeyLowerName[61:81]: KeyLegacyIntrospection,
_KeyName[81:92]: KeyUserSchema,
_KeyLowerName[81:92]: KeyUserSchema,
_KeyName[92:106]: KeyTokenExchange,
_KeyLowerName[92:106]: KeyTokenExchange,
_KeyName[0:11]: KeyUnspecified,
_KeyLowerName[0:11]: KeyUnspecified,
_KeyName[11:28]: KeyLoginDefaultOrg,
_KeyLowerName[11:28]: KeyLoginDefaultOrg,
_KeyName[28:61]: KeyTriggerIntrospectionProjections,
_KeyLowerName[28:61]: KeyTriggerIntrospectionProjections,
_KeyName[61:81]: KeyLegacyIntrospection,
_KeyLowerName[61:81]: KeyLegacyIntrospection,
_KeyName[81:92]: KeyUserSchema,
_KeyLowerName[81:92]: KeyUserSchema,
_KeyName[92:106]: KeyTokenExchange,
_KeyLowerName[92:106]: KeyTokenExchange,
_KeyName[106:113]: KeyActions,
_KeyLowerName[106:113]: KeyActions,
}
var _KeyNames = []string{
@ -56,6 +59,7 @@ var _KeyNames = []string{
_KeyName[61:81],
_KeyName[81:92],
_KeyName[92:106],
_KeyName[106:113],
}
// 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
//
// Package mock is a generated GoMock package.
package mock

View File

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

View File

@ -5,6 +5,7 @@
//
// 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

View File

@ -5,6 +5,7 @@
//
// 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

View File

@ -5,6 +5,7 @@
//
// 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

View File

@ -5,6 +5,7 @@
//
// 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

View File

@ -13,6 +13,7 @@ type InstanceFeatures struct {
LegacyIntrospection FeatureSource[bool]
UserSchema FeatureSource[bool]
TokenExchange FeatureSource[bool]
Actions FeatureSource[bool]
}
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.InstanceUserSchemaEventType,
feature_v2.InstanceTokenExchangeEventType,
feature_v2.InstanceActionsEventType,
).
Builder().ResourceOwner(m.ResourceOwner)
}
@ -75,6 +76,7 @@ func (m *InstanceFeaturesReadModel) reduceReset() {
m.instance.LegacyIntrospection = FeatureSource[bool]{}
m.instance.UserSchema = FeatureSource[bool]{}
m.instance.TokenExchange = FeatureSource[bool]{}
m.instance.Actions = FeatureSource[bool]{}
}
func (m *InstanceFeaturesReadModel) populateFromSystem() bool {
@ -86,6 +88,7 @@ func (m *InstanceFeaturesReadModel) populateFromSystem() bool {
m.instance.LegacyIntrospection = m.system.LegacyIntrospection
m.instance.UserSchema = m.system.UserSchema
m.instance.TokenExchange = m.system.TokenExchange
m.instance.Actions = m.system.Actions
return true
}
@ -109,6 +112,8 @@ func (m *InstanceFeaturesReadModel) reduceBoolFeature(event *feature_v2.SetEvent
dst = &m.instance.UserSchema
case feature.KeyTokenExchange:
dst = &m.instance.TokenExchange
case feature.KeyActions:
dst = &m.instance.Actions
}
*dst = FeatureSource[bool]{
Level: level,

View File

@ -105,6 +105,10 @@ func TestQueries_GetInstanceFeatures(t *testing.T) {
ctx, aggregate,
feature_v2.InstanceUserSchemaEventType, false,
)),
eventFromEventPusher(feature_v2.NewSetEvent[bool](
ctx, aggregate,
feature_v2.InstanceActionsEventType, false,
)),
),
),
args: args{true},
@ -128,6 +132,10 @@ func TestQueries_GetInstanceFeatures(t *testing.T) {
Level: feature.LevelInstance,
Value: false,
},
Actions: FeatureSource[bool]{
Level: feature.LevelInstance,
Value: false,
},
},
},
{
@ -154,6 +162,10 @@ func TestQueries_GetInstanceFeatures(t *testing.T) {
ctx, aggregate,
feature_v2.InstanceUserSchemaEventType, false,
)),
eventFromEventPusher(feature_v2.NewSetEvent[bool](
ctx, aggregate,
feature_v2.InstanceActionsEventType, false,
)),
eventFromEventPusher(feature_v2.NewResetEvent(
ctx, aggregate,
feature_v2.InstanceResetEventType,
@ -185,6 +197,10 @@ func TestQueries_GetInstanceFeatures(t *testing.T) {
Level: feature.LevelUnspecified,
Value: false,
},
Actions: FeatureSource[bool]{
Level: feature.LevelUnspecified,
Value: false,
},
},
},
{
@ -207,6 +223,10 @@ func TestQueries_GetInstanceFeatures(t *testing.T) {
ctx, aggregate,
feature_v2.InstanceUserSchemaEventType, false,
)),
eventFromEventPusher(feature_v2.NewSetEvent[bool](
ctx, aggregate,
feature_v2.InstanceActionsEventType, false,
)),
eventFromEventPusher(feature_v2.NewResetEvent(
ctx, aggregate,
feature_v2.InstanceResetEventType,
@ -238,6 +258,10 @@ func TestQueries_GetInstanceFeatures(t *testing.T) {
Level: feature.LevelUnspecified,
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,
Reduce: reduceInstanceSetFeature[bool],
},
{
Event: feature_v2.InstanceActionsEventType,
Reduce: reduceInstanceSetFeature[bool],
},
{
Event: instance.InstanceRemovedEventType,
Reduce: reduceInstanceRemovedHelper(InstanceDomainInstanceIDCol),

View File

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

View File

@ -20,6 +20,7 @@ type SystemFeatures struct {
LegacyIntrospection FeatureSource[bool]
UserSchema FeatureSource[bool]
TokenExchange FeatureSource[bool]
Actions FeatureSource[bool]
}
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.SystemUserSchemaEventType,
feature_v2.SystemTokenExchangeEventType,
feature_v2.SystemActionsEventType,
).
Builder().ResourceOwner(m.ResourceOwner)
}
@ -78,6 +79,8 @@ func (m *SystemFeaturesReadModel) reduceBoolFeature(event *feature_v2.SetEvent[b
dst = &m.system.UserSchema
case feature.KeyTokenExchange:
dst = &m.system.TokenExchange
case feature.KeyActions:
dst = &m.system.Actions
}
*dst = FeatureSource[bool]{

View File

@ -61,6 +61,10 @@ func TestQueries_GetSystemFeatures(t *testing.T) {
context.Background(), aggregate,
feature_v2.SystemUserSchemaEventType, false,
)),
eventFromEventPusher(feature_v2.NewSetEvent[bool](
context.Background(), aggregate,
feature_v2.SystemActionsEventType, true,
)),
),
),
want: &SystemFeatures{
@ -83,6 +87,10 @@ func TestQueries_GetSystemFeatures(t *testing.T) {
Level: feature.LevelSystem,
Value: false,
},
Actions: FeatureSource[bool]{
Level: feature.LevelSystem,
Value: true,
},
},
},
{
@ -105,6 +113,10 @@ func TestQueries_GetSystemFeatures(t *testing.T) {
context.Background(), aggregate,
feature_v2.SystemUserSchemaEventType, false,
)),
eventFromEventPusher(feature_v2.NewSetEvent[bool](
context.Background(), aggregate,
feature_v2.SystemActionsEventType, false,
)),
eventFromEventPusher(feature_v2.NewResetEvent(
context.Background(), aggregate,
feature_v2.SystemResetEventType,
@ -135,6 +147,10 @@ func TestQueries_GetSystemFeatures(t *testing.T) {
Level: feature.LevelUnspecified,
Value: false,
},
Actions: FeatureSource[bool]{
Level: feature.LevelUnspecified,
Value: false,
},
},
},
{
@ -157,6 +173,10 @@ func TestQueries_GetSystemFeatures(t *testing.T) {
context.Background(), aggregate,
feature_v2.SystemUserSchemaEventType, false,
)),
eventFromEventPusher(feature_v2.NewSetEvent[bool](
context.Background(), aggregate,
feature_v2.SystemActionsEventType, false,
)),
eventFromEventPusher(feature_v2.NewResetEvent(
context.Background(), aggregate,
feature_v2.SystemResetEventType,
@ -187,6 +207,10 @@ func TestQueries_GetSystemFeatures(t *testing.T) {
Level: feature.LevelUnspecified,
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, SystemUserSchemaEventType, 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, InstanceLoginDefaultOrgEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceTriggerIntrospectionProjectionsEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceLegacyIntrospectionEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceUserSchemaEventType, 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)
SystemUserSchemaEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyUserSchema)
SystemTokenExchangeEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyTokenExchange)
SystemActionsEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyActions)
InstanceResetEventType = resetEventTypeFromFeature(feature.LevelInstance)
InstanceLoginDefaultOrgEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyLoginDefaultOrg)
@ -24,6 +25,7 @@ var (
InstanceLegacyIntrospectionEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyLegacyIntrospection)
InstanceUserSchemaEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyUserSchema)
InstanceTokenExchangeEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyTokenExchange)
InstanceActionsEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyActions)
)
const (

View File

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

View File

@ -1,6 +1,6 @@
syntax = "proto3";
package zitadel.execution.v3alpha;
package zitadel.action.v3alpha;
import "google/api/annotations.proto";
import "google/api/field_behavior.proto";
@ -8,17 +8,17 @@ import "google/protobuf/duration.proto";
import "google/protobuf/struct.proto";
import "protoc-gen-openapiv2/options/annotations.proto";
import "validate/validate.proto";
import "zitadel/execution/v3alpha/target.proto";
import "zitadel/execution/v3alpha/execution.proto";
import "zitadel/execution/v3alpha/query.proto";
import "zitadel/action/v3alpha/target.proto";
import "zitadel/action/v3alpha/execution.proto";
import "zitadel/action/v3alpha/query.proto";
import "zitadel/object/v2beta/object.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) = {
info: {
title: "Execution Service";
title: "Action Service";
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.";
contact:{
@ -104,7 +104,7 @@ option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
}
};
service ExecutionService {
service ActionService {
// Create a target
//
@ -516,22 +516,22 @@ message ListTargetsRequest {
// list limitations and ordering.
zitadel.object.v2beta.ListQuery query = 1;
// 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) = {
example: "\"FIELD_NAME_SCHEMA_TYPE\""
}
];
// Define the criteria to query for.
repeated zitadel.execution.v3alpha.TargetSearchQuery queries = 3;
repeated zitadel.action.v3alpha.TargetSearchQuery queries = 3;
}
message ListTargetsResponse {
// Details provides information about the returned result including total amount found.
zitadel.object.v2beta.ListDetails details = 1;
// 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.
repeated zitadel.execution.v3alpha.Target result = 3;
repeated zitadel.action.v3alpha.Target result = 3;
}
message GetTargetByIDRequest {
@ -548,7 +548,7 @@ message GetTargetByIDRequest {
}
message GetTargetByIDResponse {
zitadel.execution.v3alpha.Target target = 1;
zitadel.action.v3alpha.Target target = 1;
}
message SetExecutionRequest {
@ -579,14 +579,14 @@ message ListExecutionsRequest {
// list limitations and ordering.
zitadel.object.v2beta.ListQuery query = 1;
// Define the criteria to query for.
repeated zitadel.execution.v3alpha.SearchQuery queries = 2;
repeated zitadel.action.v3alpha.SearchQuery queries = 2;
}
message ListExecutionsResponse {
// Details provides information about the returned result including total amount found.
zitadel.object.v2beta.ListDetails details = 1;
// 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{}

View File

@ -1,6 +1,6 @@
syntax = "proto3";
package zitadel.execution.v3alpha;
package zitadel.action.v3alpha;
import "google/api/annotations.proto";
import "google/api/field_behavior.proto";
@ -11,7 +11,7 @@ import "validate/validate.proto";
import "zitadel/object/v2beta/object.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 {
string execution_id = 1 [

View File

@ -1,14 +1,14 @@
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 "protoc-gen-openapiv2/options/annotations.proto";
import "validate/validate.proto";
import "zitadel/object/v2beta/object.proto";
import "zitadel/execution/v3alpha/execution.proto";
import "zitadel/action/v3alpha/execution.proto";
message SearchQuery {
oneof query {

View File

@ -1,6 +1,6 @@
syntax = "proto3";
package zitadel.execution.v3alpha;
package zitadel.action.v3alpha;
import "google/api/annotations.proto";
import "google/api/field_behavior.proto";
@ -11,7 +11,7 @@ import "validate/validate.proto";
import "zitadel/object/v2beta/object.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 {
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.";
}
];
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 {
@ -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.";
}
];
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.";
}
];
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 {
@ -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.";
}
];
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.";
}
];
}