snapshot of https://github.com/ory/kratos.git (master, 2026-09-15; blobs > 131072B omitted)
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
This commit is contained in:
116
embedx/embedx.go
Normal file
116
embedx/embedx.go
Normal file
@@ -0,0 +1,116 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package embedx
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"io"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
"github.com/ory/x/configx"
|
||||
"github.com/ory/x/otelx"
|
||||
)
|
||||
|
||||
//go:embed config.schema.json
|
||||
var ConfigSchema []byte
|
||||
|
||||
//go:embed identity_meta.schema.json
|
||||
var IdentityMetaSchema []byte
|
||||
|
||||
//go:embed identity_extension.schema.json
|
||||
var IdentityExtensionSchema []byte
|
||||
|
||||
type SchemaType int
|
||||
|
||||
const (
|
||||
Config SchemaType = iota + 1
|
||||
IdentityMeta
|
||||
IdentityExtension
|
||||
)
|
||||
|
||||
type Schema struct {
|
||||
id string
|
||||
data []byte
|
||||
dependencies []*Schema
|
||||
}
|
||||
|
||||
var (
|
||||
identityExt = &Schema{
|
||||
id: gjson.GetBytes(IdentityExtensionSchema, "$id").Str,
|
||||
data: IdentityExtensionSchema,
|
||||
dependencies: nil,
|
||||
}
|
||||
|
||||
schemas = map[SchemaType]*Schema{
|
||||
Config: {
|
||||
id: gjson.GetBytes(ConfigSchema, "$id").Str,
|
||||
data: ConfigSchema,
|
||||
dependencies: nil,
|
||||
},
|
||||
IdentityMeta: {
|
||||
id: gjson.GetBytes(IdentityMetaSchema, "$id").Str,
|
||||
data: IdentityMetaSchema,
|
||||
dependencies: []*Schema{
|
||||
identityExt,
|
||||
},
|
||||
},
|
||||
IdentityExtension: identityExt,
|
||||
}
|
||||
)
|
||||
|
||||
func getSchema(schema SchemaType) (*Schema, error) {
|
||||
if val, ok := schemas[schema]; ok {
|
||||
return val, nil
|
||||
}
|
||||
return nil, errors.Errorf("the specified schema type (%d) is not supported", int(schema))
|
||||
}
|
||||
|
||||
func (s SchemaType) GetSchemaID() string {
|
||||
return schemas[s].id
|
||||
}
|
||||
|
||||
// AddSchemaResources adds the specified schemas including their dependencies to the compiler.
|
||||
// The interface is specified instead of `jsonschema.Compiler` to allow the use of any jsonschema library fork or version.
|
||||
func AddSchemaResources(c interface {
|
||||
AddResource(url string, r io.Reader) error
|
||||
}, opts ...SchemaType) error {
|
||||
var sc []*Schema
|
||||
|
||||
for _, o := range opts {
|
||||
s, err := getSchema(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sc = append(sc, s)
|
||||
}
|
||||
|
||||
if err := addSchemaResources(c, sc); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := otelx.AddConfigSchema(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return configx.AddSchemaResources(c)
|
||||
}
|
||||
|
||||
func addSchemaResources(c interface {
|
||||
AddResource(url string, r io.Reader) error
|
||||
}, schemas []*Schema) error {
|
||||
for _, s := range schemas {
|
||||
if err := c.AddResource(s.id, bytes.NewReader(s.data)); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
if s.dependencies != nil {
|
||||
if err := addSchemaResources(c, s.dependencies); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
106
embedx/embedx_test.go
Normal file
106
embedx/embedx_test.go
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package embedx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
"io/fs"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/ory/jsonschema/v3"
|
||||
)
|
||||
|
||||
func TestAddSchemaResources(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
description string
|
||||
dependencies []SchemaType
|
||||
extraDependencies []SchemaType
|
||||
mustFail bool
|
||||
failMessage string
|
||||
}{
|
||||
{
|
||||
description: "config schema",
|
||||
dependencies: []SchemaType{Config},
|
||||
extraDependencies: nil,
|
||||
},
|
||||
{
|
||||
description: "identity schema with dependencies",
|
||||
dependencies: []SchemaType{IdentityMeta},
|
||||
extraDependencies: []SchemaType{IdentityExtension},
|
||||
},
|
||||
{
|
||||
description: "multiple schemas",
|
||||
dependencies: []SchemaType{Config, IdentityMeta, IdentityExtension},
|
||||
extraDependencies: nil,
|
||||
},
|
||||
{
|
||||
description: "verify dependencies are also loaded",
|
||||
dependencies: []SchemaType{IdentityMeta},
|
||||
extraDependencies: []SchemaType{IdentityExtension},
|
||||
},
|
||||
{
|
||||
description: "must fail on unsupported schema types",
|
||||
dependencies: []SchemaType{4, 10},
|
||||
mustFail: true,
|
||||
failMessage: "the specified schema type (4) is not supported",
|
||||
},
|
||||
} {
|
||||
t.Run("case="+tc.description, func(t *testing.T) {
|
||||
c := jsonschema.NewCompiler()
|
||||
err := AddSchemaResources(c, tc.dependencies...)
|
||||
|
||||
if tc.mustFail {
|
||||
assert.Errorf(t, err, "an error must be thrown on `%s`", tc.description)
|
||||
assert.EqualError(t, err, tc.failMessage)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
if !tc.mustFail {
|
||||
for _, s := range append(tc.dependencies, tc.extraDependencies...) {
|
||||
_, err := c.Compile(context.Background(), s.GetSchemaID())
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//go:embed testdata/identity_meta.*
|
||||
var identityMetaTestCases embed.FS
|
||||
|
||||
func TestIdentityMetaSchema(t *testing.T) {
|
||||
c := jsonschema.NewCompiler()
|
||||
err := AddSchemaResources(c, IdentityMeta, IdentityExtension)
|
||||
require.NoError(t, err)
|
||||
|
||||
schema, err := c.Compile(context.Background(), IdentityMeta.GetSchemaID())
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, fs.WalkDir(identityMetaTestCases, ".", func(path string, d fs.DirEntry, err error) error {
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
t.Run("case="+path, func(t *testing.T) {
|
||||
f, err := identityMetaTestCases.Open(path)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = schema.Validate(f)
|
||||
if strings.HasSuffix(path, "invalid.schema.json") {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
|
||||
return nil
|
||||
}))
|
||||
}
|
||||
108
embedx/identity_extension.schema.json
Normal file
108
embedx/identity_extension.schema.json
Normal file
@@ -0,0 +1,108 @@
|
||||
{
|
||||
"$id": "ory://identity-extension",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"allOf": [
|
||||
{
|
||||
"properties": {
|
||||
"ory.sh/kratos": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"credentials": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"password": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"identifier": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"webauthn": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"identifier": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"passkey": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"display_name": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"totp": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"account_name": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"code": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"identifier": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"via": {
|
||||
"type": "string",
|
||||
"enum": ["email", "sms"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"verification": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"via": {
|
||||
"type": "string",
|
||||
"enum": ["email", "sms"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"recovery": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"via": {
|
||||
"type": "string",
|
||||
"enum": ["email", "sms"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizations": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"matcher": {
|
||||
"type": "string",
|
||||
"enum": ["email_domain"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"patternProperties": {
|
||||
".*": {
|
||||
"$ref": "#"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
70
embedx/identity_meta.schema.json
Normal file
70
embedx/identity_meta.schema.json
Normal file
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"$id": "ory://identity-meta",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "http://json-schema.org/draft-07/schema#"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"properties": {
|
||||
"type": "object",
|
||||
"required": ["traits"],
|
||||
"properties": {
|
||||
"traits": {
|
||||
"type": "object",
|
||||
"required": ["properties"],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "object"
|
||||
},
|
||||
"properties": {
|
||||
"type": "object",
|
||||
"minProperties": 1,
|
||||
"patternProperties": {
|
||||
".*": {
|
||||
"type": "object",
|
||||
"if": {
|
||||
"properties": {
|
||||
"ory.sh/kratos": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"verification": {}
|
||||
},
|
||||
"required": ["verification"]
|
||||
}
|
||||
},
|
||||
"required": ["ory.sh/kratos"]
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"format": {
|
||||
"enum": [
|
||||
"email",
|
||||
"tel",
|
||||
"date",
|
||||
"time",
|
||||
"date-time",
|
||||
"no-validate"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "ory://identity-extension"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["properties"]
|
||||
}
|
||||
]
|
||||
}
|
||||
1
embedx/testdata/identity_meta.no_traits.invalid.schema.json
vendored
Normal file
1
embedx/testdata/identity_meta.no_traits.invalid.schema.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
23
embedx/testdata/identity_meta.simple.valid.schema.json
vendored
Normal file
23
embedx/testdata/identity_meta.simple.valid.schema.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"properties": {
|
||||
"traits": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"ory.sh/kratos": {
|
||||
"credentials": {
|
||||
"password": {
|
||||
"identifier": true
|
||||
}
|
||||
},
|
||||
"verification": {
|
||||
"via": "email"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
embedx/testdata/identity_meta.verification_format.invalid.schema.json
vendored
Normal file
23
embedx/testdata/identity_meta.verification_format.invalid.schema.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"properties": {
|
||||
"traits": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "unknown",
|
||||
"ory.sh/kratos": {
|
||||
"credentials": {
|
||||
"password": {
|
||||
"identifier": true
|
||||
}
|
||||
},
|
||||
"verification": {
|
||||
"via": "email"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user