def testGetDeps(self): f = open(resources.get_archive() + "/gnome-main-menu-0.9.10-26.x86_64.rpm") h = rpmhelper.readHeader(f) req, prov = h.getDeps(enableRPMVersionDeps=False) self.assertEqual( req.freeze(), "3#/bin/sh|3#/sbin/ldconfig|3#/usr/bin/gconftool-2|16#coreutils|16#dbus-1-glib|16#eel|16#gnome-main-menu-lang|16#gnome-panel|16#hal|16#libICE.so.6[64bit]|16#libORBit-2.so.0[64bit]|16#libORBitCosNaming-2.so.0[64bit]|16#libSM.so.6[64bit]|16#libX11.so.6[64bit]|16#libXau.so.6[64bit]|16#libXrender.so.1[64bit]|16#libart_lgpl_2.so.2[64bit]|16#libasound.so.2[64bit]|16#libatk-1.0.so.0[64bit]|16#libaudiofile.so.0[64bit]|16#libavahi-client.so.3[64bit]|16#libavahi-common.so.3[64bit]|16#libavahi-glib.so.1[64bit]|16#libbonobo-2.so.0[64bit]|16#libbonobo-activation.so.4[64bit]|16#libbonoboui-2.so.0[64bit]|16#libc.so.6[64bit]:GLIBC_2.2.5:GLIBC_2.3.4:GLIBC_2.4|16#libcairo.so.2[64bit]|16#libcrypto.so.0.9.8[64bit]|16#libdbus-1.so.3[64bit]|16#libdbus-glib-1.so.2[64bit]|16#libdl.so.2[64bit]|16#libeel-2.so.2[64bit]|16#libesd.so.0[64bit]|16#libexpat.so.1[64bit]|16#libfontconfig.so.1[64bit]|16#libfreetype.so.6[64bit]|16#libgailutil.so.18[64bit]|16#libgconf-2.so.4[64bit]|16#libgdk-x11-2.0.so.0[64bit]|16#libgdk_pixbuf-2.0.so.0[64bit]|16#libgio-2.0.so.0[64bit]|16#libglade-2.0.so.0[64bit]|16#libglib-2.0.so.0[64bit]|16#libglitz.so.1[64bit]|16#libgmodule-2.0.so.0[64bit]|16#libgnome-2.so.0[64bit]|16#libgnome-desktop-2.so.2[64bit]|16#libgnome-keyring.so.0[64bit]|16#libgnome-menu.so.2[64bit]|16#libgnomecanvas-2.so.0[64bit]|16#libgnomeui-2.so.0[64bit]|16#libgnomevfs-2.so.0[64bit]|16#libgobject-2.0.so.0[64bit]|16#libgthread-2.0.so.0[64bit]|16#libgtk-x11-2.0.so.0[64bit]|16#libgtop-2.0.so.7[64bit]|16#libhal-storage.so.1[64bit]|16#libhal.so.1[64bit]|16#libiw.so.29[64bit]|16#libjpeg.so.62[64bit]|16#libm.so.6[64bit]|16#libnm-util.so.0[64bit]|16#libnm_glib.so.0[64bit]|16#libnsl.so.1[64bit]|16#libnspr4.so[64bit]|16#libnss3.so[64bit]|16#libnssutil3.so[64bit]|16#libpanel-applet-2.so.0[64bit]|16#libpango-1.0.so.0[64bit]|16#libpangocairo-1.0.so.0[64bit]|16#libpangoft2-1.0.so.0[64bit]|16#libpcre.so.0[64bit]|16#libplc4.so[64bit]|16#libplds4.so[64bit]|16#libpng12.so.0[64bit]|16#libpopt.so.0[64bit]|16#libpthread.so.0[64bit]:GLIBC_2.2.5|16#libresolv.so.2[64bit]|16#librsvg-2.so.2[64bit]|16#librt.so.1[64bit]|16#libslab.so.0[64bit]|16#libsmime3.so[64bit]|16#libssl.so.0.9.8[64bit]|16#libssl3.so[64bit]|16#libssui|16#libstartup-notification-1.so.0[64bit]|16#libutil.so.1[64bit]|16#libuuid.so.1[64bit]|16#libxcb-render-util.so.0[64bit]|16#libxcb-render.so.0[64bit]|16#libxcb-xlib.so.0[64bit]|16#libxcb.so.1[64bit]|16#libxml2.so.2[64bit]|16#libz.so.1[64bit]|16#tango-icon-theme|16#wireless-tools|17#CompressedFileNames|17#PayloadFilesHavePrefix|17#PayloadIsLzma", ) self.assertEqual(prov.freeze(), "16#gnome-main-menu|16#libslab.so.0[64bit]") f = open(resources.get_archive() + "/popt-1.5-4x.i386.rpm") h = rpmhelper.readHeader(f) req, prov = h.getDeps() self.assertEqual(req.freeze(), "") self.assertEqual(prov.freeze(), "16#libpopt.so.0")
def testRpmVersionDepsRelase(self): rpmName = "versiondeps-bar-1-2.x86_64.rpm" rpmPath = os.path.join(self.archiveDir, rpmName) fileObj = file(rpmPath) header = rpmhelper.readHeader(fileObj) reqset, provset = header.getDeps() self.assertEquals( str(reqset), "\n".join( ( "rpm: baz", "rpm: baz-2:1.0-el5", "rpm: versiondeps", "rpm: versiondeps-1", "rpmlib: CompressedFileNames", "rpmlib: PayloadFilesHavePrefix", ) ), ) self.assertEquals( str(provset), "\n".join( ( "rpm: versiondeps-bar", "rpm: versiondeps-bar-2:1", "rpm: versiondeps-bar-2:1-2", "rpm: versiondeps-bar[x86-64]", "rpm: versiondeps-bar[x86-64]-2:1", "rpm: versiondeps-bar[x86-64]-2:1-2", ) ), )
def testVerifySig(self): rpmName = 'tmpwatch-2.9.7-1.1.el5.2.x86_64.rpm' rpmPath = os.path.join(self.archiveDir, rpmName) fileObj = file(rpmPath) header = rpmhelper.readHeader(fileObj) from conary.lib import openpgpfile sig = openpgpfile.readSignature(header[rpmhelper.SIG_GPG]) fileObj.seek(0) rpmhelper.readSignatureHeader(fileObj) k = openpgpfile.getKeyFromString( 'E8562897', openpgpfile.parseAsciiArmorKey(pgpKeyCentos)) rpmhelper.verifySignatures(fileObj, [k]) # Similar deal, fileObj is an ExtendedFile fileObj = util.ExtendedFile(rpmPath, buffering=False) rpmhelper.verifySignatures(fileObj, [k]) # Finally, StringIO fileObj.seek(0) fileObj = StringIO.StringIO(fileObj.read()) rpmhelper.verifySignatures(fileObj, [k]) # Replace last byte fileObj = StringIO.StringIO(fileObj.getvalue()[:-1]) fileObj.seek(0, 2) fileObj.write("\xff") fileObj.seek(0) e = self.assertRaises(rpmhelper.MD5SignatureError, rpmhelper.verifySignatures, fileObj, [k]) self.assertEqual( str(e), 'The MD5 digest fails to verify: ' 'expected 6cc7c546c3a5de90bb272b11be2f3d67, got 744d88f4164ec2974b49839a69ea589d' )
def testVerifySig(self): rpmName = "tmpwatch-2.9.7-1.1.el5.2.x86_64.rpm" rpmPath = os.path.join(self.archiveDir, rpmName) fileObj = file(rpmPath) header = rpmhelper.readHeader(fileObj) from conary.lib import openpgpfile sig = openpgpfile.readSignature(header[rpmhelper.SIG_GPG]) fileObj.seek(0) rpmhelper.readSignatureHeader(fileObj) k = openpgpfile.getKeyFromString("E8562897", openpgpfile.parseAsciiArmorKey(pgpKeyCentos)) rpmhelper.verifySignatures(fileObj, [k]) # Similar deal, fileObj is an ExtendedFile fileObj = util.ExtendedFile(rpmPath, buffering=False) rpmhelper.verifySignatures(fileObj, [k]) # Finally, StringIO fileObj.seek(0) fileObj = StringIO.StringIO(fileObj.read()) rpmhelper.verifySignatures(fileObj, [k]) # Replace last byte fileObj = StringIO.StringIO(fileObj.getvalue()[:-1]) fileObj.seek(0, 2) fileObj.write("\xff") fileObj.seek(0) e = self.assertRaises(rpmhelper.MD5SignatureError, rpmhelper.verifySignatures, fileObj, [k]) self.assertEqual( str(e), "The MD5 digest fails to verify: " "expected 6cc7c546c3a5de90bb272b11be2f3d67, got 744d88f4164ec2974b49839a69ea589d", )
def _index(self, rpm): """ Index an individual rpm. """ fh = rpmheader.SeekableStream(rpm) h = rpmhelper.readHeader(fh) name = h[rpmhelper.NAME] epoch = h.get(rpmhelper.EPOCH, None) if isinstance(epoch, (list, tuple)): assert len(epoch) == 1 epoch = str(epoch[0]) version = h[rpmhelper.VERSION] release = h[rpmhelper.RELEASE] arch = h.isSource and 'src' or h[rpmhelper.ARCH] sourcename = h.get(rpmhelper.SOURCERPM, None) basename = os.path.basename(rpm) pkg = Package(name=name, epoch=epoch, version=version, release=release, arch=arch, sourcerpm=sourcename, location=basename) return pkg
def testRpmDepsPerl(self): rpmName = 'perl-Archive-Tar-1.46-68.fc11.x86_64.rpm' rpmPath = os.path.join(self.archiveDir, rpmName) fileObj = file(rpmPath) header = rpmhelper.readHeader(fileObj) reqset, provset = header.getDeps(enableRPMVersionDeps=False) self.assertEquals( str(reqset), '\n'.join( ('file: /usr/bin/perl', 'rpm: perl', 'rpm: perl[Archive::Tar::Constant]', 'rpm: perl[Archive::Tar::File]', 'rpm: perl[Archive::Tar]', 'rpm: perl[Carp]', 'rpm: perl[Compress::Zlib]', 'rpm: perl[Config]', 'rpm: perl[Cwd]', 'rpm: perl[Data::Dumper]', 'rpm: perl[Exporter]', 'rpm: perl[File::Basename]', 'rpm: perl[File::Find]', 'rpm: perl[File::Path]', 'rpm: perl[File::Spec::Unix]', 'rpm: perl[File::Spec]', 'rpm: perl[Getopt::Std]', 'rpm: perl[IO::File]', 'rpm: perl[IO::Handle]', 'rpm: perl[IO::Zlib]', 'rpm: perl[Package::Constants]', 'rpm: perl[constant]', 'rpm: perl[strict]', 'rpm: perl[vars]', 'rpmlib: CompressedFileNames', 'rpmlib: FileDigests', 'rpmlib: PayloadFilesHavePrefix', 'rpmlib: VersionedDependencies'))) self.assertEquals( str(provset), '\n'.join( ('rpm: perl-Archive-Tar', 'rpm: perl-Archive-Tar[x86-64]', 'rpm: perl[Archive::Tar::Constant]', 'rpm: perl[Archive::Tar::File]', 'rpm: perl[Archive::Tar]')))
def testRPMSHA1SigTag(self): """make sure that SHA1HEADER/SIG_SHA1 is represented in troveinfo""" recipestr = """ class TestRPMSHA1(CapsuleRecipe): name = 'simple' version = '1.0' clearBuildReqs() def setup(r): r.addCapsule('simple-1.0-1.i386.rpm') """ pkgName = "simple" rpmName = "simple-1.0-1.i386.rpm" r = self._cookPkgs(recipestr, rpmName, pkgName, "simple") trvCs = [x for x in r[2].iterNewTroveList() if x.getName() == "simple:rpm"][0] archivePath = resources.get_archive() trv = trove.Trove(trvCs) f = open(archivePath + "/" + rpmName, "r") h = rpmhelper.readHeader(f) sha1header = trv.troveInfo.capsule.rpm.sha1header() self.assertEqual(h.get(rpmhelper.SIG_SHA1), sha1helper.sha1ToString(sha1header))
def testRPMObsoletes(self): '''make sure that obsoletes is represented in troveinfo''' recipestr = """ class TestRPMObsoletes(CapsuleRecipe): name = 'obsolete' version = '1.0' clearBuildReqs() def setup(r): r.addCapsule('obsolete-1.0-1.i386.rpm') """ pkgName = 'obsolete' rpmName = 'obsolete-1.0-1.i386.rpm' r1 = self._cookPkgs(recipestr, rpmName, pkgName, 'obsolete') trvCs = [ x for x in r1[2].iterNewTroveList() if x.getName() == 'obsolete:rpm' ][0] archivePath = resources.get_archive() trv = trove.Trove(trvCs) f = open(archivePath + '/' + rpmName, "r") h = rpmhelper.readHeader(f) obs = [x[1] for x in trv.troveInfo.capsule.rpm.obsoletes.iterAll()] obl = [(x.name(), x.flags(), x.version()) for x in obs] obl.sort() reference = [('bar', 2L, '1.0'), ('baz', 4L, '2.0'), ('foo', 0L, '')] self.assertEqual(obl, reference)
def testRPMObsoletes(self): """make sure that obsoletes is represented in troveinfo""" recipestr = """ class TestRPMObsoletes(CapsuleRecipe): name = 'obsolete' version = '1.0' clearBuildReqs() def setup(r): r.addCapsule('obsolete-1.0-1.i386.rpm') """ pkgName = "obsolete" rpmName = "obsolete-1.0-1.i386.rpm" r1 = self._cookPkgs(recipestr, rpmName, pkgName, "obsolete") trvCs = [x for x in r1[2].iterNewTroveList() if x.getName() == "obsolete:rpm"][0] archivePath = resources.get_archive() trv = trove.Trove(trvCs) f = open(archivePath + "/" + rpmName, "r") h = rpmhelper.readHeader(f) obs = [x[1] for x in trv.troveInfo.capsule.rpm.obsoletes.iterAll()] obl = [(x.name(), x.flags(), x.version()) for x in obs] obl.sort() reference = [("bar", 2L, "1.0"), ("baz", 4L, "2.0"), ("foo", 0L, "")] self.assertEqual(obl, reference)
def testRPMSHA1SigTag(self): '''make sure that SHA1HEADER/SIG_SHA1 is represented in troveinfo''' recipestr = """ class TestRPMSHA1(CapsuleRecipe): name = 'simple' version = '1.0' clearBuildReqs() def setup(r): r.addCapsule('simple-1.0-1.i386.rpm') """ pkgName = 'simple' rpmName = 'simple-1.0-1.i386.rpm' r = self._cookPkgs(recipestr, rpmName, pkgName, 'simple') trvCs = [ x for x in r[2].iterNewTroveList() if x.getName() == 'simple:rpm' ][0] archivePath = resources.get_archive() trv = trove.Trove(trvCs) f = open(archivePath + '/' + rpmName, "r") h = rpmhelper.readHeader(f) sha1header = trv.troveInfo.capsule.rpm.sha1header() self.assertEqual(h.get(rpmhelper.SIG_SHA1), sha1helper.sha1ToString(sha1header))
def testCorruptedRpm(self): # test enforcement of size and sha1 fields from rpm signature block f = open(resources.get_archive() + "/basesystem-8.0-2.src.rpm") rpmhelper.readHeader(f) f.seek(0) # change the size tmp = tempfile.TemporaryFile() util.copyfileobj(f, tmp) f.seek(0) tmp.write(" ") tmp.seek(0) try: rpmhelper.readHeader(tmp) except IOError, e: assert str(e) == "file size does not match size specified by " "header"
def testGetDeps(self): f = open(resources.get_archive() + '/gnome-main-menu-0.9.10-26.x86_64.rpm') h = rpmhelper.readHeader(f) req, prov = h.getDeps(enableRPMVersionDeps=False) self.assertEqual( req.freeze(), '3#/bin/sh|3#/sbin/ldconfig|3#/usr/bin/gconftool-2|16#coreutils|16#dbus-1-glib|16#eel|16#gnome-main-menu-lang|16#gnome-panel|16#hal|16#libICE.so.6[64bit]|16#libORBit-2.so.0[64bit]|16#libORBitCosNaming-2.so.0[64bit]|16#libSM.so.6[64bit]|16#libX11.so.6[64bit]|16#libXau.so.6[64bit]|16#libXrender.so.1[64bit]|16#libart_lgpl_2.so.2[64bit]|16#libasound.so.2[64bit]|16#libatk-1.0.so.0[64bit]|16#libaudiofile.so.0[64bit]|16#libavahi-client.so.3[64bit]|16#libavahi-common.so.3[64bit]|16#libavahi-glib.so.1[64bit]|16#libbonobo-2.so.0[64bit]|16#libbonobo-activation.so.4[64bit]|16#libbonoboui-2.so.0[64bit]|16#libc.so.6[64bit]:GLIBC_2.2.5:GLIBC_2.3.4:GLIBC_2.4|16#libcairo.so.2[64bit]|16#libcrypto.so.0.9.8[64bit]|16#libdbus-1.so.3[64bit]|16#libdbus-glib-1.so.2[64bit]|16#libdl.so.2[64bit]|16#libeel-2.so.2[64bit]|16#libesd.so.0[64bit]|16#libexpat.so.1[64bit]|16#libfontconfig.so.1[64bit]|16#libfreetype.so.6[64bit]|16#libgailutil.so.18[64bit]|16#libgconf-2.so.4[64bit]|16#libgdk-x11-2.0.so.0[64bit]|16#libgdk_pixbuf-2.0.so.0[64bit]|16#libgio-2.0.so.0[64bit]|16#libglade-2.0.so.0[64bit]|16#libglib-2.0.so.0[64bit]|16#libglitz.so.1[64bit]|16#libgmodule-2.0.so.0[64bit]|16#libgnome-2.so.0[64bit]|16#libgnome-desktop-2.so.2[64bit]|16#libgnome-keyring.so.0[64bit]|16#libgnome-menu.so.2[64bit]|16#libgnomecanvas-2.so.0[64bit]|16#libgnomeui-2.so.0[64bit]|16#libgnomevfs-2.so.0[64bit]|16#libgobject-2.0.so.0[64bit]|16#libgthread-2.0.so.0[64bit]|16#libgtk-x11-2.0.so.0[64bit]|16#libgtop-2.0.so.7[64bit]|16#libhal-storage.so.1[64bit]|16#libhal.so.1[64bit]|16#libiw.so.29[64bit]|16#libjpeg.so.62[64bit]|16#libm.so.6[64bit]|16#libnm-util.so.0[64bit]|16#libnm_glib.so.0[64bit]|16#libnsl.so.1[64bit]|16#libnspr4.so[64bit]|16#libnss3.so[64bit]|16#libnssutil3.so[64bit]|16#libpanel-applet-2.so.0[64bit]|16#libpango-1.0.so.0[64bit]|16#libpangocairo-1.0.so.0[64bit]|16#libpangoft2-1.0.so.0[64bit]|16#libpcre.so.0[64bit]|16#libplc4.so[64bit]|16#libplds4.so[64bit]|16#libpng12.so.0[64bit]|16#libpopt.so.0[64bit]|16#libpthread.so.0[64bit]:GLIBC_2.2.5|16#libresolv.so.2[64bit]|16#librsvg-2.so.2[64bit]|16#librt.so.1[64bit]|16#libslab.so.0[64bit]|16#libsmime3.so[64bit]|16#libssl.so.0.9.8[64bit]|16#libssl3.so[64bit]|16#libssui|16#libstartup-notification-1.so.0[64bit]|16#libutil.so.1[64bit]|16#libuuid.so.1[64bit]|16#libxcb-render-util.so.0[64bit]|16#libxcb-render.so.0[64bit]|16#libxcb-xlib.so.0[64bit]|16#libxcb.so.1[64bit]|16#libxml2.so.2[64bit]|16#libz.so.1[64bit]|16#tango-icon-theme|16#wireless-tools|17#CompressedFileNames|17#PayloadFilesHavePrefix|17#PayloadIsLzma' ) self.assertEqual(prov.freeze(), '16#gnome-main-menu|16#libslab.so.0[64bit]') f = open(resources.get_archive() + '/popt-1.5-4x.i386.rpm') h = rpmhelper.readHeader(f) req, prov = h.getDeps() self.assertEqual(req.freeze(), '') self.assertEqual(prov.freeze(), '16#libpopt.so.0')
def testRpmHeader(self): rpmName = 'tmpwatch-2.9.7-1.1.el5.2.x86_64.rpm' rpmPath = os.path.join(self.archiveDir, rpmName) fileObj = file(rpmPath) header = rpmhelper.readHeader(fileObj) # both NAME and SIG_SIZE are 1000, but their value should be different self.assertEqual(header[rpmhelper.NAME], 'tmpwatch') self.assertEqual(header[rpmhelper.SIG_SIZE][0], 18624)
def testRpmHeader(self): rpmName = "tmpwatch-2.9.7-1.1.el5.2.x86_64.rpm" rpmPath = os.path.join(self.archiveDir, rpmName) fileObj = file(rpmPath) header = rpmhelper.readHeader(fileObj) # both NAME and SIG_SIZE are 1000, but their value should be different self.assertEqual(header[rpmhelper.NAME], "tmpwatch") self.assertEqual(header[rpmhelper.SIG_SIZE][0], 18624)
def testCorruptedRpm(self): # test enforcement of size and sha1 fields from rpm signature block f = open(resources.get_archive() + "/basesystem-8.0-2.src.rpm") rpmhelper.readHeader(f) f.seek(0) # change the size tmp = tempfile.TemporaryFile() util.copyfileobj(f, tmp) f.seek(0) tmp.write(' ') tmp.seek(0) try: rpmhelper.readHeader(tmp) except IOError, e: assert (str(e) == 'file size does not match size specified by ' 'header')
def testRpmDepsPerl(self): rpmName = "perl-Archive-Tar-1.46-68.fc11.x86_64.rpm" rpmPath = os.path.join(self.archiveDir, rpmName) fileObj = file(rpmPath) header = rpmhelper.readHeader(fileObj) reqset, provset = header.getDeps(enableRPMVersionDeps=False) self.assertEquals( str(reqset), "\n".join( ( "file: /usr/bin/perl", "rpm: perl", "rpm: perl[Archive::Tar::Constant]", "rpm: perl[Archive::Tar::File]", "rpm: perl[Archive::Tar]", "rpm: perl[Carp]", "rpm: perl[Compress::Zlib]", "rpm: perl[Config]", "rpm: perl[Cwd]", "rpm: perl[Data::Dumper]", "rpm: perl[Exporter]", "rpm: perl[File::Basename]", "rpm: perl[File::Find]", "rpm: perl[File::Path]", "rpm: perl[File::Spec::Unix]", "rpm: perl[File::Spec]", "rpm: perl[Getopt::Std]", "rpm: perl[IO::File]", "rpm: perl[IO::Handle]", "rpm: perl[IO::Zlib]", "rpm: perl[Package::Constants]", "rpm: perl[constant]", "rpm: perl[strict]", "rpm: perl[vars]", "rpmlib: CompressedFileNames", "rpmlib: FileDigests", "rpmlib: PayloadFilesHavePrefix", "rpmlib: VersionedDependencies", ) ), ) self.assertEquals( str(provset), "\n".join( ( "rpm: perl-Archive-Tar", "rpm: perl-Archive-Tar[x86-64]", "rpm: perl[Archive::Tar::Constant]", "rpm: perl[Archive::Tar::File]", "rpm: perl[Archive::Tar]", ) ), )
def checkMtimes(trvCs, rpmPath): archivePath = resources.get_archive() trv = trove.Trove(trvCs) f = open(archivePath + '/' + rpmPath, "r") h = rpmhelper.readHeader(f) rpmMtimes = dict((path, mtime) for path, mtime in itertools.izip( h[rpmhelper.OLDFILENAMES], h[rpmhelper.FILEMTIMES])) conaryMtimes = dict( (path, mtime) for ((pathId, path, fileId, version), mtime) in itertools.izip( sorted(trv.iterFileList()), trv.troveInfo.mtimes)) self.assertEquals(rpmMtimes, conaryMtimes)
def testFilelessRpm(self): # Test that reading the paths for an rpm that has no files still works f = open(resources.get_archive() + "/fileless-0.1-1.noarch.rpm") h = rpmhelper.readHeader(f) self.assertEqual(list(h.paths()), []) tags = [ rpmhelper.DIRINDEXES, rpmhelper.BASENAMES, rpmhelper.DIRNAMES, rpmhelper.FILEUSERNAME, rpmhelper.FILEGROUPNAME, rpmhelper.OLDFILENAMES, ] for t in tags: self.assertEqual(h[t], [])
def testRpmDeps(self): rpmName = 'depstest-0.1-1.x86_64.rpm' rpmPath = os.path.join(self.archiveDir, rpmName) fileObj = file(rpmPath) header = rpmhelper.readHeader(fileObj) reqset, provset = header.getDeps(enableRPMVersionDeps=False) self.assertEquals( str(reqset), '\n'.join( ('file: /bin/sh', 'rpm: ld-linux.so.2(GLIBC_PRIVATE)', 'rpm: libc.so.6(GLIBC_2.0 GLIBC_2.1.3)', 'rpmlib: CompressedFileNames', 'rpmlib: PayloadFilesHavePrefix'))) self.assertEquals( str(provset), '\n'.join( ('rpm: depstest', 'rpm: depstest[x86-64]', 'rpm: libm.so.6(GLIBC_2.0 GLIBC_2.1 GLIBC_2.2 GLIBC_2.4)')))
def checkMtimes(trvCs, rpmPath): archivePath = resources.get_archive() trv = trove.Trove(trvCs) f = open(archivePath + "/" + rpmPath, "r") h = rpmhelper.readHeader(f) rpmMtimes = dict( (path, mtime) for path, mtime in itertools.izip(h[rpmhelper.OLDFILENAMES], h[rpmhelper.FILEMTIMES]) ) conaryMtimes = dict( (path, mtime) for ((pathId, path, fileId, version), mtime) in itertools.izip( sorted(trv.iterFileList()), trv.troveInfo.mtimes ) ) self.assertEquals(rpmMtimes, conaryMtimes)
def do(self): for comp in self.recipe.autopkg.components.items(): capsule = self.recipe._getCapsule(comp[0]) if capsule and capsule[0] == 'rpm': path = capsule[1] h = rpmhelper.readHeader(file(path)) prov = h.getProvides(mergeKmodSymbols=self.mergeKmodSymbols) fltrprov = self._filterProvides(comp[0], prov) comp[1].provides.union(fltrprov) if self.provisions: userProvs = self.provisions.get(comp[0]) if userProvs: comp[1].provides.union(userProvs)
def testRPMCapsuleKernelDeps(self): '''make sure that rpm kernel deps include symbol set hashes''' fPath = os.path.join(resources.get_archive(), 'tmpwatch-2.9.1-1.i386.rpm') def mockGet(self, item, default): if item == rpmhelper.PROVIDENAME or item == rpmhelper.REQUIRENAME: return [ 'kernel(goodVer)', 'ksym(goodVer2)', 'kernel(badver)', 'ksym(badver2)' ] if item == rpmhelper.PROVIDEVERSION or \ item == rpmhelper.REQUIREVERSION: return [ '0123456789ABCDEF', 'FEDCBA9876543210', '3.2.1', 'ABCDE' ] self.mock(rpmhelper._RpmHeader, 'get', mockGet) h = rpmhelper.readHeader(file(fPath)) (req, prov), output = self.captureOutput(h.getDeps) expected = '\n'.join(( "rpm: kernel[badver]", "rpm: kernel[goodVer:0123456789ABCDEF]", "rpm: ksym[badver2]", "rpm: ksym[goodVer2:FEDCBA9876543210]", )) self.assertEqual(str(req), expected) self.assertEqual(str(prov), expected) # assert that the two bad versions were each seen twice; once # in provides and once in requires self.assertEqual(len(output.strip().split('\n')), 4) (req, prov), output = self.captureOutput(h.getDeps, mergeKmodSymbols=True) expected = '\n'.join(( "rpm: kernel(badver goodVer:0123456789ABCDEF)", "rpm: ksym(badver2 goodVer2:FEDCBA9876543210)", )) self.assertEqual(str(req), expected) self.assertEqual(str(prov), expected) self.assertEqual(len(output.strip().split('\n')), 4)
def testRPMCapsuleKernelDeps(self): '''make sure that rpm kernel deps include symbol set hashes''' fPath = os.path.join(resources.get_archive(), 'tmpwatch-2.9.1-1.i386.rpm') def mockGet(self, item, default): if item == rpmhelper.PROVIDENAME or item == rpmhelper.REQUIRENAME: return ['kernel(goodVer)', 'ksym(goodVer2)', 'kernel(badver)', 'ksym(badver2)'] if item == rpmhelper.PROVIDEVERSION or \ item == rpmhelper.REQUIREVERSION: return ['0123456789ABCDEF', 'FEDCBA9876543210', '3.2.1', 'ABCDE'] self.mock(rpmhelper._RpmHeader, 'get', mockGet) h = rpmhelper.readHeader(file(fPath)) (req, prov), output = self.captureOutput(h.getDeps) expected = '\n'.join(( "rpm: kernel[badver]", "rpm: kernel[goodVer:0123456789ABCDEF]", "rpm: ksym[badver2]", "rpm: ksym[goodVer2:FEDCBA9876543210]", )) self.assertEqual(str(req), expected) self.assertEqual(str(prov), expected) # assert that the two bad versions were each seen twice; once # in provides and once in requires self.assertEqual(len(output.strip().split('\n')), 4) (req, prov), output = self.captureOutput(h.getDeps, mergeKmodSymbols=True) expected = '\n'.join(( "rpm: kernel(badver goodVer:0123456789ABCDEF)", "rpm: ksym(badver2 goodVer2:FEDCBA9876543210)", )) self.assertEqual(str(req), expected) self.assertEqual(str(prov), expected) self.assertEqual(len(output.strip().split('\n')), 4)
def __init__(self, path, basedir=''): Magic.__init__(self, path, basedir) try: f = file(path) except: return None # Convert list of objects to simple types self.hdr = rpmhelper.readHeader(f) for key, tagName, valType in self._tagMap: val = self.hdr.get(tagName, None) if isinstance(val, list): if not val: val = None else: val = val[0] if val is not None: if valType == int: val = int(val) elif valType == str: val = str(val) self.contents[key] = val self.contents['isSource'] = self.hdr.isSource
def _index(self, rpm): """ Index an individual rpm. """ fh = rpmheader.SeekableStream(rpm) h = rpmhelper.readHeader(fh) name = h[rpmhelper.NAME] epoch = h.get(rpmhelper.EPOCH, None) if isinstance(epoch, (list, tuple)): assert len(epoch) == 1 epoch = str(epoch[0]) version = h[rpmhelper.VERSION] release = h[rpmhelper.RELEASE] arch = h.isSource and "src" or h[rpmhelper.ARCH] sourcename = h.get(rpmhelper.SOURCERPM, None) basename = os.path.basename(rpm) pkg = Package( name=name, epoch=epoch, version=version, release=release, arch=arch, sourcerpm=sourcename, location=basename ) return pkg
def testRpmVersionDepsRelase(self): rpmName = 'versiondeps-bar-1-2.x86_64.rpm' rpmPath = os.path.join(self.archiveDir, rpmName) fileObj = file(rpmPath) header = rpmhelper.readHeader(fileObj) reqset, provset = header.getDeps() self.assertEquals( str(reqset), '\n'.join(( 'rpm: baz', 'rpm: baz-2:1.0-el5', 'rpm: versiondeps', 'rpm: versiondeps-1', 'rpmlib: CompressedFileNames', 'rpmlib: PayloadFilesHavePrefix', ))) self.assertEquals( str(provset), '\n'.join(( 'rpm: versiondeps-bar', 'rpm: versiondeps-bar-2:1', 'rpm: versiondeps-bar-2:1-2', 'rpm: versiondeps-bar[x86-64]', 'rpm: versiondeps-bar[x86-64]-2:1', 'rpm: versiondeps-bar[x86-64]-2:1-2', )))
def testRpmVersionDeps(self): rpmName = "depstest-0.1-1.x86_64.rpm" rpmPath = os.path.join(self.archiveDir, rpmName) fileObj = file(rpmPath) header = rpmhelper.readHeader(fileObj) reqset, provset = header.getDeps() self.assertEquals( str(reqset), "\n".join( ( "file: /bin/sh", "rpm: ld-linux.so.2(GLIBC_PRIVATE)", "rpm: libc.so.6(GLIBC_2.0 GLIBC_2.1.3)", "rpmlib: CompressedFileNames", "rpmlib: PayloadFilesHavePrefix", ) ), ) self.assertEquals( str(provset), "\n".join( ( "rpm: depstest", "rpm: depstest-0.1", "rpm: depstest-0.1-1", "rpm: depstest-0:0.1", "rpm: depstest-0:0.1-1", "rpm: depstest[x86-64]", "rpm: depstest[x86-64]-0.1", "rpm: depstest[x86-64]-0.1-1", "rpm: depstest[x86-64]-0:0.1", "rpm: depstest[x86-64]-0:0.1-1", "rpm: libm.so.6(GLIBC_2.0 GLIBC_2.1 GLIBC_2.2 GLIBC_2.4)", ) ), )
rpmhelper.readHeader(tmp) except IOError, e: assert str(e) == "file size does not match size specified by " "header" else: assert 0 # change a byte in the header. the offset we write to here happens # to work for basesystem-8.0-2.src.rpm; if that file changes this # offset needs to change too tmp = tempfile.TemporaryFile() util.copyfileobj(f, tmp) tmp.seek(2000) tmp.write("X") tmp.seek(0) try: rpmhelper.readHeader(tmp) except IOError, e: assert str(e) == "bad header sha1" else: assert 0 def testFilelessRpm(self): # Test that reading the paths for an rpm that has no files still works f = open(resources.get_archive() + "/fileless-0.1-1.noarch.rpm") h = rpmhelper.readHeader(f) self.assertEqual(list(h.paths()), []) tags = [ rpmhelper.DIRINDEXES, rpmhelper.BASENAMES, rpmhelper.DIRNAMES, rpmhelper.FILEUSERNAME,
def testRPMCapsuleOverlap(self): # this is a pair of evil RPMs that has many forms of conflicting # overlap recipestr = """ class TestCookWithRPMCapsule(CapsuleRecipe): name = 'overlap-special-difference' version = '1.0' clearBuildReqs() def setup(r): r.addCapsule('overlap-special-difference-1.0-1.x86_64.rpm', package='overlap-special-difference:rpm') r.addCapsule('overlap-special-other-1.0-1.x86_64.rpm', ignoreConflictingPaths=set(PATHS), package='overlap-special-other:rpm') """ pkgName = "overlap-special-difference" def initialcontents(fileObj, fpath): self.assertEquals( fileObj.flags.isInitialContents() and True, True, msg="%s should be InitialContents" % fpath ) def config(fileObj, fpath): self.assertEquals(fileObj.flags.isConfig() and True, True, msg="%s should be Config" % fpath) def directory(fileObj, fpath): self.assertEquals(isinstance(fileObj, cfiles.Directory), True, msg="%s should be Directory" % fpath) def blockdevice(fileObj, fpath): self.assertEquals(isinstance(fileObj, cfiles.BlockDevice), True, msg="%s should be BlockDevice" % fpath) def regular(fileObj, fpath): self.assertEquals(isinstance(fileObj, cfiles.RegularFile), True, msg="%s should be RegularFile" % fpath) def symlink(fileObj, fpath): self.assertEquals(isinstance(fileObj, cfiles.SymbolicLink), True, msg="%s should be SymbolicLink" % fpath) rpmVerifyData = [ ( "overlap-special-difference-1.0-1.x86_64.rpm", ( ("/etc/conf", 0600, "root", "root", initialcontents), ("/etc/conf2", 0600, "root", "root", config), ("/ghostly", 0700, "root", "root", directory), ("/ghostly/file", 0600, "root", "root", initialcontents), ("/etc/ghostconf", 0777, "root", "root", symlink), ("/dev/sda", 0600, "root", "root", blockdevice), ("/etc/noverify", 0600, "root", "root", initialcontents), ("/etc/maybeverify", 0600, "root", "root", initialcontents), ("/usr/normal", 0600, "root", "root", regular), ("/usr/lib64/python2.4/config/Makefile", 0600, "root", "root", regular), ), ), ( "overlap-special-other-1.0-1.x86_64.rpm", ( ("/etc/conf", 0644, "oot", "oot", initialcontents), ("/etc/conf2", 0644, "oot", "oot", config), ("/ghostly", 0750, "oot", "oot", directory), ("/ghostly/file", 0640, "oot", "oot", initialcontents), ("/etc/ghostconf", 0777, "root", "root", symlink), ("/dev/sda", 0660, "oot", "oot", blockdevice), ("/etc/noverify", 0660, "oot", "oot", initialcontents), ("/etc/maybeverify", 0600, "oot", "oot", regular), ("/usr/normal", 0640, "oot", "oot", regular), ("/usr/lib64/python2.4/config/Makefile", 0600, "root", "root", regular), ), ), ] rpmPaths = sorted([x[0] for x in rpmVerifyData[0][1]]) rpmNames = [x[0] for x in rpmVerifyData] builtPkgNames = [pkgName, "overlap-special-other"] pkgNames, built, cs = self._cookPkgs( recipestr.replace("PATHS", "%r" % rpmPaths), rpmNames, pkgName, builtPkgNames, macros={"lib": "lib64"} ) # Ensure that all the paths exist that should, including overlap for tcs in cs.iterNewTroveList(): trv = trove.Trove(tcs) troveName = trv.getName() if troveName.endswith(":rpm"): self.assertEquals(sorted([x[1] for x in trv.iterFileList()]), rpmPaths) pathFlavors = [] for rpmName, pathList in rpmVerifyData: pathMap = dict((x[0], x[1:5]) for x in pathList) # get file list from rpm header r = file(resources.get_archive() + "/" + rpmName, "r") h = rpmhelper.readHeader(r) rpmFileList = dict( itertools.izip( h[rpmhelper.OLDFILENAMES], itertools.izip( h[rpmhelper.FILEUSERNAME], h[rpmhelper.FILEGROUPNAME], h[rpmhelper.FILEMODES], h[rpmhelper.FILESIZES], h[rpmhelper.FILERDEVS], h[rpmhelper.FILEFLAGS], h[rpmhelper.FILEVERIFYFLAGS], h[rpmhelper.FILELINKTOS], ), ) ) foundFiles = dict.fromkeys(rpmFileList) repos = self.openRepository() desiredTrove = rpmName.replace("-1.0-1.x86_64.", ":") nvf = repos.findTrove(None, [x for x in built if x[0] == desiredTrove][0]) trv = repos.getTrove(*nvf[0]) fileList = list(trv.iterFileList()) fileObjs = repos.getFileVersions([(x[0], x[2], x[3]) for x in fileList]) for fileInfo, fileObj in zip(fileList, fileObjs): fpath = fileInfo[1] if fpath == "/usr/lib64/python2.4/config/Makefile": pathFlavors.append(str(fileObj.flavor())) foundFiles[fpath] = True rUser, rGroup, rMode, rSize, rDev, rFlags, rVflags, rLinkto = rpmFileList[fpath] user = pathMap[fpath][1] group = pathMap[fpath][2] # run the correct validator if pathMap[fpath][3]: pathMap[fpath][3](fileObj, fpath) # file metadata verification self.assertEqual(rUser, fileObj.inode.owner()) self.assertEqual(user, fileObj.inode.owner()) self.assertEqual(rGroup, fileObj.inode.group()) self.assertEqual(group, fileObj.inode.group()) self.assertEqual(stat.S_IMODE(rMode), fileObj.inode.perms()) self.assertEqual(stat.S_IMODE(rMode), pathMap[fpath][0]) if isinstance(fileObj, cfiles.RegularFile): assert stat.S_ISREG(rMode) if isinstance(fileObj, cfiles.BlockDevice): assert stat.S_ISBLK(rMode) minor = rDev & 0xFF | (rDev >> 12) & 0xFFFFFF00 major = (rDev >> 8) & 0xFFF self.assertEqual(fileObj.devt.major(), major) self.assertEqual(fileObj.devt.minor(), minor) assert not fileObj.flags.isEncapsulatedContent() elif isinstance(fileObj, cfiles.NamedPipe): assert stat.S_ISFIFO(rMode) assert not fileObj.flags.isEncapsulatedContent() elif isinstance(fileObj, cfiles.SymbolicLink): assert stat.S_ISLNK(rMode) self.assertEquals(fileObj.target(), rLinkto) assert not fileObj.flags.isEncapsulatedContent() # Make sure we have explicitly checked every file in the RPM uncheckedFiles = [x[0] for x in foundFiles.iteritems() if not x[1]] assert not uncheckedFiles, uncheckedFiles # ensure that the flavor is set (will be different on different archs [self.assertTrue(bool(x)) for x in pathFlavors] # ensure that the flavor is the same across both components self.assertEquals(pathFlavors[0], pathFlavors[1])
except IOError, e: assert (str(e) == 'file size does not match size specified by ' 'header') else: assert (0) # change a byte in the header. the offset we write to here happens # to work for basesystem-8.0-2.src.rpm; if that file changes this # offset needs to change too tmp = tempfile.TemporaryFile() util.copyfileobj(f, tmp) tmp.seek(2000) tmp.write('X') tmp.seek(0) try: rpmhelper.readHeader(tmp) except IOError, e: assert (str(e) == "bad header sha1") else: assert (0) def testFilelessRpm(self): # Test that reading the paths for an rpm that has no files still works f = open(resources.get_archive() + "/fileless-0.1-1.noarch.rpm") h = rpmhelper.readHeader(f) self.assertEqual(list(h.paths()), []) tags = [ rpmhelper.DIRINDEXES, rpmhelper.BASENAMES, rpmhelper.DIRNAMES, rpmhelper.FILEUSERNAME,
def do(self): for comp in self.recipe.autopkg.components.items(): capsule = self.recipe._getCapsule(comp[0]) if capsule and capsule[0] == 'rpm': if not self.filters: self.filters = [(x, filter.Filter(x, self.macros)) for x in self.excepts] path = capsule[1] matchFound = False for regexp, f in self.filters: if f.match(path): self.unusedFilters['exceptions'].discard(regexp) matchFound=True if matchFound: continue h = rpmhelper.readHeader(file(path)) rReqs, rProv = h.getDeps(mergeKmodSymbols=self.mergeKmodSymbols) # integrate user specified requirements if self.requirements: userReqs = self.requirements.get(comp[0]) if userReqs: rReqs.union(userReqs) # remove rpm provisions from the requirements rReqs = rReqs.difference(rProv) # cull duplicate rpm reqs that have a standard conary # representations # currently we only handle perl and sonames culledReqs = deps.DependencySet() cnyReqs = comp[1].requires cnyProv = comp[1].provides if rReqs.hasDepClass(deps.RpmDependencies): soDeps = deps.DependencySet() soDeps.addDeps(deps.SonameDependencies, \ list(cnyReqs.iterDepsByClass(deps.SonameDependencies))+\ list(cnyProv.iterDepsByClass(deps.SonameDependencies))) for r in list(rReqs.iterDepsByClass(deps.RpmDependencies)): reMatch = self.rpmStringRe.match(r.name) if reMatch and reMatch.groups(): rpmFile = reMatch.group(1) rpmFlags = reMatch.group(2).strip() else: rpmFile = r.name rpmFlags = '' if rpmFile == 'perl' and rpmFlags: ds = deps.DependencySet() dep = deps.Dependency(rpmFlags) dep.flags = r.flags ds.addDep(deps.PerlDependencies, dep) if cnyReqs.satisfies(ds) or \ cnyProv.satisfies(ds): culledReqs.addDep( deps.RpmDependencies,r) elif '.so' in rpmFile: ds = deps.DependencySet() if rpmFlags == '64bit': elfPrefix = 'ELF64/' else: elfPrefix = 'ELF32/' dep = deps.Dependency(elfPrefix + rpmFile) dep.flags = r.flags ds.addDep(deps.SonameDependencies, dep) if soDeps.satisfies(ds): culledReqs.addDep(deps.RpmDependencies,r) rReqs = rReqs.difference(culledReqs) # remove any excepted deps for filt, exceptRe in self.exceptDeps: if filt.match(path): for depClass, dep in list(rReqs.iterDeps()): matchName = '%s: %s' %(depClass.tagName, str(dep)) if exceptRe.match(matchName): rReqs.removeDeps(depClass, [ dep ]) cnyReqs.union(rReqs)
def do(self): for comp in self.recipe.autopkg.components.items(): capsule = self.recipe._getCapsule(comp[0]) if capsule and capsule[0] == 'rpm': if not self.filters: self.filters = [(x, filter.Filter(x, self.macros)) for x in self.excepts] path = capsule[1] matchFound = False for regexp, f in self.filters: if f.match(path): self.unusedFilters['exceptions'].discard(regexp) matchFound = True if matchFound: continue h = rpmhelper.readHeader(file(path)) rReqs, rProv = h.getDeps( mergeKmodSymbols=self.mergeKmodSymbols) # integrate user specified requirements if self.requirements: userReqs = self.requirements.get(comp[0]) if userReqs: rReqs.union(userReqs) # remove rpm provisions from the requirements rReqs = rReqs.difference(rProv) # cull duplicate rpm reqs that have a standard conary # representations # currently we only handle perl and sonames culledReqs = deps.DependencySet() cnyReqs = comp[1].requires cnyProv = comp[1].provides if rReqs.hasDepClass(deps.RpmDependencies): soDeps = deps.DependencySet() soDeps.addDeps(deps.SonameDependencies, \ list(cnyReqs.iterDepsByClass(deps.SonameDependencies))+\ list(cnyProv.iterDepsByClass(deps.SonameDependencies))) for r in list(rReqs.iterDepsByClass(deps.RpmDependencies)): reMatch = self.rpmStringRe.match(r.name) if reMatch and reMatch.groups(): rpmFile = reMatch.group(1) rpmFlags = reMatch.group(2).strip() else: rpmFile = r.name rpmFlags = '' if rpmFile == 'perl' and rpmFlags: ds = deps.DependencySet() dep = deps.Dependency(rpmFlags) dep.flags = r.flags ds.addDep(deps.PerlDependencies, dep) if cnyReqs.satisfies(ds) or \ cnyProv.satisfies(ds): culledReqs.addDep(deps.RpmDependencies, r) elif '.so' in rpmFile: ds = deps.DependencySet() if rpmFlags == '64bit': elfPrefix = 'ELF64/' else: elfPrefix = 'ELF32/' dep = deps.Dependency(elfPrefix + rpmFile) dep.flags = r.flags ds.addDep(deps.SonameDependencies, dep) if soDeps.satisfies(ds): culledReqs.addDep(deps.RpmDependencies, r) rReqs = rReqs.difference(culledReqs) # remove any excepted deps for filt, exceptRe in self.exceptDeps: if filt.match(path): for depClass, dep in list(rReqs.iterDeps()): matchName = '%s: %s' % (depClass.tagName, str(dep)) if exceptRe.match(matchName): rReqs.removeDeps(depClass, [dep]) cnyReqs.union(rReqs)
def testCookWithRPMCapsuleTorture(self): # this is an evil RPM that has every kind of crazy file that we could think of # recipestr = """ class TestCookWithRPMCapsule(CapsuleRecipe): name = 'with-special-files' version = '5.23' clearBuildReqs() def setup(r): r.addCapsule('with-special-files-0.1-1.x86_64.rpm') """ pkgName = 'with-special-files' rpmName = 'with-special-files-0.1-1.x86_64.rpm' pkgNames, built, _ = \ self._cookAndInstall(recipestr, rpmName, pkgName, output = 'error: unpacking of archive failed on file /dev/sda;........: ' 'cpio: mknod failed - Operation not permitted\n') # verify that the package exists self.assertEquals(pkgNames, [pkgName, pkgName + ':rpm']) # get file list from rpm header r = file(resources.get_archive() + '/' + rpmName, 'r') h = rpmhelper.readHeader(r) rpmFileList = dict( itertools.izip( h[rpmhelper.OLDFILENAMES], itertools.izip( h[rpmhelper.FILEUSERNAME], h[rpmhelper.FILEGROUPNAME], h[rpmhelper.FILEMODES], h[rpmhelper.FILESIZES], h[rpmhelper.FILERDEVS], h[rpmhelper.FILEFLAGS], h[rpmhelper.FILEVERIFYFLAGS], h[rpmhelper.FILELINKTOS], ))) foundFiles = dict.fromkeys(rpmFileList) repos = self.openRepository() nvf = repos.findTrove(None, built[0]) trv = repos.getTrove(*nvf[0]) fileList = list(trv.iterFileList()) fileObjs = repos.getFileVersions([(x[0], x[2], x[3]) for x in fileList]) for fileInfo, fileObj in zip(fileList, fileObjs): fpath = fileInfo[1] foundFiles[fpath] = True rUser, rGroup, rMode, rSize, rDev, rFlags, rVflags, rLinkto = rpmFileList[ fpath] # First, tests based on the Conary changeset # file metadata verification self.assertEqual(rUser, fileObj.inode.owner()) self.assertEqual(rGroup, fileObj.inode.group()) if isinstance(fileObj, cfiles.SymbolicLink): self.assertEqual(0777, fileObj.inode.perms()) # CNY-3304 else: self.assertEqual(stat.S_IMODE(rMode), fileObj.inode.perms()) if isinstance(fileObj, cfiles.RegularFile): assert stat.S_ISREG(rMode) # RPM config flag mapping if rFlags & rpmhelper.RPMFILE_CONFIG: if fileObj.linkGroup() or not fileObj.contents.size(): assert fileObj.flags.isInitialContents() else: assert fileObj.flags.isConfig() or \ fileObj.flags.isInitialContents() elif isinstance(fileObj, cfiles.Directory): assert stat.S_ISDIR(rMode) assert not fileObj.flags.isEncapsulatedContent() elif isinstance(fileObj, cfiles.CharacterDevice): assert stat.S_ISCHR(rMode) minor = rDev & 0xff | (rDev >> 12) & 0xffffff00 major = (rDev >> 8) & 0xfff self.assertEqual(fileObj.devt.major(), major) self.assertEqual(fileObj.devt.minor(), minor) assert not fileObj.flags.isEncapsulatedContent() elif isinstance(fileObj, cfiles.BlockDevice): assert stat.S_ISBLK(rMode) minor = rDev & 0xff | (rDev >> 12) & 0xffffff00 major = (rDev >> 8) & 0xfff self.assertEqual(fileObj.devt.major(), major) self.assertEqual(fileObj.devt.minor(), minor) assert not fileObj.flags.isEncapsulatedContent() elif isinstance(fileObj, cfiles.NamedPipe): assert (stat.S_ISFIFO(rMode)) assert not fileObj.flags.isEncapsulatedContent() elif isinstance(fileObj, cfiles.SymbolicLink): assert (stat.S_ISLNK(rMode)) self.assertEquals(fileObj.target(), rLinkto) assert not fileObj.flags.isEncapsulatedContent() else: # unhandled file type assert False, 'Found unhandled file type!' # Now, some tests based on the contents of the RPM header if (not stat.S_ISDIR(rMode)) and rFlags & rpmhelper.RPMFILE_GHOST: assert fileObj.flags.isInitialContents() if rFlags & rpmhelper.RPMFILE_MISSINGOK: assert fileObj.flags.isMissingOkay() if fileObj.flags.isMissingOkay(): assert rFlags & rpmhelper.RPMFILE_MISSINGOK if not rVflags: # %doc -- CNY-3254 assert not fileObj.flags.isInitialContents() # Finally, tests based on specific filenames for specific # semantics if fpath == '/usr/share/noverifydigest': # CNY-3254 assert fileObj.flags.isInitialContents() elif fpath == '/etc/with-special-files.symlink.unverified.cfg': # CNY-3254 assert fileObj.flags.isInitialContents() elif fpath == '/usr/share/documentation': # %doc -- CNY-3254 assert isinstance(fileObj, cfiles.RegularFile) assert not fileObj.flags.isInitialContents() # Make sure we have explicitly checked every file in the RPM uncheckedFiles = [x[0] for x in foundFiles.iteritems() if not x[1]] assert not uncheckedFiles, uncheckedFiles
def testRPMCapsuleOverlap(self): # this is a pair of evil RPMs that has many forms of conflicting # overlap recipestr = """ class TestCookWithRPMCapsule(CapsuleRecipe): name = 'overlap-special-difference' version = '1.0' clearBuildReqs() def setup(r): r.addCapsule('overlap-special-difference-1.0-1.x86_64.rpm', package='overlap-special-difference:rpm') r.addCapsule('overlap-special-other-1.0-1.x86_64.rpm', ignoreConflictingPaths=set(PATHS), package='overlap-special-other:rpm') """ pkgName = 'overlap-special-difference' def initialcontents(fileObj, fpath): self.assertEquals(fileObj.flags.isInitialContents() and True, True, msg='%s should be InitialContents' % fpath) def config(fileObj, fpath): self.assertEquals(fileObj.flags.isConfig() and True, True, msg='%s should be Config' % fpath) def directory(fileObj, fpath): self.assertEquals(isinstance(fileObj, cfiles.Directory), True, msg='%s should be Directory' % fpath) def blockdevice(fileObj, fpath): self.assertEquals(isinstance(fileObj, cfiles.BlockDevice), True, msg='%s should be BlockDevice' % fpath) def regular(fileObj, fpath): self.assertEquals(isinstance(fileObj, cfiles.RegularFile), True, msg='%s should be RegularFile' % fpath) def symlink(fileObj, fpath): self.assertEquals(isinstance(fileObj, cfiles.SymbolicLink), True, msg='%s should be SymbolicLink' % fpath) rpmVerifyData = [ ('overlap-special-difference-1.0-1.x86_64.rpm', ( ('/etc/conf', 0600, 'root', 'root', initialcontents), ('/etc/conf2', 0600, 'root', 'root', config), ('/ghostly', 0700, 'root', 'root', directory), ('/ghostly/file', 0600, 'root', 'root', initialcontents), ('/etc/ghostconf', 0777, 'root', 'root', symlink), ('/dev/sda', 0600, 'root', 'root', blockdevice), ('/etc/noverify', 0600, 'root', 'root', initialcontents), ('/etc/maybeverify', 0600, 'root', 'root', initialcontents), ('/usr/normal', 0600, 'root', 'root', regular), ('/usr/lib64/python2.4/config/Makefile', 0600, 'root', 'root', regular), )), ('overlap-special-other-1.0-1.x86_64.rpm', ( ('/etc/conf', 0644, 'oot', 'oot', initialcontents), ('/etc/conf2', 0644, 'oot', 'oot', config), ('/ghostly', 0750, 'oot', 'oot', directory), ('/ghostly/file', 0640, 'oot', 'oot', initialcontents), ('/etc/ghostconf', 0777, 'root', 'root', symlink), ('/dev/sda', 0660, 'oot', 'oot', blockdevice), ('/etc/noverify', 0660, 'oot', 'oot', initialcontents), ('/etc/maybeverify', 0600, 'oot', 'oot', regular), ('/usr/normal', 0640, 'oot', 'oot', regular), ('/usr/lib64/python2.4/config/Makefile', 0600, 'root', 'root', regular), )), ] rpmPaths = sorted([x[0] for x in rpmVerifyData[0][1]]) rpmNames = [x[0] for x in rpmVerifyData] builtPkgNames = [pkgName, 'overlap-special-other'] pkgNames, built, cs = self._cookPkgs(recipestr.replace( 'PATHS', '%r' % rpmPaths), rpmNames, pkgName, builtPkgNames, macros={'lib': 'lib64'}) # Ensure that all the paths exist that should, including overlap for tcs in cs.iterNewTroveList(): trv = trove.Trove(tcs) troveName = trv.getName() if troveName.endswith(':rpm'): self.assertEquals(sorted([x[1] for x in trv.iterFileList()]), rpmPaths) pathFlavors = [] for rpmName, pathList in rpmVerifyData: pathMap = dict((x[0], x[1:5]) for x in pathList) # get file list from rpm header r = file(resources.get_archive() + '/' + rpmName, 'r') h = rpmhelper.readHeader(r) rpmFileList = dict( itertools.izip( h[rpmhelper.OLDFILENAMES], itertools.izip( h[rpmhelper.FILEUSERNAME], h[rpmhelper.FILEGROUPNAME], h[rpmhelper.FILEMODES], h[rpmhelper.FILESIZES], h[rpmhelper.FILERDEVS], h[rpmhelper.FILEFLAGS], h[rpmhelper.FILEVERIFYFLAGS], h[rpmhelper.FILELINKTOS], ))) foundFiles = dict.fromkeys(rpmFileList) repos = self.openRepository() desiredTrove = rpmName.replace('-1.0-1.x86_64.', ':') nvf = repos.findTrove(None, [x for x in built if x[0] == desiredTrove][0]) trv = repos.getTrove(*nvf[0]) fileList = list(trv.iterFileList()) fileObjs = repos.getFileVersions([(x[0], x[2], x[3]) for x in fileList]) for fileInfo, fileObj in zip(fileList, fileObjs): fpath = fileInfo[1] if fpath == '/usr/lib64/python2.4/config/Makefile': pathFlavors.append(str(fileObj.flavor())) foundFiles[fpath] = True rUser, rGroup, rMode, rSize, rDev, rFlags, rVflags, rLinkto = rpmFileList[ fpath] user = pathMap[fpath][1] group = pathMap[fpath][2] # run the correct validator if pathMap[fpath][3]: pathMap[fpath][3](fileObj, fpath) # file metadata verification self.assertEqual(rUser, fileObj.inode.owner()) self.assertEqual(user, fileObj.inode.owner()) self.assertEqual(rGroup, fileObj.inode.group()) self.assertEqual(group, fileObj.inode.group()) self.assertEqual(stat.S_IMODE(rMode), fileObj.inode.perms()) self.assertEqual(stat.S_IMODE(rMode), pathMap[fpath][0]) if isinstance(fileObj, cfiles.RegularFile): assert stat.S_ISREG(rMode) if isinstance(fileObj, cfiles.BlockDevice): assert stat.S_ISBLK(rMode) minor = rDev & 0xff | (rDev >> 12) & 0xffffff00 major = (rDev >> 8) & 0xfff self.assertEqual(fileObj.devt.major(), major) self.assertEqual(fileObj.devt.minor(), minor) assert not fileObj.flags.isEncapsulatedContent() elif isinstance(fileObj, cfiles.NamedPipe): assert (stat.S_ISFIFO(rMode)) assert not fileObj.flags.isEncapsulatedContent() elif isinstance(fileObj, cfiles.SymbolicLink): assert (stat.S_ISLNK(rMode)) self.assertEquals(fileObj.target(), rLinkto) assert not fileObj.flags.isEncapsulatedContent() # Make sure we have explicitly checked every file in the RPM uncheckedFiles = [x[0] for x in foundFiles.iteritems() if not x[1]] assert not uncheckedFiles, uncheckedFiles # ensure that the flavor is set (will be different on different archs [self.assertTrue(bool(x)) for x in pathFlavors] # ensure that the flavor is the same across both components self.assertEquals(pathFlavors[0], pathFlavors[1])
def _sanityCheckRPMCapsule(self, jobId, fileList, fileObjs, rpmFile): """ Compare an rpm capsule with the contents of a trove to make sure that they agree. """ rpmFile.seek(0) h = rpmhelper.readHeader(rpmFile, checkSize=False) rpmFileList = dict( itertools.izip(h[rpmhelper.OLDFILENAMES], itertools.izip(h[rpmhelper.FILEUSERNAME], h[rpmhelper.FILEGROUPNAME], h[rpmhelper.FILEMODES], h[rpmhelper.FILESIZES], h[rpmhelper.FILERDEVS], h[rpmhelper.FILEFLAGS], h[rpmhelper.FILEVERIFYFLAGS], h[rpmhelper.FILELINKTOS], ))) errors = [] foundFiles = dict.fromkeys(rpmFileList) def fassert(test, path='', why=''): if not test: errors.append((path, why)) def devassert(path, rDev, fileObj): minor = rDev & 0xff | (rDev >> 12) & 0xffffff00 major = (rDev >> 8) & 0xfff fassert(fileObj.devt.major() == major, path, 'Device major mismatch: RPM %d != Conary %d' %(major, fileObj.devt.major())) fassert(fileObj.devt.minor() == minor, path, 'Device minor mismatch: RPM %d != Conary %d' %(minor, fileObj.devt.minor())) fassert(not fileObj.flags.isPayload(), path, 'Device file is marked as payload') for fileInfo, fileObj in zip(fileList, fileObjs): fpath = fileInfo[1] foundFiles[fpath] = True rUser, rGroup, rMode, rSize, rDev, rFlags, rVflags, rLinkto = \ rpmFileList[fpath] # First, tests based on the Conary changeset # file metadata verification if (rUser != fileObj.inode.owner() or rGroup != fileObj.inode.group()): fassert(False, fpath, 'User/Group mismatch: RPM %s:%s != Conary %s:%s' %(rUser, rGroup, fileObj.inode.owner(), fileObj.inode.group())) if isinstance(fileObj, files.SymbolicLink): expectedMode = 0777 # CNY-3304 else: expectedMode = stat.S_IMODE(rMode) if fileObj.inode.perms() != expectedMode: fassert(False, fpath, 'Mode mismatch: RPM 0%o != Conary 0%o' %(expectedMode, fileObj.inode.perms())) if isinstance(fileObj, files.RegularFile): if not stat.S_ISREG(rMode): fassert(False, fpath, 'Conary Regular file has non-regular mode 0%o' %rMode) # RPM config flag mapping if rFlags & rpmhelper.RPMFILE_CONFIG: if fileObj.linkGroup() or not fileObj.contents.size(): fassert(fileObj.flags.isInitialContents(), fpath, 'RPM config file without size or' ' hardlinked is not InitialContents') else: fassert(fileObj.flags.isConfig() or fileObj.flags.isInitialContents(), fpath, 'RPM config file is neither Config file ' 'nor InitialContents') elif isinstance(fileObj, files.Directory): fassert(stat.S_ISDIR(rMode), fpath, 'Conary directory has non-directory RPM mode 0%o' %rMode) fassert(not fileObj.flags.isPayload(), fpath, 'Conary directory marked as payload') elif isinstance(fileObj, files.CharacterDevice): fassert(stat.S_ISCHR(rMode), fpath, 'Conary CharacterDevice has RPM non-character-device' ' mode 0%o' %rMode) devassert(fpath, rDev, fileObj) elif isinstance(fileObj, files.BlockDevice): fassert(stat.S_ISBLK(rMode), fpath, 'Conary BlockDevice has RPM non-block-device' ' mode 0%o' %rMode) devassert(fpath, rDev, fileObj) elif isinstance(fileObj, files.NamedPipe): fassert(stat.S_ISFIFO(rMode), fpath, 'Conary NamedPipe has RPM non-named-pipe' ' mode 0%o' %rMode) fassert(not fileObj.flags.isPayload(), fpath, 'NamedPipe file is marked as payload') elif isinstance(fileObj, files.SymbolicLink): fassert(stat.S_ISLNK(rMode), fpath, 'Conary SymbolicLink has RPM non-symlink' ' mode 0%o' %rMode) fassert(fileObj.target() == rLinkto, fpath, 'Symlink target mismatch:' ' RPM %s != Conary %s' %(rLinkto, fileObj.target())) fassert(not fileObj.flags.isPayload(), fpath, 'SymbolicLink file is marked as payload') else: # unhandled file type fassert(False, fpath, 'Unknown Conary file type %r' %fileObj) # Now, some tests based on the contents of the RPM header if not stat.S_ISDIR(rMode) and rFlags & rpmhelper.RPMFILE_GHOST: fassert(fileObj.flags.isInitialContents(), fpath, 'RPM ghost non-directory is not InitialContents') if rFlags & rpmhelper.RPMFILE_MISSINGOK: fassert(fileObj.flags.isMissingOkay(), fpath, 'RPM missingok file does not have missingOkay flag') if fileObj.flags.isMissingOkay(): fassert(rFlags & rpmhelper.RPMFILE_MISSINGOK, fpath, 'missingOkay file does not have RPM missingok flag') if not rVflags: # %doc -- CNY-3254 fassert(not fileObj.flags.isInitialContents(), fpath, 'RPM %%doc file is InitialContents') # Make sure we have explicitly checked every file in the RPM uncheckedFiles = [x[0] for x in foundFiles.iteritems() if not x[1] ] fassert(not uncheckedFiles, str(uncheckedFiles), 'Files contained in RPM not contained in Conary changeset') if errors: raise ChangesetValidationFailedError(jobId=jobId, reason='\n'.join([ '%s: %s' %(x, y) for x, y in errors ]))
def testCookWithRPMCapsuleTorture(self): # this is an evil RPM that has every kind of crazy file that we could think of # recipestr = """ class TestCookWithRPMCapsule(CapsuleRecipe): name = 'with-special-files' version = '5.23' clearBuildReqs() def setup(r): r.addCapsule('with-special-files-0.1-1.x86_64.rpm') """ pkgName = "with-special-files" rpmName = "with-special-files-0.1-1.x86_64.rpm" pkgNames, built, _ = self._cookAndInstall( recipestr, rpmName, pkgName, output="error: unpacking of archive failed on file /dev/sda;........: " "cpio: mknod failed - Operation not permitted\n", ) # verify that the package exists self.assertEquals(pkgNames, [pkgName, pkgName + ":rpm"]) # get file list from rpm header r = file(resources.get_archive() + "/" + rpmName, "r") h = rpmhelper.readHeader(r) rpmFileList = dict( itertools.izip( h[rpmhelper.OLDFILENAMES], itertools.izip( h[rpmhelper.FILEUSERNAME], h[rpmhelper.FILEGROUPNAME], h[rpmhelper.FILEMODES], h[rpmhelper.FILESIZES], h[rpmhelper.FILERDEVS], h[rpmhelper.FILEFLAGS], h[rpmhelper.FILEVERIFYFLAGS], h[rpmhelper.FILELINKTOS], ), ) ) foundFiles = dict.fromkeys(rpmFileList) repos = self.openRepository() nvf = repos.findTrove(None, built[0]) trv = repos.getTrove(*nvf[0]) fileList = list(trv.iterFileList()) fileObjs = repos.getFileVersions([(x[0], x[2], x[3]) for x in fileList]) for fileInfo, fileObj in zip(fileList, fileObjs): fpath = fileInfo[1] foundFiles[fpath] = True rUser, rGroup, rMode, rSize, rDev, rFlags, rVflags, rLinkto = rpmFileList[fpath] # First, tests based on the Conary changeset # file metadata verification self.assertEqual(rUser, fileObj.inode.owner()) self.assertEqual(rGroup, fileObj.inode.group()) if isinstance(fileObj, cfiles.SymbolicLink): self.assertEqual(0777, fileObj.inode.perms()) # CNY-3304 else: self.assertEqual(stat.S_IMODE(rMode), fileObj.inode.perms()) if isinstance(fileObj, cfiles.RegularFile): assert stat.S_ISREG(rMode) # RPM config flag mapping if rFlags & rpmhelper.RPMFILE_CONFIG: if fileObj.linkGroup() or not fileObj.contents.size(): assert fileObj.flags.isInitialContents() else: assert fileObj.flags.isConfig() or fileObj.flags.isInitialContents() elif isinstance(fileObj, cfiles.Directory): assert stat.S_ISDIR(rMode) assert not fileObj.flags.isEncapsulatedContent() elif isinstance(fileObj, cfiles.CharacterDevice): assert stat.S_ISCHR(rMode) minor = rDev & 0xFF | (rDev >> 12) & 0xFFFFFF00 major = (rDev >> 8) & 0xFFF self.assertEqual(fileObj.devt.major(), major) self.assertEqual(fileObj.devt.minor(), minor) assert not fileObj.flags.isEncapsulatedContent() elif isinstance(fileObj, cfiles.BlockDevice): assert stat.S_ISBLK(rMode) minor = rDev & 0xFF | (rDev >> 12) & 0xFFFFFF00 major = (rDev >> 8) & 0xFFF self.assertEqual(fileObj.devt.major(), major) self.assertEqual(fileObj.devt.minor(), minor) assert not fileObj.flags.isEncapsulatedContent() elif isinstance(fileObj, cfiles.NamedPipe): assert stat.S_ISFIFO(rMode) assert not fileObj.flags.isEncapsulatedContent() elif isinstance(fileObj, cfiles.SymbolicLink): assert stat.S_ISLNK(rMode) self.assertEquals(fileObj.target(), rLinkto) assert not fileObj.flags.isEncapsulatedContent() else: # unhandled file type assert False, "Found unhandled file type!" # Now, some tests based on the contents of the RPM header if (not stat.S_ISDIR(rMode)) and rFlags & rpmhelper.RPMFILE_GHOST: assert fileObj.flags.isInitialContents() if rFlags & rpmhelper.RPMFILE_MISSINGOK: assert fileObj.flags.isMissingOkay() if fileObj.flags.isMissingOkay(): assert rFlags & rpmhelper.RPMFILE_MISSINGOK if not rVflags: # %doc -- CNY-3254 assert not fileObj.flags.isInitialContents() # Finally, tests based on specific filenames for specific # semantics if fpath == "/usr/share/noverifydigest": # CNY-3254 assert fileObj.flags.isInitialContents() elif fpath == "/etc/with-special-files.symlink.unverified.cfg": # CNY-3254 assert fileObj.flags.isInitialContents() elif fpath == "/usr/share/documentation": # %doc -- CNY-3254 assert isinstance(fileObj, cfiles.RegularFile) assert not fileObj.flags.isInitialContents() # Make sure we have explicitly checked every file in the RPM uncheckedFiles = [x[0] for x in foundFiles.iteritems() if not x[1]] assert not uncheckedFiles, uncheckedFiles