Merge branch 'refs/heads/main' into next-rc

This commit is contained in:
Livio Spring 2024-08-16 15:49:03 +02:00
commit dfd7dde86c
No known key found for this signature in database
GPG Key ID: 26BB1C2FA5952CF0
34 changed files with 496 additions and 26 deletions

View File

@ -25,6 +25,18 @@ Tracing:
# The endpoint of the otel collector endpoint
Endpoint: "" #ZITADEL_TRACING_ENDPOINT
# Profiler enables capturing profiling data (CPU, Memory, ...) for performance analysis
Profiler:
# Choose one of "google" and "none"
# Depending on the type there are different configuration options
# for type 'google'
# ProjectID: google-project-id
#
# type 'none' or '' disables profiling
Type: none # ZITADEL_PROFILER_TYPE
# projectID for google
ProjectID: '' # ZITADEL_PROFILER_PROJECTID
Telemetry:
# As long as Enabled is true, ZITADEL tries to send usage data to the configured Telemetry.Endpoints.
# Data is projected by ZITADEL even if Enabled is false.

View File

@ -31,6 +31,7 @@ import (
"github.com/zitadel/zitadel/internal/query/projection"
static_config "github.com/zitadel/zitadel/internal/static/config"
metrics "github.com/zitadel/zitadel/internal/telemetry/metrics/config"
profiler "github.com/zitadel/zitadel/internal/telemetry/profiler/config"
tracing "github.com/zitadel/zitadel/internal/telemetry/tracing/config"
)
@ -49,6 +50,7 @@ type Config struct {
Database database.Config
Tracing tracing.Config
Metrics metrics.Config
Profiler profiler.Config
Projections projection.Config
Auth auth_es.Config
Admin admin_es.Config
@ -114,6 +116,9 @@ func MustNewConfig(v *viper.Viper) *Config {
err = config.Metrics.NewMeter()
logging.OnError(err).Fatal("unable to set meter")
err = config.Profiler.NewProfiler()
logging.OnError(err).Fatal("unable to set profiler")
id.Configure(config.Machine)
actions.SetHTTPConfig(&config.Actions.HTTP)

View File

@ -57,11 +57,14 @@
</cnsl-action-keys>
</div>
</button>
<cnsl-filter-user
*ngIf="!selection.hasValue()"
(filterChanged)="applySearchQuery($any($event))"
(filterOpen)="filterOpen = $event"
></cnsl-filter-user>
</ng-template>
<cnsl-filter-user
actions
*ngIf="!selection.hasValue()"
(filterChanged)="applySearchQuery($any($event))"
(filterOpen)="filterOpen = $event"
></cnsl-filter-user>
<ng-template cnslHasRole [hasRole]="['user.write']" actions>
<button
(click)="gotoRouterLink(['/users', type === Type.TYPE_HUMAN ? 'create' : 'create-machine'])"
color="primary"

View File

@ -169,4 +169,19 @@ For event there are 3 levels the condition can be defined:
- Group, handling a specific group of events
- All, handling any event in ZITADEL
The concept of events can be found under [Events](/concepts/architecture/software#events)
The concept of events can be found under [Events](/concepts/architecture/software#events)
### Error forwarding
If you want to forward a specific error from the Target through ZITADEL, you can provide a response from the Target with status code 200 and a JSON in the following format:
```json
{
"forwardedStatusCode": 403,
"forwardedErrorMessage": "Call is forbidden through the IP AllowList definition"
}
```
Only values from 400 to 499 will be forwarded through ZITADEL, other StatusCodes will end in a PreconditionFailed error.
If the Target returns any other status code than >= 200 and < 299, the execution is looked at as failed, and a PreconditionFailed error is logged.

View File

@ -761,8 +761,8 @@ module.exports = {
label: "Web key Lifecycle (Preview)",
link: {
type: "generated-index",
title: "Action Service API (Preview)",
slug: "/apis/resources/action_service_v3",
title: "Web Key Service API (Preview)",
slug: "/apis/resources/webkey_service_v3",
description:
"This API is intended to manage web keys for a ZITADEL instance, used to sign and validate OIDC tokens.\n" +
"\n" +

3
go.mod
View File

@ -3,6 +3,7 @@ module github.com/zitadel/zitadel
go 1.22.2
require (
cloud.google.com/go/profiler v0.4.1
cloud.google.com/go/storage v1.43.0
github.com/BurntSushi/toml v1.4.0
github.com/DATA-DOG/go-sqlmock v1.5.2
@ -103,7 +104,7 @@ require (
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/go-tpm v0.9.0 // indirect
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/klauspost/cpuid/v2 v2.2.8 // indirect

6
go.sum
View File

@ -16,6 +16,8 @@ cloud.google.com/go/longrunning v0.5.7 h1:WLbHekDbjK1fVFD3ibpFFVoyizlLRl73I7YKuA
cloud.google.com/go/longrunning v0.5.7/go.mod h1:8GClkudohy1Fxm3owmBGid8W0pSgodEMwEAztp38Xng=
cloud.google.com/go/monitoring v1.19.0 h1:NCXf8hfQi+Kmr56QJezXRZ6GPb80ZI7El1XztyUuLQI=
cloud.google.com/go/monitoring v1.19.0/go.mod h1:25IeMR5cQ5BoZ8j1eogHE5VPJLlReQ7zFp5OiLgiGZw=
cloud.google.com/go/profiler v0.4.1 h1:Q7+lOvikTGMJ/IAWocpYYGit4SIIoILmVZfEEWTORSY=
cloud.google.com/go/profiler v0.4.1/go.mod h1:LBrtEX6nbvhv1w/e5CPZmX9ajGG9BGLtGbv56Tg4SHs=
cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs=
cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0=
cloud.google.com/go/trace v1.10.7 h1:gK8z2BIJQ3KIYGddw9RJLne5Fx0FEXkrEQzPaeEYVvk=
@ -313,8 +315,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc=
github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0=
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba h1:ql1qNgCyOB7iAEk8JTNM+zJrgIbnyCKX/wdlyPufP5g=
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=

View File

@ -263,7 +263,7 @@ func TestServer_RemovePhone(t *testing.T) {
req *user.RemovePhoneRequest
want *user.RemovePhoneResponse
wantErr bool
dep func(ctx context.Context, userID string) (*user.RemovePhoneResponse, error)
dep func(ctx context.Context, userID string) (*user.RemovePhoneResponse, error)
}{
{
name: "remove phone",
@ -303,7 +303,7 @@ func TestServer_RemovePhone(t *testing.T) {
dep: func(ctx context.Context, userID string) (*user.RemovePhoneResponse, error) {
return Client.RemovePhone(ctx, &user.RemovePhoneRequest{
UserId: doubleRemoveUser.GetUserId(),
});
})
},
},
{

View File

@ -45,3 +45,36 @@ func ZitadelErrorToHTTPStatusCode(err error) (statusCode int, ok bool) {
return http.StatusInternalServerError, false
}
}
func HTTPStatusCodeToZitadelError(parent error, statusCode int, id string, message string) error {
if statusCode == http.StatusOK {
return nil
}
var errorFunc func(parent error, id, message string) error
switch statusCode {
case http.StatusConflict:
errorFunc = zerrors.ThrowAlreadyExists
case http.StatusGatewayTimeout:
errorFunc = zerrors.ThrowDeadlineExceeded
case http.StatusInternalServerError:
errorFunc = zerrors.ThrowInternal
case http.StatusBadRequest:
errorFunc = zerrors.ThrowInvalidArgument
case http.StatusNotFound:
errorFunc = zerrors.ThrowNotFound
case http.StatusForbidden:
errorFunc = zerrors.ThrowPermissionDenied
case http.StatusUnauthorized:
errorFunc = zerrors.ThrowUnauthenticated
case http.StatusServiceUnavailable:
errorFunc = zerrors.ThrowUnavailable
case http.StatusNotImplemented:
errorFunc = zerrors.ThrowUnimplemented
case http.StatusTooManyRequests:
errorFunc = zerrors.ThrowResourceExhausted
default:
errorFunc = zerrors.ThrowUnknown
}
return errorFunc(parent, id, message)
}

View File

@ -6,6 +6,8 @@ import (
"net/http"
"testing"
"github.com/stretchr/testify/assert"
"github.com/zitadel/zitadel/internal/zerrors"
)
@ -136,3 +138,152 @@ func TestZitadelErrorToHTTPStatusCode(t *testing.T) {
})
}
}
func TestHTTPStatusCodeToZitadelError(t *testing.T) {
type args struct {
statusCode int
id string
message string
parent error
}
tests := []struct {
name string
args args
wantErr error
}{
{
name: "StatusOK",
args: args{
statusCode: http.StatusOK,
},
wantErr: nil,
},
{
name: "StatusConflict",
args: args{
statusCode: http.StatusConflict,
id: "id",
message: "message",
},
wantErr: zerrors.ThrowAlreadyExists(nil, "id", "message"),
},
{
name: "StatusGatewayTimeout",
args: args{
statusCode: http.StatusGatewayTimeout,
id: "id",
message: "message",
},
wantErr: zerrors.ThrowDeadlineExceeded(nil, "id", "message"),
},
{
name: "StatusInternalServerError",
args: args{
statusCode: http.StatusInternalServerError,
id: "id",
message: "message",
},
wantErr: zerrors.ThrowInternal(nil, "id", "message"),
},
{
name: "StatusBadRequest",
args: args{
statusCode: http.StatusBadRequest,
id: "id",
message: "message",
},
wantErr: zerrors.ThrowInvalidArgument(nil, "id", "message"),
},
{
name: "StatusNotFound",
args: args{
statusCode: http.StatusNotFound,
id: "id",
message: "message",
},
wantErr: zerrors.ThrowNotFound(nil, "id", "message"),
},
{
name: "StatusForbidden",
args: args{
statusCode: http.StatusForbidden,
id: "id",
message: "message",
},
wantErr: zerrors.ThrowPermissionDenied(nil, "id", "message"),
},
{
name: "StatusUnauthorized",
args: args{
statusCode: http.StatusUnauthorized,
id: "id",
message: "message",
},
wantErr: zerrors.ThrowUnauthenticated(nil, "id", "message"),
},
{
name: "StatusServiceUnavailable",
args: args{
statusCode: http.StatusServiceUnavailable,
id: "id",
message: "message",
},
wantErr: zerrors.ThrowUnavailable(nil, "id", "message"),
},
{
name: "StatusNotImplemented",
args: args{
statusCode: http.StatusNotImplemented,
id: "id",
message: "message",
},
wantErr: zerrors.ThrowUnimplemented(nil, "id", "message"),
},
{
name: "StatusTooManyRequests",
args: args{
statusCode: http.StatusTooManyRequests,
id: "id",
message: "message",
},
wantErr: zerrors.ThrowResourceExhausted(nil, "id", "message"),
},
{
name: "Unknown",
args: args{
statusCode: 1000,
id: "id",
message: "message",
},
wantErr: zerrors.ThrowUnknown(nil, "id", "message"),
},
{
name: "Unknown, test for statuscode",
args: args{
statusCode: 1000,
id: "id",
message: "message",
},
wantErr: zerrors.ThrowError(nil, "id", "message"),
},
{
name: "Unknown with parent",
args: args{
statusCode: 1000,
id: "id",
message: "message",
parent: errors.New("parent error"),
},
wantErr: zerrors.ThrowUnknown(nil, "id", "message"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := HTTPStatusCodeToZitadelError(tt.args.parent, tt.args.statusCode, tt.args.id, tt.args.message)
assert.ErrorIs(t, err, tt.wantErr)
if tt.args.parent != nil {
assert.ErrorIs(t, err, tt.args.parent)
}
})
}
}

View File

@ -3,12 +3,14 @@ package execution
import (
"bytes"
"context"
"encoding/json"
"io"
"net/http"
"time"
"github.com/zitadel/logging"
zhttp "github.com/zitadel/zitadel/internal/api/http"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
"github.com/zitadel/zitadel/internal/zerrors"
@ -114,9 +116,35 @@ func Call(ctx context.Context, url string, timeout time.Duration, body []byte) (
}
defer resp.Body.Close()
return HandleResponse(resp)
}
func HandleResponse(resp *http.Response) ([]byte, error) {
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
// Check for success between 200 and 299, redirect 300 to 399 is handled by the client, return error with statusCode >= 400
if resp.StatusCode >= 200 && resp.StatusCode <= 299 {
return io.ReadAll(resp.Body)
var errorBody ErrorBody
if err := json.Unmarshal(data, &errorBody); err != nil {
// if json unmarshal fails, body has no ErrorBody information, so will be taken as successful response
return data, nil
}
if errorBody.ForwardedStatusCode != 0 || errorBody.ForwardedErrorMessage != "" {
if errorBody.ForwardedStatusCode >= 400 && errorBody.ForwardedStatusCode < 500 {
return nil, zhttp.HTTPStatusCodeToZitadelError(nil, errorBody.ForwardedStatusCode, "EXEC-reUaUZCzCp", errorBody.ForwardedErrorMessage)
}
return nil, zerrors.ThrowPreconditionFailed(nil, "EXEC-bmhNhpcqpF", errorBody.ForwardedErrorMessage)
}
// no ErrorBody filled in response, so will be taken as successful response
return data, nil
}
return nil, zerrors.ThrowUnknown(nil, "EXEC-dra6yamk98", "Errors.Execution.Failed")
return nil, zerrors.ThrowPreconditionFailed(nil, "EXEC-dra6yamk98", "Errors.Execution.Failed")
}
type ErrorBody struct {
ForwardedStatusCode int `json:"forwardedStatusCode,omitempty"`
ForwardedErrorMessage string `json:"forwardedErrorMessage,omitempty"`
}

View File

@ -1,7 +1,10 @@
package execution_test
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
@ -15,6 +18,7 @@ import (
"github.com/zitadel/zitadel/internal/api/grpc/server/middleware"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/execution"
"github.com/zitadel/zitadel/internal/zerrors"
)
func Test_Call(t *testing.T) {
@ -513,3 +517,152 @@ var requestContextInfoBody2 = []byte("{\"request\":{\"request\":\"content2\"}}")
type request struct {
Request string `json:"request"`
}
func testErrorBody(code int, message string) []byte {
body := &execution.ErrorBody{ForwardedStatusCode: code, ForwardedErrorMessage: message}
data, _ := json.Marshal(body)
return data
}
func Test_handleResponse(t *testing.T) {
type args struct {
resp *http.Response
}
type res struct {
data []byte
wantErr func(error) bool
}
tests := []struct {
name string
args args
res res
}{
{
"response, statuscode unknown and body",
args{
resp: &http.Response{
StatusCode: 1000,
Body: io.NopCloser(bytes.NewReader([]byte(""))),
},
},
res{
wantErr: func(err error) bool {
return errors.Is(err, zerrors.ThrowPreconditionFailed(nil, "EXEC-dra6yamk98", "Errors.Execution.Failed"))
},
},
},
{
"response, statuscode >= 400 and no body",
args{
resp: &http.Response{
StatusCode: http.StatusForbidden,
Body: io.NopCloser(bytes.NewReader([]byte(""))),
},
},
res{
wantErr: func(err error) bool {
return errors.Is(err, zerrors.ThrowPreconditionFailed(nil, "EXEC-dra6yamk98", "Errors.Execution.Failed"))
},
},
},
{
"response, statuscode >= 400 and body",
args{
resp: &http.Response{
StatusCode: http.StatusForbidden,
Body: io.NopCloser(bytes.NewReader([]byte("body"))),
},
},
res{
wantErr: func(err error) bool {
return errors.Is(err, zerrors.ThrowPreconditionFailed(nil, "EXEC-dra6yamk98", "Errors.Execution.Failed"))
}},
},
{
"response, statuscode = 200 and body",
args{
resp: &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(bytes.NewReader([]byte("body"))),
},
},
res{
data: []byte("body"),
wantErr: nil,
},
},
{
"response, statuscode = 200 no body",
args{
resp: &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(bytes.NewReader([]byte(""))),
},
},
res{
data: []byte(""),
wantErr: nil,
},
},
{
"response, statuscode = 200, error body >= 400 < 500",
args{
resp: &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(bytes.NewReader(testErrorBody(http.StatusForbidden, "forbidden"))),
},
},
res{
wantErr: func(err error) bool {
return errors.Is(err, zerrors.ThrowPermissionDenied(nil, "EXEC-reUaUZCzCp", "forbidden"))
},
},
},
{
"response, statuscode = 200, error body >= 500",
args{
resp: &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(bytes.NewReader(testErrorBody(http.StatusInternalServerError, "internal"))),
},
},
res{
wantErr: func(err error) bool {
return errors.Is(err, zerrors.ThrowPreconditionFailed(nil, "EXEC-bmhNhpcqpF", "internal"))
},
},
},
{
"response, statuscode = 308, no body, should not happen",
args{
resp: &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(bytes.NewReader(testErrorBody(http.StatusPermanentRedirect, "redirect"))),
},
},
res{
wantErr: func(err error) bool {
return errors.Is(err, zerrors.ThrowPreconditionFailed(nil, "EXEC-bmhNhpcqpF", "redirect"))
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
respBody, err := execution.HandleResponse(
tt.args.resp,
)
if tt.res.wantErr == nil {
if !assert.NoError(t, err) {
t.FailNow()
}
} else if !tt.res.wantErr(err) {
t.Errorf("got wrong err: %v", err)
return
}
assert.Equal(t, tt.res.data, respBody)
})
}
}

View File

@ -13,7 +13,7 @@ import (
)
const (
WebKeyTable = "projections.web_keys"
WebKeyTable = "projections.web_keys1"
WebKeyInstanceIDCol = "instance_id"
WebKeyKeyIDCol = "key_id"
@ -58,9 +58,6 @@ func (*webKeyProjection) Init() *old_handler.Check {
handler.WithIndex(handler.NewIndex(
"web_key_state",
[]string{WebKeyInstanceIDCol, WebKeyStateCol},
handler.WithInclude(
WebKeyPrivateKeyCol,
),
)),
),
)

View File

@ -1,5 +1,5 @@
select private_key
from projections.web_keys
from projections.web_keys1
where instance_id = $1
and state = $2
limit 1;

View File

@ -1,4 +1,4 @@
select key_id, creation_date, change_date, sequence, state, config, config_type
from projections.web_keys
from projections.web_keys1
where instance_id = $1
order by creation_date asc;

View File

@ -1,3 +1,3 @@
select public_key
from projections.web_keys
from projections.web_keys1
where instance_id = $1;

View File

@ -582,6 +582,7 @@ Errors:
NotFound: Изпълнението не е намерено
IncludeNotFound: Включването не е намерено
NoTargets: Няма определени цели
Failed: неуспешно изпълнение
ResponseIsNotValidJSON: Отговорът не е валиден JSON
UserSchema:
NotEnabled: Функцията „Потребителска схема“ не е активирана

View File

@ -563,6 +563,7 @@ Errors:
NotFound: Provedení nenalezeno
IncludeNotFound: Zahrnout nenalezeno
NoTargets: Nejsou definovány žádné cíle
Failed: Provedení se nezdařilo
ResponseIsNotValidJSON: Odpověď není platný JSON
UserSchema:
NotEnabled: Funkce "Uživatelské schéma" není povolena

View File

@ -565,6 +565,7 @@ Errors:
NotFound: Ausführung nicht gefunden
IncludeNotFound: Einschließen nicht gefunden
NoTargets: Keine Ziele definiert
Failed: Ausführung fehlgeschlagen
ResponseIsNotValidJSON: Antwort ist kein gültiges JSON
UserSchema:
NotEnabled: Funktion Benutzerschema ist nicht aktiviert

View File

@ -565,6 +565,7 @@ Errors:
NotFound: Execution not found
IncludeNotFound: Include not found
NoTargets: No targets defined
Failed: Execution failed
ResponseIsNotValidJSON: Response is not valid JSON
UserSchema:
NotEnabled: Feature "User Schema" is not enabled
@ -595,7 +596,6 @@ Errors:
NoActive: No active web key found
NotFound: Web key not found
AggregateTypes:
action: Action
instance: Instance

View File

@ -565,6 +565,7 @@ Errors:
NotFound: Ejecución no encontrada
IncludeNotFound: Incluir no encontrado
NoTargets: No hay objetivos definidos
Failed: Ejecución fallida
ResponseIsNotValidJSON: La respuesta no es un JSON válido
UserSchema:
NotEnabled: La función "Esquema de usuario" no está habilitada

View File

@ -565,6 +565,7 @@ Errors:
NotFound: Exécution introuvable
IncludeNotFound: Inclure introuvable
NoTargets: Aucune cible définie
Failed: Exécution échouée
ResponseIsNotValidJSON: La réponse n'est pas un JSON valide
UserSchema:
NotEnabled: La fonctionnalité "Schéma utilisateur" n'est pas activée

View File

@ -565,6 +565,7 @@ Errors:
NotFound: Esecuzione non trovata
IncludeNotFound: Includi non trovato
NoTargets: Nessun obiettivo definito
Failed: Esecuzione fallita
ResponseIsNotValidJSON: La risposta non è un JSON valido
UserSchema:
NotEnabled: La funzionalità "Schema utente" non è abilitata

View File

@ -554,6 +554,7 @@ Errors:
NotFound: 実行が見つかりませんでした
IncludeNotFound: 見つからないものを含める
NoTargets: ターゲットが定義されていません
Failed: 実行に失敗しました
ResponseIsNotValidJSON: 応答は有効な JSON ではありません
UserSchema:
NotEnabled: 機能「ユーザースキーマ」が有効になっていません

View File

@ -564,6 +564,7 @@ Errors:
NotFound: Извршувањето не е пронајдено
IncludeNotFound: Вклучете не е пронајден
NoTargets: Не се дефинирани цели
Failed: Извршувањето не успеа
ResponseIsNotValidJSON: Одговорот не е валиден JSON
UserSchema:
NotEnabled: Функцијата „Корисничка шема“ не е овозможена

View File

@ -565,6 +565,7 @@ Errors:
NotFound: Uitvoering niet gevonden
IncludeNotFound: Inclusief niet gevonden
NoTargets: Geen doelstellingen gedefinieerd
Failed: Uitvoering mislukt
ResponseIsNotValidJSON: Reactie is geen geldige JSON
UserSchema:
NotEnabled: Functie "Gebruikersschema" is niet ingeschakeld

View File

@ -565,6 +565,7 @@ Errors:
NotFound: Nie znaleziono wykonania
IncludeNotFound: Nie znaleziono uwzględnienia
NoTargets: Nie zdefiniowano celów
Failed: Wykonanie nie powiodło się
ResponseIsNotValidJSON: Odpowiedź nie jest prawidłowym JSON-em
UserSchema:
NotEnabled: Funkcja „Schemat użytkownika” nie jest włączona

View File

@ -560,6 +560,7 @@ Errors:
NotFound: Execução não encontrada
IncludeNotFound: Incluir não encontrado
NoTargets: Nenhuma meta definida
Failed: Falha na execução
ResponseIsNotValidJSON: A resposta não é um JSON válido
UserSchema:
NotEnabled: O recurso "Esquema do usuário" não está habilitado

View File

@ -554,6 +554,7 @@ Errors:
NotFound: Исполнение не найдено
IncludeNotFound: Включить не найдено
NoTargets: Цели не определены
Failed: Выполнение не удалось
ResponseIsNotValidJSON: Ответ не является допустимым JSON
UserSchema:
NotEnabled: Функция «Пользовательская схема» не включена

View File

@ -564,6 +564,7 @@ Errors:
NotFound: Exekveringen hittades inte
IncludeNotFound: Inkluderingen hittades inte
NoTargets: Inga mål definierade
Failed: Utförande misslyckades
ResponseIsNotValidJSON: Svaret är inte giltigt JSON
UserSchema:
NotEnabled: Funktionen "Användarschema" är inte aktiverad

View File

@ -565,6 +565,7 @@ Errors:
NotFound: 未找到执行
IncludeNotFound: 包括未找到的内容
NoTargets: 没有定义目标
Failed: 执行失败
ResponseIsNotValidJSON: 响应不是有效的 JSON
UserSchema:
NotEnabled: 未启用“用户架构”功能

View File

@ -0,0 +1,30 @@
package config
import (
"github.com/zitadel/zitadel/internal/telemetry/profiler/google"
"github.com/zitadel/zitadel/internal/zerrors"
)
type Config struct {
Type string
Config map[string]interface{} `mapstructure:",remain"`
}
var profiler = map[string]func(map[string]interface{}) error{
"google": google.NewProfiler,
"none": NoProfiler,
"": NoProfiler,
}
func (c *Config) NewProfiler() error {
t, ok := profiler[c.Type]
if !ok {
return zerrors.ThrowInternalf(nil, "PROFI-Dfqsx", "config type %s not supported", c.Type)
}
return t(c.Config)
}
func NoProfiler(_ map[string]interface{}) error {
return nil
}

View File

@ -0,0 +1,26 @@
package google
import (
"cloud.google.com/go/profiler"
"github.com/zitadel/zitadel/cmd/build"
)
type Config struct {
ProjectID string
}
func NewProfiler(rawConfig map[string]interface{}) (err error) {
c := new(Config)
c.ProjectID, _ = rawConfig["projectid"].(string)
return c.NewProfiler()
}
func (c *Config) NewProfiler() (err error) {
cfg := profiler.Config{
Service: "zitadel",
ServiceVersion: build.Version(),
ProjectID: c.ProjectID,
}
return profiler.Start(cfg)
}

View File

@ -172,8 +172,8 @@ service ZITADELWebKeys {
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
summary: "Generate a web key pair for the instance";
description: "Delete a web key. Only inactive keys can be deleted. Once a key is deleted, any tokens signed by this key will be invalid."
summary: "Delete a web key pair for the instance";
description: "Delete a web key pair. Only inactive keys can be deleted. Once a key is deleted, any tokens signed by this key will be invalid."
responses: {
key: "200"
value: {
@ -198,7 +198,7 @@ service ZITADELWebKeys {
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
summary: "Generate a web key pair for the instance";
summary: "List web key details for the instance";
description: "List web key details for the instance"
responses: {
key: "200"