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,31 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package clienttest
import (
"github.com/ory/x/randx"
"github.com/ory/keto/ketoapi"
)
func RandomTupleWithSubjectSet(ns1, ns2 string) *ketoapi.RelationTuple {
return &ketoapi.RelationTuple{
Namespace: ns1,
Object: randx.MustString(8, randx.AlphaNum),
Relation: randx.MustString(8, randx.AlphaNum),
SubjectSet: &ketoapi.SubjectSet{
Namespace: ns2,
Object: randx.MustString(8, randx.AlphaNum),
},
}
}
func RandomTupleWithSubjectID(ns1 string) *ketoapi.RelationTuple {
return &ketoapi.RelationTuple{
Namespace: ns1,
Object: randx.MustString(8, randx.AlphaNum),
Relation: randx.MustString(8, randx.AlphaNum),
SubjectID: new(randx.MustString(8, randx.AlphaNum)),
}
}

View File

@@ -0,0 +1,96 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
// Package clienttest provides an in-process Keto server for testing the CLI
// commands. It lives outside of package client because it depends on the whole
// Keto server: anything importing package client would otherwise link the
// server, the test framework, and their dependencies into its binary.
package clienttest
import (
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/ory/x/cmdx"
"github.com/spf13/cobra"
"github.com/stretchr/testify/require"
"github.com/ory/keto/cmd/client"
"github.com/ory/keto/internal/driver"
"github.com/ory/keto/internal/driver/config"
"github.com/ory/keto/internal/namespace"
)
type (
TestServer struct {
Reg driver.Registry
Cmd *cmdx.CommandExecuter
}
ServerType string
)
const (
WriteServer ServerType = "write"
ReadServer ServerType = "read"
OplServer ServerType = "opl"
)
func (st ServerType) FlagName() string {
switch st {
case WriteServer:
return client.FlagWriteRemote
case ReadServer:
return client.FlagReadRemote
case OplServer:
return client.FlagOplRemote
default:
panic(fmt.Sprintf("unknown ServerType %s", st))
}
}
func NewTestServer(t *testing.T, nspaces []*namespace.Namespace, newCmd func() *cobra.Command, registryOpts ...driver.TestRegistryOption) *TestServer {
reg := driver.NewSqliteTestRegistry(t, append(registryOpts, driver.WithSelfSignedTransportCredentials())...)
require.NoError(t, reg.Config(t.Context()).Set(config.KeyNamespaces, nspaces))
ts := &TestServer{
Reg: reg,
Cmd: &cmdx.CommandExecuter{
New: newCmd,
PersistentArgs: []string{"--insecure-skip-hostname-verification=true"},
Ctx: t.Context(),
},
}
ts.serve(t)
return ts
}
func (ts *TestServer) serve(t *testing.T, serverTypes ...ServerType) {
if len(serverTypes) == 0 {
serverTypes = []ServerType{WriteServer, ReadServer}
}
for _, st := range serverTypes {
s := httptest.NewUnstartedServer(ts.NewHandler(t, st))
s.EnableHTTP2 = true
s.StartTLS()
t.Cleanup(s.Close)
ts.Cmd.PersistentArgs = append(ts.Cmd.PersistentArgs, "--"+st.FlagName(), s.Listener.Addr().String())
}
}
func (ts *TestServer) NewHandler(t *testing.T, st ServerType) http.Handler {
switch st {
case ReadServer:
return ts.Reg.ReadRouter(t.Context())
case WriteServer:
return ts.Reg.WriteRouter(t.Context())
case OplServer:
return ts.Reg.OPLSyntaxRouter(t.Context())
default:
panic(fmt.Sprintf("unknown ServerType %s", st))
}
}

159
cmd/client/grpc_client.go Normal file
View File

