Skip to content

Commit 2229195

Browse files
fix: relax filepath validation on schemaFile key (#652)
Co-authored-by: Maria Ines Parnisari <maria.ines.parnisari@authzed.com>
1 parent 8ffa57f commit 2229195

13 files changed

Lines changed: 327 additions & 236 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ require (
1515
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2
1616
github.com/authzed/authzed-go v1.8.0
1717
github.com/authzed/grpcutil v0.0.0-20240123194739-2ea1e3d2d98b
18-
github.com/authzed/spicedb v1.50.1-0.20260323205516-b041b8f844df
18+
github.com/authzed/spicedb v1.51.0
1919
github.com/brianvoe/gofakeit/v6 v6.28.0
2020
github.com/ccoveille/go-safecast/v2 v2.0.0
2121
github.com/cenkalti/backoff/v4 v4.3.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -744,8 +744,8 @@ github.com/authzed/grpcutil v0.0.0-20240123194739-2ea1e3d2d98b h1:wbh8IK+aMLTCey
744744
github.com/authzed/grpcutil v0.0.0-20240123194739-2ea1e3d2d98b/go.mod h1:s3qC7V7XIbiNWERv7Lfljy/Lx25/V1Qlexb0WJuA8uQ=
745745
github.com/authzed/jitterbug v0.0.0-20260128162915-e97d76daaa24 h1:BXaWSanmHFu3P0xWfTDPpwcJIQ/oSol29+CWe4lSGSU=
746746
github.com/authzed/jitterbug v0.0.0-20260128162915-e97d76daaa24/go.mod h1:WvEk4YHnUsmbUaWA/VseQty3X91f6/jEHek5mjYDZUg=
747-
github.com/authzed/spicedb v1.50.1-0.20260323205516-b041b8f844df h1:a/75Y/B8eTFBl4GSYBfJvwt5itjycEQqBI/7VLccZuI=
748-
github.com/authzed/spicedb v1.50.1-0.20260323205516-b041b8f844df/go.mod h1:v1Nn+0sDO42tP6D3fpt1Spz9Ai0+957cyv+G42Nt9f0=
747+
github.com/authzed/spicedb v1.51.0 h1:Nx202o/6vEXibw+GlPOHX5DwFHu8gYB9vYM5+UXHzvo=
748+
github.com/authzed/spicedb v1.51.0/go.mod h1:v1Nn+0sDO42tP6D3fpt1Spz9Ai0+957cyv+G42Nt9f0=
749749
github.com/aws/aws-sdk-go-v2 v1.40.1 h1:difXb4maDZkRH0x//Qkwcfpdg1XQVXEAEs2DdXldFFc=
750750
github.com/aws/aws-sdk-go-v2 v1.40.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
751751
github.com/aws/aws-sdk-go-v2/config v1.32.3 h1:cpz7H2uMNTDa0h/5CYL5dLUEzPSLo2g0NkbxTRJtSSU=

internal/cmd/import.go

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"bufio"
55
"context"
66
"fmt"
7-
"net/url"
87
"strings"
98

109
"github.com/jzelinskie/cobrautil/v2"
@@ -58,16 +57,12 @@ func registerImportCmd(rootCmd *cobra.Command) {
5857
if err != nil {
5958
return err
6059
}
61-
u, err := url.Parse(args[0])
62-
if err != nil {
63-
return err
64-
}
6560
prefix, err := determinePrefixForSchema(cmd.Context(), cobrautil.MustGetString(cmd, "schema-definition-prefix"), client, nil)
6661
if err != nil {
6762
return err
6863
}
6964
log.Trace().Msgf("using prefix: %s", prefix)
70-
return importCmdFunc(cmd, client, client, prefix, u)
65+
return importCmdFunc(cmd, client, client, prefix, args[0])
7166
},
7267
}
7368

@@ -79,13 +74,9 @@ func registerImportCmd(rootCmd *cobra.Command) {
7974
importCmd.Flags().String("schema-definition-prefix", "", "prefix to add to the schema's definition(s) before importing")
8075
}
8176

82-
func importCmdFunc(cmd *cobra.Command, schemaClient v1.SchemaServiceClient, relationshipsClient v1.PermissionsServiceClient, prefix string, u *url.URL) error {
77+
func importCmdFunc(cmd *cobra.Command, schemaClient v1.SchemaServiceClient, relationshipsClient v1.PermissionsServiceClient, prefix, filename string) error {
8378
prefix = strings.TrimRight(prefix, "/")
84-
d, err := decode.DecoderFromURL(u)
85-
if err != nil {
86-
return err
87-
}
88-
p, err := d.UnmarshalYAMLValidationFile()
79+
p, _, err := decode.ValidationFileFromFilename(filename, decode.FileTypeYaml)
8980
if err != nil {
9081
return err
9182
}

internal/cmd/import_test.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package cmd
22

33
import (
4-
"net/url"
54
"path/filepath"
65
"testing"
76

@@ -74,11 +73,8 @@ func TestImportCmd(t *testing.T) {
7473
c, err := zedtesting.ClientFromConn(conn)(cmd)
7574
require.NoError(err)
7675

77-
u, err := url.Parse(f)
78-
require.NoError(err)
79-
8076
// Run the import and assert we don't have errors
81-
err = importCmdFunc(cmd, c, c, test.prefix, u)
77+
err = importCmdFunc(cmd, c, c, test.prefix, f)
8278
require.NoError(err)
8379

8480
// Run a check with full consistency to assert that the relationships
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
definition domain {
2+
relation read: user
3+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
use import
2+
3+
import "./domain.zed"
4+
5+
definition user {}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
# This test is mostly asserting that path walking and
3+
# schema validation work correctly, so we don't have any
4+
# relations or assertions.
5+
schemaFile: "../schema/root.zed"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
schemaFile: "../nonexistant-import.zed"
3+
relationships: >-
4+
resource:1#user@user:1
5+
assertions:
6+
assertTrue:
7+
- "resource:1#user@user:1"

internal/cmd/validate-test/external-schema-escape.yaml renamed to internal/cmd/validate-test/upwards-walk/validation.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
schemaFile: "../some-schema.zed"
2+
schemaFile: "../external-schema.zed"
33
relationships: >-
44
resource:1#user@user:1
55
assertions:

internal/cmd/validate.go

Lines changed: 22 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
package cmd
22

33
import (
4-
"errors"
54
"fmt"
65
"io/fs"
7-
"net/url"
86
"os"
97
"path/filepath"
108
"strconv"
@@ -19,7 +17,6 @@ import (
1917
"github.com/authzed/spicedb/pkg/development"
2018
core "github.com/authzed/spicedb/pkg/proto/core/v1"
2119
devinterface "github.com/authzed/spicedb/pkg/proto/developer/v1"
22-
"github.com/authzed/spicedb/pkg/validationfile"
2320

2421
"github.com/authzed/zed/internal/commands"
2522
"github.com/authzed/zed/internal/console"
@@ -145,44 +142,11 @@ func validateCmdFunc(cmd *cobra.Command, filenames []string) (string, bool, erro
145142
toPrint.WriteString(filename + "\n")
146143
}
147144

148-
u, err := url.Parse(filename)
145+
parsed, contents, err := decode.ValidationFileFromFilename(filename, fileType)
149146
if err != nil {
150147
return "", true, err
151148
}
152149

153-
d, err := decode.DecoderFromURL(u)
154-
if err != nil {
155-
return "", true, err
156-
}
157-
validateContents := d.Contents
158-
159-
// Root the filesystem at the directory containing the schema file, so
160-
// that relative imports resolve correctly.
161-
fileDir := filepath.Dir(filename)
162-
if fileDir == "" {
163-
fileDir = "."
164-
}
165-
filesystem := os.DirFS(fileDir)
166-
167-
var parsed *validationfile.ValidationFile
168-
switch fileType {
169-
case decode.FileTypeYaml:
170-
parsed, err = d.UnmarshalYAMLValidationFile()
171-
case decode.FileTypeZed:
172-
parsed = d.UnmarshalSchemaValidationFile()
173-
default:
174-
parsed, err = d.UnmarshalAsYAMLOrSchema()
175-
}
176-
// This block handles the error regardless of which case statement is hit
177-
if err != nil {
178-
return "", true, err
179-
}
180-
181-
// Ensure that either schema or schemaFile is present
182-
if parsed.Schema.Schema == "" && parsed.SchemaFile == "" {
183-
return "", false, errors.New("either schema or schemaFile must be present")
184-
}
185-
186150
// This logic will use the zero value of the struct, so we don't need
187151
// to do it conditionally.
188152
tuples := make([]*core.RelationTuple, 0)
@@ -193,6 +157,20 @@ func validateCmdFunc(cmd *cobra.Command, filenames []string) (string, bool, erro
193157
tuples = append(tuples, rel.ToCoreTuple())
194158
}
195159

160+
// Root the filesystem at the directory containing the schema file, so
161+
// that relative schema imports resolve correctly.
162+
fileDir := filepath.Dir(filename)
163+
if fileDir == "" {
164+
fileDir = "."
165+
}
166+
if parsed.SchemaFile != "" {
167+
// If the schemaFile is nonempty, we want to make sure that the import
168+
// filesystem is rooted in the dir of that schemafile.
169+
// TODO: it seems like there ought to be a better way to handle this.
170+
fileDir = filepath.Join(fileDir, filepath.Dir(parsed.SchemaFile))
171+
}
172+
filesystem := os.DirFS(fileDir)
173+
196174
// Create the development context for each run
197175
ctx := cmd.Context()
198176
devCtx, devErrs, err := development.NewDevContext(ctx, &devinterface.RequestContext{
@@ -204,9 +182,12 @@ func validateCmdFunc(cmd *cobra.Command, filenames []string) (string, bool, erro
204182
}
205183
if devErrs != nil {
206184
schemaOffset := parsed.Schema.SourcePosition.LineNumber
185+
if parsed.SchemaFile != "" {
186+
contents = []byte(parsed.Schema.Schema)
187+
}
207188

208189
// Output errors
209-
outputDeveloperErrorsWithLineOffset(toPrint, validateContents, devErrs.InputErrors, schemaOffset, filesystem)
190+
outputDeveloperErrorsWithLineOffset(toPrint, contents, devErrs.InputErrors, schemaOffset, filesystem)
210191
return toPrint.String(), true, nil
211192
}
212193
// Run assertions
@@ -215,7 +196,7 @@ func validateCmdFunc(cmd *cobra.Command, filenames []string) (string, bool, erro
215196
return "", false, aerr
216197
}
217198
if adevErrs != nil {
218-
outputDeveloperErrors(toPrint, validateContents, adevErrs, filesystem)
199+
outputDeveloperErrors(toPrint, contents, adevErrs, filesystem)
219200
return toPrint.String(), true, nil
220201
}
221202
successfullyValidatedFiles++
@@ -226,7 +207,7 @@ func validateCmdFunc(cmd *cobra.Command, filenames []string) (string, bool, erro
226207
return "", false, rerr
227208
}
228209
if erDevErrs != nil {
229-
outputDeveloperErrors(toPrint, validateContents, erDevErrs, filesystem)
210+
outputDeveloperErrors(toPrint, contents, erDevErrs, filesystem)
230211
return toPrint.String(), true, nil
231212
}
232213
// Print out any warnings for file
@@ -238,7 +219,7 @@ func validateCmdFunc(cmd *cobra.Command, filenames []string) (string, bool, erro
238219
if len(warnings) > 0 {
239220
for _, warning := range warnings {
240221
fmt.Fprintf(toPrint, "%s%s\n", warningPrefix(), warning.Message)
241-
outputForLine(toPrint, validateContents, uint64(warning.Line), warning.SourceCode, uint64(warning.Column)) // warning.LineNumber is 1-indexed
222+
outputForLine(toPrint, contents, uint64(warning.Line), warning.SourceCode, uint64(warning.Column)) // warning.LineNumber is 1-indexed
242223
toPrint.WriteString("\n")
243224
}
244225

0 commit comments

Comments
 (0)