Release testing
This commit is contained in:
@@ -30,6 +30,11 @@ def main() -> None:
|
||||
if frontend_version != extension_version:
|
||||
fail(f'frontend version {frontend_version} does not match extension version {extension_version}')
|
||||
|
||||
gecko_settings = manifest.get('browser_specific_settings', {}).get('gecko', {})
|
||||
data_permissions = gecko_settings.get('data_collection_permissions')
|
||||
if data_permissions != {'required': ['websiteActivity'], 'optional': []}:
|
||||
fail('Firefox data_collection_permissions must require websiteActivity and have no optional categories')
|
||||
|
||||
settings = SETTINGS_PATH.read_text()
|
||||
match = re.search(r"version: str = os\.getenv\('LINKLOG_VERSION', '([^']+)'\)", settings)
|
||||
if not match:
|
||||
@@ -52,7 +57,7 @@ def main() -> None:
|
||||
fail('signed XPI contains a corrupt member')
|
||||
|
||||
updates = json.loads(UPDATES_PATH.read_text())
|
||||
addon_id = manifest['browser_specific_settings']['gecko']['id']
|
||||
addon_id = gecko_settings['id']
|
||||
update_entries = updates.get('addons', {}).get(addon_id, {}).get('updates', [])
|
||||
if not any(entry.get('version') == extension_version for entry in update_entries):
|
||||
fail(f'webextension/updates.json has no update entry for {extension_version}')
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Validate an unsigned LinkLog XPI produced by the Makefile."""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
REQUIRED_FILES = {
|
||||
'manifest.json',
|
||||
'logo.svg',
|
||||
'icon-16.png',
|
||||
'icon-32.png',
|
||||
'icon-48.png',
|
||||
'icon-96.png',
|
||||
'options.css',
|
||||
'options.html',
|
||||
'options.js',
|
||||
'popup.css',
|
||||
'popup.html',
|
||||
'popup.js',
|
||||
}
|
||||
|
||||
|
||||
def fail(message: str) -> None:
|
||||
raise SystemExit(f'XPI validation failed: {message}')
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if len(sys.argv) != 3:
|
||||
fail('usage: validate_xpi.py <xpi> <source-manifest>')
|
||||
|
||||
xpi_path = Path(sys.argv[1])
|
||||
source_manifest_path = Path(sys.argv[2])
|
||||
try:
|
||||
source_manifest = json.loads(source_manifest_path.read_text())
|
||||
with zipfile.ZipFile(xpi_path) as archive:
|
||||
names = set(archive.namelist())
|
||||
corrupt_member = archive.testzip()
|
||||
if corrupt_member is not None:
|
||||
fail(f'corrupt archive member: {corrupt_member}')
|
||||
if 'manifest.json' not in names:
|
||||
fail('manifest.json is missing')
|
||||
packaged_manifest = json.loads(archive.read('manifest.json'))
|
||||
except (OSError, zipfile.BadZipFile, json.JSONDecodeError) as error:
|
||||
fail(str(error))
|
||||
|
||||
missing_files = REQUIRED_FILES - names
|
||||
if missing_files:
|
||||
fail(f'missing required files: {", ".join(sorted(missing_files))}')
|
||||
unexpected_files = names - REQUIRED_FILES
|
||||
if any(name.startswith('__MACOSX/') or name == '.DS_Store' for name in unexpected_files):
|
||||
fail('archive contains macOS metadata')
|
||||
if packaged_manifest != source_manifest:
|
||||
fail('packaged manifest does not match webextension/manifest.json')
|
||||
|
||||
print(f'validated unsigned XPI {xpi_path}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user