Skip to content

Commit

Permalink
Fix: move_ent with signed binpkg
Browse files Browse the repository at this point in the history
The gpkg file that cannot be updated will be removed.

Signed-off-by: Sheng Yu <syu.os@protonmail.com>
  • Loading branch information
syu-nya committed Dec 8, 2023
1 parent 1d85674 commit caf914d
Show file tree
Hide file tree
Showing 7 changed files with 436 additions and 5 deletions.
21 changes: 20 additions & 1 deletion lib/portage/dbapi/bintree.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,24 @@ def aux_update(self, cpv, values):
elif binpkg_format == "gpkg":
mybinpkg = portage.gpkg.gpkg(self.settings, cpv_str, binpkg_path)
mydata = mybinpkg.get_metadata()
if mybinpkg.signature_exist:
writemsg(
colorize(
"WARN",
f"Binpkg update ignored for signed package: {binpkg_path}, "
"the file will be removed.",
)
)
try:
os.remove(binpkg_path)
except OSError as err:
writemsg(
colorize(
"WARN",
f"Failed to remove moved signed package: {binpkg_path} {str(err)}",
)
)
return
encoding_key = False
else:
raise InvalidBinaryPackageFormat(
Expand Down Expand Up @@ -687,7 +705,6 @@ def move_ent(self, mylist, repo_match=None):
)
continue

moves += 1
binpkg_format = get_binpkg_format(binpkg_path)
if binpkg_format == "xpak":
mytbz2 = portage.xpak.tbz2(binpkg_path)
Expand All @@ -708,6 +725,8 @@ def move_ent(self, mylist, repo_match=None):
else:
continue

moves += 1

updated_items = update_dbentries([mylist], mydata, parent=mycpv)
mydata.update(updated_items)
if decode_metadata_name:
Expand Down
4 changes: 4 additions & 0 deletions lib/portage/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ class CompressorOperationFailed(PortagePackageException):
"""An error occurred during external operation"""


class SignedPackage(PortagePackageException):
"""Unable to update a signed package"""


class InvalidAtom(PortagePackageException):
"""Malformed atom spec"""

Expand Down
6 changes: 5 additions & 1 deletion lib/portage/gpkg.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
DigestException,
MissingSignature,
InvalidSignature,
SignedPackage,
)
from portage.output import colorize, EOutput
from portage.util._urlopen import urlopen
Expand Down Expand Up @@ -991,14 +992,17 @@ def decompress(self, decompress_dir):
finally:
image_tar.kill()

def update_metadata(self, metadata, new_basename=None):
def update_metadata(self, metadata, new_basename=None, force=False):
"""
Update metadata in the gpkg file.
"""
self._verify_binpkg()
self.checksums = []
old_basename = self.prefix

if self.signature_exist and not force:
raise SignedPackage("Cannot update a signed gpkg file")

if new_basename is None:
new_basename = old_basename
else:
Expand Down
2 changes: 1 addition & 1 deletion lib/portage/tests/gpkg/test_gpkg_metadata_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class test_gpkg_metadata_case(TestCase):
def test_gpkg_update_metadata(self):
playground = ResolverPlayground(
user_config={
"make.conf": ('BINPKG_COMPRESS="gzip"',),
"make.conf": ('BINPKG_COMPRESS="gzip"', 'FEATURES="-binpkg-signing"'),
}
)
tmpdir = tempfile.mkdtemp()
Expand Down
108 changes: 108 additions & 0 deletions lib/portage/tests/update/test_move_ent.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,111 @@ def testMoveEnt(self):

finally:
playground.cleanup()

def testMoveEntWithSignature(self):
ebuilds = {
"dev-libs/A-2::dont_apply_updates": {
"EAPI": "4",
"SLOT": "2",
},
}

installed = {
"dev-libs/A-1::test_repo": {
"EAPI": "4",
},
"dev-libs/A-2::dont_apply_updates": {
"EAPI": "4",
"SLOT": "2",
},
}

binpkgs = {
"dev-libs/A-1::test_repo": {
"EAPI": "4",
},
"dev-libs/A-2::dont_apply_updates": {
"EAPI": "4",
"SLOT": "2",
},
}

updates = textwrap.dedent(
"""
move dev-libs/A dev-libs/A-moved
"""
)

for binpkg_format in ("gpkg",):
with self.subTest(binpkg_format=binpkg_format):
print(colorize("HILITE", binpkg_format), end=" ... ")
sys.stdout.flush()
playground = ResolverPlayground(
binpkgs=binpkgs,
ebuilds=ebuilds,
installed=installed,
user_config={
"make.conf": (f'BINPKG_FORMAT="{binpkg_format}"',),
},
)

settings = playground.settings
trees = playground.trees
eroot = settings["EROOT"]
test_repo_location = settings.repositories["test_repo"].location
portdb = trees[eroot]["porttree"].dbapi
vardb = trees[eroot]["vartree"].dbapi
bindb = trees[eroot]["bintree"].dbapi

updates_dir = os.path.join(test_repo_location, "profiles", "updates")

try:
ensure_dirs(updates_dir)
with open(os.path.join(updates_dir, "1Q-2010"), "w") as f:
f.write(updates)

# Create an empty updates directory, so that this
# repo doesn't inherit updates from the main repo.
ensure_dirs(
os.path.join(
portdb.getRepositoryPath("dont_apply_updates"),
"profiles",
"updates",
)
)

global_noiselimit = portage.util.noiselimit
portage.util.noiselimit = -2
try:
_do_global_updates(trees, {})
finally:
portage.util.noiselimit = global_noiselimit

# Workaround for cache validation not working
# correctly when filesystem has timestamp precision
# of 1 second.
vardb._clear_cache()

