Merge "services/agent:  Add a vbecome command to run with derived principals."
diff --git a/cmd/principal/bless.go b/cmd/principal/bless.go
index 3ed3ed9..80db361 100644
--- a/cmd/principal/bless.go
+++ b/cmd/principal/bless.go
@@ -59,7 +59,7 @@
 	return service, macaroon, root, nil
 }
 
-func getMacaroonForBlessRPC(blessServerURL string, blessedChan <-chan string, browser bool) (<-chan string, error) {
+func getMacaroonForBlessRPC(key security.PublicKey, blessServerURL string, blessedChan <-chan string, browser bool) (<-chan string, error) {
 	// Setup a HTTP server to recieve a blessing macaroon from the identity server.
 	// Steps:
 	// 1. Generate a state token to be included in the HTTP request
@@ -118,7 +118,7 @@
 	go http.Serve(ln, nil)
 
 	// Print the link to start the flow.
-	url, err := seekBlessingsURL(blessServerURL, redirectURL, state)
+	url, err := seekBlessingsURL(key, blessServerURL, redirectURL, state)
 	if err != nil {
 		return nil, fmt.Errorf("failed to create seekBlessingsURL: %s", err)
 	}
@@ -135,14 +135,19 @@
 	return result, nil
 }
 
-func seekBlessingsURL(blessServerURL, redirectURL, state string) (string, error) {
+func seekBlessingsURL(key security.PublicKey, blessServerURL, redirectURL, state string) (string, error) {
 	baseURL, err := url.Parse(joinURL(blessServerURL, identity.SeekBlessingsRoute))
 	if err != nil {
 		return "", fmt.Errorf("failed to parse url: %v", err)
 	}
+	keyBytes, err := key.MarshalBinary()
+	if err != nil {
+		return "", fmt.Errorf("failed to marshal public key: %v", err)
+	}
 	params := url.Values{}
 	params.Add("redirect_url", redirectURL)
 	params.Add("state", state)
+	params.Add("public_key", base64.URLEncoding.EncodeToString(keyBytes))
 	baseURL.RawQuery = params.Encode()
 	return baseURL.String(), nil
 }
diff --git a/cmd/principal/main.go b/cmd/principal/main.go
index 2c76e3a..dc95990 100644
--- a/cmd/principal/main.go
+++ b/cmd/principal/main.go
@@ -691,9 +691,11 @@
 			ctx, shutdown := v23.Init()
 			defer shutdown()
 
+			p := v23.GetPrincipal(ctx)
+
 			blessedChan := make(chan string)
 			defer close(blessedChan)
-			macaroonChan, err := getMacaroonForBlessRPC(flagSeekBlessingsFrom, blessedChan, flagSeekBlessingsBrowser)
+			macaroonChan, err := getMacaroonForBlessRPC(p.PublicKey(), flagSeekBlessingsFrom, blessedChan, flagSeekBlessingsBrowser)
 			if err != nil {
 				return fmt.Errorf("failed to get macaroon from Vanadium blesser: %v", err)
 			}
@@ -706,8 +708,6 @@
 			// Wait for getTokenForBlessRPC to clean up:
 			<-macaroonChan
 
-			p := v23.GetPrincipal(ctx)
-
 			if flagSeekBlessingsSetDefault {
 				if err := p.BlessingStore().SetDefault(blessings); err != nil {
 					return fmt.Errorf("failed to set blessings %v as default: %v", blessings, err)
diff --git a/services/device/internal/impl/impl_test.go b/services/device/internal/impl/impl_test.go
index babe024..0a3bccd 100644
--- a/services/device/internal/impl/impl_test.go
+++ b/services/device/internal/impl/impl_test.go
@@ -9,10 +9,8 @@
 package impl_test
 
 import (
-	"bytes"
 	"crypto/md5"
 	"encoding/base64"
-	"encoding/hex"
 	"fmt"
 	"io/ioutil"
 	"os"
@@ -83,16 +81,6 @@
 	return path
 }
 
-func initForTest() (*context.T, v23.Shutdown) {
-	roots, _ := envvar.NamespaceRoots()
-	for key, _ := range roots {
-		os.Unsetenv(key)
-	}
-	ctx, shutdown := test.InitForTest()
-	v23.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
-	return ctx, shutdown
-}
-
 // TestDeviceManagerUpdateAndRevert makes the device manager go through the
 // motions of updating itself to newer versions (twice), and reverting itself
 // back (twice). It also checks that update and revert fail when they're
@@ -100,7 +88,7 @@
 // command. Further versions are running through the soft link that the device
 // manager itself updates.
 func TestDeviceManagerUpdateAndRevert(t *testing.T) {
-	ctx, shutdown := initForTest()
+	ctx, shutdown := utiltest.InitForTest()
 	defer shutdown()
 
 	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, v23.GetPrincipal(ctx))
@@ -324,7 +312,7 @@
 // TestLifeOfAnApp installs an app, instantiates, runs, kills, and deletes
 // several instances, and performs updates.
 func TestLifeOfAnApp(t *testing.T) {
-	ctx, shutdown := initForTest()
+	ctx, shutdown := utiltest.InitForTest()
 	defer shutdown()
 
 	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
@@ -624,173 +612,6 @@
 	}
 }
 
-// TestDeviceManagerClaim claims a devicemanager and tests AccessList permissions on
-// its methods.
-func TestDeviceManagerClaim(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-
-	// root blessing provider so that the principals of all the contexts
-	// recognize each other.
-	idp := testutil.NewIDProvider("root")
-	if err := idp.Bless(v23.GetPrincipal(ctx), "ctx"); err != nil {
-		t.Fatal(err)
-	}
-
-	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
-	defer deferFn()
-
-	// Set up mock application and binary repositories.
-	envelope, cleanup := utiltest.StartMockRepos(t, ctx)
-	defer cleanup()
-
-	root, cleanup := servicetest.SetupRootDir(t, "devicemanager")
-	defer cleanup()
-	if err := impl.SaveCreatorInfo(root); err != nil {
-		t.Fatal(err)
-	}
-
-	// Create a script wrapping the test target that implements suidhelper.
-	helperPath := utiltest.GenerateSuidHelperScript(t, root)
-
-	// Set up the device manager.  Since we won't do device manager updates,
-	// don't worry about its application envelope and current link.
-	pairingToken := "abcxyz"
-	dmh := servicetest.RunCommand(t, sh, nil, utiltest.DeviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link", pairingToken)
-	pid := servicetest.ReadPID(t, dmh)
-	defer syscall.Kill(pid, syscall.SIGINT)
-
-	*envelope = utiltest.EnvelopeFromShell(sh, nil, utiltest.AppCmd, "google naps", "trapp")
-
-	claimantCtx := utiltest.CtxWithNewPrincipal(t, ctx, idp, "claimant")
-	octx, err := v23.WithPrincipal(ctx, testutil.NewPrincipal("other"))
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// Unclaimed devices cannot do anything but be claimed.
-	// TODO(ashankar,caprita): The line below will currently fail with
-	// ErrUnclaimedDevice != NotTrusted. NotTrusted can be avoided by
-	// passing options.SkipServerEndpointAuthorization{} to the "Install" RPC.
-	// Refactor the helper function to make this possible.
-	//installAppExpectError(t, octx, impl.ErrUnclaimedDevice.ID)
-
-	// Claim the device with an incorrect pairing token should fail.
-	utiltest.ClaimDeviceExpectError(t, claimantCtx, "claimable", "mydevice", "badtoken", impl.ErrInvalidPairingToken.ID)
-	// But succeed with a valid pairing token
-	utiltest.ClaimDevice(t, claimantCtx, "claimable", "dm", "mydevice", pairingToken)
-
-	// Installation should succeed since claimantRT is now the "owner" of
-	// the devicemanager.
-	appID := utiltest.InstallApp(t, claimantCtx)
-
-	// octx will not install the app now since it doesn't recognize the
-	// device's blessings. The error returned will be ErrNoServers as that
-	// is what the IPC stack does when there are no authorized servers.
-	utiltest.InstallAppExpectError(t, octx, verror.ErrNoServers.ID)
-	// Even if it does recognize the device (by virtue of recognizing the
-	// claimant), the device will not allow it to install.
-	if err := v23.GetPrincipal(octx).AddToRoots(v23.GetPrincipal(claimantCtx).BlessingStore().Default()); err != nil {
-		t.Fatal(err)
-	}
-	utiltest.InstallAppExpectError(t, octx, verror.ErrNoAccess.ID)
-
-	// Create the local server that the app uses to let us know it's ready.
-	pingCh, cleanup := utiltest.SetupPingServer(t, claimantCtx)
-	defer cleanup()
-
-	// Start an instance of the app.
-	instanceID := utiltest.LaunchApp(t, claimantCtx, appID)
-
-	// Wait until the app pings us that it's ready.
-	pingCh.WaitForPingArgs(t)
-	utiltest.Resolve(t, ctx, "trapp", 1)
-	utiltest.KillApp(t, claimantCtx, appID, instanceID)
-
-	// TODO(gauthamt): Test that AccessLists persist across devicemanager restarts
-}
-
-func TestDeviceManagerUpdateAccessList(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-
-	// Identity provider to ensure that all processes recognize each
-	// others' blessings.
-	idp := testutil.NewIDProvider("root")
-	ctx = utiltest.CtxWithNewPrincipal(t, ctx, idp, "self")
-
-	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
-	defer deferFn()
-
-	// Set up mock application and binary repositories.
-	envelope, cleanup := utiltest.StartMockRepos(t, ctx)
-	defer cleanup()
-
-	root, cleanup := servicetest.SetupRootDir(t, "devicemanager")
-	defer cleanup()
-	if err := impl.SaveCreatorInfo(root); err != nil {
-		t.Fatal(err)
-	}
-
-	selfCtx := ctx
-	octx := utiltest.CtxWithNewPrincipal(t, selfCtx, idp, "other")
-
-	// Set up the device manager.  Since we won't do device manager updates,
-	// don't worry about its application envelope and current link.
-	dmh := servicetest.RunCommand(t, sh, nil, utiltest.DeviceManagerCmd, "dm", root, "unused_helper", "unused_app_repo_name", "unused_curr_link")
-	pid := servicetest.ReadPID(t, dmh)
-	defer syscall.Kill(pid, syscall.SIGINT)
-	defer utiltest.VerifyNoRunningProcesses(t)
-
-	// Create an envelope for an app.
-	*envelope = utiltest.EnvelopeFromShell(sh, nil, utiltest.AppCmd, "google naps")
-
-	// On an unclaimed device manager, there will be no AccessLists.
-	if _, _, err := device.DeviceClient("claimable").GetPermissions(selfCtx); err == nil {
-		t.Fatalf("GetPermissions should have failed but didn't.")
-	}
-
-	// Claim the devicemanager as "root/self/mydevice"
-	utiltest.ClaimDevice(t, selfCtx, "claimable", "dm", "mydevice", utiltest.NoPairingToken)
-	expectedAccessList := make(access.Permissions)
-	for _, tag := range access.AllTypicalTags() {
-		expectedAccessList[string(tag)] = access.AccessList{In: []security.BlessingPattern{"root/$", "root/self/$", "root/self/mydevice/$"}}
-	}
-	var b bytes.Buffer
-	if err := expectedAccessList.WriteTo(&b); err != nil {
-		t.Fatalf("Failed to save AccessList:%v", err)
-	}
-	// Note, "version" below refers to the Permissions version, not the device
-	// manager version.
-	md5hash := md5.Sum(b.Bytes())
-	expectedVersion := hex.EncodeToString(md5hash[:])
-	deviceStub := device.DeviceClient("dm/device")
-	perms, version, err := deviceStub.GetPermissions(selfCtx)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if version != expectedVersion {
-		t.Fatalf("getAccessList expected:%v(%v), got:%v(%v)", expectedAccessList, expectedVersion, perms, version)
-	}
-	// Install from octx should fail, since it does not match the AccessList.
-	utiltest.InstallAppExpectError(t, octx, verror.ErrNoAccess.ID)
-
-	newAccessList := make(access.Permissions)
-	for _, tag := range access.AllTypicalTags() {
-		newAccessList.Add("root/other", string(tag))
-	}
-	if err := deviceStub.SetPermissions(selfCtx, newAccessList, "invalid"); err == nil {
-		t.Fatalf("SetPermissions should have failed with invalid version")
-	}
-	if err := deviceStub.SetPermissions(selfCtx, newAccessList, version); err != nil {
-		t.Fatal(err)
-	}
-	// Install should now fail with selfCtx, which no longer matches the
-	// AccessLists but succeed with octx, which does.
-	utiltest.InstallAppExpectError(t, selfCtx, verror.ErrNoAccess.ID)
-	utiltest.InstallApp(t, octx)
-}
-
 type simpleRW chan []byte
 
 func (s simpleRW) Write(p []byte) (n int, err error) {
@@ -807,7 +628,7 @@
 // This should bring up a functioning device manager.  In the end it runs
 // Uninstall and verifies that the installation is gone.
 func TestDeviceManagerInstallation(t *testing.T) {
-	ctx, shutdown := initForTest()
+	ctx, shutdown := utiltest.InitForTest()
 	defer shutdown()
 
 	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
@@ -867,7 +688,7 @@
 }
 
 func TestDeviceManagerGlobAndDebug(t *testing.T) {
-	ctx, shutdown := initForTest()
+	ctx, shutdown := utiltest.InitForTest()
 	defer shutdown()
 
 	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
@@ -966,7 +787,7 @@
 // TODO(caprita): We need better test coverage for how updating/reverting apps
 // affects the package configured for the app.
 func TestDeviceManagerPackages(t *testing.T) {
-	ctx, shutdown := initForTest()
+	ctx, shutdown := utiltest.InitForTest()
 	defer shutdown()
 
 	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
@@ -1106,7 +927,7 @@
 // TODO(rjkroege): Verify that associations persist across restarts once
 // permanent storage is added.
 func TestAccountAssociation(t *testing.T) {
-	ctx, shutdown := initForTest()
+	ctx, shutdown := utiltest.InitForTest()
 	defer shutdown()
 
 	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
@@ -1192,7 +1013,7 @@
 }
 
 func TestAppWithSuidHelper(t *testing.T) {
-	ctx, shutdown := initForTest()
+	ctx, shutdown := utiltest.InitForTest()
 	defer shutdown()
 
 	// Identity provider used to ensure that all processes recognize each
@@ -1357,7 +1178,7 @@
 }
 
 func TestDownloadSignatureMatch(t *testing.T) {
-	ctx, shutdown := initForTest()
+	ctx, shutdown := utiltest.InitForTest()
 	defer shutdown()
 
 	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
diff --git a/services/device/internal/impl/debug_perms_test.go b/services/device/internal/impl/perms/debug_perms_test.go
similarity index 96%
rename from services/device/internal/impl/debug_perms_test.go
rename to services/device/internal/impl/perms/debug_perms_test.go
index 306cebe..9c6e757 100644
--- a/services/device/internal/impl/debug_perms_test.go
+++ b/services/device/internal/impl/perms/debug_perms_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package impl_test
+package perms_test
 
 import (
 	"io/ioutil"
@@ -226,15 +226,15 @@
 			[]string{
 				// STDERR and STDOUT are not handled through the log package so
 				// are not included here.
-				"impl.test.INFO",
-				"impl.test.<*>.INFO.<timestamp>",
+				"perms.test.INFO",
+				"perms.test.<*>.INFO.<timestamp>",
 			},
 		},
 	}
-	res := utiltest.NewGlobTestRegexHelper(`impl\.test`)
+	res := utiltest.NewGlobTestRegexHelper(`perms\.test`)
 
 	// Bob claimed the DM so can access it.
-	utiltest.VerifyGlob(t, bobCtx, "impl.test", dmGlobtests, res)
+	utiltest.VerifyGlob(t, bobCtx, "perms.test", dmGlobtests, res)
 	utiltest.VerifyStatsValues(t, bobCtx, "dm", "__debug", "stats/system/start-time*")
 
 	// Without permissions, hackerjoe can't access the device manager.
@@ -247,14 +247,14 @@
 
 	// Alice is an adminstrator and so can can access device manager __debug
 	// values.
-	utiltest.VerifyGlob(t, aliceCtx, "impl.test", dmGlobtests, res)
+	utiltest.VerifyGlob(t, aliceCtx, "perms.test", dmGlobtests, res)
 	utiltest.VerifyStatsValues(t, aliceCtx, "dm", "__debug", "stats/system/start-time*")
 
 	// Bob gives debug access to the device manager to hackerjoe
 	updateAccessList(t, bobCtx, "root/hackerjoe/$", string(access.Debug), "dm", "device")
 
 	// hackerjoe can now access the device manager
-	utiltest.VerifyGlob(t, hjCtx, "impl.test", dmGlobtests, res)
+	utiltest.VerifyGlob(t, hjCtx, "perms.test", dmGlobtests, res)
 	utiltest.VerifyStatsValues(t, hjCtx, "dm", "__debug", "stats/system/start-time*")
 
 	// Cleanly shut down the device manager.
diff --git a/services/device/internal/impl/perms/doc.go b/services/device/internal/impl/perms/doc.go
new file mode 100644
index 0000000..afd8566
--- /dev/null
+++ b/services/device/internal/impl/perms/doc.go
@@ -0,0 +1,7 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package perms
+
+// Test code for claiming and permission list code in the device manager.
diff --git a/services/device/internal/impl/perms/impl_test.go b/services/device/internal/impl/perms/impl_test.go
new file mode 100644
index 0000000..37a5102
--- /dev/null
+++ b/services/device/internal/impl/perms/impl_test.go
@@ -0,0 +1,19 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package perms_test
+
+import (
+	"testing"
+
+	"v.io/x/ref/services/device/internal/impl/utiltest"
+)
+
+func TestMain(m *testing.M) {
+	utiltest.TestMainImpl(m)
+}
+
+func TestSuidHelper(t *testing.T) {
+	utiltest.TestSuidHelperImpl(t)
+}
diff --git a/services/device/internal/impl/perms/perms_test.go b/services/device/internal/impl/perms/perms_test.go
new file mode 100644
index 0000000..83bd086
--- /dev/null
+++ b/services/device/internal/impl/perms/perms_test.go
@@ -0,0 +1,191 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package perms_test
+
+import (
+	"bytes"
+	"crypto/md5"
+	"encoding/hex"
+	"syscall"
+	"testing"
+
+	"v.io/v23"
+	"v.io/v23/security"
+	"v.io/v23/security/access"
+	"v.io/v23/services/device"
+	"v.io/v23/verror"
+
+	"v.io/x/ref/services/device/internal/impl"
+	"v.io/x/ref/services/device/internal/impl/utiltest"
+	"v.io/x/ref/services/internal/servicetest"
+	"v.io/x/ref/test/testutil"
+)
+
+// TestDeviceManagerClaim claims a devicemanager and tests AccessList permissions on
+// its methods.
+func TestDeviceManagerClaim(t *testing.T) {
+	ctx, shutdown := utiltest.InitForTest()
+	defer shutdown()
+
+	// root blessing provider so that the principals of all the contexts
+	// recognize each other.
+	idp := testutil.NewIDProvider("root")
+	if err := idp.Bless(v23.GetPrincipal(ctx), "ctx"); err != nil {
+		t.Fatal(err)
+	}
+
+	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
+	defer deferFn()
+
+	// Set up mock application and binary repositories.
+	envelope, cleanup := utiltest.StartMockRepos(t, ctx)
+	defer cleanup()
+
+	root, cleanup := servicetest.SetupRootDir(t, "devicemanager")
+	defer cleanup()
+	if err := impl.SaveCreatorInfo(root); err != nil {
+		t.Fatal(err)
+	}
+
+	// Create a script wrapping the test target that implements suidhelper.
+	helperPath := utiltest.GenerateSuidHelperScript(t, root)
+
+	// Set up the device manager.  Since we won't do device manager updates,
+	// don't worry about its application envelope and current link.
+	pairingToken := "abcxyz"
+	dmh := servicetest.RunCommand(t, sh, nil, utiltest.DeviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link", pairingToken)
+	pid := servicetest.ReadPID(t, dmh)
+	defer syscall.Kill(pid, syscall.SIGINT)
+
+	*envelope = utiltest.EnvelopeFromShell(sh, nil, utiltest.AppCmd, "google naps", "trapp")
+
+	claimantCtx := utiltest.CtxWithNewPrincipal(t, ctx, idp, "claimant")
+	octx, err := v23.WithPrincipal(ctx, testutil.NewPrincipal("other"))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Unclaimed devices cannot do anything but be claimed.
+	// TODO(ashankar,caprita): The line below will currently fail with
+	// ErrUnclaimedDevice != NotTrusted. NotTrusted can be avoided by
+	// passing options.SkipServerEndpointAuthorization{} to the "Install" RPC.
+	// Refactor the helper function to make this possible.
+	//installAppExpectError(t, octx, impl.ErrUnclaimedDevice.ID)
+
+	// Claim the device with an incorrect pairing token should fail.
+	utiltest.ClaimDeviceExpectError(t, claimantCtx, "claimable", "mydevice", "badtoken", impl.ErrInvalidPairingToken.ID)
+	// But succeed with a valid pairing token
+	utiltest.ClaimDevice(t, claimantCtx, "claimable", "dm", "mydevice", pairingToken)
+
+	// Installation should succeed since claimantRT is now the "owner" of
+	// the devicemanager.
+	appID := utiltest.InstallApp(t, claimantCtx)
+
+	// octx will not install the app now since it doesn't recognize the
+	// device's blessings. The error returned will be ErrNoServers as that
+	// is what the IPC stack does when there are no authorized servers.
+	utiltest.InstallAppExpectError(t, octx, verror.ErrNoServers.ID)
+	// Even if it does recognize the device (by virtue of recognizing the
+	// claimant), the device will not allow it to install.
+	if err := v23.GetPrincipal(octx).AddToRoots(v23.GetPrincipal(claimantCtx).BlessingStore().Default()); err != nil {
+		t.Fatal(err)
+	}
+	utiltest.InstallAppExpectError(t, octx, verror.ErrNoAccess.ID)
+
+	// Create the local server that the app uses to let us know it's ready.
+	pingCh, cleanup := utiltest.SetupPingServer(t, claimantCtx)
+	defer cleanup()
+
+	// Start an instance of the app.
+	instanceID := utiltest.LaunchApp(t, claimantCtx, appID)
+
+	// Wait until the app pings us that it's ready.
+	pingCh.WaitForPingArgs(t)
+	utiltest.Resolve(t, ctx, "trapp", 1)
+	utiltest.KillApp(t, claimantCtx, appID, instanceID)
+
+	// TODO(gauthamt): Test that AccessLists persist across devicemanager restarts
+}
+
+func TestDeviceManagerUpdateAccessList(t *testing.T) {
+	ctx, shutdown := utiltest.InitForTest()
+	defer shutdown()
+
+	// Identity provider to ensure that all processes recognize each
+	// others' blessings.
+	idp := testutil.NewIDProvider("root")
+	ctx = utiltest.CtxWithNewPrincipal(t, ctx, idp, "self")
+
+	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
+	defer deferFn()
+
+	// Set up mock application and binary repositories.
+	envelope, cleanup := utiltest.StartMockRepos(t, ctx)
+	defer cleanup()
+
+	root, cleanup := servicetest.SetupRootDir(t, "devicemanager")
+	defer cleanup()
+	if err := impl.SaveCreatorInfo(root); err != nil {
+		t.Fatal(err)
+	}
+
+	selfCtx := ctx
+	octx := utiltest.CtxWithNewPrincipal(t, selfCtx, idp, "other")
+
+	// Set up the device manager.  Since we won't do device manager updates,
+	// don't worry about its application envelope and current link.
+	dmh := servicetest.RunCommand(t, sh, nil, utiltest.DeviceManagerCmd, "dm", root, "unused_helper", "unused_app_repo_name", "unused_curr_link")
+	pid := servicetest.ReadPID(t, dmh)
+	defer syscall.Kill(pid, syscall.SIGINT)
+	defer utiltest.VerifyNoRunningProcesses(t)
+
+	// Create an envelope for an app.
+	*envelope = utiltest.EnvelopeFromShell(sh, nil, utiltest.AppCmd, "google naps")
+
+	// On an unclaimed device manager, there will be no AccessLists.
+	if _, _, err := device.DeviceClient("claimable").GetPermissions(selfCtx); err == nil {
+		t.Fatalf("GetPermissions should have failed but didn't.")
+	}
+
+	// Claim the devicemanager as "root/self/mydevice"
+	utiltest.ClaimDevice(t, selfCtx, "claimable", "dm", "mydevice", utiltest.NoPairingToken)
+	expectedAccessList := make(access.Permissions)
+	for _, tag := range access.AllTypicalTags() {
+		expectedAccessList[string(tag)] = access.AccessList{In: []security.BlessingPattern{"root/$", "root/self/$", "root/self/mydevice/$"}}
+	}
+	var b bytes.Buffer
+	if err := expectedAccessList.WriteTo(&b); err != nil {
+		t.Fatalf("Failed to save AccessList:%v", err)
+	}
+	// Note, "version" below refers to the Permissions version, not the device
+	// manager version.
+	md5hash := md5.Sum(b.Bytes())
+	expectedVersion := hex.EncodeToString(md5hash[:])
+	deviceStub := device.DeviceClient("dm/device")
+	perms, version, err := deviceStub.GetPermissions(selfCtx)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if version != expectedVersion {
+		t.Fatalf("getAccessList expected:%v(%v), got:%v(%v)", expectedAccessList, expectedVersion, perms, version)
+	}
+	// Install from octx should fail, since it does not match the AccessList.
+	utiltest.InstallAppExpectError(t, octx, verror.ErrNoAccess.ID)
+
+	newAccessList := make(access.Permissions)
+	for _, tag := range access.AllTypicalTags() {
+		newAccessList.Add("root/other", string(tag))
+	}
+	if err := deviceStub.SetPermissions(selfCtx, newAccessList, "invalid"); err == nil {
+		t.Fatalf("SetPermissions should have failed with invalid version")
+	}
+	if err := deviceStub.SetPermissions(selfCtx, newAccessList, version); err != nil {
+		t.Fatal(err)
+	}
+	// Install should now fail with selfCtx, which no longer matches the
+	// AccessLists but succeed with octx, which does.
+	utiltest.InstallAppExpectError(t, selfCtx, verror.ErrNoAccess.ID)
+	utiltest.InstallApp(t, octx)
+}
diff --git a/services/device/internal/impl/reaping/impl_test.go b/services/device/internal/impl/reaping/impl_test.go
index abc7f7a..66d1c4e 100644
--- a/services/device/internal/impl/reaping/impl_test.go
+++ b/services/device/internal/impl/reaping/impl_test.go
@@ -14,8 +14,6 @@
 	utiltest.TestMainImpl(m)
 }
 
-// TestSuidHelper is testing boilerplate for suidhelper that does not
-// create a runtime because the suidhelper is not a Vanadium application.
 func TestSuidHelper(t *testing.T) {
 	utiltest.TestSuidHelperImpl(t)
 }
diff --git a/services/device/internal/impl/utiltest/helpers.go b/services/device/internal/impl/utiltest/helpers.go
index 5b753c0..4e82508 100644
--- a/services/device/internal/impl/utiltest/helpers.go
+++ b/services/device/internal/impl/utiltest/helpers.go
@@ -33,6 +33,7 @@
 	"v.io/v23/services/stats"
 	"v.io/v23/verror"
 
+	"v.io/x/ref/envvar"
 	_ "v.io/x/ref/profiles/roaming"
 	"v.io/x/ref/services/device/internal/impl"
 	"v.io/x/ref/services/internal/servicetest"
@@ -665,3 +666,13 @@
 	}
 	return u.Username
 }
+
+func InitForTest() (*context.T, v23.Shutdown) {
+	roots, _ := envvar.NamespaceRoots()
+	for key, _ := range roots {
+		os.Unsetenv(key)
+	}
+	ctx, shutdown := test.InitForTest()
+	v23.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
+	return ctx, shutdown
+}
diff --git a/services/mounttable/mounttablelib/mounttable.go b/services/mounttable/mounttablelib/mounttable.go
index 7ba7f4e..3b87098 100644
--- a/services/mounttable/mounttablelib/mounttable.go
+++ b/services/mounttable/mounttablelib/mounttable.go
@@ -534,7 +534,7 @@
 // removeUselessRecursive removes any useless nodes on the tail of the path.
 func (mt *mountTable) removeUselessRecursive(elems []string) {
 	for i := len(elems); i > 0; i-- {
-		n, nelems, _ := mt.traverse(nil, nil, elems[:i-1], false)
+		n, nelems, _ := mt.traverse(nil, nil, elems[:i], false)
 		if n == nil {
 			break
 		}
diff --git a/services/mounttable/mounttablelib/mounttable_test.go b/services/mounttable/mounttablelib/mounttable_test.go
index 5704ef1..5f0da6e 100644
--- a/services/mounttable/mounttablelib/mounttable_test.go
+++ b/services/mounttable/mounttablelib/mounttable_test.go
@@ -506,6 +506,7 @@
 
 	// After the unmount nothing should be left
 	doUnmount(t, rootCtx, estr, "one/bright/day", "", true)
+	checkMatch(t, nil, doGlob(t, rootCtx, estr, "", "one"))
 	checkMatch(t, nil, doGlob(t, rootCtx, estr, "", "*/..."))
 
 	// Set up a mount, then set the AccessList.