-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
repack: do not include Volume paths in new layers
This is (unfortunately) not mandated in the specification[1,2], but in order to avoid accidentally spilling private information into published layers (which is one use of Volumes) we must ignore all layers included in Config.Volumes. In future we should also add some flags or alernative ways of masking paths. [1]: opencontainers/image-spec#496 [2]: opencontainers/image-spec#504 Signed-off-by: Aleksa Sarai <[email protected]>
- Loading branch information
Showing
3 changed files
with
224 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* | ||
* umoci: Umoci Modifies Open Containers' Images | ||
* Copyright (C) 2017 SUSE LLC. | ||
* | ||
* 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 | ||
* | ||
* http://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 mtreefilter | ||
|
||
import ( | ||
"path/filepath" | ||
|
||
"github.com/apex/log" | ||
"github.com/vbatts/go-mtree" | ||
) | ||
|
||
// FilterFunc is a function used when filtering deltas with FilterDeltas. | ||
type FilterFunc func(path string) bool | ||
|
||
// isParent returns whether the path a is lexically an ancestor of the path b. | ||
func isParent(a, b string) bool { | ||
a = filepath.Clean(a) | ||
b = filepath.Clean(b) | ||
|
||
for a != b { | ||
if b == filepath.Dir(b) { | ||
break | ||
} | ||
b = filepath.Dir(b) | ||
} | ||
return a == b | ||
} | ||
|
||
// MaskFilter is a factory for FilterFuncs that will mask all InodeDelta paths | ||
// that are lexical children of any path in the mask slice. All paths are | ||
// considered to be relative to '/'. | ||
func MaskFilter(masks []string) FilterFunc { | ||
return func(path string) bool { | ||
// Convert path to relative-to-root. | ||
path = filepath.Clean(path) | ||
path = filepath.Join("/", path) | ||
|
||
// Check that no masks are matched. | ||
for _, mask := range masks { | ||
// Mask also needs to be relative-to-root. | ||
mask = filepath.Clean(mask) | ||
mask = filepath.Join("/", mask) | ||
|
||
// Is it a parent? | ||
if isParent(mask, path) { | ||
log.Debugf("maskfilter: ignoring path %q matched by mask %q", path, mask) | ||
return false | ||
} | ||
} | ||
|
||
return true | ||
} | ||
} | ||
|
||
// FilterDeltas is a helper function to easily filter []mtree.InodeDelta with a | ||
// filter function. Only entries which have `filter(delta.Path()) == true` will | ||
// be included in the returned slice. | ||
func FilterDeltas(deltas []mtree.InodeDelta, filter FilterFunc) []mtree.InodeDelta { | ||
var filtered []mtree.InodeDelta | ||
for _, delta := range deltas { | ||
if filter(delta.Path()) { | ||
filtered = append(filtered, delta) | ||
} | ||
} | ||
return filtered | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
/* | ||
* umoci: Umoci Modifies Open Containers' Images | ||
* Copyright (C) 2017 SUSE LLC. | ||
* | ||
* 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 | ||
* | ||
* http://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 mtreefilter | ||
|
||
import ( | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/vbatts/go-mtree" | ||
) | ||
|
||
func TestIsParent(t *testing.T) { | ||
for _, test := range []struct { | ||
parent, path string | ||
expected bool | ||
}{ | ||
{"/", "/a", true}, | ||
{"/", "/a/b/c", true}, | ||
{"/", "/", true}, | ||
{"/a path/", "/a path", true}, | ||
{"/a nother path", "/a nother path/test", true}, | ||
{"/a nother path", "/a nother path/test/1 2/ 33 /", true}, | ||
{"/path1", "/path2", false}, | ||
{"/pathA", "/PATHA", false}, | ||
{"/pathC", "/path", false}, | ||
{"/path9", "/", false}, | ||
// Make sure it's not the same as filepath.HasPrefix. | ||
{"/a/b/c", "/a/b/c/d", true}, | ||
{"/a/b/c", "/a/b/cd", false}, | ||
{"/a/b/c", "/a/bcd", false}, | ||
{"/a/bc", "/a/bcd", false}, | ||
{"/abc", "/abcd", false}, | ||
} { | ||
got := isParent(test.parent, test.path) | ||
if got != test.expected { | ||
t.Errorf("isParent(%q, %q) got %v expected %v", test.parent, test.path, got, test.expected) | ||
} | ||
} | ||
} | ||
|
||
func TestMaskDeltas(t *testing.T) { | ||
dir, err := ioutil.TempDir("", "TestMaskDeltas-") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
defer os.RemoveAll(dir) | ||
|
||
var mtreeKeywords []mtree.Keyword = append(mtree.DefaultKeywords, "sha256digest") | ||
|
||
// Create some files. | ||
if err != ioutil.WriteFile(filepath.Join(dir, "file1"), []byte("contents"), 0644) { | ||
t.Fatal(err) | ||
} | ||
if err != ioutil.WriteFile(filepath.Join(dir, "file2"), []byte("another content"), 0644) { | ||
t.Fatal(err) | ||
} | ||
if err != os.MkdirAll(filepath.Join(dir, "dir", "child"), 0755) { | ||
t.Fatal(err) | ||
} | ||
if err != os.MkdirAll(filepath.Join(dir, "dir", "child2"), 0755) { | ||
t.Fatal(err) | ||
} | ||
if err != ioutil.WriteFile(filepath.Join(dir, "dir", "file 3"), []byte("more content"), 0644) { | ||
t.Fatal(err) | ||
} | ||
if err != ioutil.WriteFile(filepath.Join(dir, "dir", "child2", "4 files"), []byte("very content"), 0644) { | ||
t.Fatal(err) | ||
} | ||
|
||
// Generate a diff. | ||
originalDh, err := mtree.Walk(dir, nil, mtreeKeywords, nil) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
// Modify the root. | ||
if err := os.RemoveAll(filepath.Join(dir, "file2")); err != nil { | ||
t.Fatal(err) | ||
} | ||
if err := ioutil.WriteFile(filepath.Join(dir, "dir", "new"), []byte("more content"), 0755); err != nil { | ||
t.Fatal(err) | ||
} | ||
if err := ioutil.WriteFile(filepath.Join(dir, "file1"), []byte("different contents"), 0666); err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
// Generate the set of diffs. | ||
newDh, err := mtree.Walk(dir, nil, mtreeKeywords, nil) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
diff, err := mtree.Compare(originalDh, newDh, mtreeKeywords) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
for _, test := range []struct { | ||
paths []string | ||
len int | ||
}{ | ||
{nil, len(diff)}, | ||
{[]string{"/"}, 0}, | ||
{[]string{"dir"}, 3}, | ||
{[]string{filepath.Join("dir", "child2")}, 5}, | ||
{[]string{"file2"}, 4}, | ||
{[]string{"/", "file2"}, 0}, | ||
{[]string{"file2", filepath.Join("dir", "child2")}, 4}, | ||
} { | ||
newDiff := FilterDeltas(diff, MaskFilter(test.paths)) | ||
if len(newDiff) != test.len { | ||
t.Errorf("diff %v expected %d got %d", test.paths, test.len, len(newDiff)) | ||
} | ||
} | ||
} |