feat: App API v2 (#10077)

# Which Problems Are Solved

This PR *partially* addresses #9450 . Specifically, it implements the
resource based API for the apps. APIs for app keys ARE not part of this
PR.

# How the Problems Are Solved

- `CreateApplication`, `PatchApplication` (update) and
`RegenerateClientSecret` endpoints are now unique for all app types:
API, SAML and OIDC apps.
  - All new endpoints have integration tests
  - All new endpoints are using permission checks V2

# Additional Changes

- The `ListApplications` endpoint allows to do sorting (see protobuf for
details) and filtering by app type (see protobuf).
- SAML and OIDC update endpoint can now receive requests for partial
updates

# Additional Context

Partially addresses #9450
This commit is contained in:
Marco A.
2025-06-27 17:25:44 +02:00
committed by GitHub
parent 016676e1dc
commit 2691dae2b6
48 changed files with 6845 additions and 603 deletions

View File

@@ -142,6 +142,7 @@ func TestAddAPIConfig(t *testing.T) {
}
func TestCommandSide_AddAPIApplication(t *testing.T) {
t.Parallel()
type fields struct {
eventstore func(t *testing.T) *eventstore.Eventstore
idGenerator id.Generator
@@ -238,6 +239,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
domain.PrivateLabelingSettingUnspecified),
),
),
expectFilter(),
expectPush(
project.NewApplicationAddedEvent(context.Background(),
&project.NewAggregate("project1", "org1").Aggregate,
@@ -292,6 +294,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
domain.PrivateLabelingSettingUnspecified),
),
),
expectFilter(),
expectPush(
project.NewApplicationAddedEvent(context.Background(),
&project.NewAggregate("project1", "org1").Aggregate,
@@ -346,6 +349,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
domain.PrivateLabelingSettingUnspecified),
),
),
expectFilter(),
expectPush(
project.NewApplicationAddedEvent(context.Background(),
&project.NewAggregate("project1", "org1").Aggregate,
@@ -390,6 +394,8 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
r := &Commands{
eventstore: tt.fields.eventstore(t),
idGenerator: tt.fields.idGenerator,
@@ -397,6 +403,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
defaultSecretGenerators: &SecretGenerators{
ClientSecret: emptyConfig,
},
checkPermission: newMockPermissionCheckAllowed(),
}
got, err := r.AddAPIApplication(tt.args.ctx, tt.args.apiApp, tt.args.resourceOwner)
if tt.res.err == nil {
@@ -413,6 +420,8 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
}
func TestCommandSide_ChangeAPIApplication(t *testing.T) {
t.Parallel()
type fields struct {
eventstore func(t *testing.T) *eventstore.Eventstore
}
@@ -516,6 +525,7 @@ func TestCommandSide_ChangeAPIApplication(t *testing.T) {
domain.APIAuthMethodTypePrivateKeyJWT),
),
),
expectFilter(),
),
},
args: args{
@@ -555,6 +565,7 @@ func TestCommandSide_ChangeAPIApplication(t *testing.T) {
domain.APIAuthMethodTypeBasic),
),
),
expectFilter(),
expectPush(
newAPIAppChangedEvent(context.Background(),
"app1",
@@ -593,14 +604,17 @@ func TestCommandSide_ChangeAPIApplication(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
r := &Commands{
eventstore: tt.fields.eventstore(t),
newHashedSecret: mockHashedSecret("secret"),
defaultSecretGenerators: &SecretGenerators{
ClientSecret: emptyConfig,
},
checkPermission: newMockPermissionCheckAllowed(),
}
got, err := r.ChangeAPIApplication(tt.args.ctx, tt.args.apiApp, tt.args.resourceOwner)
got, err := r.UpdateAPIApplication(tt.args.ctx, tt.args.apiApp, tt.args.resourceOwner)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -615,6 +629,8 @@ func TestCommandSide_ChangeAPIApplication(t *testing.T) {
}
func TestCommandSide_ChangeAPIApplicationSecret(t *testing.T) {
t.Parallel()
type fields struct {
eventstore func(*testing.T) *eventstore.Eventstore
}
@@ -734,12 +750,15 @@ func TestCommandSide_ChangeAPIApplicationSecret(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
r := &Commands{
eventstore: tt.fields.eventstore(t),
newHashedSecret: mockHashedSecret("secret"),
defaultSecretGenerators: &SecretGenerators{
ClientSecret: emptyConfig,
},
checkPermission: newMockPermissionCheckAllowed(),
}
got, err := r.ChangeAPIApplicationSecret(tt.args.ctx, tt.args.projectID, tt.args.appID, tt.args.resourceOwner)
if tt.res.err == nil {