Review of 62a50eb: the layer lay in the workspace, which every step binds read-write,
so a change's command could swap a kept directory for a symlink and the move, run
outside the sandbox, would write into the shared cache (ADR 0541 §2). The layer now
lies beside the workspace (Workspaces.CacheLayer, removed by Release and Sweep),
Command refuses a layer within reach of the workspace, a writable directory or a
cache, and every move goes through an os.Root on the layer and keeps no symlink. Only
LayerCaches (the build cache) are layered; a module cache keeps its throwaway layer
(issue 1921).
76 lines
3.3 KiB
Go
76 lines
3.3 KiB
Go
package buildstep
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// The shared warm caches are read under a throwaway writable layer (novox/hq ADR 0448; issue 1309): a candidate's step
|
|
// writes into them as a build does, and nothing it writes outlives it or reaches a later build; only a trunk build
|
|
// writes them.
|
|
func TestACandidatesStepWritesTheCachesOnlyIntoAThrowawayLayer(t *testing.T) {
|
|
fixedSystem(t)
|
|
iso := Isolation{Workspace: "/w", Caches: []string{"/var/cache/go-build", "/var/cache/npm"}}
|
|
argv, err := iso.Command("go", "test")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, c := range iso.Caches {
|
|
if !holds(argv, "--overlay-src", c, "--tmp-overlay", c) {
|
|
t.Errorf("the cache %s is not under a throwaway layer: %v", c, argv)
|
|
}
|
|
if holds(argv, "--bind", c, c) {
|
|
t.Errorf("a candidate's step writes the cache %s: %v", c, argv)
|
|
}
|
|
}
|
|
iso.WriteCaches = true
|
|
argv, _ = iso.Command("go", "build")
|
|
for _, c := range iso.Caches {
|
|
if !holds(argv, "--bind", c, c) || holds(argv, "--tmp-overlay", c) {
|
|
t.Errorf("a trunk build does not write the cache %s: %v", c, argv)
|
|
}
|
|
}
|
|
// 1921/S2: with a cache layer, a command reads the ask's kept layer above the shared cache and writes into a layer
|
|
// on disk of the ask's own, never into the shared cache and never into a throwaway tmpfs.
|
|
// Only the layered caches (the build cache) are; the module cache keeps its throwaway layer.
|
|
iso = Isolation{Workspace: "/w/ws1", Caches: []string{"/cache/gomod", "/cache/gobuild"}, CacheLayer: "/w/ws1.cachelayer",
|
|
LayerCaches: []string{"/cache/gobuild"}}
|
|
argv, err = iso.Command("go", "vet")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !holds(argv, "--overlay-src", "/cache/gobuild", "--overlay-src", keptLayer(iso.CacheLayer, 1), "--overlay") {
|
|
t.Errorf("the build cache is not read beneath the ask's kept layer: %v", argv)
|
|
}
|
|
if up := overlayOf(argv, "/cache/gobuild"); up == "" || !strings.HasPrefix(up, "/w/ws1.cachelayer/") {
|
|
t.Errorf("the build cache is written into %q, not a layer of the ask's own: %v", up, argv)
|
|
}
|
|
if !holds(argv, "--overlay-src", "/cache/gomod", "--tmp-overlay", "/cache/gomod") || overlayOf(argv, "/cache/gomod") != "" {
|
|
t.Errorf("the module cache is not under a throwaway layer: %v", argv)
|
|
}
|
|
// A layer a command could reach is refused: in the workspace (bound read-write), in a writable directory, in a
|
|
// cache, or above one of them; so is a relative one, and a layered cache that is no cache.
|
|
for _, bad := range []Isolation{
|
|
{Workspace: "/w/ws1", CacheLayer: "/w/ws1/cachelayer"},
|
|
{Workspace: "/w/ws1", CacheLayer: "/w"},
|
|
{Workspace: "/w/ws1", Writable: []string{"/out"}, CacheLayer: "/out/layer"},
|
|
{Workspace: "/w/ws1", Caches: []string{"/cache/gobuild"}, CacheLayer: "/cache/gobuild/layer"},
|
|
{Workspace: "/w/ws1", CacheLayer: "cachelayer"},
|
|
{Workspace: "/w/ws1", Caches: []string{"/cache/gobuild"}, CacheLayer: "/w/ws1.cachelayer", LayerCaches: []string{"/cache/other"}},
|
|
} {
|
|
if _, err := bad.Command("go"); err == nil {
|
|
t.Errorf("the cache layer %s of %+v was taken", bad.CacheLayer, bad)
|
|
}
|
|
}
|
|
}
|
|
|
|
// overlayOf answers the upper directory a command line gives the cache c, "" when it gives none.
|
|
func overlayOf(argv []string, c string) string {
|
|
for i := 0; i+3 < len(argv); i++ {
|
|
if argv[i] == "--overlay" && argv[i+3] == c {
|
|
return argv[i+1]
|
|
}
|
|
}
|
|
return ""
|
|
}
|