# A -> A-moved
self.assertRaises(KeyError, vardb.aux_get, "dev-libs/A-1", ["EAPI"])
vardb.aux_get("dev-libs/A-moved-1", ["EAPI"])
# The original package should still exist because a binary
# package move is a copy on write operation.
bindb.aux_get("dev-libs/A-1", ["EAPI"])
print(bindb.aux_get("dev-libs/A-1", "PF"))
self.assertRaises(
KeyError, bindb.aux_get, "dev-libs/A-moved-1", ["EAPI"]
)

# dont_apply_updates
self.assertRaises(
KeyError, vardb.aux_get, "dev-libs/A-moved-2", ["EAPI"]
)
vardb.aux_get("dev-libs/A-2", ["EAPI"])
self.assertRaises(
KeyError, bindb.aux_get, "dev-libs/A-moved-2", ["EAPI"]
)
bindb.aux_get("dev-libs/A-2", ["EAPI"])

finally:
playground.cleanup()
148 changes: 147 additions & 1 deletion lib/portage/tests/update/test_move_slot_ent.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,10 @@ def testMoveSlotEnt(self):
ebuilds=ebuilds,
installed=installed,
user_config={
"make.conf": (f'BINPKG_FORMAT="{binpkg_format}"',),
"make.conf": (
f'BINPKG_FORMAT="{binpkg_format}"',
'FEATURES="-binpkg-signing"',
),
},
)

Expand Down Expand Up @@ -154,3 +157,146 @@ def testMoveSlotEnt(self):

finally:
playground.cleanup()

def testMoveSlotEntWithSignature(self):
ebuilds = {
"dev-libs/A-2::dont_apply_updates": {
"EAPI": "5",
"SLOT": "0/2.30",
},
"dev-libs/B-2::dont_apply_updates": {
"SLOT": "0",
},
"dev-libs/C-2.1::dont_apply_updates": {
"EAPI": "5",
"SLOT": "0/2.1",
},
}

installed = {
"dev-libs/A-1::test_repo": {
"EAPI": "5",
"SLOT": "0/2.30",
},
"dev-libs/B-1::test_repo": {
"SLOT": "0",
},
"dev-libs/C-1::test_repo": {
"EAPI": "5",
"SLOT": "0/1",
},
}

binpkgs = {
"dev-libs/A-1::test_repo": {
"EAPI": "5",
"SLOT": "0/2.30",
},
"dev-libs/A-2::dont_apply_updates": {
"EAPI": "5",
"SLOT": "0/2.30",
},
"dev-libs/B-1::test_repo": {
"SLOT": "0",
},
"dev-libs/B-2::dont_apply_updates": {
"SLOT": "0",
},
"dev-libs/C-1::test_repo": {
"EAPI": "5",
"SLOT": "0/1",
},
"dev-libs/C-2.1::dont_apply_updates": {
"EAPI": "5",
"SLOT": "0/2.1",
},
}

updates = textwrap.dedent(
"""
slotmove dev-libs/A 0 2
slotmove dev-libs/B 0 1
slotmove dev-libs/C 0 1
"""
)

for binpkg_format in ("gpkg",):
with self.subTest(binpkg_format=binpkg_format):
print(colorize("HILITE", binpkg_format), end=" ... ")
sys.stdout.flush()
playground = ResolverPlayground(
binpkgs=binpkgs,
ebuilds=ebuilds,
installed=installed,
user_config={
"make.conf": (
f'BINPKG_FORMAT="{binpkg_format}"',
'FEATURES="binpkg-signing"',
),
},
)

settings = playground.settings
trees = playground.trees
eroot = settings["EROOT"]
test_repo_location = settings.repositories["test_repo"].location
portdb = trees[eroot]["porttree"].dbapi
vardb = trees[eroot]["vartree"].dbapi
bindb = trees[eroot]["bintree"].dbapi

updates_dir = os.path.join(test_repo_location, "profiles", "updates")

try:
ensure_dirs(updates_dir)
with open(os.path.join(updates_dir, "1Q-2010"), "w") as f:
f.write(updates)

# Create an empty updates directory, so that this
# repo doesn't inherit updates from the main repo.
ensure_dirs(
os.path.join(
portdb.getRepositoryPath("dont_apply_updates"),
"profiles",
"updates",
)
)

global_noiselimit = portage.util.noiselimit
portage.util.noiselimit = -2
try:
_do_global_updates(trees, {})
finally:
portage.util.noiselimit = global_noiselimit

# Workaround for cache validation not working
# correctly when filesystem has timestamp precision
# of 1 second.
vardb._clear_cache()

# 0/2.30 -> 2/2.30
self.assertEqual(
"2/2.30", vardb.aux_get("dev-libs/A-1", ["SLOT"])[0]
)
self.assertEqual(
"0/2.30", bindb.aux_get("dev-libs/A-1", ["SLOT"])[0]
)

# 0 -> 1
self.assertEqual("1", vardb.aux_get("dev-libs/B-1", ["SLOT"])[0])
self.assertEqual("0", bindb.aux_get("dev-libs/B-1", ["SLOT"])[0])

# 0/1 -> 1 (equivalent to 1/1)
self.assertEqual("1", vardb.aux_get("dev-libs/C-1", ["SLOT"])[0])
self.assertEqual("0/1", bindb.aux_get("dev-libs/C-1", ["SLOT"])[0])

# dont_apply_updates
self.assertEqual(
"0/2.30", bindb.aux_get("dev-libs/A-2", ["SLOT"])[0]
)
self.assertEqual("0", bindb.aux_get("dev-libs/B-2", ["SLOT"])[0])
self.assertEqual(
"0/2.1", bindb.aux_get("dev-libs/C-2.1", ["SLOT"])[0]
)

finally:
playground.cleanup()

0 comments on commit caf914d

Please sign in to comment.