mesh/delivery failed: its walk failed, carrying its own commit: a gate on a first machine (what it carried put back), a build, a machine
mesh/check failed: integration: meshbuildnode/cmd/mesh-build-node.TestAFixtureBundleBuiltTwiceHasOneDigest: build_integration_test.go:71: no toolchain…
167 lines
6.3 KiB
Go
167 lines
6.3 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/forgekey"
|
|
)
|
|
|
|
// npmAsUmask077 installs as npm does under a umask of 077: node_modules with a package whose folders are 0700, its
|
|
// file 0600 and its program 0700.
|
|
func npmAsUmask077(f *fakeNpm) forgekey.Runner {
|
|
return func(ctx context.Context, env []string, name string, args ...string) forgekey.Ran {
|
|
ran := f.run(ctx, env, name, args...)
|
|
for i, a := range args {
|
|
if a == "--prefix" {
|
|
pkg := filepath.Join(args[i+1], "node_modules", "typescript", "bin")
|
|
os.MkdirAll(pkg, 0o700)
|
|
os.WriteFile(filepath.Join(args[i+1], "node_modules", "typescript", "package.json"), []byte("{}"), 0o600)
|
|
os.WriteFile(filepath.Join(pkg, "tsc"), []byte("#!/bin/sh\n"), 0o700)
|
|
}
|
|
}
|
|
return ran
|
|
}
|
|
}
|
|
|
|
// checkOpen fails unless every folder from the cache's toolchain down lets others enter and read it and every file lets
|
|
// others read it, a program others run, and nothing lets anyone but the owner write.
|
|
func checkOpen(t *testing.T, tc Toolchain) {
|
|
t.Helper()
|
|
root := filepath.Join(tc.Paths.Cache, "toolchain")
|
|
err := filepath.WalkDir(root, func(p string, d fs.DirEntry, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
info, err := d.Info()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
mode := info.Mode().Perm()
|
|
switch {
|
|
case mode&0o022 != 0:
|
|
t.Errorf("%s is %o: writable by others than its owner", p, mode)
|
|
case d.IsDir() && mode&0o005 != 0o005:
|
|
t.Errorf("%s is %o: others may not enter and read it", p, mode)
|
|
case !d.IsDir() && mode&0o004 == 0:
|
|
t.Errorf("%s is %o: others may not read it", p, mode)
|
|
case !d.IsDir() && mode&0o100 != 0 && mode&0o001 == 0:
|
|
t.Errorf("%s is %o: a program others may not run", p, mode)
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// 1891 (ADR 0533 §2): a toolchain the module installs can be read by the other build module's integration level:
|
|
// its folders 0755 and its files 0644 (programs 0755), whatever umask npm ran under, and writable by its owner alone.
|
|
func TestAnInstalledToolchainIsReadableByOthersAndWritableByItsOwnerAlone(t *testing.T) {
|
|
fake := &fakeNpm{}
|
|
tc := toolchainIn(t, fake)
|
|
tc.Run = npmAsUmask077(fake)
|
|
npm := filepath.Join(tc.Paths.Cache, "npm")
|
|
if err := os.MkdirAll(npm, 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := tc.Ensure(context.Background(), "v1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
checkOpen(t, tc)
|
|
if st, err := os.Stat(npm); err != nil || st.Mode().Perm() != 0o700 {
|
|
t.Errorf("the npm download cache beside the toolchains is %v (%v), want 0700: only the toolchains are opened", st.Mode().Perm(), err)
|
|
}
|
|
}
|
|
|
|
// 1891 (ADR 0533 §2): a toolchain installed before this release, shut to its owner, is opened by the next Ensure
|
|
// without installing it again.
|
|
func TestAToolchainInstalledShutIsOpenedWithoutAnInstall(t *testing.T) {
|
|
fake := &fakeNpm{}
|
|
tc := toolchainIn(t, fake)
|
|
dir := tc.Paths.Dir("v1")
|
|
os.MkdirAll(filepath.Join(dir, "node_modules", "esbuild", "bin"), 0o700)
|
|
os.WriteFile(filepath.Join(dir, "node_modules", "esbuild", "bin", "esbuild"), []byte("x"), 0o700)
|
|
os.WriteFile(filepath.Join(dir, "package-lock.json"), []byte("{}"), 0o600)
|
|
os.WriteFile(filepath.Join(dir, installedMark), []byte("v1\n"), 0o600)
|
|
os.Chmod(filepath.Join(tc.Paths.Cache, "toolchain"), 0o700)
|
|
if err := tc.Ensure(context.Background(), "v1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(fake.calls) != 0 {
|
|
t.Errorf("npm ran %d times for a toolchain already there", len(fake.calls))
|
|
}
|
|
checkOpen(t, tc)
|
|
}
|
|
|
|
// 1891 (ADR 0533 §2): the cache directory lets other accounts enter it and not list it, so the toolchains beneath it
|
|
// can be reached by their path and the npm cache beside them (0700) cannot.
|
|
func TestTheCacheDirectoryIsEnteredByOthersNotListed(t *testing.T) {
|
|
r := resource(t, readManifest(t), "cache")
|
|
if r["mode"] != "0711" {
|
|
t.Errorf("the cache directory's mode is %v, want 0711", r["mode"])
|
|
}
|
|
}
|
|
|
|
// 1891 review (ADR 0533 §2): the registry credential npm is told is never written beneath the cache, so opening a
|
|
// toolchain can never open it: npm reads it from a file in the account's own home, readable by its owner alone, and
|
|
// the file is gone when Ensure returns.
|
|
func TestTheInstallCredentialIsNeverInTheFolderThatIsOpened(t *testing.T) {
|
|
fake := &fakeNpm{}
|
|
tc := toolchainIn(t, fake)
|
|
var userconfig string
|
|
inner := npmAsUmask077(fake)
|
|
tc.Run = func(ctx context.Context, env []string, name string, args ...string) forgekey.Ran {
|
|
for i, a := range args {
|
|
if a == "--userconfig" {
|
|
userconfig = args[i+1]
|
|
}
|
|
}
|
|
if st, err := os.Stat(userconfig); err != nil || st.Mode().Perm() != 0o600 {
|
|
t.Errorf("the credential file %s is %v (%v), want 0600", userconfig, st.Mode().Perm(), err)
|
|
}
|
|
return inner(ctx, env, name, args...)
|
|
}
|
|
if err := tc.Ensure(context.Background(), "v1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if rel, err := filepath.Rel(tc.Paths.Home, userconfig); err != nil || rel != filepath.Base(userconfig) {
|
|
t.Errorf("the credential file %s is not in the account's home %s", userconfig, tc.Paths.Home)
|
|
}
|
|
if _, err := os.Stat(userconfig); err == nil {
|
|
t.Errorf("the credential file %s is left after the install", userconfig)
|
|
}
|
|
filepath.WalkDir(tc.Paths.Cache, func(p string, d fs.DirEntry, err error) error {
|
|
if err == nil && strings.Contains(d.Name(), "npmrc") {
|
|
t.Errorf("a credential file %s lies beneath the cache", p)
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
// 1891 review (ADR 0533 §2): open refuses a toolchain folder that holds an npm config file, naming it, and opens
|
|
// nothing of it, so a credential left by a dead install is never made readable.
|
|
func TestOpenRefusesAFolderHoldingAnNpmConfig(t *testing.T) {
|
|
fake := &fakeNpm{}
|
|
tc := toolchainIn(t, fake)
|
|
dir := tc.Paths.Dir("v1")
|
|
os.MkdirAll(filepath.Join(dir, "node_modules"), 0o700)
|
|
left := filepath.Join(dir, ".npmrc-install")
|
|
os.WriteFile(left, []byte("//x/:_auth=secret\n"), 0o600)
|
|
os.WriteFile(filepath.Join(dir, installedMark), []byte("v1\n"), 0o600)
|
|
err := tc.Ensure(context.Background(), "v1")
|
|
if err == nil || !strings.Contains(err.Error(), left) {
|
|
t.Errorf("Ensure = %v, want a refusal naming %s", err, left)
|
|
}
|
|
if st, _ := os.Stat(left); st.Mode().Perm() != 0o600 {
|
|
t.Errorf("the credential file was opened to %o", st.Mode().Perm())
|
|
}
|
|
if st, _ := os.Stat(dir); st.Mode().Perm()&0o005 != 0 {
|
|
t.Errorf("the folder holding it was opened to %o", st.Mode().Perm())
|
|
}
|
|
}
|