From 7c00105ce408a16f3871971cee42f7a785921e53 Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Wed, 8 Jan 2025 17:40:07 -0500 Subject: [PATCH] Add --explain support for check bulk permission --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- internal/commands/permission.go | 15 ++++++++++++++- internal/printers/debug.go | 27 +++++++++++++++++++++++++-- 4 files changed, 51 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 4186507..97fb4e0 100644 --- a/go.mod +++ b/go.mod @@ -7,9 +7,9 @@ toolchain go1.23.2 require ( github.com/99designs/keyring v1.2.2 github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 - github.com/authzed/authzed-go v1.2.0 + github.com/authzed/authzed-go v1.2.2-0.20250107172318-7fd4159ab2b7 github.com/authzed/grpcutil v0.0.0-20240123194739-2ea1e3d2d98b - github.com/authzed/spicedb v1.39.1-0.20250103205252-d2f772136d13 + github.com/authzed/spicedb v1.39.1-0.20250108165209-c18b1656bdd0 github.com/brianvoe/gofakeit/v6 v6.28.0 github.com/ccoveille/go-safecast v1.5.0 github.com/cenkalti/backoff/v4 v4.3.0 @@ -141,7 +141,7 @@ require ( github.com/googleapis/gax-go/v2 v2.14.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect - github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -243,7 +243,7 @@ require ( golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.8.0 // indirect - google.golang.org/api v0.214.0 // indirect + google.golang.org/api v0.209.0 // indirect google.golang.org/genproto v0.0.0-20241113202542-65e8d215514f // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index fc86cce..488217c 100644 --- a/go.sum +++ b/go.sum @@ -670,16 +670,16 @@ github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9 github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= -github.com/authzed/authzed-go v1.2.0 h1:Ep1sRJMxcArB++kYqHbYKQCb/GgdGZI0cW4gZrJ1K40= -github.com/authzed/authzed-go v1.2.0/go.mod h1:4lkFxvaCISG1roRdnUt35/Sk1StVuMD1QCwTd/BcWcM= +github.com/authzed/authzed-go v1.2.2-0.20250107172318-7fd4159ab2b7 h1:f99Iz0FoEyqPelojk1kWWgSDVJtDEMrLb+6qVdohoqs= +github.com/authzed/authzed-go v1.2.2-0.20250107172318-7fd4159ab2b7/go.mod h1:/+NblSrzA6Lm6vUO3fqZyLh8MDCLUQq2AyJMlHb32DE= github.com/authzed/cel-go v0.20.2 h1:GlmLecGry7Z8HU0k+hmaHHUV05ZHrsFxduXHtIePvck= github.com/authzed/cel-go v0.20.2/go.mod h1:pJHVFWbqUHV1J+klQoZubdKswlbxcsbojda3mye9kiU= github.com/authzed/consistent v0.1.0 h1:tlh1wvKoRbjRhMm2P+X5WQQyR54SRoS4MyjLOg17Mp8= github.com/authzed/consistent v0.1.0/go.mod h1:plwHlrN/EJUCwQ+Bca0MhM1KnisPs7HEkZI5giCXrcc= github.com/authzed/grpcutil v0.0.0-20240123194739-2ea1e3d2d98b h1:wbh8IK+aMLTCey9sZasO7b6BWLAJnHHvb79fvWCXwxw= github.com/authzed/grpcutil v0.0.0-20240123194739-2ea1e3d2d98b/go.mod h1:s3qC7V7XIbiNWERv7Lfljy/Lx25/V1Qlexb0WJuA8uQ= -github.com/authzed/spicedb v1.39.1-0.20250103205252-d2f772136d13 h1:zd1vGmGpTLaHUJwJ1DdJuSIealZ6bgwv1r3wfdC5Ju0= -github.com/authzed/spicedb v1.39.1-0.20250103205252-d2f772136d13/go.mod h1:OaAq+dNZ1T0kb+67iCoZ/AiS7Rfx9gGV6/TZpqUVVcQ= +github.com/authzed/spicedb v1.39.1-0.20250108165209-c18b1656bdd0 h1:ewOiKCJmuLU7/+HyUrJD/oIMgd7NG0NrpHfl4nzeW/s= +github.com/authzed/spicedb v1.39.1-0.20250108165209-c18b1656bdd0/go.mod h1:/UVC4ZJkMUZFN4MVjjOLAU7m/fqitkBP57ZPffyicOs= github.com/aws/aws-sdk-go-v2 v1.32.7 h1:ky5o35oENWi0JYWUZkB7WYvVPP+bcRF5/Iq7JWSb5Rw= github.com/aws/aws-sdk-go-v2 v1.32.7/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= github.com/aws/aws-sdk-go-v2/config v1.28.7 h1:GduUnoTXlhkgnxTD93g1nv4tVPILbdNQOzav+Wpg7AE= @@ -1044,8 +1044,8 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDa github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU= -github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 h1:kQ0NI7W1B3HwiN5gAYtY+XFItDPbLBwYRxAqbFTyDes= -github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0/go.mod h1:zrT2dxOAjNFPRGjTUe2Xmb4q4YdUwVvQFV6xiCSf+z0= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= @@ -1913,8 +1913,8 @@ google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/ google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= -google.golang.org/api v0.214.0 h1:h2Gkq07OYi6kusGOaT/9rnNljuXmqPnaig7WGPmKbwA= -google.golang.org/api v0.214.0/go.mod h1:bYPpLG8AyeMWwDU6NXoB00xC0DFkikVvd5MfwoxjLqE= +google.golang.org/api v0.209.0 h1:Ja2OXNlyRlWCWu8o+GgI4yUn/wz9h/5ZfFbKz+dQX+w= +google.golang.org/api v0.209.0/go.mod h1:I53S168Yr/PNDNMi5yPnDc0/LGRZO6o7PoEbl/HY3CM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= diff --git a/internal/commands/permission.go b/internal/commands/permission.go index a3853b9..7c6a2e2 100644 --- a/internal/commands/permission.go +++ b/internal/commands/permission.go @@ -82,9 +82,11 @@ func RegisterPermissionCmd(rootCmd *cobra.Command) *cobra.Command { registerConsistencyFlags(checkCmd.Flags()) permissionCmd.AddCommand(checkBulkCmd) - registerConsistencyFlags(checkBulkCmd.Flags()) checkBulkCmd.Flags().String("revision", "", "optional revision at which to check") checkBulkCmd.Flags().Bool("json", false, "output as JSON") + checkBulkCmd.Flags().Bool("explain", false, "requests debug information from SpiceDB and prints out a trace of the requests") + checkBulkCmd.Flags().Bool("schema", false, "requests debug information from SpiceDB and prints out the schema used") + registerConsistencyFlags(checkBulkCmd.Flags()) permissionCmd.AddCommand(expandCmd) expandCmd.Flags().Bool("json", false, "output as JSON") @@ -222,6 +224,7 @@ func checkCmdFunc(cmd *cobra.Command, args []string) error { if cobrautil.MustGetBool(cmd, "explain") || cobrautil.MustGetBool(cmd, "schema") { log.Info().Msg("debugging requested on check") ctx = requestmeta.AddRequestHeaders(ctx, requestmeta.RequestDebugInformation) + request.WithTracing = true } var trailerMD metadata.MD @@ -331,6 +334,10 @@ func checkBulkCmdFunc(cmd *cobra.Command, args []string) error { return err } + if cobrautil.MustGetBool(cmd, "explain") || cobrautil.MustGetBool(cmd, "schema") { + bulk.WithTracing = true + } + resp, err := c.CheckBulkPermissions(ctx, bulk) if err != nil { return err @@ -362,6 +369,12 @@ func checkBulkCmdFunc(cmd *cobra.Command, args []string) error { case v1.CheckPermissionResponse_PERMISSIONSHIP_NO_PERMISSION: console.Println("false") } + + err = displayDebugInformationIfRequested(cmd, responseType.Item.DebugTrace, nil, false) + if err != nil { + return err + } + case *v1.CheckBulkPermissionsPair_Error: console.Println(fmt.Sprintf("error: %s", responseType.Error)) } diff --git a/internal/printers/debug.go b/internal/printers/debug.go index e1b79d2..c4b4024 100644 --- a/internal/printers/debug.go +++ b/internal/printers/debug.go @@ -22,6 +22,7 @@ func displayCheckTrace(checkTrace *v1.CheckDebugTrace, tp *TreePrinter, hasError white := color.FgWhite.Render faint := color.FgGray.Render magenta := color.FgMagenta.Render + yellow := color.FgYellow.Render orange := color.C256(166).Sprint purple := color.C256(99).Sprint @@ -50,15 +51,37 @@ func displayCheckTrace(checkTrace *v1.CheckDebugTrace, tp *TreePrinter, hasError resourceColor = faint permissionColor = faint } - } else if checkTrace.Result != v1.CheckDebugTrace_PERMISSIONSHIP_HAS_PERMISSION { + } else if checkTrace.Result == v1.CheckDebugTrace_PERMISSIONSHIP_NO_PERMISSION { hasPermission = red("⨉") resourceColor = faint permissionColor = faint + } else if checkTrace.Result == v1.CheckDebugTrace_PERMISSIONSHIP_UNSPECIFIED { + hasPermission = yellow("∵") } additional := "" if checkTrace.GetWasCachedResult() { - additional = cyan(" (cached)") + sourceKind := "" + source := checkTrace.Source + if source != "" { + parts := strings.Split(source, ":") + if len(parts) > 0 { + sourceKind = parts[0] + } + } + switch sourceKind { + case "": + additional = cyan(" (cached)") + + case "spicedb": + additional = cyan(" (cached by spicedb)") + + case "materialize": + additional = purple(" (cached by materialize)") + + default: + additional = cyan(fmt.Sprintf(" (cached by %s)", sourceKind)) + } } else if hasError && isPartOfCycle(checkTrace, map[string]struct{}{}) { hasPermission = orange("!") resourceColor = white