Skip to content

Commit 8bedc2b

Browse files
mpvlrogpeppe
authored andcommitted
cue/interpreter/embed: don't allow hidden files in glob
This could later be allowed as an option. This is a security feature. We also disallow hidden files on Windows for the same reason, which is a bit more involved. Note that this results in potentially slightly different behavior under Windows and Unix. This is already the case. For instance, the set of valid filenames is different on the different supported OSes. So we accept this discrepancy in favor of added security. Verified that without adding the new logic, the hidden file that was added to embed.txtar gets included in the output. Issue #2031 Signed-off-by: Marcel van Lohuizen <[email protected]> Change-Id: Iacff803f4c388d1f2792665ed5adb32f68f00ffa Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1196775 TryBot-Result: CUEcueckoo <[email protected]> Reviewed-by: Roger Peppe <[email protected]> Unity-Result: CUE porcuepine <[email protected]> Reviewed-by: Daniel Martí <[email protected]>
1 parent 7e1f140 commit 8bedc2b

File tree

3 files changed

+66
-4
lines changed

3 files changed

+66
-4
lines changed

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,6 @@ c: """
133133

134134
"""
135135
d: {
136-
"y/.test.json": {
137-
z: 46
138-
}
139136
"y/_test.json": {
140137
z: 45
141138
}
@@ -222,7 +219,6 @@ c: """
222219

223220
"""
224221
d: {
225-
"y/.test.json": z: 46
226222
"y/_test.json": z: 45
227223
"x/input.yaml": a1: 2
228224
"y/test.json": x: 34

cue/interpreter/embed/embed.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ import (
107107
// TODO: record files in build.Instance
108108
// TODO: support stream values
109109
// TODO: support schema-based decoding
110+
// TODO: maybe: option to include hidden files?
110111

111112
// interpreter is a [cuecontext.ExternInterpreter] for embedded files.
112113
type interpreter struct{}
@@ -240,6 +241,10 @@ func (c *compiler) processGlob(glob, scope string, schema adt.Value) (adt.Expr,
240241

241242
dirs := make(map[string]string)
242243
for _, f := range matches {
244+
if c.isHidden(f) {
245+
// TODO: allow option for including hidden files?
246+
continue
247+
}
243248
// TODO: lots of stat calls happening in this MVP so another won't hurt.
244249
// We don't support '**' initially, and '*' only matches files, so skip
245250
// any directories.
@@ -290,6 +295,12 @@ func (c *compiler) clean(s string) (string, errors.Error) {
290295
return file, nil
291296
}
292297

298+
// isHidden checks if a file is hidden on Windows. We do not return an error
299+
// if the file does not exist and will check that elsewhere.
300+
func (c *compiler) isHidden(file string) bool {
301+
return strings.HasPrefix(file, ".") || strings.Contains(file, "/.")
302+
}
303+
293304
func (c *compiler) decodeFile(file, scope string, schema adt.Value) (adt.Expr, errors.Error) {
294305
// Do not use the most obvious filetypes.Input in order to disable "auto"
295306
// mode.

cue/interpreter/embed/embed_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright 2024 CUE Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package embed
16+
17+
import "testing"
18+
19+
func TestIsHidden(t *testing.T) {
20+
// These test cases are the same for both Unix and Windows.
21+
testCases := []struct {
22+
path string
23+
want bool
24+
}{{
25+
path: "",
26+
want: false,
27+
}, {
28+
path: "foo",
29+
want: false,
30+
}, {
31+
path: ".foo",
32+
want: true,
33+
}, {
34+
path: "foo/bar",
35+
want: false,
36+
}, {
37+
path: "foo/.bar",
38+
want: true,
39+
}, {
40+
path: ".foo/bar",
41+
want: true,
42+
}, {
43+
path: "x/.foo/bar",
44+
want: true,
45+
}}
46+
c := &compiler{dir: "/tmp"}
47+
for _, tc := range testCases {
48+
t.Run(tc.path, func(t *testing.T) {
49+
got := c.isHidden(tc.path)
50+
if got != tc.want {
51+
t.Errorf("isHidden(%q) = %t; want %t", tc.path, got, tc.want)
52+
}
53+
})
54+
}
55+
}

0 commit comments

Comments
 (0)