feat: App Keys API v2 (#10140)

# Which Problems Are Solved

This PR *partially* addresses #9450 . Specifically, it implements the
resource based API for app keys.

This PR, together with https://github.com/zitadel/zitadel/pull/10077
completes #9450 .

# How the Problems Are Solved

- Implementation of the following endpoints: `CreateApplicationKey`,
`DeleteApplicationKey`, `GetApplicationKey`, `ListApplicationKeys`
- `ListApplicationKeys` can filter by project, app or organization ID.
Sorting is also possible according to some criteria.
  - All endpoints use permissions V2

# TODO

 - [x] Deprecate old endpoints

# Additional Context

Closes #9450
This commit is contained in:
Marco A.
2025-07-02 09:34:19 +02:00
committed by GitHub
parent 64a03fba28
commit fce9e770ac
19 changed files with 1350 additions and 69 deletions

View File

@@ -0,0 +1,206 @@
//go:build integration
package app_test
import (
"context"
"testing"
"time"
"github.com/brianvoe/gofakeit/v6"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
app "github.com/zitadel/zitadel/pkg/grpc/app/v2beta"
)
func TestCreateApplicationKey(t *testing.T) {
p, projectOwnerCtx := getProjectAndProjectContext(t, instance, IAMOwnerCtx)
createdApp := createAPIApp(t, IAMOwnerCtx, instance, p.GetId())
t.Parallel()
tt := []struct {
testName string
creationRequest *app.CreateApplicationKeyRequest
inputCtx context.Context
expectedErrorType codes.Code
}{
{
testName: "when app id is not found should return failed precondition",
inputCtx: IAMOwnerCtx,
creationRequest: &app.CreateApplicationKeyRequest{
ProjectId: p.GetId(),
AppId: gofakeit.UUID(),
ExpirationDate: timestamppb.New(time.Now().AddDate(0, 0, 1).UTC()),
},
expectedErrorType: codes.FailedPrecondition,
},
{
testName: "when CreateAPIApp request is valid should create app and return no error",
inputCtx: IAMOwnerCtx,
creationRequest: &app.CreateApplicationKeyRequest{
ProjectId: p.GetId(),
AppId: createdApp.GetAppId(),
ExpirationDate: timestamppb.New(time.Now().AddDate(0, 0, 1).UTC()),
},
},
// LoginUser
{
testName: "when user has no project.app.write permission for app key generation should return permission error",
inputCtx: LoginUserCtx,
creationRequest: &app.CreateApplicationKeyRequest{
ProjectId: p.GetId(),
AppId: createdApp.GetAppId(),
ExpirationDate: timestamppb.New(time.Now().AddDate(0, 0, 1).UTC()),
},
expectedErrorType: codes.PermissionDenied,
},
// OrgOwner
{
testName: "when user is OrgOwner app key request should succeed",
inputCtx: OrgOwnerCtx,
creationRequest: &app.CreateApplicationKeyRequest{
ProjectId: p.GetId(),
AppId: createdApp.GetAppId(),
ExpirationDate: timestamppb.New(time.Now().AddDate(0, 0, 1).UTC()),
},
},
// ProjectOwner
{
testName: "when user is ProjectOwner app key request should succeed",
inputCtx: projectOwnerCtx,
creationRequest: &app.CreateApplicationKeyRequest{
ProjectId: p.GetId(),
AppId: createdApp.GetAppId(),
ExpirationDate: timestamppb.New(time.Now().AddDate(0, 0, 1).UTC()),
},
},
}
for _, tc := range tt {
t.Run(tc.testName, func(t *testing.T) {
t.Parallel()
res, err := instance.Client.AppV2Beta.CreateApplicationKey(tc.inputCtx, tc.creationRequest)
require.Equal(t, tc.expectedErrorType, status.Code(err))
if tc.expectedErrorType == codes.OK {
assert.NotZero(t, res.GetId())
assert.NotZero(t, res.GetCreationDate())
assert.NotZero(t, res.GetKeyDetails())
}
})
}
}
func TestDeleteApplicationKey(t *testing.T) {
p, projectOwnerCtx := getProjectAndProjectContext(t, instance, IAMOwnerCtx)
createdApp := createAPIApp(t, IAMOwnerCtx, instance, p.GetId())
t.Parallel()
tt := []struct {
testName string
deletionRequest func(ttt *testing.T) *app.DeleteApplicationKeyRequest
inputCtx context.Context
expectedErrorType codes.Code
}{
{
testName: "when app key ID is not found should return not found error",
inputCtx: IAMOwnerCtx,
deletionRequest: func(ttt *testing.T) *app.DeleteApplicationKeyRequest {
return &app.DeleteApplicationKeyRequest{
Id: gofakeit.UUID(),
ProjectId: p.GetId(),
ApplicationId: createdApp.GetAppId(),
}
},
expectedErrorType: codes.NotFound,
},
{
testName: "when valid app key ID should delete successfully",
inputCtx: IAMOwnerCtx,
deletionRequest: func(ttt *testing.T) *app.DeleteApplicationKeyRequest {
createdAppKey := createAppKey(ttt, IAMOwnerCtx, instance, p.GetId(), createdApp.GetAppId(), time.Now().AddDate(0, 0, 1))
return &app.DeleteApplicationKeyRequest{
Id: createdAppKey.GetId(),
ProjectId: p.GetId(),
ApplicationId: createdApp.GetAppId(),
}
},
},
// LoginUser
{
testName: "when user has no project.app.write permission for app key deletion should return permission error",
inputCtx: LoginUserCtx,
deletionRequest: func(ttt *testing.T) *app.DeleteApplicationKeyRequest {
createdAppKey := createAppKey(ttt, IAMOwnerCtx, instance, p.GetId(), createdApp.GetAppId(), time.Now().AddDate(0, 0, 1))
return &app.DeleteApplicationKeyRequest{
Id: createdAppKey.GetId(),
ProjectId: p.GetId(),
ApplicationId: createdApp.GetAppId(),
}
},
expectedErrorType: codes.PermissionDenied,
},
// ProjectOwner
{
testName: "when user is OrgOwner API request should succeed",
inputCtx: projectOwnerCtx,
deletionRequest: func(ttt *testing.T) *app.DeleteApplicationKeyRequest {
createdAppKey := createAppKey(ttt, IAMOwnerCtx, instance, p.GetId(), createdApp.GetAppId(), time.Now().AddDate(0, 0, 1))
return &app.DeleteApplicationKeyRequest{
Id: createdAppKey.GetId(),
ProjectId: p.GetId(),
ApplicationId: createdApp.GetAppId(),
}
},
},
// OrganizationOwner
{
testName: "when user is OrgOwner app key deletion request should succeed",
inputCtx: OrgOwnerCtx,
deletionRequest: func(ttt *testing.T) *app.DeleteApplicationKeyRequest {
createdAppKey := createAppKey(ttt, IAMOwnerCtx, instance, p.GetId(), createdApp.GetAppId(), time.Now().AddDate(0, 0, 1))
return &app.DeleteApplicationKeyRequest{
Id: createdAppKey.GetId(),
ProjectId: p.GetId(),
ApplicationId: createdApp.GetAppId(),
}
},
},
}
for _, tc := range tt {
t.Run(tc.testName, func(t *testing.T) {
t.Parallel()
// Given
deletionReq := tc.deletionRequest(t)
// When
res, err := instance.Client.AppV2Beta.DeleteApplicationKey(tc.inputCtx, deletionReq)
// Then
require.Equal(t, tc.expectedErrorType, status.Code(err))
if tc.expectedErrorType == codes.OK {
assert.NotEmpty(t, res.GetDeletionDate())
}
})
}
}

View File

@@ -1,6 +1,6 @@
//go:build integration
package instance_test
package app_test
import (
"context"
@@ -653,9 +653,9 @@ func TestUpdateApplication_WithDifferentPermissions(t *testing.T) {
})
require.Nil(t, appNameChangeErr)
appForAPIConfigChangeForProjectOwner := createAPIApp(t, p.GetId())
appForAPIConfigChangeForOrgOwner := createAPIApp(t, p.GetId())
appForAPIConfigChangeForLoginUser := createAPIApp(t, p.GetId())
appForAPIConfigChangeForProjectOwner := createAPIApp(t, IAMOwnerCtx, instance, p.GetId())
appForAPIConfigChangeForOrgOwner := createAPIApp(t, IAMOwnerCtx, instance, p.GetId())
appForAPIConfigChangeForLoginUser := createAPIApp(t, IAMOwnerCtx, instance, p.GetId())
appForOIDCConfigChangeForProjectOwner := createOIDCApp(t, baseURI, p.GetId())
appForOIDCConfigChangeForOrgOwner := createOIDCApp(t, baseURI, p.GetId())
@@ -914,9 +914,9 @@ func TestDeleteApplication(t *testing.T) {
func TestDeleteApplication_WithDifferentPermissions(t *testing.T) {
p, projectOwnerCtx := getProjectAndProjectContext(t, instance, IAMOwnerCtx)
appToDeleteForLoginUser := createAPIApp(t, p.GetId())
appToDeleteForProjectOwner := createAPIApp(t, p.GetId())
appToDeleteForOrgOwner := createAPIApp(t, p.GetId())
appToDeleteForLoginUser := createAPIApp(t, IAMOwnerCtx, instance, p.GetId())
appToDeleteForProjectOwner := createAPIApp(t, IAMOwnerCtx, instance, p.GetId())
appToDeleteForOrgOwner := createAPIApp(t, IAMOwnerCtx, instance, p.GetId())
t.Parallel()
tt := []struct {
@@ -1035,9 +1035,9 @@ func TestDeactivateApplication(t *testing.T) {
func TestDeactivateApplication_WithDifferentPermissions(t *testing.T) {
p, projectOwnerCtx := getProjectAndProjectContext(t, instance, IAMOwnerCtx)
appToDeactivateForLoginUser := createAPIApp(t, p.GetId())
appToDeactivateForPrjectOwner := createAPIApp(t, p.GetId())
appToDeactivateForOrgOwner := createAPIApp(t, p.GetId())
appToDeactivateForLoginUser := createAPIApp(t, IAMOwnerCtx, instance, p.GetId())
appToDeactivateForPrjectOwner := createAPIApp(t, IAMOwnerCtx, instance, p.GetId())
appToDeactivateForOrgOwner := createAPIApp(t, IAMOwnerCtx, instance, p.GetId())
t.Parallel()
@@ -1162,13 +1162,13 @@ func TestReactivateApplication(t *testing.T) {
func TestReactivateApplication_WithDifferentPermissions(t *testing.T) {
p, projectOwnerCtx := getProjectAndProjectContext(t, instance, IAMOwnerCtx)
appToReactivateForLoginUser := createAPIApp(t, p.GetId())
appToReactivateForLoginUser := createAPIApp(t, IAMOwnerCtx, instance, p.GetId())
deactivateApp(t, appToReactivateForLoginUser, p.GetId())
appToReactivateForProjectOwner := createAPIApp(t, p.GetId())
appToReactivateForProjectOwner := createAPIApp(t, IAMOwnerCtx, instance, p.GetId())
deactivateApp(t, appToReactivateForProjectOwner, p.GetId())
appToReactivateForOrgOwner := createAPIApp(t, p.GetId())
appToReactivateForOrgOwner := createAPIApp(t, IAMOwnerCtx, instance, p.GetId())
deactivateApp(t, appToReactivateForOrgOwner, p.GetId())
t.Parallel()
@@ -1342,9 +1342,9 @@ func TestRegenerateClientSecret(t *testing.T) {
func TestRegenerateClientSecret_WithDifferentPermissions(t *testing.T) {
p, projectOwnerCtx := getProjectAndProjectContext(t, instance, IAMOwnerCtx)
apiAppToRegenForLoginUser := createAPIApp(t, p.GetId())
apiAppToRegenForProjectOwner := createAPIApp(t, p.GetId())
apiAppToRegenForOrgOwner := createAPIApp(t, p.GetId())
apiAppToRegenForLoginUser := createAPIApp(t, IAMOwnerCtx, instance, p.GetId())
apiAppToRegenForProjectOwner := createAPIApp(t, IAMOwnerCtx, instance, p.GetId())
apiAppToRegenForOrgOwner := createAPIApp(t, IAMOwnerCtx, instance, p.GetId())
oidcAppToRegenForLoginUser := createOIDCApp(t, baseURI, p.GetId())
oidcAppToRegenForProjectOwner := createOIDCApp(t, baseURI, p.GetId())

View File

@@ -1,6 +1,6 @@
//go:build integration
package instance_test
package app_test
import (
"context"
@@ -165,9 +165,9 @@ func TestListApplications(t *testing.T) {
t.Parallel()
createdApiApp, apiAppName := createAPIAppWithName(t, p.GetId())
createdApiApp, apiAppName := createAPIAppWithName(t, IAMOwnerCtx, instance, p.GetId())
createdDeactivatedApiApp, deactivatedApiAppName := createAPIAppWithName(t, p.GetId())
createdDeactivatedApiApp, deactivatedApiAppName := createAPIAppWithName(t, IAMOwnerCtx, instance, p.GetId())
deactivateApp(t, createdDeactivatedApiApp, p.GetId())
_, createdSAMLApp, samlAppName := createSAMLAppWithName(t, gofakeit.URL(), p.GetId())
@@ -573,3 +573,248 @@ func TestListApplications_WithPermissionV2(t *testing.T) {
})
}
}
func TestGetApplicationKey(t *testing.T) {
p, projectOwnerCtx := getProjectAndProjectContext(t, instance, IAMOwnerCtx)
createdApiApp := createAPIApp(t, IAMOwnerCtx, instance, p.GetId())
createdAppKey := createAppKey(t, IAMOwnerCtx, instance, p.GetId(), createdApiApp.GetAppId(), time.Now().AddDate(0, 0, 1))
t.Parallel()
tt := []struct {
testName string
inputRequest *app.GetApplicationKeyRequest
inputCtx context.Context
expectedErrorType codes.Code
expectedAppKeyID string
}{
{
testName: "when unknown app ID should return not found error",
inputCtx: IAMOwnerCtx,
inputRequest: &app.GetApplicationKeyRequest{
Id: gofakeit.Sentence(2),
},
expectedErrorType: codes.NotFound,
},
{
testName: "when user has no permission should return membership not found error",
inputCtx: NoPermissionCtx,
inputRequest: &app.GetApplicationKeyRequest{
Id: createdAppKey.GetId(),
},
expectedErrorType: codes.NotFound,
},
{
testName: "when providing API app ID should return valid API app result",
inputCtx: projectOwnerCtx,
inputRequest: &app.GetApplicationKeyRequest{
Id: createdAppKey.GetId(),
},
expectedAppKeyID: createdAppKey.GetId(),
},
{
testName: "when user is OrgOwner should return request key",
inputCtx: OrgOwnerCtx,
inputRequest: &app.GetApplicationKeyRequest{
Id: createdAppKey.GetId(),
ProjectId: p.GetId(),
},
expectedAppKeyID: createdAppKey.GetId(),
},
{
testName: "when user is IAMOwner should return request key",
inputCtx: OrgOwnerCtx,
inputRequest: &app.GetApplicationKeyRequest{
Id: createdAppKey.GetId(),
OrganizationId: instance.DefaultOrg.GetId(),
},
expectedAppKeyID: createdAppKey.GetId(),
},
}
for _, tc := range tt {
t.Run(tc.testName, func(t *testing.T) {
t.Parallel()
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(tc.inputCtx, 30*time.Second)
require.EventuallyWithT(t, func(ttt *assert.CollectT) {
// When
res, err := instance.Client.AppV2Beta.GetApplicationKey(tc.inputCtx, tc.inputRequest)
// Then
require.Equal(t, tc.expectedErrorType, status.Code(err))
if tc.expectedErrorType == codes.OK {
assert.Equal(t, tc.expectedAppKeyID, res.GetId())
assert.NotEmpty(t, res.GetCreationDate())
assert.NotEmpty(t, res.GetExpirationDate())
}
}, retryDuration, tick)
})
}
}
func TestListApplicationKeys(t *testing.T) {
p, projectOwnerCtx := getProjectAndProjectContext(t, instance, IAMOwnerCtx)
createdApiApp1 := createAPIApp(t, IAMOwnerCtx, instance, p.GetId())
createdApiApp2 := createAPIApp(t, IAMOwnerCtx, instance, p.GetId())
tomorrow := time.Now().AddDate(0, 0, 1)
in2Days := tomorrow.AddDate(0, 0, 1)
in3Days := in2Days.AddDate(0, 0, 1)
appKey1 := createAppKey(t, IAMOwnerCtx, instance, p.GetId(), createdApiApp1.GetAppId(), in2Days)
appKey2 := createAppKey(t, IAMOwnerCtx, instance, p.GetId(), createdApiApp1.GetAppId(), in3Days)
appKey3 := createAppKey(t, IAMOwnerCtx, instance, p.GetId(), createdApiApp1.GetAppId(), tomorrow)
appKey4 := createAppKey(t, IAMOwnerCtx, instance, p.GetId(), createdApiApp2.GetAppId(), tomorrow)
t.Parallel()
tt := []struct {
testName string
inputRequest *app.ListApplicationKeysRequest
deps func() (projectID, applicationID, organizationID string)
inputCtx context.Context
expectedErrorType codes.Code
expectedAppKeysIDs []string
}{
{
testName: "when sorting by expiration date should return keys sorted by expiration date ascending",
inputCtx: LoginUserCtx,
inputRequest: &app.ListApplicationKeysRequest{
ResourceId: &app.ListApplicationKeysRequest_ProjectId{ProjectId: p.GetId()},
Pagination: &filter.PaginationRequest{Asc: true},
SortingColumn: app.ApplicationKeysSorting_APPLICATION_KEYS_SORT_BY_EXPIRATION,
},
expectedAppKeysIDs: []string{appKey3.GetId(), appKey4.GetId(), appKey1.GetId(), appKey2.GetId()},
},
{
testName: "when sorting by creation date should return keys sorted by creation date descending",
inputCtx: IAMOwnerCtx,
inputRequest: &app.ListApplicationKeysRequest{
ResourceId: &app.ListApplicationKeysRequest_ProjectId{ProjectId: p.GetId()},
SortingColumn: app.ApplicationKeysSorting_APPLICATION_KEYS_SORT_BY_CREATION_DATE,
},
expectedAppKeysIDs: []string{appKey4.GetId(), appKey3.GetId(), appKey2.GetId(), appKey1.GetId()},
},
{
testName: "when filtering by app ID should return keys matching app ID sorted by ID",
inputCtx: projectOwnerCtx,
inputRequest: &app.ListApplicationKeysRequest{
Pagination: &filter.PaginationRequest{Asc: true},
ResourceId: &app.ListApplicationKeysRequest_ApplicationId{ApplicationId: createdApiApp1.GetAppId()},
},
expectedAppKeysIDs: []string{appKey1.GetId(), appKey2.GetId(), appKey3.GetId()},
},
}
for _, tc := range tt {
t.Run(tc.testName, func(t *testing.T) {
t.Parallel()
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(tc.inputCtx, 5*time.Second)
require.EventuallyWithT(t, func(ttt *assert.CollectT) {
// When
res, err := instance.Client.AppV2Beta.ListApplicationKeys(tc.inputCtx, tc.inputRequest)
// Then
require.Equal(ttt, tc.expectedErrorType, status.Code(err))
if tc.expectedErrorType == codes.OK {
require.Len(ttt, res.GetKeys(), len(tc.expectedAppKeysIDs))
for i, k := range res.GetKeys() {
assert.Equal(ttt, tc.expectedAppKeysIDs[i], k.GetId())
}
}
}, retryDuration, tick)
})
}
}
func TestListApplicationKeys_WithPermissionV2(t *testing.T) {
ensureFeaturePermissionV2Enabled(t, instancePermissionV2)
iamOwnerCtx := instancePermissionV2.WithAuthorization(context.Background(), integration.UserTypeIAMOwner)
loginUserCtx := instancePermissionV2.WithAuthorization(context.Background(), integration.UserTypeLogin)
p, projectOwnerCtx := getProjectAndProjectContext(t, instancePermissionV2, iamOwnerCtx)
createdApiApp1 := createAPIApp(t, iamOwnerCtx, instancePermissionV2, p.GetId())
createdApiApp2 := createAPIApp(t, iamOwnerCtx, instancePermissionV2, p.GetId())
tomorrow := time.Now().AddDate(0, 0, 1)
in2Days := tomorrow.AddDate(0, 0, 1)
in3Days := in2Days.AddDate(0, 0, 1)
appKey1 := createAppKey(t, iamOwnerCtx, instancePermissionV2, p.GetId(), createdApiApp1.GetAppId(), in2Days)
appKey2 := createAppKey(t, iamOwnerCtx, instancePermissionV2, p.GetId(), createdApiApp1.GetAppId(), in3Days)
appKey3 := createAppKey(t, iamOwnerCtx, instancePermissionV2, p.GetId(), createdApiApp1.GetAppId(), tomorrow)
appKey4 := createAppKey(t, iamOwnerCtx, instancePermissionV2, p.GetId(), createdApiApp2.GetAppId(), tomorrow)
t.Parallel()
tt := []struct {
testName string
inputRequest *app.ListApplicationKeysRequest
deps func() (projectID, applicationID, organizationID string)
inputCtx context.Context
expectedErrorType codes.Code
expectedAppKeysIDs []string
}{
{
testName: "when sorting by expiration date should return keys sorted by expiration date ascending",
inputCtx: loginUserCtx,
inputRequest: &app.ListApplicationKeysRequest{
Pagination: &filter.PaginationRequest{Asc: true},
SortingColumn: app.ApplicationKeysSorting_APPLICATION_KEYS_SORT_BY_EXPIRATION,
},
expectedAppKeysIDs: []string{appKey3.GetId(), appKey4.GetId(), appKey1.GetId(), appKey2.GetId()},
},
{
testName: "when sorting by creation date should return keys sorted by creation date descending",
inputCtx: iamOwnerCtx,
inputRequest: &app.ListApplicationKeysRequest{
SortingColumn: app.ApplicationKeysSorting_APPLICATION_KEYS_SORT_BY_CREATION_DATE,
},
expectedAppKeysIDs: []string{appKey4.GetId(), appKey3.GetId(), appKey2.GetId(), appKey1.GetId()},
},
{
testName: "when filtering by app ID should return keys matching app ID sorted by ID",
inputCtx: projectOwnerCtx,
inputRequest: &app.ListApplicationKeysRequest{
Pagination: &filter.PaginationRequest{Asc: true},
ResourceId: &app.ListApplicationKeysRequest_ApplicationId{ApplicationId: createdApiApp1.GetAppId()},
},
expectedAppKeysIDs: []string{appKey1.GetId(), appKey2.GetId(), appKey3.GetId()},
},
}
for _, tc := range tt {
t.Run(tc.testName, func(t *testing.T) {
// t.Parallel()
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(tc.inputCtx, 5*time.Second)
require.EventuallyWithT(t, func(ttt *assert.CollectT) {
// When
res, err := instancePermissionV2.Client.AppV2Beta.ListApplicationKeys(tc.inputCtx, tc.inputRequest)
// Then
require.Equal(ttt, tc.expectedErrorType, status.Code(err))
if tc.expectedErrorType == codes.OK {
require.Len(ttt, res.GetKeys(), len(tc.expectedAppKeysIDs))
for i, k := range res.GetKeys() {
assert.Equal(ttt, tc.expectedAppKeysIDs[i], k.GetId())
}
}
}, retryDuration, tick)
})
}
}

View File

@@ -1,6 +1,6 @@
//go:build integration
package instance_test
package app_test
import (
"context"
@@ -13,6 +13,7 @@ import (
"github.com/muhlemmer/gu"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/integration"
app "github.com/zitadel/zitadel/pkg/grpc/app/v2beta"
@@ -150,14 +151,14 @@ func createOIDCApp(t *testing.T, baseURI, projctID string) *app.CreateApplicatio
return app
}
func createAPIAppWithName(t *testing.T, projectID string) (*app.CreateApplicationResponse, string) {
func createAPIAppWithName(t *testing.T, ctx context.Context, inst *integration.Instance, projectID string) (*app.CreateApplicationResponse, string) {
appName := gofakeit.AppName()
reqForAPIAppCreation := &app.CreateApplicationRequest_ApiRequest{
ApiRequest: &app.CreateAPIApplicationRequest{AuthMethodType: app.APIAuthMethodType_API_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT},
}
appForAPIConfigChange, appAPIConfigChangeErr := instance.Client.AppV2Beta.CreateApplication(IAMOwnerCtx, &app.CreateApplicationRequest{
appForAPIConfigChange, appAPIConfigChangeErr := inst.Client.AppV2Beta.CreateApplication(ctx, &app.CreateApplicationRequest{
ProjectId: projectID,
Name: appName,
CreationRequestType: reqForAPIAppCreation,
@@ -167,8 +168,8 @@ func createAPIAppWithName(t *testing.T, projectID string) (*app.CreateApplicatio
return appForAPIConfigChange, appName
}
func createAPIApp(t *testing.T, projectID string) *app.CreateApplicationResponse {
res, _ := createAPIAppWithName(t, projectID)
func createAPIApp(t *testing.T, ctx context.Context, inst *integration.Instance, projectID string) *app.CreateApplicationResponse {
res, _ := createAPIAppWithName(t, ctx, inst, projectID)
return res
}
@@ -203,3 +204,17 @@ func ensureFeaturePermissionV2Enabled(t *testing.T, instance *integration.Instan
assert.True(tt, f.PermissionCheckV2.GetEnabled())
}, retryDuration, tick, "timed out waiting for ensuring instance feature")
}
func createAppKey(t *testing.T, ctx context.Context, inst *integration.Instance, projectID, appID string, expirationDate time.Time) *app.CreateApplicationKeyResponse {
res, err := inst.Client.AppV2Beta.CreateApplicationKey(ctx,
&app.CreateApplicationKeyRequest{
AppId: appID,
ProjectId: projectID,
ExpirationDate: timestamppb.New(expirationDate.UTC()),
},
)
require.Nil(t, err)
return res
}