api: controller: Fix pb2_path_to_pathlib_path() chroot assumptions

It's not valid to do path concatenation or subtraction using
chroot.path. Use chroot_lib instead.

BUG=b:265885353
TEST=./run_tests

Change-Id: I1f5be1b97a16bdb0f91ee66b0e657aa71c9c501d
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/4661950
Reviewed-by: Greg Edelston <gredelston@google.com>
Tested-by: Brian Norris <briannorris@chromium.org>
Commit-Queue: Brian Norris <briannorris@chromium.org>
diff --git a/api/controller/controller_util.py b/api/controller/controller_util.py
index 054838a..04a6f5e 100644
--- a/api/controller/controller_util.py
+++ b/api/controller/controller_util.py
@@ -317,5 +317,4 @@
         return Path(pb2_path.path)
     if chroot is None:
         raise ValueError("Cannot convert inside path without a chroot.")
-    path_relative_to_root = pb2_path.path[1:]
-    return Path(chroot.path, path_relative_to_root)
+    return Path(ParseChroot(chroot).full_path(pb2_path.path))
diff --git a/api/controller/controller_util_unittest.py b/api/controller/controller_util_unittest.py
index fe2adf1..545681c 100644
--- a/api/controller/controller_util_unittest.py
+++ b/api/controller/controller_util_unittest.py
@@ -13,6 +13,7 @@
 from chromite.lib import binpkg
 from chromite.lib import build_target_lib
 from chromite.lib import chroot_lib
+from chromite.lib import cros_build_lib
 from chromite.lib import cros_test_lib
 from chromite.lib import sysroot_lib
 from chromite.lib.parser import package_info
@@ -229,10 +230,13 @@
     assert obj == controller_util.deserialize_package_index_info(msg)
 
 
-class Pb2PathToPathlibPathTest(cros_test_lib.TestCase):
+class Pb2PathToPathlibPathTest(cros_test_lib.MockTestCase):
     """Verify functionality for pb2_path_to_pathlib_path()."""
 
-    chroot = common_pb2.Chroot(path="/path/to/chroot")
+    chroot = common_pb2.Chroot(path="/path/to/chroot", out_path="/path/to/out")
+
+    def setUp(self):
+        self.PatchObject(cros_build_lib, "IsInsideChroot", return_value=False)
 
     @staticmethod
     def create_pb2_path(path: str, inside: bool) -> common_pb2.Path:
diff --git a/api/controller/sdk_unittest.py b/api/controller/sdk_unittest.py
index 014e281..0ca944f 100644
--- a/api/controller/sdk_unittest.py
+++ b/api/controller/sdk_unittest.py
@@ -5,7 +5,7 @@
 """SDK tests."""
 
 import os
-import pathlib
+from pathlib import Path
 from typing import List, Optional
 from unittest import mock
 
@@ -13,6 +13,7 @@
 from chromite.api.controller import sdk as sdk_controller
 from chromite.api.gen.chromite.api import sdk_pb2
 from chromite.api.gen.chromiumos import common_pb2
+from chromite.lib import chroot_lib
 from chromite.lib import constants
 from chromite.lib import cros_build_lib
 from chromite.lib import cros_test_lib
@@ -369,16 +370,17 @@
 ):
     """Test the SdkService/CreateManifestFromSdk endpoint."""
 
-    _chroot_path = "/path/to/chroot"
-    _sdk_path_relative = "build/my_sdk"
+    _sdk_path = "/build/my_sdk"
     _dest_dir = "/build"
     _manifest_path = "/build/my_sdk.Manifest"
 
     def _NewRequest(self, inside: bool) -> sdk_pb2.CreateManifestFromSdkRequest:
         return sdk_pb2.CreateManifestFromSdkRequest(
-            chroot=common_pb2.Chroot(path=self._chroot_path),
+            chroot=common_pb2.Chroot(
+                path=self.chroot.path, out_path=str(self.chroot.out_path)
+            ),
             sdk_path=common_pb2.Path(
-                path="/%s" % self._sdk_path_relative,
+                path=self._sdk_path,
                 location=common_pb2.Path.Location.INSIDE
                 if inside
                 else common_pb2.Path.Location.OUTSIDE,
@@ -392,6 +394,14 @@
     def _NewResponse(self) -> sdk_pb2.CreateManifestFromSdkResponse:
         return sdk_pb2.CreateManifestFromSdkResponse()
 
+    def setUp(self):
+        self.PatchObject(cros_build_lib, "IsInsideChroot", return_value=False)
+
+        self.chroot = chroot_lib.Chroot(
+            path=Path("/path/to/chroot"),
+            out_path=Path("/path/to/out"),
+        )
+
     def testValidateOnly(self):
         """Check that a validate only call does not execute any logic."""
         impl_patch = self.PatchObject(sdk_service, "CreateManifestFromSdk")
@@ -407,7 +417,7 @@
         impl_patch = self.PatchObject(
             sdk_service,
             "CreateManifestFromSdk",
-            return_value=pathlib.Path(self._manifest_path),
+            return_value=Path(self._manifest_path),
         )
         request = self._NewRequest(inside=False)
         response = self._NewResponse()
@@ -417,8 +427,8 @@
             self.api_config,
         )
         impl_patch.assert_called_with(
-            pathlib.Path("/", self._sdk_path_relative),
-            pathlib.Path(self._dest_dir),
+            Path(self._sdk_path),
+            Path(self._dest_dir),
         )
         self.assertEqual(
             response.manifest_path.location, common_pb2.Path.Location.OUTSIDE
@@ -430,7 +440,7 @@
         impl_patch = self.PatchObject(
             sdk_service,
             "CreateManifestFromSdk",
-            return_value=pathlib.Path(self._manifest_path),
+            return_value=Path(self._manifest_path),
         )
         request = self._NewRequest(inside=True)
         response = self._NewResponse()
@@ -440,8 +450,8 @@
             self.api_config,
         )
         impl_patch.assert_called_with(
-            pathlib.Path(self._chroot_path, self._sdk_path_relative),
-            pathlib.Path(self._dest_dir),
+            Path(self.chroot.full_path(self._sdk_path)),
+            Path(self._dest_dir),
         )
         self.assertEqual(
             response.manifest_path.location, common_pb2.Path.Location.OUTSIDE