Skip to content

Commit

Permalink
cue/interpreter/embed: don't allow hidden files in glob
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
mpvl authored and rogpeppe committed Jul 9, 2024
1 parent 7e1f140 commit 8bedc2b
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 4 deletions.
4 changes: 0 additions & 4 deletions cmd/cue/cmd/testdata/script/embed.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,6 @@ c: """

"""
d: {
"y/.test.json": {
z: 46
}
"y/_test.json": {
z: 45
}
Expand Down Expand Up @@ -222,7 +219,6 @@ c: """

"""
d: {
"y/.test.json": z: 46
"y/_test.json": z: 45
"x/input.yaml": a1: 2
"y/test.json": x: 34
Expand Down
11 changes: 11 additions & 0 deletions cue/interpreter/embed/embed.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ import (
// TODO: record files in build.Instance
// TODO: support stream values
// TODO: support schema-based decoding
// TODO: maybe: option to include hidden files?

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

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

// isHidden checks if a file is hidden on Windows. We do not return an error
// if the file does not exist and will check that elsewhere.
func (c *compiler) isHidden(file string) bool {
return strings.HasPrefix(file, ".") || strings.Contains(file, "/.")
}

func (c *compiler) decodeFile(file, scope string, schema adt.Value) (adt.Expr, errors.Error) {
// Do not use the most obvious filetypes.Input in order to disable "auto"
// mode.
Expand Down
55 changes: 55 additions & 0 deletions cue/interpreter/embed/embed_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2024 CUE Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package embed

import "testing"

func TestIsHidden(t *testing.T) {
// These test cases are the same for both Unix and Windows.
testCases := []struct {
path string
want bool
}{{
path: "",
want: false,
}, {
path: "foo",
want: false,
}, {
path: ".foo",
want: true,
}, {
path: "foo/bar",
want: false,
}, {
path: "foo/.bar",
want: true,
}, {
path: ".foo/bar",
want: true,
}, {
path: "x/.foo/bar",
want: true,
}}
c := &compiler{dir: "/tmp"}
for _, tc := range testCases {
t.Run(tc.path, func(t *testing.T) {
got := c.isHidden(tc.path)
if got != tc.want {
t.Errorf("isHidden(%q) = %t; want %t", tc.path, got, tc.want)
}
})
}
}

0 comments on commit 8bedc2b

Please sign in to comment.