diff --git a/bundles/roundcube/items.py b/bundles/roundcube/items.py index aabb2e3..4037dbb 100644 --- a/bundles/roundcube/items.py +++ b/bundles/roundcube/items.py @@ -1,6 +1,8 @@ assert node.has_bundle('php') assert node.has_bundle('mailserver') +version = node.metadata.get('roundcube/version') + directories = { '/opt/roundcube': { 'owner': 'www-data', @@ -8,27 +10,48 @@ directories = { '/opt/roundcube/logs': { 'owner': 'www-data', 'needs': [ - 'git_deploy:/opt/roundcube', + 'action:extract_roundcube', ], }, '/opt/roundcube/temp': { 'owner': 'www-data', 'needs': [ - 'git_deploy:/opt/roundcube', + 'action:extract_roundcube', ], } } -git_deploy['/opt/roundcube'] = { - 'repo': "git://github.com/roundcube/roundcubemail.git", - 'rev': node.metadata.get('roundcube/version'), + +downloads[f'/tmp/roundcube-{version}.tar.gz'] = { + 'url': f'https://github.com/roundcube/roundcubemail/releases/download/{version}/roundcubemail-{version}-complete.tar.gz', + 'gpg_signature_url': '{url}.asc', + 'gpg_pubkey_url': 'https://roundcube.net/download/pubkey.asc', + 'triggered': True, +} +actions['delete_roundcube'] = { + 'command': 'rm -rf /opt/roundcube/*', + 'triggered': True, +} +actions['extract_roundcube'] = { + 'command': f'tar xfvz /tmp/roundcube-{version}.tar.gz --strip 1 -C /opt/roundcube', + 'unless': f'grep -q "Version {version}" /opt/roundcube/index.php', + 'preceded_by': [ + 'action:delete_roundcube', + f'download:/tmp/roundcube-{version}.tar.gz', + ], 'needs': [ 'directory:/opt/roundcube', ], 'triggers': [ + 'action:chown_roundcube', 'action:composer_install', ], } +actions['chown_roundcube'] = { + 'command': 'chown -R www-data /opt/roundcube', + 'triggered': True, +} + files['/opt/roundcube/config/config.inc.php'] = { 'content_type': 'mako', @@ -40,11 +63,14 @@ files['/opt/roundcube/config/config.inc.php'] = { 'plugins': node.metadata.get('roundcube/plugins'), }, 'needs': [ - 'git_deploy:/opt/roundcube', + 'action:chown_roundcube', ], } actions['composer_install'] = { 'command': "cp /opt/roundcube/composer.json-dist /opt/roundcube/composer.json && su www-data -s /bin/bash -c '/usr/bin/composer -d /opt/roundcube install'", 'triggered': True, + 'needs': [ + 'action:chown_roundcube', + ], } diff --git a/bundles/roundcube/metadata.py b/bundles/roundcube/metadata.py index e6ec684..3014194 100644 --- a/bundles/roundcube/metadata.py +++ b/bundles/roundcube/metadata.py @@ -22,6 +22,7 @@ defaults = { 'php-curl': {}, 'php-gd': {}, 'composer': {}, + 'php-ldap': {}, }, }, 'roundcube': { diff --git a/items/download.py b/items/download.py index 8d52e50..c710f01 100644 --- a/items/download.py +++ b/items/download.py @@ -20,14 +20,16 @@ class Download(Item): "pkg_zypper:", ] ITEM_ATTRIBUTES = { - 'url': "", - 'sha256': "", - 'sha256_url': "", + 'url': None, + 'sha256': None, + 'sha256_url': None, + 'gpg_signature_url': None, + 'gpg_pubkey_url': None, 'verifySSL': True, 'decompress': None, } ITEM_TYPE_NAME = "download" - REQUIRED_ATTRIBUTES = [] + REQUIRED_ATTRIBUTES = ['url'] def __repr__(self): return "".format(self.name) @@ -67,9 +69,15 @@ class Download(Item): """This is how the world should be""" cdict = { 'type': 'download', - 'sha256': self.attributes['sha256'], } + if self.attributes.get('sha256'): + cdict['sha256'] = self.attributes['sha256'] + elif self.attributes.get('gpg_signature_url'): + cdict['verified'] = True + else: + raise + return cdict def sdict(self): @@ -81,19 +89,35 @@ class Download(Item): sdict = { 'type': 'download', } - if 'sha256' in self.attributes: + if self.attributes.get('sha256'): sdict['sha256'] = self.attributes['sha256'] - elif 'sha256_url' in self.attributes: - sha256_url = self.attributes['sha256_url'].format(url=self.attributes['url']) + elif self.attributes.get('sha256_url'): + full_sha256_url = self.attributes['sha256_url'].format(url=self.attributes['url']) sdict['sha256'] = force_text( - self.node.run(f"curl -L -s -- {quote(sha256_url)}").stdout + self.node.run(f"curl -sL -- {quote(full_sha256_url)}").stdout ).strip().split()[0] - + elif self.attributes.get('gpg_signature_url'): + full_signature_url = self.attributes['gpg_signature_url'].format(url=self.attributes['url']) + signature_path = f'{self.name}.signature' + + self.node.run(f"curl -sSL {self.attributes['gpg_pubkey_url']} | gpg --import -") + self.node.run(f"curl -L {full_signature_url} -o {quote(signature_path)}") + gpg_output = self.node.run(f"gpg --verify {quote(signature_path)} {quote(self.name)}").stderr + + if b'Good signature' in gpg_output: + sdict['verified'] = True + else: + sdict['verified'] = False + return sdict @classmethod def validate_attributes(cls, bundle, item_id, attributes): - if 'sha256' not in attributes and 'sha256_url' not in attributes: + if ( + 'sha256' not in attributes and + 'sha256_url' not in attributes and + 'gpg_signature_url'not in attributes + ): raise BundleError(_( "at least one hash must be set on {item} in bundle '{bundle}'" ).format( diff --git a/nodes/htz.mails.py b/nodes/htz.mails.py index 27dd41e..17aa7f0 100644 --- a/nodes/htz.mails.py +++ b/nodes/htz.mails.py @@ -78,7 +78,7 @@ }, 'roundcube': { 'product_name': 'Sublimity Mail', - 'version': '6466d10339d44a077de4fe094c89ed35ae84da96', + 'version': '1.5-rc', 'installer': True, }, 'users': {