@@ -0,0 +1,159 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package client
import (
"context"
"crypto/tls"
"fmt"
"os"
"strings"
"time"
"golang.org/x/oauth2"
"github.com/ory/x/flagx"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/credentials/oauth"
)
type contextKeys string
const (
FlagReadRemote = "read-remote"
FlagWriteRemote = "write-remote"
FlagOplRemote = "syntax-remote"
FlagInsecureNoTransportSecurity = "insecure-disable-transport-security"
FlagInsecureSkipHostVerification = "insecure-skip-hostname-verification"
FlagAuthority = "authority"
FlagBlock = "block"
EnvReadRemote = "KETO_READ_REMOTE"
EnvWriteRemote = "KETO_WRITE_REMOTE"
EnvAuthToken = "KETO_BEARER_TOKEN" //nolint:gosec // just the key, not the value
EnvAuthority = "KETO_AUTHORITY"
ContextKeyTimeout contextKeys = "timeout"
ContextKeyDialFunc contextKeys = "dial"
)
type connectionDetails struct {
token, authority string
skipHostVerification bool
noTransportSecurity bool
block bool
}
func (d *connectionDetails) dialOptions() (opts []grpc.DialOption) {
if d.token != "" {
opts = append(opts,
grpc.WithPerRPCCredentials(
oauth.TokenSource{TokenSource: oauth2.StaticTokenSource(&oauth2.Token{AccessToken: d.token})},
))
}
if d.authority != "" {
opts = append(opts, grpc.WithAuthority(d.authority))
}
// TLS settings
switch {
case d.noTransportSecurity:
opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
case d.skipHostVerification:
opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
//nolint:gosec // explicity set through scary flag
InsecureSkipVerify: true,
})))
default:
// Defaults to the default host root CA bundle
opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(nil)))
}
if d.block {
opts = append(opts, grpc.WithBlock()) //nolint:staticcheck // SA1019 grpc.WithBlock is deprecated, but we actually want to block here until the connection is up.
}
return opts
}
func getRemote(cmd *cobra.Command, flagRemote, envRemote string) (remote string) {
defer (func() {
if strings.HasPrefix(remote, "http://") || strings.HasPrefix(remote, "https://") {
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "remote %q seems to be an http URL instead of a remote address\n", remote)
}
})()
if cmd.Flags().Changed(flagRemote) {
return flagx.MustGetString(cmd, flagRemote)
} else if remote, isSet := os.LookupEnv(envRemote); isSet {
return remote
}
// no value is set, use fallback from the flag and warn about that
remote = flagx.MustGetString(cmd, flagRemote)
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "neither flag --%s nor env var %s are set, falling back to %s\n", flagRemote, envRemote, remote)
return remote
}
func getAuthority(cmd *cobra.Command) string {
if cmd.Flags().Changed(FlagAuthority) {
return flagx.MustGetString(cmd, FlagAuthority)
}
return os.Getenv(EnvAuthority)
}
func getConnectionDetails(cmd *cobra.Command) connectionDetails {
return connectionDetails{
token: os.Getenv(EnvAuthToken),
authority: getAuthority(cmd),
skipHostVerification: flagx.MustGetBool(cmd, FlagInsecureSkipHostVerification),
noTransportSecurity: flagx.MustGetBool(cmd, FlagInsecureNoTransportSecurity),
block: flagx.MustGetBool(cmd, "block"),
}
}
func GetReadConn(cmd *cobra.Command) (*grpc.ClientConn, error) {
return Conn(cmd.Context(),
getRemote(cmd, FlagReadRemote, EnvReadRemote),
getConnectionDetails(cmd),
)
}
func GetWriteConn(cmd *cobra.Command) (*grpc.ClientConn, error) {
return Conn(cmd.Context(),
getRemote(cmd, FlagWriteRemote, EnvWriteRemote),
getConnectionDetails(cmd),
)
}
func Conn(ctx context.Context, remote string, details connectionDetails) (*grpc.ClientConn, error) {
if d, ok := ctx.Value(ContextKeyTimeout).(time.Duration); ok {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, d)
defer cancel()
}
if dial, ok := ctx.Value(ContextKeyDialFunc).(func(context.Context, string) (*grpc.ClientConn, error)); ok {
return dial(ctx, remote)
}
return grpc.DialContext( // nolint:staticcheck // SA1019 grpc.DialContext is deprecated, but we actually want to connect here right away.
ctx,
remote,
details.dialOptions()...,
)
}
func RegisterRemoteURLFlags(flags *pflag.FlagSet) {
flags.String(FlagReadRemote, "127.0.0.1:4466", "Remote address of the read API endpoint.")
flags.String(FlagWriteRemote, "127.0.0.1:4467", "Remote address of the write API endpoint.")
flags.String(FlagAuthority, "", "Set the authority header for the remote gRPC server.")
flags.Bool(FlagInsecureNoTransportSecurity, false, "Disables transport security. Do not use this in production.")
flags.Bool(FlagInsecureSkipHostVerification, false, "Disables hostname verification. Do not use this in production.")
flags.Bool(FlagBlock, false, "Block until the connection is up.")
}

View File

@@ -0,0 +1,65 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package client
import (
"bytes"
"os"
"testing"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGetRemote(t *testing.T) {
setup := func() (cmd *cobra.Command, stdOut, stdErr *bytes.Buffer) {
cmd = &cobra.Command{}
stdOut, stdErr = &bytes.Buffer{}, &bytes.Buffer{}
cmd.SetOut(stdOut)
cmd.SetErr(stdErr)
RegisterRemoteURLFlags(cmd.Flags())
return
}
setEnv := func(t *testing.T, env, val string) {
require.NoError(t, os.Setenv(env, val))
t.Cleanup(func() {
require.NoError(t, os.Unsetenv(EnvReadRemote))
})
}
t.Run("case=prefers flag value", func(t *testing.T) {
cmd, stdOut, stdErr := setup()
expectedRemote := "ketotest.oryapis.com"
require.NoError(t, cmd.Flags().Set(FlagReadRemote, "ketotest.oryapis.com"))
setEnv(t, EnvReadRemote, "not"+expectedRemote)
assert.Equal(t, expectedRemote, getRemote(cmd, FlagReadRemote, EnvReadRemote))
assert.Equal(t, 0, stdOut.Len())
assert.Equal(t, 0, stdErr.Len())
})
t.Run("case=uses env value", func(t *testing.T) {
cmd, stdOut, stdErr := setup()
expectedRemote := "ketotest.oryapis.com"
setEnv(t, EnvReadRemote, expectedRemote)
assert.Equal(t, expectedRemote, getRemote(cmd, FlagReadRemote, EnvReadRemote))
assert.Equal(t, 0, stdOut.Len())
assert.Equal(t, 0, stdErr.Len())
})
t.Run("case=falls back to flag default and prints warning", func(t *testing.T) {
cmd, stdOut, stdErr := setup()
expectedRemote := cmd.Flags().Lookup(FlagReadRemote).DefValue
assert.Equal(t, expectedRemote, getRemote(cmd, FlagReadRemote, EnvReadRemote))
assert.Equal(t, 0, stdOut.Len())
assert.Contains(t, stdErr.String(), "falling back")
})
}