snapshot of https://github.com/ory/keto.git (master, 2026-09-16; blobs > 131072B omitted)
Some checks failed
CI / Run lints and checks (push) Failing after 47s
CI / Run tests (push) Failing after 1s
CI / Run race tests (push) Failing after 5s
CI / Build CLI docs (push) Has been skipped
CI / Run buf actions (push) Failing after 5s
CodeQL / Analyze (go) (push) Failing after 3s
CodeQL / Analyze (javascript) (push) Failing after 2s
Docker Image Scanners / scanners (push) Failing after 3s
Format / format (push) Failing after 3s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Draft newsletter (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:
upstream-mirror
2026-09-16 01:08:34 +05:00
commit 9456a4e922
2560 changed files with 120911 additions and 0 deletions

View File

@@ -0,0 +1 @@
"foo"

View File

@@ -0,0 +1,3 @@
{
"some": "key"
}

View File

@@ -0,0 +1,3 @@
{
"some_key": 1234
}

View File

@@ -0,0 +1,15 @@
{
"nested": {
"object": {
"source": "base64://aGVsbG8gd29ybGQ="
},
"array": [
{
"nested": {
"source": "base64://aGVsbG8gd29ybGQ="
}
},
"base64://aGVsbG8gd29ybGQ="
]
}
}

View File

@@ -0,0 +1 @@
"https://gist.githubusercontent.com/aeneasr/eb4612d295f613ee44bada6e30e2a856/raw/29edbda41bcb27492a1ac56926e03dee9480708f/hello-world.txt"

View File

@@ -0,0 +1,15 @@
{
"nested": {
"object": {
"ignore_this_key": "https://gist.githubusercontent.com/aeneasr/eb4612d295f613ee44bada6e30e2a856/raw/29edbda41bcb27492a1ac56926e03dee9480708f/hello-world.txt"
},
"array": [
{
"nested": {
"source": "base64://aGVsbG8gd29ybGQ="
}
},
"base64://aGVsbG8gd29ybGQ="
]
}
}

View File

@@ -0,0 +1,4 @@
{
"key": "https://foobar.com",
"bar": "base64://YXNkZg=="
}

76
oryx/jsonx/debug.go Normal file
View File

@@ -0,0 +1,76 @@
// Copyright © 2025 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package jsonx
import (
"encoding/json"
"fmt"
"slices"
)
// Anonymize takes a JSON byte array and anonymizes its content by
// recursively replacing all values with a string indicating their type.
//
// It recurses into nested objects and arrays, but ignores the "schemas" and "id".
func Anonymize(data []byte, except ...string) []byte {
obj := make(map[string]any)
if err := json.Unmarshal(data, &obj); err != nil {
return []byte(fmt.Sprintf(`{"error": "invalid JSON", "message": %q}`, err.Error()))
}
anonymize(obj, except...)
out, err := json.MarshalIndent(obj, "", " ")
if err != nil {
return []byte(fmt.Sprintf(`{"error": "could not marshal JSON shape", "message": %q}`, err.Error()))
}
return out
}
func anonymize(obj map[string]any, except ...string) {
for k, v := range obj {
if slices.Contains(except, k) {
continue
}
switch v := v.(type) {
case []any:
for elIdx, el := range v {
switch el := el.(type) {
case map[string]any:
anonymize(el)
v[elIdx] = el
default:
v[elIdx] = jsonType(el)
}
}
case map[string]any:
anonymize(v)
obj[k] = v
default:
obj[k] = jsonType(v)
}
}
}
func jsonType(v any) string {
switch v := v.(type) {
case string:
return "string"
case float64:
return "number"
case bool:
return "boolean"
case nil:
return "null"
case []any:
return "array"
case map[string]any:
return "object"
default:
return fmt.Sprintf("%T", v)
}
}

16
oryx/jsonx/decoder.go Normal file
View File

@@ -0,0 +1,16 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package jsonx
import (
"encoding/json"
"io"
)
// NewStrictDecoder is a shorthand for json.Decoder.DisallowUnknownFields
func NewStrictDecoder(b io.Reader) *json.Decoder {
d := json.NewDecoder(b)
d.DisallowUnknownFields()
return d
}

113
oryx/jsonx/embed.go Normal file
View File

@@ -0,0 +1,113 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package jsonx
import (
"encoding/base64"
"encoding/json"
"net/url"
"slices"
"strconv"
"strings"
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"
"github.com/ory/x/osx"
)
type options struct {
ignoreKeys []string
onlySchemes []string
}
type OptionsModifier func(*options)
func newOptions(o []OptionsModifier) *options {
opt := &options{}
for _, f := range o {
f(opt)
}
return opt
}
func WithIgnoreKeys(keys ...string) OptionsModifier {
return func(o *options) {
o.ignoreKeys = keys
}
}
func WithOnlySchemes(scheme ...string) OptionsModifier {
return func(o *options) {
o.onlySchemes = scheme
}
}
func EmbedSources(in json.RawMessage, opts ...OptionsModifier) (out json.RawMessage, err error) {
out = make([]byte, len(in))
copy(out, in)
if err := embed(gjson.ParseBytes(in), nil, &out, newOptions(opts)); err != nil {
return nil, err
}
return out, nil
}
func embed(parsed gjson.Result, parents []string, result *json.RawMessage, o *options) (err error) {
if parsed.IsObject() {
parsed.ForEach(func(k, v gjson.Result) bool {
err = embed(v, append(parents, strings.ReplaceAll(k.String(), ".", "\\.")), result, o)
return err == nil
})
if err != nil {
return err
}
} else if parsed.IsArray() {
for kk, vv := range parsed.Array() {
if err = embed(vv, append(parents, strconv.Itoa(kk)), result, o); err != nil {
return err
}
}
} else if parsed.Type != gjson.String {
return nil
}
if len(parents) > 0 && slices.Contains(o.ignoreKeys, parents[len(parents)-1]) {
return nil
}
loc, err := url.ParseRequestURI(parsed.String())
if err != nil {
// Not a URL, return
return nil
}
if len(o.onlySchemes) == 0 {
if loc.Scheme != "file" && loc.Scheme != "http" && loc.Scheme != "https" && loc.Scheme != "base64" {
// Not a known pattern, ignore
return nil
}
} else if !slices.Contains(o.onlySchemes, loc.Scheme) {
// Not a known pattern, ignore
return nil
}
contents, err := osx.ReadFileFromAllSources(loc.String())
if err != nil {
return err
}
encoded := base64.StdEncoding.EncodeToString(contents)
key := strings.Join(parents, ".")
if key == "" {
key = "@"
}
interim, err := sjson.SetBytes(*result, key, "base64://"+encoded)
if err != nil {
return err
}
*result = interim
return
}

View File

@@ -0,0 +1 @@
"foo"

View File

@@ -0,0 +1,3 @@
{
"some": "key"
}

View File

@@ -0,0 +1,3 @@
{
"some_key": 1234
}

View File

@@ -0,0 +1,15 @@
{
"nested": {
"object": {
"source": "https://gist.githubusercontent.com/aeneasr/eb4612d295f613ee44bada6e30e2a856/raw/29edbda41bcb27492a1ac56926e03dee9480708f/hello-world.txt"
},
"array": [
{
"nested": {
"source": "https://gist.githubusercontent.com/aeneasr/eb4612d295f613ee44bada6e30e2a856/raw/29edbda41bcb27492a1ac56926e03dee9480708f/hello-world.txt"
}
},
"https://gist.githubusercontent.com/aeneasr/eb4612d295f613ee44bada6e30e2a856/raw/29edbda41bcb27492a1ac56926e03dee9480708f/hello-world.txt"
]
}
}

View File

@@ -0,0 +1 @@
"https://gist.githubusercontent.com/aeneasr/eb4612d295f613ee44bada6e30e2a856/raw/29edbda41bcb27492a1ac56926e03dee9480708f/hello-world.txt"

View File

@@ -0,0 +1,15 @@
{
"nested": {
"object": {
"ignore_this_key": "https://gist.githubusercontent.com/aeneasr/eb4612d295f613ee44bada6e30e2a856/raw/29edbda41bcb27492a1ac56926e03dee9480708f/hello-world.txt"
},
"array": [
{
"nested": {
"source": "https://gist.githubusercontent.com/aeneasr/eb4612d295f613ee44bada6e30e2a856/raw/29edbda41bcb27492a1ac56926e03dee9480708f/hello-world.txt"
}
},
"https://gist.githubusercontent.com/aeneasr/eb4612d295f613ee44bada6e30e2a856/raw/29edbda41bcb27492a1ac56926e03dee9480708f/hello-world.txt"
]
}
}

39
oryx/jsonx/flatten.go Normal file
View File

@@ -0,0 +1,39 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package jsonx
import (
"encoding/json"
"strconv"
"strings"
"github.com/tidwall/gjson"
)
// Flatten flattens a JSON object using dot notation.
func Flatten(raw json.RawMessage) map[string]interface{} {
parsed := gjson.ParseBytes(raw)
if !parsed.IsObject() {
return nil
}
flattened := make(map[string]interface{})
flatten(parsed, nil, flattened)
return flattened
}
func flatten(parsed gjson.Result, parents []string, flattened map[string]interface{}) {
if parsed.IsObject() {
parsed.ForEach(func(k, v gjson.Result) bool {
flatten(v, append(parents, strings.ReplaceAll(k.String(), ".", "\\.")), flattened)
return true
})
} else if parsed.IsArray() {
for kk, vv := range parsed.Array() {
flatten(vv, append(parents, strconv.Itoa(kk)), flattened)
}
} else {
flattened[strings.Join(parents, ".")] = parsed.Value()
}
}

77
oryx/jsonx/get.go Normal file
View File

@@ -0,0 +1,77 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package jsonx
import (
"reflect"
"strings"
"github.com/stretchr/testify/require"
"github.com/tidwall/gjson"
)
func jsonKey(f reflect.StructField) *string {
if jsonTag := f.Tag.Get("json"); jsonTag != "" {
if jsonTag == "-" {
return nil
}
return &strings.Split(jsonTag, ",")[0]
} else if f.Anonymous {
return nil
} else if f.IsExported() {
return &f.Name
}
return nil
}
// AllValidJSONKeys returns all JSON keys from the struct or *struct type.
// It does not return keys from nested slices, but embedded/nested structs.
func AllValidJSONKeys(s interface{}) (keys []string) {
t := reflect.TypeOf(s)
v := reflect.ValueOf(s)
if t.Kind() == reflect.Pointer {
t = t.Elem()
v = v.Elem()
}
for i := range t.NumField() {
f := t.Field(i)
jKey := jsonKey(f)
if k := f.Type.Kind(); k == reflect.Struct || k == reflect.Pointer {
subKeys := AllValidJSONKeys(v.Field(i).Interface())
for _, subKey := range subKeys {
if jKey != nil {
keys = append(keys, *jKey+"."+subKey)
} else {
keys = append(keys, subKey)
}
}
} else if jKey != nil {
keys = append(keys, *jKey)
}
}
return keys
}
// ParseEnsureKeys returns a result that has the GetRequireValidKey function.
func ParseEnsureKeys(original interface{}, raw []byte) *Result {
return &Result{
keys: AllValidJSONKeys(original),
result: gjson.ParseBytes(raw),
}
}
type Result struct {
result gjson.Result
keys []string
}
// GetRequireValidKey ensures that the key is valid before returning the result.
func (r *Result) GetRequireValidKey(t require.TestingT, key string) gjson.Result {
require.Contains(t, r.keys, key)
return r.result.Get(key)
}
func GetRequireValidKey(t require.TestingT, original interface{}, raw []byte, key string) gjson.Result {
return ParseEnsureKeys(original, raw).GetRequireValidKey(t, key)
}

17
oryx/jsonx/helpers.go Normal file
View File

@@ -0,0 +1,17 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package jsonx
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/require"
)
func TestMarshalJSONString(t *testing.T, i interface{}) string {
out, err := json.Marshal(i)
require.NoError(t, err)
return string(out)
}

