fix: remove action feature flag and include execution (#9727)

# Which Problems Are Solved

Actions v2 is not a feature flag anymore, include functionality on
executions is not used and json tags of proto messages are handled
incorrectly.

# How the Problems Are Solved

- Remove actions from the feature flags on system and instance level
- Remove include type on executions, only in the API, later maybe in the
handling logic as well
- Use protojson in request and response handling of actions v2

# Additional Changes

- Correct integration tests for request and response handling
- Use json.RawMessage for events, so that the event payload is not
base64 encoded
- Added separate context for async webhook calls, that executions are
not cancelled when called async

# Additional Context

Related to #9759 
Closes #9710

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
Stefan Benz
2025-04-28 11:24:50 +02:00
committed by GitHub
parent 84628671bd
commit b8ba7bd5ba
55 changed files with 427 additions and 799 deletions

View File

@@ -145,7 +145,14 @@ the [Sent information Event](./usage#sent-information-event) payload description
"event_type": "user.human.added",
"created_at": "2025-03-27T10:22:43.262665+01:00",
"userID": "312909075212468632",
"event_payload": "eyJ1c2VyTmFtZSI6ImV4YW1wbGVAdGVzdC5jb20iLCJmaXJzdE5hbWUiOiJUZXN0IiwibGFzdE5hbWUiOiJVc2VyIiwiZGlzcGxheU5hbWUiOiJUZXN0IFVzZXIiLCJwcmVmZXJyZWRMYW5ndWFnZSI6InVuZCIsImVtYWlsIjoiZXhhbXBsZUB0ZXN0LmNvbSJ9"
"event_payload": {
"userName":"example@test.com",
"firstName":"Test",
"lastName":"User",
"displayName":"Test User",
"preferredLanguage":"und",
"email":"example@test.com"
}
}
```

View File

@@ -18,6 +18,11 @@ Note that this guide assumes that ZITADEL is running on the same machine as the
In case you are using a different setup, you need to adjust the target URL accordingly and will need to make sure that the target is reachable from ZITADEL.
:::
:::warning
To marshal and unmarshal the request please use a package like [protojson](https://pkg.go.dev/google.golang.org/protobuf/encoding/protojson),
as the request is a protocol buffer message, to avoid potential problems with the attribute names.
:::
## Start example target
To test the actions feature, you need to create a target that will be called when an API endpoint is called.
@@ -37,10 +42,28 @@ import (
"net/http"
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
"google.golang.org/protobuf/encoding/protojson"
)
type contextRequest struct {
Request *user.AddHumanUserRequest `json:"request"`
Request *addHumanUserRequestWrapper `json:"request"`
}
// addHumanUserRequestWrapper necessary to marshal and unmarshal the JSON into the proto message correctly
type addHumanUserRequestWrapper struct {
user.AddHumanUserRequest
}
func (r *addHumanUserRequestWrapper) MarshalJSON() ([]byte, error) {
data, err := protojson.Marshal(r)
if err != nil {
return nil, err
}
return data, nil
}
func (r *addHumanUserRequestWrapper) UnmarshalJSON(data []byte) error {
return protojson.Unmarshal(data, r)
}
// call HandleFunc to read the request body, manipulate the content and return the manipulated request

View File

@@ -18,6 +18,11 @@ Note that this guide assumes that ZITADEL is running on the same machine as the
In case you are using a different setup, you need to adjust the target URL accordingly and will need to make sure that the target is reachable from ZITADEL.
:::
:::warning
To marshal and unmarshal the request please use a package like [protojson](https://pkg.go.dev/google.golang.org/protobuf/encoding/protojson),
as the request is a protocol buffer message, to avoid potential problems with the attribute names.
:::
## Start example target
To test the actions feature, you need to create a target that will be called when an API endpoint is called.

View File

@@ -18,6 +18,11 @@ Note that this guide assumes that ZITADEL is running on the same machine as the
In case you are using a different setup, you need to adjust the target URL accordingly and will need to make sure that the target is reachable from ZITADEL.
:::
:::warning
To marshal and unmarshal the request please use a package like [protojson](https://pkg.go.dev/google.golang.org/protobuf/encoding/protojson),
as the request is a protocol buffer message, to avoid potential problems with the attribute names.
:::
## Start example target
To test the actions feature, you need to create a target that will be called when an API endpoint is called.

View File

@@ -18,6 +18,11 @@ Note that this guide assumes that ZITADEL is running on the same machine as the
In case you are using a different setup, you need to adjust the target URL accordingly and will need to make sure that the target is reachable from ZITADEL.
:::
:::warning
To marshal and unmarshal the request and response please use a package like [protojson](https://pkg.go.dev/google.golang.org/protobuf/encoding/protojson),
as the request and response are protocol buffer messages, to avoid potential problems with the attribute names.
:::
## Start example target
To test the actions feature, you need to create a target that will be called when an API endpoint is called.
@@ -37,11 +42,46 @@ import (
"net/http"
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
"google.golang.org/protobuf/encoding/protojson"
)
type response struct {
Request *user.RetrieveIdentityProviderIntentRequest `json:"request"`
Response *user.RetrieveIdentityProviderIntentResponse `json:"response"`
type contextResponse struct {
Request *retrieveIdentityProviderIntentRequestWrapper `json:"request"`
Response *retrieveIdentityProviderIntentResponseWrapper `json:"response"`
}
// RetrieveIdentityProviderIntentRequestWrapper necessary to marshal and unmarshal the JSON into the proto message correctly
type retrieveIdentityProviderIntentRequestWrapper struct {
user.RetrieveIdentityProviderIntentRequest
}
func (r *retrieveIdentityProviderIntentRequestWrapper) MarshalJSON() ([]byte, error) {
data, err := protojson.Marshal(r)
if err != nil {
return nil, err
}
return data, nil
}
func (r *retrieveIdentityProviderIntentRequestWrapper) UnmarshalJSON(data []byte) error {
return protojson.Unmarshal(data, r)
}
// RetrieveIdentityProviderIntentResponseWrapper necessary to marshal and unmarshal the JSON into the proto message correctly
type retrieveIdentityProviderIntentResponseWrapper struct {
user.RetrieveIdentityProviderIntentResponse
}
func (r *retrieveIdentityProviderIntentResponseWrapper) MarshalJSON() ([]byte, error) {
data, err := protojson.Marshal(r)
if err != nil {
return nil, err
}
return data, nil
}
func (r *retrieveIdentityProviderIntentResponseWrapper) UnmarshalJSON(data []byte) error {
return protojson.Unmarshal(data, r)
}
// call HandleFunc to read the response body, manipulate the content and return the response
@@ -56,7 +96,7 @@ func call(w http.ResponseWriter, req *http.Request) {
defer req.Body.Close()
// read the response into the expected structure
request := new(response)
request := new(contextResponse)
if err := json.Unmarshal(sentBody, request); err != nil {
http.Error(w, "error", http.StatusInternalServerError)
}

View File

@@ -18,6 +18,11 @@ Note that this guide assumes that ZITADEL is running on the same machine as the
In case you are using a different setup, you need to adjust the target URL accordingly and will need to make sure that the target is reachable from ZITADEL.
:::
:::warning
To marshal and unmarshal the request and response please use a package like [protojson](https://pkg.go.dev/google.golang.org/protobuf/encoding/protojson),
as the request and response are protocol buffer messages, to avoid potential problems with the attribute names.
:::
## Start example target
To test the actions feature, you need to create a target that will be called when an API endpoint is called.

View File

@@ -36,6 +36,11 @@ The information sent to the Endpoint is structured as JSON:
}
```
:::warning
To marshal and unmarshal the request please use a package like [protojson](https://pkg.go.dev/google.golang.org/protobuf/encoding/protojson),
as the request is a protocol buffer message, to avoid potential problems with the attribute names.
:::
### Sent information Response
The information sent to the Endpoint is structured as JSON:
@@ -56,6 +61,11 @@ The information sent to the Endpoint is structured as JSON:
}
```
:::warning
To marshal and unmarshal the request and response please use a package like [protojson](https://pkg.go.dev/google.golang.org/protobuf/encoding/protojson),
as the request and response are protocol buffer messages, to avoid potential problems with the attribute names.
:::
### Sent information Function
Information sent and expected back are specific to the function.
@@ -338,7 +348,7 @@ The information sent to the Endpoint is structured as JSON:
"event_type": "Type of the event",
"created_at": "Time the event was created",
"userID": "ID of the creator of the event",
"event_payload": "Base64 encoded content of the event"
"event_payload": "Content of the event in JSON format"
}
```

View File

@@ -14,22 +14,10 @@ import (
)
func (s *Server) SetExecution(ctx context.Context, req *action.SetExecutionRequest) (*action.SetExecutionResponse, error) {
if err := checkActionsEnabled(ctx); err != nil {
return nil, err
}
reqTargets := req.GetTargets()
targets := make([]*execution.Target, len(reqTargets))
for i, target := range reqTargets {
switch t := target.GetType().(type) {
case *action.ExecutionTargetType_Include:
include, err := conditionToInclude(t.Include)
if err != nil {
return nil, err
}
targets[i] = &execution.Target{Type: domain.ExecutionTargetTypeInclude, Target: include}
case *action.ExecutionTargetType_Target:
targets[i] = &execution.Target{Type: domain.ExecutionTargetTypeTarget, Target: t.Target}
}
targets[i] = &execution.Target{Type: domain.ExecutionTargetTypeTarget, Target: target}
}
set := &command.SetExecution{
Targets: targets,
@@ -60,59 +48,19 @@ func (s *Server) SetExecution(ctx context.Context, req *action.SetExecutionReque
}, nil
}
func conditionToInclude(cond *action.Condition) (string, error) {
switch t := cond.GetConditionType().(type) {
case *action.Condition_Request:
cond := executionConditionFromRequest(t.Request)
if err := cond.IsValid(); err != nil {
return "", err
}
return cond.ID(domain.ExecutionTypeRequest), nil
case *action.Condition_Response:
cond := executionConditionFromResponse(t.Response)
if err := cond.IsValid(); err != nil {
return "", err
}
return cond.ID(domain.ExecutionTypeRequest), nil
case *action.Condition_Event:
cond := executionConditionFromEvent(t.Event)
if err := cond.IsValid(); err != nil {
return "", err
}
return cond.ID(), nil
case *action.Condition_Function:
cond := command.ExecutionFunctionCondition(t.Function.GetName())
if err := cond.IsValid(); err != nil {
return "", err
}
return cond.ID(), nil
default:
return "", zerrors.ThrowInvalidArgument(nil, "ACTION-9BBob", "Errors.Execution.ConditionInvalid")
}
}
func (s *Server) ListExecutionFunctions(ctx context.Context, _ *action.ListExecutionFunctionsRequest) (*action.ListExecutionFunctionsResponse, error) {
if err := checkActionsEnabled(ctx); err != nil {
return nil, err
}
return &action.ListExecutionFunctionsResponse{
Functions: s.ListActionFunctions(),
}, nil
}
func (s *Server) ListExecutionMethods(ctx context.Context, _ *action.ListExecutionMethodsRequest) (*action.ListExecutionMethodsResponse, error) {
if err := checkActionsEnabled(ctx); err != nil {
return nil, err
}
return &action.ListExecutionMethodsResponse{
Methods: s.ListGRPCMethods(),
}, nil
}
func (s *Server) ListExecutionServices(ctx context.Context, _ *action.ListExecutionServicesRequest) (*action.ListExecutionServicesResponse, error) {
if err := checkActionsEnabled(ctx); err != nil {
return nil, err
}
return &action.ListExecutionServicesResponse{
Services: s.ListGRPCServices(),
}, nil

View File

@@ -48,7 +48,6 @@ var (
func TestServer_ExecutionTarget(t *testing.T) {
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
fullMethod := action.ActionService_GetTarget_FullMethodName
@@ -77,14 +76,14 @@ func TestServer_ExecutionTarget(t *testing.T) {
targetCreated := instance.CreateTarget(ctx, t, targetCreatedName, targetCreatedURL, domain.TargetTypeCall, false)
// request received by target
wantRequest := &middleware.ContextInfoRequest{FullMethod: fullMethod, InstanceID: instance.ID(), OrgID: orgID, ProjectID: projectID, UserID: userID, Request: request}
wantRequest := &middleware.ContextInfoRequest{FullMethod: fullMethod, InstanceID: instance.ID(), OrgID: orgID, ProjectID: projectID, UserID: userID, Request: middleware.Message{Message: request}}
changedRequest := &action.GetTargetRequest{Id: targetCreated.GetId()}
// replace original request with different targetID
urlRequest, closeRequest, calledRequest, _ := integration.TestServerCall(wantRequest, 0, http.StatusOK, changedRequest)
urlRequest, closeRequest, calledRequest, _ := integration.TestServerCallProto(wantRequest, 0, http.StatusOK, changedRequest)
targetRequest := waitForTarget(ctx, t, instance, urlRequest, domain.TargetTypeCall, false)
waitForExecutionOnCondition(ctx, t, instance, conditionRequestFullMethod(fullMethod), executionTargetsSingleTarget(targetRequest.GetId()))
waitForExecutionOnCondition(ctx, t, instance, conditionRequestFullMethod(fullMethod), []string{targetRequest.GetId()})
// expected response from the GetTarget
expectedResponse := &action.GetTargetResponse{
@@ -103,9 +102,26 @@ func TestServer_ExecutionTarget(t *testing.T) {
SigningKey: targetCreated.GetSigningKey(),
},
}
// has to be set separately because of the pointers
changedResponse := &action.GetTargetResponse{
Target: &action.Target{
Id: "changed",
CreationDate: targetCreated.GetCreationDate(),
ChangeDate: targetCreated.GetCreationDate(),
Name: targetCreatedName,
TargetType: &action.Target_RestCall{
RestCall: &action.RESTCall{
InterruptOnError: false,
},
},
Timeout: durationpb.New(5 * time.Second),
Endpoint: targetCreatedURL,
SigningKey: targetCreated.GetSigningKey(),
},
}
// content for update
response.Target = &action.Target{
Id: targetCreated.GetId(),
Id: "changed",
CreationDate: targetCreated.GetCreationDate(),
ChangeDate: targetCreated.GetCreationDate(),
Name: targetCreatedName,
@@ -119,18 +135,6 @@ func TestServer_ExecutionTarget(t *testing.T) {
SigningKey: targetCreated.GetSigningKey(),
}
// content for partial update
changedResponse := &action.GetTargetResponse{
Target: &action.Target{
Id: targetCreated.GetId(),
TargetType: &action.Target_RestCall{
RestCall: &action.RESTCall{
InterruptOnError: false,
},
},
},
}
// response received by target
wantResponse := &middleware.ContextInfoResponse{
FullMethod: fullMethod,
@@ -138,14 +142,14 @@ func TestServer_ExecutionTarget(t *testing.T) {
OrgID: orgID,
ProjectID: projectID,
UserID: userID,
Request: changedRequest,
Response: expectedResponse,
Request: middleware.Message{Message: changedRequest},
Response: middleware.Message{Message: expectedResponse},
}
// after request with different targetID, return changed response
targetResponseURL, closeResponse, calledResponse, _ := integration.TestServerCall(wantResponse, 0, http.StatusOK, changedResponse)
targetResponseURL, closeResponse, calledResponse, _ := integration.TestServerCallProto(wantResponse, 0, http.StatusOK, changedResponse)
targetResponse := waitForTarget(ctx, t, instance, targetResponseURL, domain.TargetTypeCall, false)
waitForExecutionOnCondition(ctx, t, instance, conditionResponseFullMethod(fullMethod), executionTargetsSingleTarget(targetResponse.GetId()))
waitForExecutionOnCondition(ctx, t, instance, conditionResponseFullMethod(fullMethod), []string{targetResponse.GetId()})
return func() {
closeRequest()
closeResponse()
@@ -167,9 +171,7 @@ func TestServer_ExecutionTarget(t *testing.T) {
Id: "something",
},
want: &action.GetTargetResponse{
Target: &action.Target{
Id: "changed",
},
// defined in the dependency function
},
},
{
@@ -181,11 +183,11 @@ func TestServer_ExecutionTarget(t *testing.T) {
userID := instance.Users.Get(integration.UserTypeIAMOwner).ID
// request received by target
wantRequest := &middleware.ContextInfoRequest{FullMethod: fullMethod, InstanceID: instance.ID(), OrgID: orgID, ProjectID: projectID, UserID: userID, Request: request}
urlRequest, closeRequest, calledRequest, _ := integration.TestServerCall(wantRequest, 0, http.StatusInternalServerError, &action.GetTargetRequest{Id: "notchanged"})
wantRequest := &middleware.ContextInfoRequest{FullMethod: fullMethod, InstanceID: instance.ID(), OrgID: orgID, ProjectID: projectID, UserID: userID, Request: middleware.Message{Message: request}}
urlRequest, closeRequest, calledRequest, _ := integration.TestServerCallProto(wantRequest, 0, http.StatusInternalServerError, nil)
targetRequest := waitForTarget(ctx, t, instance, urlRequest, domain.TargetTypeCall, true)
waitForExecutionOnCondition(ctx, t, instance, conditionRequestFullMethod(fullMethod), executionTargetsSingleTarget(targetRequest.GetId()))
waitForExecutionOnCondition(ctx, t, instance, conditionRequestFullMethod(fullMethod), []string{targetRequest.GetId()})
// GetTarget with used target
request.Id = targetRequest.GetId()
return func() {
@@ -234,17 +236,6 @@ func TestServer_ExecutionTarget(t *testing.T) {
SigningKey: targetCreated.GetSigningKey(),
},
}
// content for partial update
changedResponse := &action.GetTargetResponse{
Target: &action.Target{
Id: "changed",
TargetType: &action.Target_RestCall{
RestCall: &action.RESTCall{
InterruptOnError: false,
},
},
},
}
// response received by target
wantResponse := &middleware.ContextInfoResponse{
@@ -253,14 +244,14 @@ func TestServer_ExecutionTarget(t *testing.T) {
OrgID: orgID,
ProjectID: projectID,
UserID: userID,
Request: request,
Response: expectedResponse,
Request: middleware.Message{Message: request},
Response: middleware.Message{Message: expectedResponse},
}
// after request with different targetID, return changed response
targetResponseURL, closeResponse, calledResponse, _ := integration.TestServerCall(wantResponse, 0, http.StatusInternalServerError, changedResponse)
targetResponseURL, closeResponse, calledResponse, _ := integration.TestServerCallProto(wantResponse, 0, http.StatusInternalServerError, nil)
targetResponse := waitForTarget(ctx, t, instance, targetResponseURL, domain.TargetTypeCall, true)
waitForExecutionOnCondition(ctx, t, instance, conditionResponseFullMethod(fullMethod), executionTargetsSingleTarget(targetResponse.GetId()))
waitForExecutionOnCondition(ctx, t, instance, conditionResponseFullMethod(fullMethod), []string{targetResponse.GetId()})
return func() {
closeResponse()
}, func() bool {
@@ -301,7 +292,6 @@ func TestServer_ExecutionTarget(t *testing.T) {
func TestServer_ExecutionTarget_Event(t *testing.T) {
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
event := "session.added"
@@ -309,7 +299,7 @@ func TestServer_ExecutionTarget_Event(t *testing.T) {
defer closeF()
targetResponse := waitForTarget(isolatedIAMOwnerCTX, t, instance, urlRequest, domain.TargetTypeWebhook, true)
waitForExecutionOnCondition(isolatedIAMOwnerCTX, t, instance, conditionEvent(event), executionTargetsSingleTarget(targetResponse.GetId()))
waitForExecutionOnCondition(isolatedIAMOwnerCTX, t, instance, conditionEvent(event), []string{targetResponse.GetId()})
tests := []struct {
name string
@@ -359,7 +349,6 @@ func TestServer_ExecutionTarget_Event(t *testing.T) {
func TestServer_ExecutionTarget_Event_LongerThanTargetTimeout(t *testing.T) {
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
event := "session.added"
@@ -368,7 +357,7 @@ func TestServer_ExecutionTarget_Event_LongerThanTargetTimeout(t *testing.T) {
defer closeF()
targetResponse := waitForTarget(isolatedIAMOwnerCTX, t, instance, urlRequest, domain.TargetTypeWebhook, true)
waitForExecutionOnCondition(isolatedIAMOwnerCTX, t, instance, conditionEvent(event), executionTargetsSingleTarget(targetResponse.GetId()))
waitForExecutionOnCondition(isolatedIAMOwnerCTX, t, instance, conditionEvent(event), []string{targetResponse.GetId()})
tests := []struct {
name string
@@ -412,7 +401,6 @@ func TestServer_ExecutionTarget_Event_LongerThanTargetTimeout(t *testing.T) {
func TestServer_ExecutionTarget_Event_LongerThanTransactionTimeout(t *testing.T) {
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
event := "session.added"
@@ -420,7 +408,7 @@ func TestServer_ExecutionTarget_Event_LongerThanTransactionTimeout(t *testing.T)
defer closeF()
targetResponse := waitForTarget(isolatedIAMOwnerCTX, t, instance, urlRequest, domain.TargetTypeWebhook, true)
waitForExecutionOnCondition(isolatedIAMOwnerCTX, t, instance, conditionEvent(event), executionTargetsSingleTarget(targetResponse.GetId()))
waitForExecutionOnCondition(isolatedIAMOwnerCTX, t, instance, conditionEvent(event), []string{targetResponse.GetId()})
tests := []struct {
name string
@@ -474,7 +462,7 @@ func TestServer_ExecutionTarget_Event_LongerThanTransactionTimeout(t *testing.T)
}
}
func waitForExecutionOnCondition(ctx context.Context, t *testing.T, instance *integration.Instance, condition *action.Condition, targets []*action.ExecutionTargetType) {
func waitForExecutionOnCondition(ctx context.Context, t *testing.T, instance *integration.Instance, condition *action.Condition, targets []string) {
instance.SetExecution(ctx, t, condition, targets)
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(ctx, time.Minute)
@@ -496,7 +484,7 @@ func waitForExecutionOnCondition(ctx context.Context, t *testing.T, instance *in
// always first check length, otherwise its failed anyway
if assert.Len(ttt, gotTargets, len(targets)) {
for i := range targets {
assert.EqualExportedValues(ttt, targets[i].GetType(), gotTargets[i].GetType())
assert.EqualExportedValues(ttt, targets[i], gotTargets[i])
}
}
}, retryDuration, tick, "timeout waiting for expected execution result")
@@ -589,7 +577,6 @@ func conditionFunction(function string) *action.Condition {
func TestServer_ExecutionTargetPreUserinfo(t *testing.T) {
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMCtx := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
ctxLoginClient := instance.WithAuthorization(CTX, integration.UserTypeLogin)
@@ -785,7 +772,7 @@ func expectPreUserinfoExecution(ctx context.Context, t *testing.T, instance *int
targetURL, closeF, _, _ := integration.TestServerCall(expectedContextInfo, 0, http.StatusOK, response)
targetResp := waitForTarget(ctx, t, instance, targetURL, domain.TargetTypeCall, true)
waitForExecutionOnCondition(ctx, t, instance, conditionFunction("preuserinfo"), executionTargetsSingleTarget(targetResp.GetId()))
waitForExecutionOnCondition(ctx, t, instance, conditionFunction("preuserinfo"), []string{targetResp.GetId()})
return userResp.GetUserId(), closeF
}
@@ -903,7 +890,6 @@ func contextInfoForUserOIDC(instance *integration.Instance, function string, use
func TestServer_ExecutionTargetPreAccessToken(t *testing.T) {
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMCtx := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
ctxLoginClient := instance.WithAuthorization(CTX, integration.UserTypeLogin)
@@ -1091,13 +1077,12 @@ func expectPreAccessTokenExecution(ctx context.Context, t *testing.T, instance *
targetURL, closeF, _, _ := integration.TestServerCall(expectedContextInfo, 0, http.StatusOK, response)
targetResp := waitForTarget(ctx, t, instance, targetURL, domain.TargetTypeCall, true)
waitForExecutionOnCondition(ctx, t, instance, conditionFunction("preaccesstoken"), executionTargetsSingleTarget(targetResp.GetId()))
waitForExecutionOnCondition(ctx, t, instance, conditionFunction("preaccesstoken"), []string{targetResp.GetId()})
return userResp.GetUserId(), closeF
}
func TestServer_ExecutionTargetPreSAMLResponse(t *testing.T) {
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMCtx := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
ctxLoginClient := instance.WithAuthorization(CTX, integration.UserTypeLogin)
@@ -1257,7 +1242,7 @@ func expectPreSAMLResponseExecution(ctx context.Context, t *testing.T, instance
targetURL, closeF, _, _ := integration.TestServerCall(expectedContextInfo, 0, http.StatusOK, response)
targetResp := waitForTarget(ctx, t, instance, targetURL, domain.TargetTypeCall, true)
waitForExecutionOnCondition(ctx, t, instance, conditionFunction("presamlresponse"), executionTargetsSingleTarget(targetResp.GetId()))
waitForExecutionOnCondition(ctx, t, instance, conditionFunction("presamlresponse"), []string{targetResp.GetId()})
return userResp.GetUserId(), closeF
}

View File

@@ -15,17 +15,8 @@ import (
action "github.com/zitadel/zitadel/pkg/grpc/action/v2beta"
)
func executionTargetsSingleTarget(id string) []*action.ExecutionTargetType {
return []*action.ExecutionTargetType{{Type: &action.ExecutionTargetType_Target{Target: id}}}
}
func executionTargetsSingleInclude(include *action.Condition) []*action.ExecutionTargetType {
return []*action.ExecutionTargetType{{Type: &action.ExecutionTargetType_Include{Include: include}}}
}
func TestServer_SetExecution_Request(t *testing.T) {
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
targetResp := instance.CreateTarget(isolatedIAMOwnerCTX, t, "", "https://notexisting", domain.TargetTypeWebhook, false)
@@ -59,7 +50,7 @@ func TestServer_SetExecution_Request(t *testing.T) {
Request: &action.RequestExecution{},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantErr: true,
},
@@ -76,7 +67,7 @@ func TestServer_SetExecution_Request(t *testing.T) {
},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantErr: true,
},
@@ -93,7 +84,7 @@ func TestServer_SetExecution_Request(t *testing.T) {
},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantSetDate: true,
},
@@ -110,7 +101,7 @@ func TestServer_SetExecution_Request(t *testing.T) {
},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantErr: true,
},
@@ -127,7 +118,7 @@ func TestServer_SetExecution_Request(t *testing.T) {
},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantSetDate: true,
},
@@ -144,7 +135,7 @@ func TestServer_SetExecution_Request(t *testing.T) {
},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantSetDate: true,
},
@@ -181,125 +172,8 @@ func assertSetExecutionResponse(t *testing.T, creationDate, setDate time.Time, e
}
}
func TestServer_SetExecution_Request_Include(t *testing.T) {
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
targetResp := instance.CreateTarget(isolatedIAMOwnerCTX, t, "", "https://notexisting", domain.TargetTypeWebhook, false)
executionCond := &action.Condition{
ConditionType: &action.Condition_Request{
Request: &action.RequestExecution{
Condition: &action.RequestExecution_All{
All: true,
},
},
},
}
instance.SetExecution(isolatedIAMOwnerCTX, t,
executionCond,
executionTargetsSingleTarget(targetResp.GetId()),
)
circularExecutionService := &action.Condition{
ConditionType: &action.Condition_Request{
Request: &action.RequestExecution{
Condition: &action.RequestExecution_Service{
Service: "zitadel.session.v2beta.SessionService",
},
},
},
}
instance.SetExecution(isolatedIAMOwnerCTX, t,
circularExecutionService,
executionTargetsSingleInclude(executionCond),
)
circularExecutionMethod := &action.Condition{
ConditionType: &action.Condition_Request{
Request: &action.RequestExecution{
Condition: &action.RequestExecution_Method{
Method: "/zitadel.session.v2beta.SessionService/ListSessions",
},
},
},
}
instance.SetExecution(isolatedIAMOwnerCTX, t,
circularExecutionMethod,
executionTargetsSingleInclude(circularExecutionService),
)
tests := []struct {
name string
ctx context.Context
req *action.SetExecutionRequest
wantSetDate bool
wantErr bool
}{
{
name: "method, circular error",
ctx: isolatedIAMOwnerCTX,
req: &action.SetExecutionRequest{
Condition: circularExecutionService,
Targets: executionTargetsSingleInclude(circularExecutionMethod),
},
wantErr: true,
},
{
name: "method, ok",
ctx: isolatedIAMOwnerCTX,
req: &action.SetExecutionRequest{
Condition: &action.Condition{
ConditionType: &action.Condition_Request{
Request: &action.RequestExecution{
Condition: &action.RequestExecution_Method{
Method: "/zitadel.session.v2beta.SessionService/ListSessions",
},
},
},
},
Targets: executionTargetsSingleInclude(executionCond),
},
wantSetDate: true,
},
{
name: "service, ok",
ctx: isolatedIAMOwnerCTX,
req: &action.SetExecutionRequest{
Condition: &action.Condition{
ConditionType: &action.Condition_Request{
Request: &action.RequestExecution{
Condition: &action.RequestExecution_Service{
Service: "zitadel.user.v2beta.UserService",
},
},
},
},
Targets: executionTargetsSingleInclude(executionCond),
},
wantSetDate: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
creationDate := time.Now().UTC()
got, err := instance.Client.ActionV2beta.SetExecution(tt.ctx, tt.req)
setDate := time.Now().UTC()
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
assertSetExecutionResponse(t, creationDate, setDate, tt.wantSetDate, got)
// cleanup to not impact other requests
instance.DeleteExecution(tt.ctx, t, tt.req.GetCondition())
})
}
}
func TestServer_SetExecution_Response(t *testing.T) {
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
targetResp := instance.CreateTarget(isolatedIAMOwnerCTX, t, "", "https://notexisting", domain.TargetTypeWebhook, false)
@@ -333,7 +207,7 @@ func TestServer_SetExecution_Response(t *testing.T) {
Response: &action.ResponseExecution{},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantErr: true,
},
@@ -350,7 +224,7 @@ func TestServer_SetExecution_Response(t *testing.T) {
},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantErr: true,
},
@@ -367,7 +241,7 @@ func TestServer_SetExecution_Response(t *testing.T) {
},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantSetDate: true,
},
@@ -384,7 +258,7 @@ func TestServer_SetExecution_Response(t *testing.T) {
},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantErr: true,
},
@@ -401,7 +275,7 @@ func TestServer_SetExecution_Response(t *testing.T) {
},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantSetDate: true,
},
@@ -418,7 +292,7 @@ func TestServer_SetExecution_Response(t *testing.T) {
},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantSetDate: true,
},
@@ -444,7 +318,6 @@ func TestServer_SetExecution_Response(t *testing.T) {
func TestServer_SetExecution_Event(t *testing.T) {
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
targetResp := instance.CreateTarget(isolatedIAMOwnerCTX, t, "", "https://notexisting", domain.TargetTypeWebhook, false)
@@ -480,7 +353,7 @@ func TestServer_SetExecution_Event(t *testing.T) {
Event: &action.EventExecution{},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantErr: true,
},
@@ -497,7 +370,7 @@ func TestServer_SetExecution_Event(t *testing.T) {
},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantErr: true,
},
@@ -514,7 +387,7 @@ func TestServer_SetExecution_Event(t *testing.T) {
},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantSetDate: true,
},
@@ -531,7 +404,7 @@ func TestServer_SetExecution_Event(t *testing.T) {
},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantErr: true,
},
@@ -548,7 +421,7 @@ func TestServer_SetExecution_Event(t *testing.T) {
},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantSetDate: true,
},
@@ -565,7 +438,7 @@ func TestServer_SetExecution_Event(t *testing.T) {
},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantSetDate: true,
},
@@ -582,7 +455,7 @@ func TestServer_SetExecution_Event(t *testing.T) {
},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantSetDate: true,
},
@@ -608,7 +481,6 @@ func TestServer_SetExecution_Event(t *testing.T) {
func TestServer_SetExecution_Function(t *testing.T) {
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
targetResp := instance.CreateTarget(isolatedIAMOwnerCTX, t, "", "https://notexisting", domain.TargetTypeWebhook, false)
@@ -642,7 +514,7 @@ func TestServer_SetExecution_Function(t *testing.T) {
Response: &action.ResponseExecution{},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantErr: true,
},
@@ -655,7 +527,7 @@ func TestServer_SetExecution_Function(t *testing.T) {
Function: &action.FunctionExecution{Name: "xxx"},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantErr: true,
},
@@ -668,7 +540,7 @@ func TestServer_SetExecution_Function(t *testing.T) {
Function: &action.FunctionExecution{Name: "presamlresponse"},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
wantSetDate: true,
},

View File

@@ -8,6 +8,7 @@ import (
"time"
"github.com/brianvoe/gofakeit/v6"
"github.com/muhlemmer/gu"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/durationpb"
@@ -20,7 +21,6 @@ import (
func TestServer_GetTarget(t *testing.T) {
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
type args struct {
ctx context.Context
@@ -213,7 +213,6 @@ func TestServer_GetTarget(t *testing.T) {
func TestServer_ListTargets(t *testing.T) {
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
type args struct {
ctx context.Context
@@ -446,7 +445,6 @@ func assertPaginationResponse(t *assert.CollectT, expected *filter.PaginationRes
func TestServer_ListExecutions(t *testing.T) {
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
targetResp := instance.CreateTarget(isolatedIAMOwnerCTX, t, "", "https://example.com", domain.TargetTypeWebhook, false)
@@ -475,7 +473,7 @@ func TestServer_ListExecutions(t *testing.T) {
ctx: isolatedIAMOwnerCTX,
dep: func(ctx context.Context, request *action.ListExecutionsRequest, response *action.ListExecutionsResponse) {
cond := request.Filters[0].GetInConditionsFilter().GetConditions()[0]
resp := instance.SetExecution(ctx, t, cond, executionTargetsSingleTarget(targetResp.GetId()))
resp := instance.SetExecution(ctx, t, cond, []string{targetResp.GetId()})
// Set expected response with used values for SetExecution
response.Result[0].CreationDate = resp.GetSetDate()
@@ -516,7 +514,7 @@ func TestServer_ListExecutions(t *testing.T) {
},
},
},
Targets: executionTargetsSingleTarget(targetResp.GetId()),
Targets: []string{targetResp.GetId()},
},
},
},
@@ -544,13 +542,12 @@ func TestServer_ListExecutions(t *testing.T) {
},
},
}
targets := executionTargetsSingleTarget(target.GetId())
resp := instance.SetExecution(ctx, t, cond, targets)
resp := instance.SetExecution(ctx, t, cond, []string{target.GetId()})
response.Result[0].CreationDate = resp.GetSetDate()
response.Result[0].ChangeDate = resp.GetSetDate()
response.Result[0].Condition = cond
response.Result[0].Targets = targets
response.Result[0].Targets = []string{target.GetId()}
},
req: &action.ListExecutionsRequest{
Filters: []*action.ExecutionSearchFilter{{}},
@@ -564,63 +561,10 @@ func TestServer_ListExecutions(t *testing.T) {
Result: []*action.Execution{
{
Condition: &action.Condition{},
Targets: executionTargetsSingleTarget(""),
Targets: []string{""},
},
},
},
}, {
name: "list request single include",
args: args{
ctx: isolatedIAMOwnerCTX,
dep: func(ctx context.Context, request *action.ListExecutionsRequest, response *action.ListExecutionsResponse) {
cond := &action.Condition{
ConditionType: &action.Condition_Request{
Request: &action.RequestExecution{
Condition: &action.RequestExecution_Method{
Method: "/zitadel.management.v1.ManagementService/GetAction",
},
},
},
}
instance.SetExecution(ctx, t, cond, executionTargetsSingleTarget(targetResp.GetId()))
request.Filters[0].GetIncludeFilter().Include = cond
includeCond := &action.Condition{
ConditionType: &action.Condition_Request{
Request: &action.RequestExecution{
Condition: &action.RequestExecution_Method{
Method: "/zitadel.management.v1.ManagementService/ListActions",
},
},
},
}
includeTargets := executionTargetsSingleInclude(cond)
resp2 := instance.SetExecution(ctx, t, includeCond, includeTargets)
response.Result[0] = &action.Execution{
Condition: includeCond,
CreationDate: resp2.GetSetDate(),
ChangeDate: resp2.GetSetDate(),
Targets: includeTargets,
}
},
req: &action.ListExecutionsRequest{
Filters: []*action.ExecutionSearchFilter{{
Filter: &action.ExecutionSearchFilter_IncludeFilter{
IncludeFilter: &action.IncludeFilter{},
},
}},
},
},
want: &action.ListExecutionsResponse{
Pagination: &filter.PaginationResponse{
TotalResult: 1,
AppliedLimit: 100,
},
Result: []*action.Execution{
{},
},
},
},
{
name: "list multiple conditions",
@@ -659,33 +603,30 @@ func TestServer_ListExecutions(t *testing.T) {
}
cond1 := request.Filters[0].GetInConditionsFilter().GetConditions()[0]
targets1 := executionTargetsSingleTarget(targetResp.GetId())
resp1 := instance.SetExecution(ctx, t, cond1, targets1)
resp1 := instance.SetExecution(ctx, t, cond1, []string{targetResp.GetId()})
response.Result[2] = &action.Execution{
CreationDate: resp1.GetSetDate(),
ChangeDate: resp1.GetSetDate(),
Condition: cond1,
Targets: targets1,
Targets: []string{targetResp.GetId()},
}
cond2 := request.Filters[0].GetInConditionsFilter().GetConditions()[1]
targets2 := executionTargetsSingleTarget(targetResp.GetId())
resp2 := instance.SetExecution(ctx, t, cond2, targets2)
resp2 := instance.SetExecution(ctx, t, cond2, []string{targetResp.GetId()})
response.Result[1] = &action.Execution{
CreationDate: resp2.GetSetDate(),
ChangeDate: resp2.GetSetDate(),
Condition: cond2,
Targets: targets2,
Targets: []string{targetResp.GetId()},
}
cond3 := request.Filters[0].GetInConditionsFilter().GetConditions()[2]
targets3 := executionTargetsSingleTarget(targetResp.GetId())
resp3 := instance.SetExecution(ctx, t, cond3, targets3)
resp3 := instance.SetExecution(ctx, t, cond3, []string{targetResp.GetId()})
response.Result[0] = &action.Execution{
CreationDate: resp3.GetSetDate(),
ChangeDate: resp3.GetSetDate(),
Condition: cond3,
Targets: targets3,
Targets: []string{targetResp.GetId()},
}
},
req: &action.ListExecutionsRequest{
@@ -709,15 +650,14 @@ func TestServer_ListExecutions(t *testing.T) {
args: args{
ctx: isolatedIAMOwnerCTX,
dep: func(ctx context.Context, request *action.ListExecutionsRequest, response *action.ListExecutionsResponse) {
targets := executionTargetsSingleTarget(targetResp.GetId())
conditions := request.Filters[0].GetInConditionsFilter().GetConditions()
for i, cond := range conditions {
resp := instance.SetExecution(ctx, t, cond, targets)
resp := instance.SetExecution(ctx, t, cond, []string{targetResp.GetId()})
response.Result[(len(conditions)-1)-i] = &action.Execution{
CreationDate: resp.GetSetDate(),
ChangeDate: resp.GetSetDate(),
Condition: cond,
Targets: targets,
Targets: []string{targetResp.GetId()},
}
}
},
@@ -761,6 +701,63 @@ func TestServer_ListExecutions(t *testing.T) {
},
},
},
{
name: "list multiple conditions all types, sort id",
args: args{
ctx: isolatedIAMOwnerCTX,
dep: func(ctx context.Context, request *action.ListExecutionsRequest, response *action.ListExecutionsResponse) {
conditions := request.Filters[0].GetInConditionsFilter().GetConditions()
for i, cond := range conditions {
resp := instance.SetExecution(ctx, t, cond, []string{targetResp.GetId()})
response.Result[i] = &action.Execution{
CreationDate: resp.GetSetDate(),
ChangeDate: resp.GetSetDate(),
Condition: cond,
Targets: []string{targetResp.GetId()},
}
}
},
req: &action.ListExecutionsRequest{
SortingColumn: gu.Ptr(action.ExecutionFieldName_EXECUTION_FIELD_NAME_ID),
Filters: []*action.ExecutionSearchFilter{{
Filter: &action.ExecutionSearchFilter_InConditionsFilter{
InConditionsFilter: &action.InConditionsFilter{
Conditions: []*action.Condition{
{ConditionType: &action.Condition_Response{Response: &action.ResponseExecution{Condition: &action.ResponseExecution_Method{Method: "/zitadel.session.v2.SessionService/GetSession"}}}},
{ConditionType: &action.Condition_Response{Response: &action.ResponseExecution{Condition: &action.ResponseExecution_Service{Service: "zitadel.session.v2.SessionService"}}}},
{ConditionType: &action.Condition_Response{Response: &action.ResponseExecution{Condition: &action.ResponseExecution_All{All: true}}}},
{ConditionType: &action.Condition_Request{Request: &action.RequestExecution{Condition: &action.RequestExecution_Method{Method: "/zitadel.session.v2.SessionService/GetSession"}}}},
{ConditionType: &action.Condition_Request{Request: &action.RequestExecution{Condition: &action.RequestExecution_Service{Service: "zitadel.session.v2.SessionService"}}}},
{ConditionType: &action.Condition_Request{Request: &action.RequestExecution{Condition: &action.RequestExecution_All{All: true}}}},
{ConditionType: &action.Condition_Function{Function: &action.FunctionExecution{Name: "presamlresponse"}}},
{ConditionType: &action.Condition_Event{Event: &action.EventExecution{Condition: &action.EventExecution_Event{Event: "user.added"}}}},
{ConditionType: &action.Condition_Event{Event: &action.EventExecution{Condition: &action.EventExecution_Group{Group: "user"}}}},
{ConditionType: &action.Condition_Event{Event: &action.EventExecution{Condition: &action.EventExecution_All{All: true}}}},
},
},
},
}},
},
},
want: &action.ListExecutionsResponse{
Pagination: &filter.PaginationResponse{
TotalResult: 10,
AppliedLimit: 100,
},
Result: []*action.Execution{
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@@ -7,14 +7,6 @@ import (
"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/v2beta"
"github.com/zitadel/zitadel/pkg/grpc/feature/v2"
)
var (
@@ -29,41 +21,3 @@ func TestMain(m *testing.M) {
return m.Run()
}())
}
func ensureFeatureEnabled(t *testing.T, instance *integration.Instance) {
ctx := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
f, err := instance.Client.FeatureV2.GetInstanceFeatures(ctx, &feature.GetInstanceFeaturesRequest{
Inheritance: true,
})
require.NoError(t, err)
if f.Actions.GetEnabled() {
return
}
_, err = instance.Client.FeatureV2.SetInstanceFeatures(ctx, &feature.SetInstanceFeaturesRequest{
Actions: gu.Ptr(true),
})
require.NoError(t, err)
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(ctx, 5*time.Minute)
require.EventuallyWithT(t,
func(ttt *assert.CollectT) {
f, err := instance.Client.FeatureV2.GetInstanceFeatures(ctx, &feature.GetInstanceFeaturesRequest{
Inheritance: true,
})
assert.NoError(ttt, err)
assert.True(ttt, f.Actions.GetEnabled())
},
retryDuration,
tick,
"timed out waiting for ensuring instance feature")
retryDuration, tick = integration.WaitForAndTickWithMaxDuration(ctx, 5*time.Minute)
require.EventuallyWithT(t,
func(ttt *assert.CollectT) {
_, err := instance.Client.ActionV2beta.ListExecutionMethods(ctx, &action.ListExecutionMethodsRequest{})
assert.NoError(ttt, err)
},
retryDuration,
tick,
"timed out waiting for ensuring instance feature call")
}

View File

@@ -19,7 +19,6 @@ import (
func TestServer_CreateTarget(t *testing.T) {
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
type want struct {
id bool
@@ -244,7 +243,6 @@ func assertCreateTargetResponse(t *testing.T, creationDate, changeDate time.Time
func TestServer_UpdateTarget(t *testing.T) {
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
type args struct {
ctx context.Context
@@ -463,7 +461,6 @@ func assertUpdateTargetResponse(t *testing.T, creationDate, changeDate time.Time
func TestServer_DeleteTarget(t *testing.T) {
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
iamOwnerCtx := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
tests := []struct {
name string

View File

@@ -23,10 +23,6 @@ const (
)
func (s *Server) GetTarget(ctx context.Context, req *action.GetTargetRequest) (*action.GetTargetResponse, error) {
if err := checkActionsEnabled(ctx); err != nil {
return nil, err
}
resp, err := s.query.GetTargetByID(ctx, req.GetId())
if err != nil {
return nil, err
@@ -46,9 +42,6 @@ type Context interface {
}
func (s *Server) ListTargets(ctx context.Context, req *action.ListTargetsRequest) (*action.ListTargetsResponse, error) {
if err := checkActionsEnabled(ctx); err != nil {
return nil, err
}
queries, err := s.ListTargetsRequestToModel(req)
if err != nil {
return nil, err
@@ -64,9 +57,6 @@ func (s *Server) ListTargets(ctx context.Context, req *action.ListTargetsRequest
}
func (s *Server) ListExecutions(ctx context.Context, req *action.ListExecutionsRequest) (*action.ListExecutionsResponse, error) {
if err := checkActionsEnabled(ctx); err != nil {
return nil, err
}
queries, err := s.ListExecutionsRequestToModel(req)
if err != nil {
return nil, err
@@ -252,12 +242,6 @@ func executionQueryToQuery(searchQuery *action.ExecutionSearchFilter) (query.Sea
return inConditionsQueryToQuery(q.InConditionsFilter)
case *action.ExecutionSearchFilter_ExecutionTypeFilter:
return executionTypeToQuery(q.ExecutionTypeFilter)
case *action.ExecutionSearchFilter_IncludeFilter:
include, err := conditionToInclude(q.IncludeFilter.GetInclude())
if err != nil {
return nil, err
}
return query.NewIncludeSearchQuery(include)
case *action.ExecutionSearchFilter_TargetFilter:
return query.NewTargetSearchQuery(q.TargetFilter.GetTargetId())
default:
@@ -333,14 +317,12 @@ func executionsToPb(executions []*query.Execution) []*action.Execution {
}
func executionToPb(e *query.Execution) *action.Execution {
targets := make([]*action.ExecutionTargetType, len(e.Targets))
targets := make([]string, len(e.Targets))
for i := range e.Targets {
switch e.Targets[i].Type {
case domain.ExecutionTargetTypeInclude:
targets[i] = &action.ExecutionTargetType{Type: &action.ExecutionTargetType_Include{Include: executionIDToCondition(e.Targets[i].Target)}}
case domain.ExecutionTargetTypeTarget:
targets[i] = &action.ExecutionTargetType{Type: &action.ExecutionTargetType_Target{Target: e.Targets[i].Target}}
case domain.ExecutionTargetTypeUnspecified:
targets[i] = e.Targets[i].Target
case domain.ExecutionTargetTypeInclude, domain.ExecutionTargetTypeUnspecified:
continue
default:
continue

View File

@@ -1,8 +1,6 @@
package action
import (
"context"
"google.golang.org/grpc"
"github.com/zitadel/zitadel/internal/api/authz"
@@ -10,7 +8,6 @@ import (
"github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/config/systemdefaults"
"github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/internal/zerrors"
action "github.com/zitadel/zitadel/pkg/grpc/action/v2beta"
)
@@ -65,10 +62,3 @@ func (s *Server) AuthMethods() authz.MethodMapping {
func (s *Server) RegisterGateway() server.RegisterGatewayFunc {
return action.RegisterActionServiceHandler
}
func checkActionsEnabled(ctx context.Context) error {
if authz.GetInstance(ctx).Features().Actions {
return nil
}
return zerrors.ThrowPreconditionFailed(nil, "ACTION-8o6pvqfjhs", "Errors.Action.NotEnabled")
}

View File

@@ -14,9 +14,6 @@ import (
)
func (s *Server) CreateTarget(ctx context.Context, req *action.CreateTargetRequest) (*action.CreateTargetResponse, error) {
if err := checkActionsEnabled(ctx); err != nil {
return nil, err
}
add := createTargetToCommand(req)
instanceID := authz.GetInstance(ctx).InstanceID()
createdAt, err := s.command.AddTarget(ctx, add, instanceID)
@@ -35,9 +32,6 @@ func (s *Server) CreateTarget(ctx context.Context, req *action.CreateTargetReque
}
func (s *Server) UpdateTarget(ctx context.Context, req *action.UpdateTargetRequest) (*action.UpdateTargetResponse, error) {
if err := checkActionsEnabled(ctx); err != nil {
return nil, err
}
instanceID := authz.GetInstance(ctx).InstanceID()
update := updateTargetToCommand(req)
changedAt, err := s.command.ChangeTarget(ctx, update, instanceID)
@@ -55,9 +49,6 @@ func (s *Server) UpdateTarget(ctx context.Context, req *action.UpdateTargetReque
}
func (s *Server) DeleteTarget(ctx context.Context, req *action.DeleteTargetRequest) (*action.DeleteTargetResponse, error) {
if err := checkActionsEnabled(ctx); err != nil {
return nil, err
}
instanceID := authz.GetInstance(ctx).InstanceID()
deletedAt, err := s.command.DeleteTarget(ctx, req.GetId(), instanceID)
if err != nil {

View File

@@ -22,7 +22,6 @@ func systemFeaturesToCommand(req *feature_pb.SetSystemFeaturesRequest) (*command
TriggerIntrospectionProjections: req.OidcTriggerIntrospectionProjections,
LegacyIntrospection: req.OidcLegacyIntrospection,
UserSchema: req.UserSchema,
Actions: req.Actions,
TokenExchange: req.OidcTokenExchange,
ImprovedPerformance: improvedPerformanceListToDomain(req.ImprovedPerformance),
OIDCSingleV1SessionTermination: req.OidcSingleV1SessionTermination,
@@ -41,7 +40,6 @@ func systemFeaturesToPb(f *query.SystemFeatures) *feature_pb.GetSystemFeaturesRe
OidcLegacyIntrospection: featureSourceToFlagPb(&f.LegacyIntrospection),
UserSchema: featureSourceToFlagPb(&f.UserSchema),
OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange),
Actions: featureSourceToFlagPb(&f.Actions),
ImprovedPerformance: featureSourceToImprovedPerformanceFlagPb(&f.ImprovedPerformance),
OidcSingleV1SessionTermination: featureSourceToFlagPb(&f.OIDCSingleV1SessionTermination),
DisableUserTokenEvent: featureSourceToFlagPb(&f.DisableUserTokenEvent),
@@ -62,7 +60,6 @@ func instanceFeaturesToCommand(req *feature_pb.SetInstanceFeaturesRequest) (*com
LegacyIntrospection: req.OidcLegacyIntrospection,
UserSchema: req.UserSchema,
TokenExchange: req.OidcTokenExchange,
Actions: req.Actions,
ImprovedPerformance: improvedPerformanceListToDomain(req.ImprovedPerformance),
WebKey: req.WebKey,
DebugOIDCParentError: req.DebugOidcParentError,
@@ -83,7 +80,6 @@ func instanceFeaturesToPb(f *query.InstanceFeatures) *feature_pb.GetInstanceFeat
OidcLegacyIntrospection: featureSourceToFlagPb(&f.LegacyIntrospection),
UserSchema: featureSourceToFlagPb(&f.UserSchema),
OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange),
Actions: featureSourceToFlagPb(&f.Actions),
ImprovedPerformance: featureSourceToImprovedPerformanceFlagPb(&f.ImprovedPerformance),
WebKey: featureSourceToFlagPb(&f.WebKey),
DebugOidcParentError: featureSourceToFlagPb(&f.DebugOIDCParentError),

View File

@@ -23,7 +23,6 @@ func Test_systemFeaturesToCommand(t *testing.T) {
OidcTriggerIntrospectionProjections: gu.Ptr(false),
OidcLegacyIntrospection: nil,
UserSchema: gu.Ptr(true),
Actions: gu.Ptr(true),
OidcTokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
OidcSingleV1SessionTermination: gu.Ptr(true),
@@ -37,7 +36,6 @@ func Test_systemFeaturesToCommand(t *testing.T) {
TriggerIntrospectionProjections: gu.Ptr(false),
LegacyIntrospection: nil,
UserSchema: gu.Ptr(true),
Actions: gu.Ptr(true),
TokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
OIDCSingleV1SessionTermination: gu.Ptr(true),
@@ -74,10 +72,6 @@ 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,
@@ -132,10 +126,6 @@ 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,
},
ImprovedPerformance: &feature_pb.ImprovedPerformanceFeatureFlag{
ExecutionPaths: []feature_pb.ImprovedPerformance{feature_pb.ImprovedPerformance_IMPROVED_PERFORMANCE_ORG_BY_ID},
Source: feature_pb.Source_SOURCE_SYSTEM,
@@ -173,7 +163,6 @@ func Test_instanceFeaturesToCommand(t *testing.T) {
OidcLegacyIntrospection: nil,
UserSchema: gu.Ptr(true),
OidcTokenExchange: gu.Ptr(true),
Actions: gu.Ptr(true),
ImprovedPerformance: nil,
WebKey: gu.Ptr(true),
DebugOidcParentError: gu.Ptr(true),
@@ -191,7 +180,6 @@ func Test_instanceFeaturesToCommand(t *testing.T) {
LegacyIntrospection: nil,
UserSchema: gu.Ptr(true),
TokenExchange: gu.Ptr(true),
Actions: gu.Ptr(true),
ImprovedPerformance: nil,
WebKey: gu.Ptr(true),
DebugOIDCParentError: gu.Ptr(true),
@@ -231,10 +219,6 @@ 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,
@@ -293,10 +277,6 @@ 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

@@ -211,7 +211,6 @@ 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)
})
}
}
@@ -374,10 +373,6 @@ func TestServer_GetInstanceFeatures(t *testing.T) {
Enabled: false,
Source: feature.Source_SOURCE_UNSPECIFIED,
},
Actions: &feature.FeatureFlag{
Enabled: false,
Source: feature.Source_SOURCE_UNSPECIFIED,
},
},
},
{
@@ -387,7 +382,6 @@ 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)
},
@@ -408,10 +402,6 @@ func TestServer_GetInstanceFeatures(t *testing.T) {
Enabled: true,
Source: feature.Source_SOURCE_INSTANCE,
},
Actions: &feature.FeatureFlag{
Enabled: true,
Source: feature.Source_SOURCE_INSTANCE,
},
},
},
{
@@ -445,10 +435,6 @@ 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

@@ -14,7 +14,6 @@ func systemFeaturesToCommand(req *feature_pb.SetSystemFeaturesRequest) *command.
TriggerIntrospectionProjections: req.OidcTriggerIntrospectionProjections,
LegacyIntrospection: req.OidcLegacyIntrospection,
UserSchema: req.UserSchema,
Actions: req.Actions,
TokenExchange: req.OidcTokenExchange,
ImprovedPerformance: improvedPerformanceListToDomain(req.ImprovedPerformance),
OIDCSingleV1SessionTermination: req.OidcSingleV1SessionTermination,
@@ -29,7 +28,6 @@ func systemFeaturesToPb(f *query.SystemFeatures) *feature_pb.GetSystemFeaturesRe
OidcLegacyIntrospection: featureSourceToFlagPb(&f.LegacyIntrospection),
UserSchema: featureSourceToFlagPb(&f.UserSchema),
OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange),
Actions: featureSourceToFlagPb(&f.Actions),
ImprovedPerformance: featureSourceToImprovedPerformanceFlagPb(&f.ImprovedPerformance),
OidcSingleV1SessionTermination: featureSourceToFlagPb(&f.OIDCSingleV1SessionTermination),
}
@@ -42,7 +40,6 @@ func instanceFeaturesToCommand(req *feature_pb.SetInstanceFeaturesRequest) *comm
LegacyIntrospection: req.OidcLegacyIntrospection,
UserSchema: req.UserSchema,
TokenExchange: req.OidcTokenExchange,
Actions: req.Actions,
ImprovedPerformance: improvedPerformanceListToDomain(req.ImprovedPerformance),
WebKey: req.WebKey,
DebugOIDCParentError: req.DebugOidcParentError,
@@ -58,7 +55,6 @@ func instanceFeaturesToPb(f *query.InstanceFeatures) *feature_pb.GetInstanceFeat
OidcLegacyIntrospection: featureSourceToFlagPb(&f.LegacyIntrospection),
UserSchema: featureSourceToFlagPb(&f.UserSchema),
OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange),
Actions: featureSourceToFlagPb(&f.Actions),
ImprovedPerformance: featureSourceToImprovedPerformanceFlagPb(&f.ImprovedPerformance),
WebKey: featureSourceToFlagPb(&f.WebKey),
DebugOidcParentError: featureSourceToFlagPb(&f.DebugOIDCParentError),

View File

@@ -22,7 +22,6 @@ func Test_systemFeaturesToCommand(t *testing.T) {
OidcTriggerIntrospectionProjections: gu.Ptr(false),
OidcLegacyIntrospection: nil,
UserSchema: gu.Ptr(true),
Actions: gu.Ptr(true),
OidcTokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
OidcSingleV1SessionTermination: gu.Ptr(true),
@@ -32,7 +31,6 @@ func Test_systemFeaturesToCommand(t *testing.T) {
TriggerIntrospectionProjections: gu.Ptr(false),
LegacyIntrospection: nil,
UserSchema: gu.Ptr(true),
Actions: gu.Ptr(true),
TokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
OIDCSingleV1SessionTermination: gu.Ptr(true),
@@ -64,10 +62,6 @@ 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,
@@ -107,10 +101,6 @@ 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,
},
ImprovedPerformance: &feature_pb.ImprovedPerformanceFeatureFlag{
ExecutionPaths: []feature_pb.ImprovedPerformance{feature_pb.ImprovedPerformance_IMPROVED_PERFORMANCE_ORG_BY_ID},
Source: feature_pb.Source_SOURCE_SYSTEM,
@@ -131,7 +121,6 @@ func Test_instanceFeaturesToCommand(t *testing.T) {
OidcLegacyIntrospection: nil,
UserSchema: gu.Ptr(true),
OidcTokenExchange: gu.Ptr(true),
Actions: gu.Ptr(true),
ImprovedPerformance: nil,
WebKey: gu.Ptr(true),
OidcSingleV1SessionTermination: gu.Ptr(true),
@@ -142,7 +131,6 @@ func Test_instanceFeaturesToCommand(t *testing.T) {
LegacyIntrospection: nil,
UserSchema: gu.Ptr(true),
TokenExchange: gu.Ptr(true),
Actions: gu.Ptr(true),
ImprovedPerformance: nil,
WebKey: gu.Ptr(true),
OIDCSingleV1SessionTermination: gu.Ptr(true),
@@ -174,10 +162,6 @@ 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,
@@ -217,10 +201,6 @@ 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

@@ -202,10 +202,6 @@ func TestServer_GetInstanceFeatures(t *testing.T) {
Enabled: false,
Source: feature.Source_SOURCE_UNSPECIFIED,
},
Actions: &feature.FeatureFlag{
Enabled: false,
Source: feature.Source_SOURCE_UNSPECIFIED,
},
},
},
{
@@ -215,7 +211,6 @@ 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)
},
@@ -236,10 +231,6 @@ func TestServer_GetInstanceFeatures(t *testing.T) {
Enabled: true,
Source: feature.Source_SOURCE_INSTANCE,
},
Actions: &feature.FeatureFlag{
Enabled: true,
Source: feature.Source_SOURCE_INSTANCE,
},
},
},
{
@@ -273,10 +264,6 @@ 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

@@ -5,12 +5,13 @@ import (
"encoding/json"
"google.golang.org/grpc"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/execution"
"github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
"github.com/zitadel/zitadel/internal/zerrors"
)
func ExecutionHandler(queries *query.Queries) grpc.UnaryServerInterceptor {
@@ -48,7 +49,7 @@ func executeTargetsForRequest(ctx context.Context, targets []execution.Target, f
ProjectID: ctxData.ProjectID,
OrgID: ctxData.OrgID,
UserID: ctxData.UserID,
Request: req,
Request: Message{req.(proto.Message)},
}
return execution.CallTargets(ctx, targets, info)
@@ -70,8 +71,8 @@ func executeTargetsForResponse(ctx context.Context, targets []execution.Target,
ProjectID: ctxData.ProjectID,
OrgID: ctxData.OrgID,
UserID: ctxData.UserID,
Request: req,
Response: resp,
Request: Message{req.(proto.Message)},
Response: Message{resp.(proto.Message)},
}
return execution.CallTargets(ctx, targets, info)
@@ -85,7 +86,23 @@ type ContextInfoRequest struct {
OrgID string `json:"orgID,omitempty"`
ProjectID string `json:"projectID,omitempty"`
UserID string `json:"userID,omitempty"`
Request interface{} `json:"request,omitempty"`
Request Message `json:"request,omitempty"`
}
type Message struct {
proto.Message
}
func (r *Message) MarshalJSON() ([]byte, error) {
data, err := protojson.Marshal(r.Message)
if err != nil {
return nil, err
}
return data, nil
}
func (r *Message) UnmarshalJSON(data []byte) error {
return protojson.Unmarshal(data, r.Message)
}
func (c *ContextInfoRequest) GetHTTPRequestBody() []byte {
@@ -97,14 +114,11 @@ func (c *ContextInfoRequest) GetHTTPRequestBody() []byte {
}
func (c *ContextInfoRequest) SetHTTPResponseBody(resp []byte) error {
if !json.Valid(resp) {
return zerrors.ThrowPreconditionFailed(nil, "ACTION-4m9s2", "Errors.Execution.ResponseIsNotValidJSON")
}
return json.Unmarshal(resp, c.Request)
return json.Unmarshal(resp, &c.Request)
}
func (c *ContextInfoRequest) GetContent() interface{} {
return c.Request
return c.Request.Message
}
var _ execution.ContextInfo = &ContextInfoResponse{}
@@ -115,8 +129,8 @@ type ContextInfoResponse struct {
OrgID string `json:"orgID,omitempty"`
ProjectID string `json:"projectID,omitempty"`
UserID string `json:"userID,omitempty"`
Request interface{} `json:"request,omitempty"`
Response interface{} `json:"response,omitempty"`
Request Message `json:"request,omitempty"`
Response Message `json:"response,omitempty"`
}
func (c *ContextInfoResponse) GetHTTPRequestBody() []byte {
@@ -128,9 +142,9 @@ func (c *ContextInfoResponse) GetHTTPRequestBody() []byte {
}
func (c *ContextInfoResponse) SetHTTPResponseBody(resp []byte) error {
return json.Unmarshal(resp, c.Response)
return json.Unmarshal(resp, &c.Response)
}
func (c *ContextInfoResponse) GetContent() interface{} {
return c.Response
return c.Response.Message
}

View File

@@ -11,6 +11,9 @@ import (
"time"
"github.com/stretchr/testify/assert"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/structpb"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/execution"
@@ -54,28 +57,28 @@ func (e *mockExecutionTarget) GetSigningKey() string {
return e.SigningKey
}
type mockContentRequest struct {
Content string
}
func newMockContentRequest(content string) *mockContentRequest {
return &mockContentRequest{
Content: content,
func newMockContentRequest(content string) proto.Message {
return &structpb.Struct{
Fields: map[string]*structpb.Value{
"content": {
Kind: &structpb.Value_StringValue{StringValue: content},
},
},
}
}
func newMockContextInfoRequest(fullMethod, request string) *ContextInfoRequest {
return &ContextInfoRequest{
FullMethod: fullMethod,
Request: newMockContentRequest(request),
Request: Message{Message: newMockContentRequest(request)},
}
}
func newMockContextInfoResponse(fullMethod, request, response string) *ContextInfoResponse {
return &ContextInfoResponse{
FullMethod: fullMethod,
Request: newMockContentRequest(request),
Response: newMockContentRequest(response),
Request: Message{Message: newMockContentRequest(request)},
Response: Message{Message: newMockContentRequest(response)},
}
}
@@ -591,7 +594,7 @@ func Test_executeTargetsForGRPCFullMethod_request(t *testing.T) {
} else {
assert.NoError(t, err)
}
assert.Equal(t, tt.res.want, resp)
assert.EqualExportedValues(t, tt.res.want, resp)
for _, closeF := range closeFuncs {
closeF()
@@ -632,7 +635,7 @@ func testServerCall(
time.Sleep(sleep)
w.Header().Set("Content-Type", "application/json")
resp, err := json.Marshal(respBody)
resp, err := protojson.Marshal(respBody.(proto.Message))
if err != nil {
http.Error(w, "error", http.StatusInternalServerError)
return
@@ -723,7 +726,8 @@ func Test_executeTargetsForGRPCFullMethod_response(t *testing.T) {
statusCode: http.StatusOK,
},
},
req: []byte{},
req: newMockContentRequest(""),
resp: newMockContentRequest(""),
},
res{
wantErr: true,
@@ -790,7 +794,7 @@ func Test_executeTargetsForGRPCFullMethod_response(t *testing.T) {
} else {
assert.NoError(t, err)
}
assert.Equal(t, tt.res.want, resp)
assert.EqualExportedValues(t, tt.res.want, resp)
for _, closeF := range closeFuncs {
closeF()

View File

@@ -21,7 +21,6 @@ type InstanceFeatures struct {
LegacyIntrospection *bool
UserSchema *bool
TokenExchange *bool
Actions *bool
ImprovedPerformance []feature.ImprovedPerformanceType
WebKey *bool
DebugOIDCParentError *bool
@@ -39,7 +38,6 @@ func (m *InstanceFeatures) isEmpty() bool {
m.LegacyIntrospection == nil &&
m.UserSchema == nil &&
m.TokenExchange == nil &&
m.Actions == nil &&
// nil check to allow unset improvements
m.ImprovedPerformance == nil &&
m.WebKey == nil &&

View File

@@ -71,7 +71,6 @@ func (m *InstanceFeaturesWriteModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.InstanceLegacyIntrospectionEventType,
feature_v2.InstanceUserSchemaEventType,
feature_v2.InstanceTokenExchangeEventType,
feature_v2.InstanceActionsEventType,
feature_v2.InstanceImprovedPerformanceEventType,
feature_v2.InstanceWebKeyEventType,
feature_v2.InstanceDebugOIDCParentErrorEventType,
@@ -108,9 +107,6 @@ func reduceInstanceFeature(features *InstanceFeatures, key feature.Key, value an
case feature.KeyUserSchema:
v := value.(bool)
features.UserSchema = &v
case feature.KeyActions:
v := value.(bool)
features.Actions = &v
case feature.KeyImprovedPerformance:
v := value.([]feature.ImprovedPerformanceType)
features.ImprovedPerformance = v
@@ -148,7 +144,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)
cmds = appendFeatureSliceUpdate(ctx, cmds, aggregate, wm.ImprovedPerformance, f.ImprovedPerformance, feature_v2.InstanceImprovedPerformanceEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.WebKey, f.WebKey, feature_v2.InstanceWebKeyEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.DebugOIDCParentError, f.DebugOIDCParentError, feature_v2.InstanceDebugOIDCParentErrorEventType)

View File

@@ -149,24 +149,6 @@ 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(
@@ -204,10 +186,6 @@ func TestCommands_SetInstanceFeatures(t *testing.T) {
ctx, aggregate,
feature_v2.InstanceUserSchemaEventType, true,
),
feature_v2.NewSetEvent[bool](
ctx, aggregate,
feature_v2.InstanceActionsEventType, true,
),
feature_v2.NewSetEvent[bool](
ctx, aggregate,
feature_v2.InstanceOIDCSingleV1SessionTerminationEventType, true,
@@ -219,7 +197,6 @@ func TestCommands_SetInstanceFeatures(t *testing.T) {
TriggerIntrospectionProjections: gu.Ptr(false),
LegacyIntrospection: gu.Ptr(true),
UserSchema: gu.Ptr(true),
Actions: gu.Ptr(true),
OIDCSingleV1SessionTermination: gu.Ptr(true),
}},
want: &domain.ObjectDetails{

View File

@@ -15,7 +15,6 @@ type SystemFeatures struct {
LegacyIntrospection *bool
TokenExchange *bool
UserSchema *bool
Actions *bool
ImprovedPerformance []feature.ImprovedPerformanceType
OIDCSingleV1SessionTermination *bool
DisableUserTokenEvent *bool
@@ -30,7 +29,6 @@ func (m *SystemFeatures) isEmpty() bool {
m.LegacyIntrospection == nil &&
m.UserSchema == nil &&
m.TokenExchange == nil &&
m.Actions == nil &&
// nil check to allow unset improvements
m.ImprovedPerformance == nil &&
m.OIDCSingleV1SessionTermination == nil &&

View File

@@ -64,7 +64,6 @@ func (m *SystemFeaturesWriteModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.SystemLegacyIntrospectionEventType,
feature_v2.SystemUserSchemaEventType,
feature_v2.SystemTokenExchangeEventType,
feature_v2.SystemActionsEventType,
feature_v2.SystemImprovedPerformanceEventType,
feature_v2.SystemOIDCSingleV1SessionTerminationEventType,
feature_v2.SystemDisableUserTokenEvent,
@@ -98,9 +97,6 @@ func reduceSystemFeature(features *SystemFeatures, key feature.Key, value any) {
case feature.KeyTokenExchange:
v := value.(bool)
features.TokenExchange = &v
case feature.KeyActions:
v := value.(bool)
features.Actions = &v
case feature.KeyImprovedPerformance:
features.ImprovedPerformance = value.([]feature.ImprovedPerformanceType)
case feature.KeyOIDCSingleV1SessionTermination:
@@ -128,7 +124,6 @@ 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)
cmds = appendFeatureSliceUpdate(ctx, cmds, aggregate, wm.ImprovedPerformance, f.ImprovedPerformance, feature_v2.SystemImprovedPerformanceEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.OIDCSingleV1SessionTermination, f.OIDCSingleV1SessionTermination, feature_v2.SystemOIDCSingleV1SessionTerminationEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.DisableUserTokenEvent, f.DisableUserTokenEvent, feature_v2.SystemDisableUserTokenEvent)

View File

@@ -117,24 +117,6 @@ 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(
@@ -172,10 +154,6 @@ func TestCommands_SetSystemFeatures(t *testing.T) {
context.Background(), aggregate,
feature_v2.SystemUserSchemaEventType, true,
),
feature_v2.NewSetEvent[bool](
context.Background(), aggregate,
feature_v2.SystemActionsEventType, true,
),
feature_v2.NewSetEvent[bool](
context.Background(), aggregate,
feature_v2.SystemOIDCSingleV1SessionTerminationEventType, true,
@@ -187,7 +165,6 @@ func TestCommands_SetSystemFeatures(t *testing.T) {
TriggerIntrospectionProjections: gu.Ptr(false),
LegacyIntrospection: gu.Ptr(true),
UserSchema: gu.Ptr(true),
Actions: gu.Ptr(true),
OIDCSingleV1SessionTermination: gu.Ptr(true),
}},
want: &domain.ObjectDetails{
@@ -233,10 +210,6 @@ func TestCommands_SetSystemFeatures(t *testing.T) {
context.Background(), aggregate,
feature_v2.SystemUserSchemaEventType, true,
),
feature_v2.NewSetEvent[bool](
context.Background(), aggregate,
feature_v2.SystemActionsEventType, false,
),
feature_v2.NewSetEvent[bool](
context.Background(), aggregate,
feature_v2.SystemOIDCSingleV1SessionTerminationEventType, false,
@@ -248,7 +221,6 @@ func TestCommands_SetSystemFeatures(t *testing.T) {
TriggerIntrospectionProjections: gu.Ptr(false),
LegacyIntrospection: gu.Ptr(true),
UserSchema: gu.Ptr(true),
Actions: gu.Ptr(false),
OIDCSingleV1SessionTermination: gu.Ptr(false),
}},
want: &domain.ObjectDetails{

View File

@@ -82,11 +82,11 @@ func CallTarget(
case domain.TargetTypeCall:
return Call(ctx, target.GetEndpoint(), target.GetTimeout(), info.GetHTTPRequestBody(), target.GetSigningKey())
case domain.TargetTypeAsync:
go func(target Target, info ContextInfoRequest) {
if _, err := Call(ctx, target.GetEndpoint(), target.GetTimeout(), info.GetHTTPRequestBody(), target.GetSigningKey()); err != nil {
go func(ctx context.Context, target Target, info []byte) {
if _, err := Call(ctx, target.GetEndpoint(), target.GetTimeout(), info, target.GetSigningKey()); err != nil {
logging.WithFields("target", target.GetTargetID()).OnError(err).Info(err)
}
}(target, info)
}(context.WithoutCancel(ctx), target, info.GetHTTPRequestBody())
return nil, nil
default:
return nil, zerrors.ThrowInternal(nil, "EXEC-auqnansr2m", "Errors.Execution.Unknown")

View File

@@ -13,6 +13,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/structpb"
"github.com/zitadel/zitadel/internal/api/grpc/server/middleware"
"github.com/zitadel/zitadel/internal/domain"
@@ -149,8 +150,8 @@ func Test_CallTarget(t *testing.T) {
info: requestContextInfo1,
server: &callTestServer{
method: http.MethodPost,
expectBody: []byte("{\"request\":{\"request\":\"content1\"}}"),
respondBody: []byte("{\"request\":\"content2\"}"),
expectBody: []byte("{\"request\":{\"content\":\"request1\"}}"),
respondBody: []byte("{\"content\":\"request2\"}"),
timeout: time.Second,
statusCode: http.StatusInternalServerError,
},
@@ -170,8 +171,8 @@ func Test_CallTarget(t *testing.T) {
server: &callTestServer{
timeout: time.Second,
method: http.MethodPost,
expectBody: []byte("{\"request\":{\"request\":\"content1\"}}"),
respondBody: []byte("{\"request\":\"content2\"}"),
expectBody: []byte("{\"request\":{\"content\":\"request1\"}}"),
respondBody: []byte("{\"content\":\"request2\"}"),
statusCode: http.StatusInternalServerError,
},
target: &mockTarget{
@@ -191,8 +192,8 @@ func Test_CallTarget(t *testing.T) {
server: &callTestServer{
timeout: time.Second,
method: http.MethodPost,
expectBody: []byte("{\"request\":{\"request\":\"content1\"}}"),
respondBody: []byte("{\"request\":\"content2\"}"),
expectBody: []byte("{\"request\":{\"content\":\"request1\"}}"),
respondBody: []byte("{\"content\":\"request2\"}"),
statusCode: http.StatusOK,
},
target: &mockTarget{
@@ -212,8 +213,8 @@ func Test_CallTarget(t *testing.T) {
server: &callTestServer{
timeout: time.Second,
method: http.MethodPost,
expectBody: []byte("{\"request\":{\"request\":\"content1\"}}"),
respondBody: []byte("{\"request\":\"content2\"}"),
expectBody: []byte("{\"request\":{\"content\":\"request1\"}}"),
respondBody: []byte("{\"content\":\"request2\"}"),
statusCode: http.StatusOK,
signingKey: "signingkey",
},
@@ -235,8 +236,8 @@ func Test_CallTarget(t *testing.T) {
server: &callTestServer{
timeout: time.Second,
method: http.MethodPost,
expectBody: []byte("{\"request\":{\"request\":\"content1\"}}"),
respondBody: []byte("{\"request\":\"content2\"}"),
expectBody: []byte("{\"request\":{\"content\":\"request1\"}}"),
respondBody: []byte("{\"content\":\"request2\"}"),
statusCode: http.StatusInternalServerError,
},
target: &mockTarget{
@@ -256,8 +257,8 @@ func Test_CallTarget(t *testing.T) {
server: &callTestServer{
timeout: time.Second,
method: http.MethodPost,
expectBody: []byte("{\"request\":{\"request\":\"content1\"}}"),
respondBody: []byte("{\"request\":\"content2\"}"),
expectBody: []byte("{\"request\":{\"content\":\"request1\"}}"),
respondBody: []byte("{\"content\":\"request2\"}"),
statusCode: http.StatusOK,
},
target: &mockTarget{
@@ -266,7 +267,7 @@ func Test_CallTarget(t *testing.T) {
},
},
res{
body: []byte("{\"request\":\"content2\"}"),
body: []byte("{\"content\":\"request2\"}"),
},
},
{
@@ -277,8 +278,8 @@ func Test_CallTarget(t *testing.T) {
server: &callTestServer{
timeout: time.Second,
method: http.MethodPost,
expectBody: []byte("{\"request\":{\"request\":\"content1\"}}"),
respondBody: []byte("{\"request\":\"content2\"}"),
expectBody: []byte("{\"request\":{\"content\":\"request1\"}}"),
respondBody: []byte("{\"content\":\"request2\"}"),
statusCode: http.StatusOK,
signingKey: "signingkey",
},
@@ -289,7 +290,7 @@ func Test_CallTarget(t *testing.T) {
},
},
res{
body: []byte("{\"request\":\"content2\"}"),
body: []byte("{\"content\":\"request2\"}"),
},
},
}
@@ -576,13 +577,13 @@ func testCallTargets(ctx context.Context,
}
var requestContextInfo1 = &middleware.ContextInfoRequest{
Request: &request{
Request: "content1",
},
Request: middleware.Message{Message: &structpb.Struct{
Fields: map[string]*structpb.Value{"content": structpb.NewStringValue("request1")},
}},
}
var requestContextInfoBody1 = []byte("{\"request\":{\"request\":\"content1\"}}")
var requestContextInfoBody2 = []byte("{\"request\":{\"request\":\"content2\"}}")
var requestContextInfoBody1 = []byte("{\"request\":{\"content\":\"request1\"}}")
var requestContextInfoBody2 = []byte("{\"request\":{\"content\":\"request2\"}}")
type request struct {
Request string `json:"request"`

View File

@@ -15,7 +15,7 @@ const (
KeyLegacyIntrospection
KeyUserSchema
KeyTokenExchange
KeyActions
KeyActionsDeprecated
KeyImprovedPerformance
KeyWebKey
KeyDebugOIDCParentError
@@ -46,7 +46,6 @@ 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"`
ImprovedPerformance []ImprovedPerformanceType `json:"improved_performance,omitempty"`
WebKey bool `json:"web_key,omitempty"`
DebugOIDCParentError bool `json:"debug_oidc_parent_error,omitempty"`

View File

@@ -30,7 +30,7 @@ func _KeyNoOp() {
_ = x[KeyLegacyIntrospection-(3)]
_ = x[KeyUserSchema-(4)]
_ = x[KeyTokenExchange-(5)]
_ = x[KeyActions-(6)]
_ = x[KeyActionsDeprecated-(6)]
_ = x[KeyImprovedPerformance-(7)]
_ = x[KeyWebKey-(8)]
_ = x[KeyDebugOIDCParentError-(9)]
@@ -42,7 +42,7 @@ func _KeyNoOp() {
_ = x[KeyConsoleUseV2UserApi-(15)]
}
var _KeyValues = []Key{KeyUnspecified, KeyLoginDefaultOrg, KeyTriggerIntrospectionProjections, KeyLegacyIntrospection, KeyUserSchema, KeyTokenExchange, KeyActions, KeyImprovedPerformance, KeyWebKey, KeyDebugOIDCParentError, KeyOIDCSingleV1SessionTermination, KeyDisableUserTokenEvent, KeyEnableBackChannelLogout, KeyLoginV2, KeyPermissionCheckV2, KeyConsoleUseV2UserApi}
var _KeyValues = []Key{KeyUnspecified, KeyLoginDefaultOrg, KeyTriggerIntrospectionProjections, KeyLegacyIntrospection, KeyUserSchema, KeyTokenExchange, KeyActionsDeprecated, KeyImprovedPerformance, KeyWebKey, KeyDebugOIDCParentError, KeyOIDCSingleV1SessionTermination, KeyDisableUserTokenEvent, KeyEnableBackChannelLogout, KeyLoginV2, KeyPermissionCheckV2, KeyConsoleUseV2UserApi}
var _KeyNameToValueMap = map[string]Key{
_KeyName[0:11]: KeyUnspecified,
@@ -57,8 +57,8 @@ var _KeyNameToValueMap = map[string]Key{
_KeyLowerName[81:92]: KeyUserSchema,
_KeyName[92:106]: KeyTokenExchange,
_KeyLowerName[92:106]: KeyTokenExchange,
_KeyName[106:113]: KeyActions,
_KeyLowerName[106:113]: KeyActions,
_KeyName[106:113]: KeyActionsDeprecated,
_KeyLowerName[106:113]: KeyActionsDeprecated,
_KeyName[113:133]: KeyImprovedPerformance,
_KeyLowerName[113:133]: KeyImprovedPerformance,
_KeyName[133:140]: KeyWebKey,

View File

@@ -8,6 +8,9 @@ import (
"reflect"
"sync"
"time"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
)
type server struct {
@@ -100,3 +103,61 @@ func TestServerCall(
server.server = httptest.NewServer(http.HandlerFunc(handler))
return server.URL(), server.Close, server.Called, server.ResetCalled
}
func TestServerCallProto(
reqBody interface{},
sleep time.Duration,
statusCode int,
respBody proto.Message,
) (url string, closeF func(), calledF func() int, resetCalledF func()) {
server := &server{
called: 0,
}
handler := func(w http.ResponseWriter, r *http.Request) {
server.Increase()
if reqBody != nil {
data, err := json.Marshal(reqBody)
if err != nil {
http.Error(w, "error, marshall: "+err.Error(), http.StatusInternalServerError)
return
}
sentBody, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "error, read body: "+err.Error(), http.StatusInternalServerError)
return
}
if !reflect.DeepEqual(data, sentBody) {
http.Error(w, "error, equal:\n"+string(data)+"\nsent:\n"+string(sentBody), http.StatusInternalServerError)
return
}
}
if statusCode != http.StatusOK {
http.Error(w, "error, statusCode", statusCode)
return
}
time.Sleep(sleep)
if respBody != nil {
w.Header().Set("Content-Type", "application/json")
resp, err := protojson.Marshal(respBody)
if err != nil {
http.Error(w, "error", http.StatusInternalServerError)
return
}
if _, err := io.Writer.Write(w, resp); err != nil {
http.Error(w, "error", http.StatusInternalServerError)
return
}
} else {
if _, err := io.WriteString(w, "finished successfully"); err != nil {
http.Error(w, "error", http.StatusInternalServerError)
return
}
}
}
server.server = httptest.NewServer(http.HandlerFunc(handler))
return server.URL(), server.Close, server.Called, server.ResetCalled
}

View File

@@ -763,7 +763,7 @@ func (i *Instance) DeleteExecution(ctx context.Context, t *testing.T, cond *acti
require.NoError(t, err)
}
func (i *Instance) SetExecution(ctx context.Context, t *testing.T, cond *action.Condition, targets []*action.ExecutionTargetType) *action.SetExecutionResponse {
func (i *Instance) SetExecution(ctx context.Context, t *testing.T, cond *action.Condition, targets []string) *action.SetExecutionResponse {
target, err := i.Client.ActionV2beta.SetExecution(ctx, &action.SetExecutionRequest{
Condition: cond,
Targets: targets,

View File

@@ -14,7 +14,6 @@ type InstanceFeatures struct {
LegacyIntrospection FeatureSource[bool]
UserSchema FeatureSource[bool]
TokenExchange FeatureSource[bool]
Actions FeatureSource[bool]
ImprovedPerformance FeatureSource[[]feature.ImprovedPerformanceType]
WebKey FeatureSource[bool]
DebugOIDCParentError FeatureSource[bool]

View File

@@ -67,7 +67,6 @@ func (m *InstanceFeaturesReadModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.InstanceLegacyIntrospectionEventType,
feature_v2.InstanceUserSchemaEventType,
feature_v2.InstanceTokenExchangeEventType,
feature_v2.InstanceActionsEventType,
feature_v2.InstanceImprovedPerformanceEventType,
feature_v2.InstanceWebKeyEventType,
feature_v2.InstanceDebugOIDCParentErrorEventType,
@@ -98,7 +97,6 @@ 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
m.instance.ImprovedPerformance = m.system.ImprovedPerformance
m.instance.OIDCSingleV1SessionTermination = m.system.OIDCSingleV1SessionTermination
m.instance.DisableUserTokenEvent = m.system.DisableUserTokenEvent
@@ -113,7 +111,8 @@ func reduceInstanceFeatureSet[T any](features *InstanceFeatures, event *feature_
return err
}
switch key {
case feature.KeyUnspecified:
case feature.KeyUnspecified,
feature.KeyActionsDeprecated:
return nil
case feature.KeyLoginDefaultOrg:
features.LoginDefaultOrg.set(level, event.Value)
@@ -125,8 +124,6 @@ func reduceInstanceFeatureSet[T any](features *InstanceFeatures, event *feature_
features.UserSchema.set(level, event.Value)
case feature.KeyTokenExchange:
features.TokenExchange.set(level, event.Value)
case feature.KeyActions:
features.Actions.set(level, event.Value)
case feature.KeyImprovedPerformance:
features.ImprovedPerformance.set(level, event.Value)
case feature.KeyWebKey:

View File

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

View File

@@ -80,10 +80,6 @@ func (*instanceFeatureProjection) Reducers() []handler.AggregateReducer {
Event: feature_v2.InstanceTokenExchangeEventType,
Reduce: reduceInstanceSetFeature[bool],
},
{
Event: feature_v2.InstanceActionsEventType,
Reduce: reduceInstanceSetFeature[bool],
},
{
Event: feature_v2.InstanceImprovedPerformanceEventType,
Reduce: reduceInstanceSetFeature[[]feature.ImprovedPerformanceType],

View File

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

View File

@@ -25,7 +25,6 @@ type SystemFeatures struct {
LegacyIntrospection FeatureSource[bool]
UserSchema FeatureSource[bool]
TokenExchange FeatureSource[bool]
Actions FeatureSource[bool]
ImprovedPerformance FeatureSource[[]feature.ImprovedPerformanceType]
OIDCSingleV1SessionTermination FeatureSource[bool]
DisableUserTokenEvent FeatureSource[bool]

View File

@@ -60,7 +60,6 @@ func (m *SystemFeaturesReadModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.SystemLegacyIntrospectionEventType,
feature_v2.SystemUserSchemaEventType,
feature_v2.SystemTokenExchangeEventType,
feature_v2.SystemActionsEventType,
feature_v2.SystemImprovedPerformanceEventType,
feature_v2.SystemOIDCSingleV1SessionTerminationEventType,
feature_v2.SystemDisableUserTokenEvent,
@@ -82,7 +81,8 @@ func reduceSystemFeatureSet[T any](features *SystemFeatures, event *feature_v2.S
return err
}
switch key {
case feature.KeyUnspecified:
case feature.KeyUnspecified,
feature.KeyActionsDeprecated:
return nil
case feature.KeyLoginDefaultOrg:
features.LoginDefaultOrg.set(level, event.Value)
@@ -94,8 +94,6 @@ func reduceSystemFeatureSet[T any](features *SystemFeatures, event *feature_v2.S
features.UserSchema.set(level, event.Value)
case feature.KeyTokenExchange:
features.TokenExchange.set(level, event.Value)
case feature.KeyActions:
features.Actions.set(level, event.Value)
case feature.KeyImprovedPerformance:
features.ImprovedPerformance.set(level, event.Value)
case feature.KeyOIDCSingleV1SessionTermination:

View File

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

View File

@@ -50,7 +50,7 @@ type ContextInfoEvent struct {
EventType string `json:"event_type,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
UserID string `json:"userID,omitempty"`
EventPayload []byte `json:"event_payload,omitempty"`
EventPayload json.RawMessage `json:"event_payload,omitempty"`
}
func (c *ContextInfoEvent) GetHTTPRequestBody() []byte {

View File

@@ -12,7 +12,6 @@ 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, SystemImprovedPerformanceEventType, eventstore.GenericEventMapper[SetEvent[[]feature.ImprovedPerformanceType]])
eventstore.RegisterFilterEventMapper(AggregateType, SystemOIDCSingleV1SessionTerminationEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, SystemDisableUserTokenEvent, eventstore.GenericEventMapper[SetEvent[bool]])
@@ -26,7 +25,6 @@ func init() {
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]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceImprovedPerformanceEventType, eventstore.GenericEventMapper[SetEvent[[]feature.ImprovedPerformanceType]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceWebKeyEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceDebugOIDCParentErrorEventType, eventstore.GenericEventMapper[SetEvent[bool]])

View File

@@ -17,7 +17,6 @@ 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)
SystemImprovedPerformanceEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyImprovedPerformance)
SystemOIDCSingleV1SessionTerminationEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyOIDCSingleV1SessionTermination)
SystemDisableUserTokenEvent = setEventTypeFromFeature(feature.LevelSystem, feature.KeyDisableUserTokenEvent)
@@ -31,7 +30,6 @@ 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)
InstanceImprovedPerformanceEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyImprovedPerformance)
InstanceWebKeyEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyWebKey)
InstanceDebugOIDCParentErrorEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyDebugOIDCParentError)

View File

@@ -7,6 +7,10 @@ deps:
breaking:
use:
- FILE
- FIELD_NO_DELETE_UNLESS_NAME_RESERVED
- FIELD_NO_DELETE_UNLESS_NUMBER_RESERVED
except:
- FIELD_NO_DELETE
ignore_unstable_packages: true
lint:
use:

View File

@@ -670,8 +670,8 @@ message ListTargetsResponse {
message SetExecutionRequest {
// Condition defining when the execution should be used.
Condition condition = 1;
// Ordered list of targets/includes called during the execution.
repeated ExecutionTargetType targets = 2;
// Ordered list of targets called during the execution.
repeated string targets = 2;
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = {
example: "{\"condition\":{\"request\":{\"method\":\"zitadel.session.v2.SessionService/ListSessions\"}},\"targets\":[{\"target\":\"69629026806489455\"}]}";
};

View File

@@ -29,18 +29,8 @@ message Execution {
example: "\"2025-01-23T10:34:18.051Z\"";
}
];
// Ordered list of targets/includes called during the execution.
repeated ExecutionTargetType targets = 4;
}
message ExecutionTargetType {
oneof type {
option (validate.required) = true;
// Unique identifier of existing target to call.
string target = 1;
// Unique identifier of existing execution to include targets of.
Condition include = 2;
}
// Ordered list of targets called during the execution.
repeated string targets = 4;
}
message Condition {

View File

@@ -19,7 +19,6 @@ message ExecutionSearchFilter {
InConditionsFilter in_conditions_filter = 1;
ExecutionTypeFilter execution_type_filter = 2;
TargetFilter target_filter = 3;
IncludeFilter include_filter = 4;
}
}
@@ -43,16 +42,6 @@ message TargetFilter {
];
}
message IncludeFilter {
// Defines the include to query for.
Condition include = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "the id of the include"
example: "\"request.zitadel.session.v2.SessionService\"";
}
];
}
enum TargetFieldName {
TARGET_FIELD_NAME_UNSPECIFIED = 0;
TARGET_FIELD_NAME_ID = 1;

View File

@@ -11,6 +11,8 @@ import "zitadel/feature/v2/feature.proto";
option go_package = "github.com/zitadel/zitadel/pkg/grpc/feature/v2;feature";
message SetInstanceFeaturesRequest{
reserved 6;
reserved "actions";
optional bool login_default_org = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
@@ -43,12 +45,6 @@ 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.";
}
];
repeated ImprovedPerformance improved_performance = 7 [
(validate.rules).repeated.unique = true,
@@ -135,6 +131,8 @@ message GetInstanceFeaturesRequest {
}
message GetInstanceFeaturesResponse {
reserved 7;
reserved "actions";
zitadel.object.v2.Details details = 1;
FeatureFlag login_default_org = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
@@ -171,13 +169,6 @@ message GetInstanceFeaturesResponse {
}
];
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.";
}
];
ImprovedPerformanceFeatureFlag improved_performance = 8 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "[1]";

View File

@@ -11,6 +11,8 @@ import "zitadel/feature/v2/feature.proto";
option go_package = "github.com/zitadel/zitadel/pkg/grpc/feature/v2;feature";
message SetSystemFeaturesRequest{
reserved 6;
reserved "actions";
optional bool login_default_org = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
@@ -46,13 +48,6 @@ message SetSystemFeaturesRequest{
}
];
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.";
}
];
repeated ImprovedPerformance improved_performance = 7 [
(validate.rules).repeated.unique = true,
(validate.rules).repeated.items.enum = {defined_only: true, not_in: [0]},
@@ -110,6 +105,8 @@ message ResetSystemFeaturesResponse {
message GetSystemFeaturesRequest {}
message GetSystemFeaturesResponse {
reserved 7;
reserved "actions";
zitadel.object.v2.Details details = 1;
FeatureFlag login_default_org = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
@@ -146,13 +143,6 @@ message GetSystemFeaturesResponse {
}
];
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.";
}
];
ImprovedPerformanceFeatureFlag improved_performance = 8 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "[1]";

View File

@@ -11,6 +11,8 @@ import "zitadel/feature/v2beta/feature.proto";
option go_package = "github.com/zitadel/zitadel/pkg/grpc/feature/v2beta;feature";
message SetInstanceFeaturesRequest{
reserved 6;
reserved "actions";
optional bool login_default_org = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
@@ -43,12 +45,6 @@ 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.";
}
];
repeated ImprovedPerformance improved_performance = 7 [
(validate.rules).repeated.unique = true,
@@ -101,6 +97,8 @@ message GetInstanceFeaturesRequest {
}
message GetInstanceFeaturesResponse {
reserved 7;
reserved "actions";
zitadel.object.v2beta.Details details = 1;
FeatureFlag login_default_org = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
@@ -137,13 +135,6 @@ message GetInstanceFeaturesResponse {
}
];
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.";
}
];
ImprovedPerformanceFeatureFlag improved_performance = 8 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "[1]";

View File

@@ -11,6 +11,8 @@ import "zitadel/feature/v2beta/feature.proto";
option go_package = "github.com/zitadel/zitadel/pkg/grpc/feature/v2beta;feature";
message SetSystemFeaturesRequest{
reserved 6;
reserved "actions";
optional bool login_default_org = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
@@ -46,13 +48,6 @@ message SetSystemFeaturesRequest{
}
];
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.";
}
];
repeated ImprovedPerformance improved_performance = 7 [
(validate.rules).repeated.unique = true,
(validate.rules).repeated.items.enum = {defined_only: true, not_in: [0]},
@@ -83,6 +78,8 @@ message ResetSystemFeaturesResponse {
message GetSystemFeaturesRequest {}
message GetSystemFeaturesResponse {
reserved 7;
reserved "actions";
zitadel.object.v2beta.Details details = 1;
FeatureFlag login_default_org = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
@@ -119,13 +116,6 @@ message GetSystemFeaturesResponse {
}
];
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.";
}
];
ImprovedPerformanceFeatureFlag improved_performance = 8 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "[1]";