Release testing
This commit is contained in:
@@ -28,6 +28,7 @@ xpi: logos
|
|||||||
@mkdir -p $(XPI_UNSIGNED_DIR) $(XPI_SIGNED_DIR)
|
@mkdir -p $(XPI_UNSIGNED_DIR) $(XPI_SIGNED_DIR)
|
||||||
@rm -f $(XPI_OUTPUT)
|
@rm -f $(XPI_OUTPUT)
|
||||||
@cd webextension && zip -q -9 "../$(XPI_OUTPUT)" $(EXTENSION_FILES)
|
@cd webextension && zip -q -9 "../$(XPI_OUTPUT)" $(EXTENSION_FILES)
|
||||||
|
@python3 scripts/release/validate_xpi.py "$(XPI_OUTPUT)" webextension/manifest.json
|
||||||
@echo "Created $(XPI_OUTPUT)"
|
@echo "Created $(XPI_OUTPUT)"
|
||||||
|
|
||||||
check-tools:
|
check-tools:
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -30,6 +30,11 @@ def main() -> None:
|
|||||||
if frontend_version != extension_version:
|
if frontend_version != extension_version:
|
||||||
fail(f'frontend version {frontend_version} does not match extension 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()
|
settings = SETTINGS_PATH.read_text()
|
||||||
match = re.search(r"version: str = os\.getenv\('LINKLOG_VERSION', '([^']+)'\)", settings)
|
match = re.search(r"version: str = os\.getenv\('LINKLOG_VERSION', '([^']+)'\)", settings)
|
||||||
if not match:
|
if not match:
|
||||||
@@ -52,7 +57,7 @@ def main() -> None:
|
|||||||
fail('signed XPI contains a corrupt member')
|
fail('signed XPI contains a corrupt member')
|
||||||
|
|
||||||
updates = json.loads(UPDATES_PATH.read_text())
|
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', [])
|
update_entries = updates.get('addons', {}).get(addon_id, {}).get('updates', [])
|
||||||
if not any(entry.get('version') == extension_version for entry in update_entries):
|
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}')
|
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()
|
||||||
@@ -27,6 +27,10 @@
|
|||||||
"gecko": {
|
"gecko": {
|
||||||
"id": "linklog@kolkman.org",
|
"id": "linklog@kolkman.org",
|
||||||
"strict_min_version": "109.0",
|
"strict_min_version": "109.0",
|
||||||
|
"data_collection_permissions": {
|
||||||
|
"required": ["websiteActivity"],
|
||||||
|
"optional": []
|
||||||
|
},
|
||||||
"update_url": "https://git.kolkman.org/olaf/Link-Log/raw/branch/main/webextension/updates.json"
|
"update_url": "https://git.kolkman.org/olaf/Link-Log/raw/branch/main/webextension/updates.json"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user