Skip to content

Commit 6056916

Browse files
committed
cue/interpreter/embed: respect module boundaries
The embed proposal specifies that it should not be possible to embed files across module boundaries. This CL implements that restriction. Also fix in passing an unnecessarily broad "is parent directory" check: it's OK for a file to start with two dots. Fixes #3273. Signed-off-by: Roger Peppe <[email protected]> Change-Id: I4e80edcc49f5d6475ccdd3f46d206e46be55723b Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1197383 Reviewed-by: Daniel Martí <[email protected]> TryBot-Result: CUEcueckoo <[email protected]>
1 parent ddfe8eb commit 6056916

File tree

3 files changed

+45
-27
lines changed

3 files changed

+45
-27
lines changed

cmd/cue/cmd/testdata/script/embed.txtar

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,17 @@ special: {
3535
// These are all valid.
3636
underscoreFile: _ @embed(file="y/_test.json")
3737
dotFile: _ @embed(file="y/.test.json")
38+
dotdotFile: _ @embed(file="..dotdot.json")
3839
underscoreDir: _ @embed(file="_y/test.json")
3940
dotDir: _ @embed(file=".y/test.json")
40-
41-
// TODO: fix nested modules are currently not supported, but we may opt to
42-
// support them in the future. This is currently not handled. It should
43-
// probably be up to the loader to provide a fs.FS that handles this
44-
// according to spec.
45-
nestedModJSON: _ @embed(file="a/b/foo.json")
4641
}
4742

4843
-- test.json --
4944
{ "x": 34 }
5045
-- input.yaml --
5146
a1: 2
52-
47+
-- ..dotdot.json --
48+
{"dotdot": true}
5349
-- y/test.json --
5450
{ "x": 34 }
5551
-- y/_test.json --
@@ -121,9 +117,9 @@ g: _
121117
special: {
122118
underscoreFile: _
123119
dotFile: _
120+
dotdotFile: _
124121
underscoreDir: _
125122
dotDir: _
126-
nestedModJSON: _
127123
}
128124
-- out/eval --
129125
a: {
@@ -208,16 +204,15 @@ special: {
208204
dotFile: {
209205
z: 46
210206
}
207+
dotdotFile: {
208+
dotdot: true
209+
}
211210
underscoreDir: {
212211
z: 47
213212
}
214213
dotDir: {
215214
z: 48
216215
}
217-
nestedModJSON: {
218-
a: 1
219-
b: 2
220-
}
221216
}
222217
-- out/export --
223218
a: x: 34
@@ -265,18 +260,10 @@ g: {
265260
}
266261
special: {
267262
// These are all valid.
268-
underscoreFile: z: 45
269-
dotFile: z: 46
270-
underscoreDir: z: 47
271-
dotDir: z: 48
272-
273-
// TODO: fix nested modules are currently not supported, but we may opt to
274-
// support them in the future. This is currently not handled. It should
275-
// probably be up to the loader to provide a fs.FS that handles this
276-
// according to spec.
277-
nestedModJSON: {
278-
a: 1
279-
b: 2
280-
}
263+
underscoreFile: z: 45
264+
dotFile: z: 46
265+
dotdotFile: dotdot: true
266+
underscoreDir: z: 47
267+
dotDir: z: 48
281268
}
282269
-- out/vet --

cmd/cue/cmd/testdata/script/embed_err.txtar

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ unspecifiedFiletype2: _ @embed(glob=x/*)
5656
unspecifiedFiletype3: _ @embed(glob=x/*.?son)
5757
unspecifiedFiletype4: _ @embed(glob=x/*.[j]son)
5858

59+
nestedModJSON: _ @embed(file="a/b/foo.json")
60+
nestedModJSONWithGlob: _ @embed(glob="a/*/*.json")
61+
5962
-- test.json --
6063
{ "x": 34 }
6164
-- test.ldjson --
@@ -80,6 +83,11 @@ a: 1
8083
x: 5
8184
-- xcue --
8285
x: 5
86+
-- a/b/cue.mod/modules.cue --
87+
module: "acme.com"
88+
language: version: "v0.9.0"
89+
-- a/b/foo.json --
90+
{"a": 1, "b": 2}
8391
-- out/std --
8492
-- out/err --
8593
@embed: attribute must have file or glob field:
@@ -130,3 +138,7 @@ x: 5
130138
./test.cue:49:25
131139
@embed: extension not fully specified; type argument required:
132140
./test.cue:50:25
141+
@embed: cannot embed file "a/b/foo.json": in different module:
142+
./test.cue:52:18
143+
@embed: cannot embed file "a/b/foo.json": in different module:
144+
./test.cue:53:26

cue/interpreter/embed/embed.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,11 @@ func (c *compiler) processFile(file, scope string, schema adt.Value) (adt.Expr,
202202
if err != nil {
203203
return nil, err
204204
}
205+
for dir := path.Dir(file); dir != "."; dir = path.Dir(dir) {
206+
if _, err := c.fs.Stat(path.Join(dir, "cue.mod")); err == nil {
207+
return nil, errors.Newf(c.pos, "cannot embed file %q: in different module", file)
208+
}
209+
}
205210

206211
return c.decodeFile(file, scope, schema)
207212
}
@@ -233,6 +238,7 @@ func (c *compiler) processGlob(glob, scope string, schema adt.Value) (adt.Expr,
233238
return nil, errors.Promote(err, "failed to match glob")
234239
}
235240

241+
dirs := make(map[string]string)
236242
for _, f := range matches {
237243
// TODO: lots of stat calls happening in this MVP so another won't hurt.
238244
// We don't support '**' initially, and '*' only matches files, so skip
@@ -242,6 +248,13 @@ func (c *compiler) processGlob(glob, scope string, schema adt.Value) (adt.Expr,
242248
} else if fi.IsDir() {
243249
continue
244250
}
251+
// Add all parents of the embedded file that
252+
// aren't the current directory (if there's a cue.mod
253+
// in the current directory, that's the current module
254+
// not nested).
255+
for dir := path.Dir(f); dir != "."; dir = path.Dir(dir) {
256+
dirs[dir] = f
257+
}
245258

246259
expr, err := c.decodeFile(f, scope, schema)
247260
if err != nil {
@@ -253,7 +266,13 @@ func (c *compiler) processGlob(glob, scope string, schema adt.Value) (adt.Expr,
253266
Value: expr,
254267
})
255268
}
256-
269+
// Check that none of the matches were in a nested module
270+
// directory.
271+
for dir, f := range dirs {
272+
if _, err := c.fs.Stat(path.Join(dir, "cue.mod")); err == nil {
273+
return nil, errors.Newf(c.pos, "cannot embed file %q: in different module", f)
274+
}
275+
}
257276
return m, nil
258277
}
259278

@@ -265,7 +284,7 @@ func (c *compiler) clean(s string) (string, errors.Error) {
265284
if path.IsAbs(file) {
266285
return "", errors.Newf(c.pos, "only relative files are allowed")
267286
}
268-
if strings.HasPrefix(file, "..") {
287+
if file == ".." || strings.HasPrefix(file, "../") {
269288
return "", errors.Newf(c.pos, "cannot refer to parent directory")
270289
}
271290
return file, nil

0 commit comments

Comments
 (0)