97
oryx/jsonx/patch.go Normal file
View File

@@ -0,0 +1,97 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package jsonx
import (
"encoding/json"
"fmt"
"strconv"
"strings"
jsonpatch "github.com/evanphx/json-patch/v5"
"github.com/gobwas/glob"
"github.com/pkg/errors"
)
var opAllowList = map[string]struct{}{
"add": {},
"remove": {},
"replace": {},
}
func isUnsupported(op jsonpatch.Operation) bool {
_, ok := opAllowList[op.Kind()]
return !ok
}
func isElementAccess(path string) bool {
if path == "" {
return false
}
elements := strings.Split(path, "/")
lastElement := elements[len(elements)-1:][0]
if lastElement == "-" {
return true
}
if _, err := strconv.Atoi(lastElement); err == nil {
return true
}
return false
}
// ApplyJSONPatch applies a JSON patch to an object and returns the modified
// object. The original object is not modified. It returns an error if the patch
// is invalid or if the patch includes paths that are denied. denyPaths is a
// list of path globs (interpreted with [glob.Compile] that are not allowed to
// be patched.
func ApplyJSONPatch[T any](p json.RawMessage, object T, denyPaths ...string) (result T, err error) {
patch, err := jsonpatch.DecodePatch(p)
if err != nil {
return result, errors.WithStack(err)
}
denyPattern := fmt.Sprintf("{%s}", strings.ToLower(strings.Join(denyPaths, ",")))
matcher, err := glob.Compile(denyPattern, '/')
if err != nil {
return result, errors.WithStack(err)
}
for _, op := range patch {
// Some operations are buggy, see https://github.com/evanphx/json-patch/pull/158
if isUnsupported(op) {
return result, errors.Errorf("unsupported operation: %s", op.Kind())
}
path, err := op.Path()
if err != nil {
return result, errors.Errorf("error parsing patch operations: %v", err)
}
if matcher.Match(strings.ToLower(path)) {
return result, errors.Errorf("patch includes denied path: %s", path)
}
// JSON patch officially rejects replacing paths that don't exist, but we want to be more tolerant.
// Therefore, we will ensure that all paths that we want to replace exist in the original document.
if op.Kind() == "replace" && !isElementAccess(path) {
op["op"] = new(json.RawMessage(`"add"`))
}
}
original, err := json.Marshal(object)
if err != nil {
return result, errors.WithStack(err)
}
options := jsonpatch.NewApplyOptions()
options.EnsurePathExistsOnAdd = true
modified, err := patch.ApplyWithOptions(original, options)
if err != nil {
return result, errors.WithStack(err)
}
err = json.Unmarshal(modified, &result)
return result, errors.WithStack(err)
}

View File

@@ -0,0 +1,64 @@
{
"floating": [
-1273085434,
953442581,
{
"ready": "silent",
"worker": "situation",
"joy": "difference",
"probably": -413625494,
"gray": {
"parent": "pull",
"shore": -738396277,
"usually": 1050049449,
"hold": [
[
181518765,
[
{
"steam": {
"box": false,
"cry": 1463961818,
"appropriate": 1249911539,
"through": 695239749,
"ago": true,
"entirely": -851427469
},
"leather": "across",
"flies": -1571371799,
"over": 512666854,
"thank": true,
"shaking": true
},
"hit",
-648178744.4899056,
1225027271,
-1481507228,
true
],
-2114582277,
1390060204.9360588,
1615602630.9049141,
"darkness"
],
63427197.713988304,
-580344963.961421,
"stems",
1016960217.612642,
1240918909
],
"buy": true,
"wonder": false
},
"little": "cloud"
},
"grade",
false,
"thou"
],
"wagon": -1722583702,
"shop": 1294397217,
"spend": "greatest",
"product": "whale",
"fall": "to"
}