mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-10-26 23:33:02 +08:00
[build] remove license validation from mobile builds
This commit is contained in:
@@ -36,7 +36,6 @@ on:
|
||||
- "apps/android/**"
|
||||
- "apps/ios/CrossDeskMobile/Resources/ThirdPartyLicenses.json"
|
||||
- "apps/ios/licenses/**"
|
||||
- "apps/ios/scripts/generate_third_party_licenses.py"
|
||||
- "deps/submodules/minirtc"
|
||||
- "libs/wire/**"
|
||||
|
||||
@@ -155,9 +154,6 @@ jobs:
|
||||
cache-provider: basic
|
||||
cache-read-only: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
- name: Verify shared license catalog
|
||||
run: python3 -B apps/ios/scripts/generate_third_party_licenses.py
|
||||
|
||||
- name: Resolve Android version
|
||||
shell: python
|
||||
env:
|
||||
|
||||
@@ -169,9 +169,6 @@ jobs:
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
- name: Verify iOS license catalog
|
||||
run: python3 -B apps/ios/scripts/generate_third_party_licenses.py
|
||||
|
||||
- name: Install xmake
|
||||
uses: xmake-io/github-action-setup-xmake@v1
|
||||
with:
|
||||
@@ -181,7 +178,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
xmake --version | tee "${RUNNER_TEMP}/xmake-version.txt"
|
||||
python3 -B apps/ios/scripts/generate_third_party_licenses.py \
|
||||
python3 -B apps/ios/scripts/verify_native_build.py \
|
||||
--xmake-version "${RUNNER_TEMP}/xmake-version.txt"
|
||||
|
||||
- name: Pin xmake package repository
|
||||
|
||||
@@ -246,4 +246,4 @@ AV1 硬件路径尚无对应实机验证;Retroid 上使用 dav1d 软件解码
|
||||
|
||||
设置 → 关于使用与 iOS 相同的分组及入口:版本、软件许可、开源组件、源码与构建说明。软件许可中可分别阅读 GNU GPL 第 3 版及开源软件权利说明;开源组件页单独展示 OpenFEC 告知,其余组件列出名称和许可证,详情包含版本、源码、适用的构建配方和每一份许可文档。内容按 Android 构建生成,不显示未使用的 iOS 依赖,Android 签名说明替换 Apple 签名说明。
|
||||
|
||||
APK 保留完整 `THIRD_PARTY_NOTICES.txt`,并生成轻量的 `ThirdPartyLicenses.json` 索引、72 份独立许可文档及 `SourceMetadata.json`。打开文档时才读取正文,长文按有限长度分块显示,支持文本选择、复制与网页链接;打包验证核对每份正文的 SHA-256。源码页面显示标签或提交版本及未发布修改提示,源码链接指向基础提交。当前 Android 构建说明、构建脚本、MiniRTC、OpenSSL 及 SVT-AV1 配方随 APK 离线提供,避免开发版链接指向基础提交中尚不存在的 Android 文件。
|
||||
APK 保留完整 `THIRD_PARTY_NOTICES.txt`,并生成轻量的 `ThirdPartyLicenses.json` 索引、72 份独立许可文档及 `SourceMetadata.json`。打开文档时才读取正文,长文按有限长度分块显示,支持文本选择、复制与网页链接。构建继续生成并打包许可资料,CI 和 APK 验证不再检查许可证内容、哈希或组件清单。源码页面显示标签或提交版本及未发布修改提示,源码链接指向基础提交。当前 Android 构建说明、构建脚本、MiniRTC、OpenSSL 及 SVT-AV1 配方随 APK 离线提供,避免开发版链接指向基础提交中尚不存在的 Android 文件。
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Package existing reviewed notices for the Android runtime dependency set."""
|
||||
import json
|
||||
import hashlib
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
@@ -70,8 +69,7 @@ def write_pages(output, catalog, additional, revision, minirtc):
|
||||
target = output / asset
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
target.write_text(document['text'], encoding='utf-8')
|
||||
documents.append({'title': document['title'], 'asset': asset,
|
||||
'sha256': hashlib.sha256(document['text'].encode('utf-8')).hexdigest()})
|
||||
documents.append({'title': document['title'], 'asset': asset})
|
||||
component['documents'] = documents
|
||||
(output / 'ThirdPartyLicenses.json').write_text(json.dumps(
|
||||
{'schemaVersion': 1, 'components': components}, ensure_ascii=False, indent=2)+'\n', encoding='utf-8')
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
"""Check the shipped native ABI, ELF load alignment and APK zip alignment."""
|
||||
from pathlib import Path
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
import struct
|
||||
@@ -40,33 +39,15 @@ def verify(path):
|
||||
name, extra = struct.unpack('<HH', raw.read(4))
|
||||
if (library.header_offset + 30 + name + extra) % 16384:
|
||||
raise ValueError('APK native library entry is not 16 KB aligned')
|
||||
if 'assets/THIRD_PARTY_NOTICES.txt' not in archive.namelist():
|
||||
raise ValueError('Missing third-party notices')
|
||||
if archive.read('assets/PRIVACY.md') != (Path(__file__).resolve().parents[3] / 'PRIVACY.md').read_bytes():
|
||||
raise ValueError('Missing or outdated bundled privacy policy')
|
||||
catalog = json.loads(archive.read('assets/ThirdPartyLicenses.json'))
|
||||
source = json.loads(archive.read('assets/SourceMetadata.json'))
|
||||
components = catalog['components']
|
||||
ids = [item['id'] for item in components]
|
||||
if catalog['schemaVersion'] != 1 or len(ids) != len(set(ids)) or not {
|
||||
'crossdesk', 'minirtc', 'openfec', 'openh264', 'libiconv', 'android-ndk', 'svt-av1'}.issubset(ids):
|
||||
raise ValueError('Incomplete About catalog')
|
||||
for component in components:
|
||||
if not component['documents']:
|
||||
raise ValueError('Missing component documents')
|
||||
for document in component['documents']:
|
||||
text = archive.read('assets/'+document['asset'])
|
||||
if not text or hashlib.sha256(text).hexdigest() != document['sha256']:
|
||||
raise ValueError('Incomplete license document: '+document['asset'])
|
||||
for document in component.get('buildDocuments', []):
|
||||
if not archive.read('assets/'+document['asset']):
|
||||
raise ValueError('Missing build document')
|
||||
if source['schemaVersion'] != 1 or len(source['revision']) != 40:
|
||||
raise ValueError('Missing source revision')
|
||||
for document in source['buildDocuments']:
|
||||
if not archive.read('assets/'+document['asset']):
|
||||
raise ValueError('Missing source build instructions')
|
||||
print(f'PASS: {Path(path).name}: arm64, 16 KB ELF/ZIP alignment, privacy policy, notices, About catalog and documents')
|
||||
print(f'PASS: {Path(path).name}: arm64, 16 KB ELF/ZIP alignment, privacy policy and source metadata')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -274,7 +274,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/zsh;
|
||||
shellScript = "set -e\npython3 \"${PROJECT_DIR}/scripts/generate_third_party_licenses.py\"\npython3 \"${PROJECT_DIR}/scripts/prepare_source_metadata.py\" --output \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SourceMetadata.json\"\n\"${PROJECT_DIR}/scripts/build_minirtc_ios.sh\"\npython3 \"${PROJECT_DIR}/scripts/generate_third_party_licenses.py\" --inputs \"${PROJECT_DIR}/Vendor/${PLATFORM_NAME}/${CONFIGURATION}/libCrossDeskMiniRTC.a.inputs.sha256\" --target-info \"${PROJECT_DIR}/Vendor/${PLATFORM_NAME}/${CONFIGURATION}/minirtc-target-info.txt\" --xmake-version \"${PROJECT_DIR}/Vendor/${PLATFORM_NAME}/${CONFIGURATION}/xmake-version.txt\" --xmake-repository \"$(cat \"${PROJECT_DIR}/Vendor/${PLATFORM_NAME}/${CONFIGURATION}/xmake-repository.txt\")\"\npython3 \"${PROJECT_DIR}/scripts/package_openssl_ios.py\" --inputs \"${PROJECT_DIR}/Vendor/${PLATFORM_NAME}/${CONFIGURATION}/libCrossDeskMiniRTC.a.inputs.sha256\" --output \"${BUILT_PRODUCTS_DIR}/OpenSSL.framework\" --platform \"${PLATFORM_NAME}\"\n";
|
||||
shellScript = "set -e\npython3 \"${PROJECT_DIR}/scripts/prepare_source_metadata.py\" --output \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SourceMetadata.json\"\n\"${PROJECT_DIR}/scripts/build_minirtc_ios.sh\"\npython3 \"${PROJECT_DIR}/scripts/verify_native_build.py\" --inputs \"${PROJECT_DIR}/Vendor/${PLATFORM_NAME}/${CONFIGURATION}/libCrossDeskMiniRTC.a.inputs.sha256\" --xmake-version \"${PROJECT_DIR}/Vendor/${PLATFORM_NAME}/${CONFIGURATION}/xmake-version.txt\" --xmake-repository \"$(cat \"${PROJECT_DIR}/Vendor/${PLATFORM_NAME}/${CONFIGURATION}/xmake-repository.txt\")\"\npython3 \"${PROJECT_DIR}/scripts/package_openssl_ios.py\" --inputs \"${PROJECT_DIR}/Vendor/${PLATFORM_NAME}/${CONFIGURATION}/libCrossDeskMiniRTC.a.inputs.sha256\" --output \"${BUILT_PRODUCTS_DIR}/OpenSSL.framework\" --platform \"${PLATFORM_NAME}\"\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
|
||||
+13
-13
@@ -145,7 +145,7 @@ workflow on branch/tag pushes and manual runs, and waits for its result before
|
||||
publishing a version-tag release.
|
||||
|
||||
The workflow builds with the minimum supported Xmake version (3.1.1) and retains
|
||||
the pinned Xcode/SDK, dependency cache, license catalog validation, unsigned arm64
|
||||
the pinned Xcode/SDK, dependency cache, native input validation, unsigned arm64
|
||||
Release build, and app-bundle verification. Unit tests run locally as needed.
|
||||
It uploads
|
||||
`crossdesk-ios-arm64-unsigned-v<version>-<date>.zip`,
|
||||
@@ -366,16 +366,16 @@ collected from the reviewed runtime source directories; the catalog is an
|
||||
attribution superset, not a claim that every source file survives linker
|
||||
dead stripping.
|
||||
|
||||
Normal Xcode builds verify the checked-in resource, local license files and
|
||||
package recipes offline before compiling native code. After compilation they
|
||||
also compare all resolved dependency versions (including header-only packages)
|
||||
with the catalog and check the merged archive's input hashes and pinned
|
||||
toolchain. A missing, stale or altered catalog fails the build. Ordinary MiniRTC
|
||||
code changes do not require changing the notice-review revision or regenerating
|
||||
the catalog. Changes to dependencies, license texts or embedded third-party
|
||||
notices still require reviewing and updating the affected catalog entries;
|
||||
regeneration alone does not select a new dependency version.
|
||||
`MINIRTC_ENABLE_AOM=true` also requires a reviewed AOM entry.
|
||||
Builds package the license resources without validating their contents, hashes
|
||||
or agreement with resolved dependency versions. License generation is a manual
|
||||
maintenance step and is not run by CI or Xcode. Update the catalog and regenerate
|
||||
the resource when the notices need to change; regeneration does not select a
|
||||
new dependency version.
|
||||
|
||||
`scripts/verify_native_build.py` independently checks the native archive input
|
||||
hashes and pinned Xmake toolchain after compilation. These checks do not read
|
||||
the license catalog. Downloaded source archives retain their SHA-256 checks
|
||||
when manually regenerating notices.
|
||||
|
||||
The source screen links to the exact application tag/commit, MiniRTC commit,
|
||||
and custom dependency recipes/patches. `SourceMetadata.json` is generated in
|
||||
@@ -395,8 +395,8 @@ archives available for recipients of that release.
|
||||
To change a library, edit MiniRTC in its submodule, or modify the relevant
|
||||
package recipe/patch under `deps/submodules/minirtc/thirdparty`. If a package
|
||||
recipe changes, change its package configuration revision (or rebuild that
|
||||
package) so Xmake does not reuse a previous binary. Review affected notices,
|
||||
update recipe hashes, and commit MiniRTC. When the notice catalog changes,
|
||||
package) so Xmake does not reuse a previous binary. Update affected notices
|
||||
and commit MiniRTC. When the notice catalog changes,
|
||||
record the reviewed revision in `sources.json` and regenerate the catalog.
|
||||
Build the application again to relink it with
|
||||
the modified library. Use your own team and bundle identifier to install the
|
||||
|
||||
+47
-114
@@ -14,15 +14,12 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "asio/COPYING",
|
||||
"sha256": "5cc69ca9afd3417ed8e58bcd9c0bb730375e9e3e92b5aaf6483b93a2837e0cac"
|
||||
"path": "asio/COPYING"
|
||||
},
|
||||
{
|
||||
"path": "asio/LICENSE_1_0.txt",
|
||||
"sha256": "c9bff75738922193e67fa726fa225535870d2aa1059f91452c411736284ad566"
|
||||
"path": "asio/LICENSE_1_0.txt"
|
||||
}
|
||||
],
|
||||
"recipe_sha256": "52bddc12cf0837117e935ea5d71aa5c35e7fd6ae802aa7401c6dba598cae0989",
|
||||
"recipe_path": "xmake-repo/packages/a/asio/xmake.lua",
|
||||
"package": "asio",
|
||||
"notice_prefixes": [
|
||||
@@ -41,11 +38,9 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "LICENSE.md",
|
||||
"sha256": "22331571e5e3dbe4c79ad715e23127bdf3beabd75052c953ddabf191ef799e14"
|
||||
"path": "LICENSE.md"
|
||||
}
|
||||
],
|
||||
"recipe_sha256": "23c69dc09488527b0d6adf1d25f795a9f0afdc7a1d594c44603c2dd07162faa4",
|
||||
"recipe_path": "xmake-repo/packages/c/concurrentqueue/xmake.lua",
|
||||
"package": "concurrentqueue",
|
||||
"notice_prefixes": [
|
||||
@@ -66,12 +61,10 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "LICENSE",
|
||||
"sha256": "3972dc9744f6499f0f9b2dbf76696f2ae7ad8af9b23dde66d6af86c9dfb36986"
|
||||
"path": "LICENSE"
|
||||
},
|
||||
{
|
||||
"path": "apps/ios/licenses/OPEN_SOURCE_NOTICE.txt",
|
||||
"sha256": "34720d126e6373603d0c1802a8c3276802b93f2a8fbbf2b61837c6fdefea8877"
|
||||
"path": "apps/ios/licenses/OPEN_SOURCE_NOTICE.txt"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -88,12 +81,10 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "COPYING",
|
||||
"sha256": "b327887de263238deaa80c34cdd2ff3e0ba1d35db585ce14a37ce3e74ee389e9"
|
||||
"path": "COPYING"
|
||||
},
|
||||
{
|
||||
"path": "doc/PATENTS",
|
||||
"sha256": "335eca574598bf4ca181b12f708d6669e5a5e78c8e1513e5b35fa1f03901484b"
|
||||
"path": "doc/PATENTS"
|
||||
}
|
||||
],
|
||||
"package": "dav1d",
|
||||
@@ -114,39 +105,30 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "COPYING",
|
||||
"sha256": "fa6f36630bb1e0c571d34b2bbdf188d08495c9dbf58f28cac112f303fc1f58fb"
|
||||
"path": "COPYING"
|
||||
},
|
||||
{
|
||||
"path": "LICENSES/Apache-2.0.txt",
|
||||
"sha256": "074e6e32c86a4c0ef8b3ed25b721ca23aca83df277cd88106ef7177c354615ff"
|
||||
"path": "LICENSES/Apache-2.0.txt"
|
||||
},
|
||||
{
|
||||
"path": "LICENSES/CC0-1.0.txt",
|
||||
"sha256": "a2010f343487d3f7618affe54f789f5487602331c0a8d03f49e9a7c547cf0499"
|
||||
"path": "LICENSES/CC0-1.0.txt"
|
||||
},
|
||||
{
|
||||
"path": "LICENSES/LGPL-2.1-only.txt",
|
||||
"sha256": "fa6f36630bb1e0c571d34b2bbdf188d08495c9dbf58f28cac112f303fc1f58fb"
|
||||
"path": "LICENSES/LGPL-2.1-only.txt"
|
||||
},
|
||||
{
|
||||
"path": "LICENSES/LLVM-exception.txt",
|
||||
"sha256": "e34c58338bd89d43e709e226610d8f32b3e3c47f4ad9a99a8dc1d4ac7842488e"
|
||||
"path": "LICENSES/LLVM-exception.txt"
|
||||
},
|
||||
{
|
||||
"path": "LICENSES/MIT.txt",
|
||||
"sha256": "b85dcd3e453d05982552c52b5fc9e0bdd6d23c6f8e844b984a88af32570b0cc0"
|
||||
"path": "LICENSES/MIT.txt"
|
||||
},
|
||||
{
|
||||
"path": "LICENSES/MPL-1.1.txt",
|
||||
"sha256": "6214f8b1300bb9f37b16ebc146f8f61af0187e0025042ff95c8b3030744a8795"
|
||||
"path": "LICENSES/MPL-1.1.txt"
|
||||
},
|
||||
{
|
||||
"path": "subprojects/gvdb/COPYING",
|
||||
"sha256": "bdbcdaa7858872393e9d6b216bbdc8a23e99d98dd6cdb7cda19458025b9e19fc"
|
||||
"path": "subprojects/gvdb/COPYING"
|
||||
}
|
||||
],
|
||||
"recipe_sha256": "650e2f9a1c4b5079694a5626cfcb625c650a938f32878cf0caab3b0cf58216b9",
|
||||
"recipe_path": "deps/submodules/minirtc/thirdparty/glib/xmake.lua",
|
||||
"package": "glib",
|
||||
"notice_prefixes": [
|
||||
@@ -169,8 +151,7 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "deps/submodules/minirtc/src/inih/LICENSE",
|
||||
"sha256": "bd2a675a5a26fbff77f171f3a15afb1a9c7855be1a01c7e3fd16b8d2617acdda"
|
||||
"path": "deps/submodules/minirtc/src/inih/LICENSE"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -186,11 +167,9 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "LICENSE.MIT",
|
||||
"sha256": "86b998c792894ccb911a1cb7994f7a9652894e7a094c0b5e45be2f553f45cf14"
|
||||
"path": "LICENSE.MIT"
|
||||
}
|
||||
],
|
||||
"recipe_sha256": "eadd211f0521a18207e9544c0c5a08c41dca578fce99df5c2577f6fcf2a0fdce",
|
||||
"recipe_path": "xmake-repo/packages/n/nlohmann_json/xmake.lua",
|
||||
"package": "nlohmann_json",
|
||||
"notice_prefixes": [
|
||||
@@ -209,11 +188,9 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "LICENSE",
|
||||
"sha256": "6587fd02a924b97dbd6758b0573ddec056fb494a84f3709c5aaa33ce1f7f029c"
|
||||
"path": "LICENSE"
|
||||
}
|
||||
],
|
||||
"recipe_sha256": "f86cac2c4b884f3347a39a59f3dd8de566c257c7fd481c6e49b05f4730f12c4f",
|
||||
"recipe_path": "xmake-repo/packages/k/kcp/xmake.lua",
|
||||
"package": "kcp",
|
||||
"notice_prefixes": [
|
||||
@@ -233,11 +210,9 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "LICENSE",
|
||||
"sha256": "fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85"
|
||||
"path": "LICENSE"
|
||||
}
|
||||
],
|
||||
"recipe_sha256": "b3ec15652a47d65e0a1f85f62d02c098c5cf5b8d8c3cf7b03ff099efa7016326",
|
||||
"recipe_path": "deps/submodules/minirtc/thirdparty/libdatachannel/xmake.lua",
|
||||
"package": "libdatachannel",
|
||||
"notice_prefixes": [
|
||||
@@ -257,11 +232,9 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "LICENSE",
|
||||
"sha256": "67894089811f93fca47a76f85e017da6f8582d4ba0905963c6e0f1ad6df7a195"
|
||||
"path": "LICENSE"
|
||||
}
|
||||
],
|
||||
"recipe_sha256": "de19ac4e3e91ef5715ac582c75e0d10404dc14ec4e33b2e764dc2637a78d24e9",
|
||||
"recipe_path": "xmake-repo/packages/l/libffi/xmake.lua",
|
||||
"package": "libffi",
|
||||
"notice_prefixes": [
|
||||
@@ -281,23 +254,18 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "COPYING",
|
||||
"sha256": "e5504e5ffe894870ea1a652df957a120ead9c3f9a5e9d314ca41ba06f2d72024"
|
||||
"path": "COPYING"
|
||||
},
|
||||
{
|
||||
"path": "COPYING.LGPL",
|
||||
"sha256": "a9bdde5616ecdd1e980b44f360600ee8783b1f99b8cc83a2beb163a0a390e861"
|
||||
"path": "COPYING.LGPL"
|
||||
},
|
||||
{
|
||||
"path": "COPYING.MPL",
|
||||
"sha256": "3b3c75ae6c663c4f93987647eb5463d33dc1602a1aded3ac479773f2c3928e3a"
|
||||
"path": "COPYING.MPL"
|
||||
},
|
||||
{
|
||||
"path": "AUTHORS",
|
||||
"sha256": "d72eb6fa9d5e93abb11d13b6c6f04fda2ba183d0705e703887cda243f6f1eead"
|
||||
"path": "AUTHORS"
|
||||
}
|
||||
],
|
||||
"recipe_sha256": "dbb3cd85fd197f6495c611a08f99b1c70b88c48c91f6e6ea24946a1b0701a3d5",
|
||||
"recipe_path": "deps/submodules/minirtc/thirdparty/libnice/xmake.lua",
|
||||
"package": "libnice",
|
||||
"notice_prefixes": [
|
||||
@@ -320,11 +288,9 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "LICENSE",
|
||||
"sha256": "8e19d42a1eec9561f3f347253ddf2e385c55f392f025bb0fd41b88dbf38db5ae"
|
||||
"path": "LICENSE"
|
||||
}
|
||||
],
|
||||
"recipe_sha256": "9629edb8d395ea3017af1702cafea57173ca0a6a1ea305a6174b1936598faec6",
|
||||
"recipe_path": "deps/submodules/minirtc/thirdparty/libsrtp/xmake.lua",
|
||||
"package": "libsrtp",
|
||||
"notice_prefixes": [
|
||||
@@ -346,16 +312,13 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "LICENSE",
|
||||
"sha256": "2b2cc1180c7e6988328ad2033b04b80117419db9c4c584918bbb3cfec7e9364f"
|
||||
"path": "LICENSE"
|
||||
},
|
||||
{
|
||||
"path": "PATENTS",
|
||||
"sha256": "4da84211f947c6f9f7dd8fbce513e1522e01833407ae732b8c9a2bbb75fed495"
|
||||
"path": "PATENTS"
|
||||
},
|
||||
{
|
||||
"path": "AUTHORS",
|
||||
"sha256": "0c4a51c72a06b3431bb2b750e3b04dbe3694b22e2fcae6e370216424eec56d52"
|
||||
"path": "AUTHORS"
|
||||
}
|
||||
],
|
||||
"package": "libyuv",
|
||||
@@ -376,8 +339,7 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "deps/submodules/minirtc/LICENSE",
|
||||
"sha256": "ea8af5e789cb2d4e9b10bce3874982ade163b749b6bfbdb32e2df21c4d106de1"
|
||||
"path": "deps/submodules/minirtc/LICENSE"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -394,11 +356,9 @@
|
||||
"documents": [
|
||||
{
|
||||
"path": "LICENCE_CeCILL-C_V1-en.txt",
|
||||
"sha256": "b48f5dc16f144cd79ddaadce3cc8ef183778a0b4f75ab4362e134b347ca20f3d",
|
||||
"encoding": "iso-8859-1"
|
||||
}
|
||||
],
|
||||
"recipe_sha256": "a9bc4a460195c77543a91c0a2b40a094f4a3869dc917e4eb98e7e8005ea441ab",
|
||||
"recipe_path": "deps/submodules/minirtc/thirdparty/openfec/xmake.lua",
|
||||
"package": "openfec",
|
||||
"notice_prefixes": [
|
||||
@@ -422,11 +382,9 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "LICENSE.txt",
|
||||
"sha256": "7d5450cb2d142651b8afa315b5f238efc805dad827d91ba367d8516bc9d49e7a"
|
||||
"path": "LICENSE.txt"
|
||||
}
|
||||
],
|
||||
"recipe_sha256": "230631f3cddc72674fa21d2639044b00120ee346ef186eddfb5dc04bf4df3ee9",
|
||||
"recipe_path": "deps/submodules/minirtc/thirdparty/openssl/xmake.lua",
|
||||
"package": "openssl3",
|
||||
"notice_prefixes": [
|
||||
@@ -448,11 +406,9 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "COPYING",
|
||||
"sha256": "01e1167d54a096d123cf6dfbbeb19587278845c6481d2d66d545669846079551"
|
||||
"path": "COPYING"
|
||||
}
|
||||
],
|
||||
"recipe_sha256": "c965643eb4e093858c27c402e6cde544620460f2169c89d8ff2bab01111d022b",
|
||||
"recipe_path": "xmake-repo/packages/l/libopus/xmake.lua",
|
||||
"package": "libopus",
|
||||
"notice_prefixes": [
|
||||
@@ -475,19 +431,15 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "LICENCE.md",
|
||||
"sha256": "197d8a73ffee0d6b09adba2f9c677b5f5aede24edf89258a68e48248d010d811"
|
||||
"path": "LICENCE.md"
|
||||
},
|
||||
{
|
||||
"path": "COPYING",
|
||||
"sha256": "99272c55f3dcfa07a8a7e15a5c1a33096e4727de74241d65fa049fccfdd59507"
|
||||
"path": "COPYING"
|
||||
},
|
||||
{
|
||||
"path": "deps/sljit/LICENSE",
|
||||
"sha256": "5f216505c0f6ea3273caec89e766eef93cdeb7bbb0c429f9360116d7c938feeb"
|
||||
"path": "deps/sljit/LICENSE"
|
||||
}
|
||||
],
|
||||
"recipe_sha256": "821f1fbc91434f4324be88eeea754db09c5d7be31446242764861ca2aee136b7",
|
||||
"recipe_path": "xmake-repo/packages/p/pcre2/xmake.lua",
|
||||
"package": "pcre2",
|
||||
"notice_prefixes": [
|
||||
@@ -508,11 +460,9 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "LICENSE",
|
||||
"sha256": "e4d01796524cbc13b1571a1f0914823c6a23b316ba039e7014f47a4eef7fd4c3"
|
||||
"path": "LICENSE"
|
||||
}
|
||||
],
|
||||
"recipe_sha256": "deb525d09b5b79351eeb524ab3bc6a3009e434974e585e5e8852c491d7fa07c8",
|
||||
"recipe_path": "xmake-repo/packages/p/plog/xmake.lua",
|
||||
"package": "plog",
|
||||
"notice_prefixes": [
|
||||
@@ -532,8 +482,7 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "COPYING",
|
||||
"sha256": "d245807f90032872d1438d741ed21e2490e1175dc8aa3afa5ddb6c8e529b58e5"
|
||||
"path": "COPYING"
|
||||
}
|
||||
],
|
||||
"bundled_by": "glib",
|
||||
@@ -555,11 +504,9 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "LICENSE",
|
||||
"sha256": "4ccecab18d1ff0b61174fe3d6c430541625d3ddb865b0d5887db296f883c76e7"
|
||||
"path": "LICENSE"
|
||||
}
|
||||
],
|
||||
"recipe_sha256": "5b299effb366420b4920c5b89e6535b76173136d91ee01f8f7d3423486a93549",
|
||||
"recipe_path": "xmake-repo/packages/s/spdlog/xmake.lua",
|
||||
"package": "spdlog",
|
||||
"notice_prefixes": [
|
||||
@@ -579,24 +526,19 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "LICENSE.md",
|
||||
"sha256": "0acc2fcb27472bdc9aaf8b71f37055bbdac4f54671b7d922f241bd7fcd0dd3e6"
|
||||
"path": "LICENSE.md"
|
||||
},
|
||||
{
|
||||
"path": "LICENSE-BSD2.md",
|
||||
"sha256": "c582fcbeb9cf972a60d298bfaf41dc5adff2dd14208946edcb9bb56a281e8438"
|
||||
"path": "LICENSE-BSD2.md"
|
||||
},
|
||||
{
|
||||
"path": "PATENTS.md",
|
||||
"sha256": "20678ab10402659106dc4c147c97b2a6e94b5c0695415e15a8f195ebc3547922"
|
||||
"path": "PATENTS.md"
|
||||
},
|
||||
{
|
||||
"path": "third_party/fastfeat/LICENSE",
|
||||
"sha256": "043dcfd059386f9facd376351b2bd79325778744aa442177390cdfcca54babed"
|
||||
"path": "third_party/fastfeat/LICENSE"
|
||||
},
|
||||
{
|
||||
"path": "third_party/safestringlib/LICENSE",
|
||||
"sha256": "c0f99a208799ca20c9ccf31a30533d49334eb458dca5a3d14f9afe3e884e5d7d"
|
||||
"path": "third_party/safestringlib/LICENSE"
|
||||
}
|
||||
],
|
||||
"package": "svt-av1",
|
||||
@@ -618,11 +560,9 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "LICENSE.md",
|
||||
"sha256": "fa53711b25af4b9a9b8dadfea3cb38166ec4b96760c8d62b284055554537d9ef"
|
||||
"path": "LICENSE.md"
|
||||
}
|
||||
],
|
||||
"recipe_sha256": "e3dac7d1db8e5bc79d99851e2486371af19962a4b8fca6eaac3156c00eb73b92",
|
||||
"recipe_path": "xmake-repo/packages/u/usrsctp/xmake.lua",
|
||||
"package": "usrsctp",
|
||||
"notice_prefixes": [
|
||||
@@ -641,12 +581,10 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "deps/submodules/minirtc/thirdparty/webrtc/LICENSE",
|
||||
"sha256": "ab00a482b6a3902e40211b43c5d0441962ea99b6cc7c25c0f243fa270b78d482"
|
||||
"path": "deps/submodules/minirtc/thirdparty/webrtc/LICENSE"
|
||||
},
|
||||
{
|
||||
"path": "deps/submodules/minirtc/thirdparty/webrtc/PATENTS",
|
||||
"sha256": "01462e2068d1a04c2274f3389773014c14ed9bc3446b28303543bd3e3c064145"
|
||||
"path": "deps/submodules/minirtc/thirdparty/webrtc/PATENTS"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -662,11 +600,9 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "COPYING",
|
||||
"sha256": "b31e597bc777d884a39663c11d0557a0af40780e1f451de11ea5103924a69667"
|
||||
"path": "COPYING"
|
||||
}
|
||||
],
|
||||
"recipe_sha256": "beac245a717c2bc3bc8d17265d9fc9b54f699f3833b11513f8723c4dbaffd539",
|
||||
"recipe_path": "deps/submodules/minirtc/thirdparty/websocketpp/xmake.lua",
|
||||
"package": "websocketpp",
|
||||
"notice_prefixes": [
|
||||
@@ -685,11 +621,9 @@
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"path": "LICENSE",
|
||||
"sha256": "e32ff4e00d9d94930537635291da39e7e612703334bf6fde8c7f1686fe8a45a2"
|
||||
"path": "LICENSE"
|
||||
}
|
||||
],
|
||||
"recipe_sha256": "7832bcb086709a0739ae1abeff035f7a103c7169dc8af61ebf91dd887fcbd054",
|
||||
"recipe_path": "xmake-repo/packages/z/zlib/xmake.lua",
|
||||
"package": "zlib",
|
||||
"notice_prefixes": [
|
||||
@@ -697,7 +631,6 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"bundle_sha256": "a27c89beaaee2397a306417ff133d7f48c74fe6db9041e145fc08f18ec69a080",
|
||||
"toolchain": {
|
||||
"xmake_min_version": "3.1.1",
|
||||
"xmake_repository_revision": "121109352da272cd1a3d4ed52f2dcda34f839955"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Collect iOS notices from pinned source archives; validate them offline at build time."""
|
||||
"""Generate iOS notice resources from pinned source archives."""
|
||||
|
||||
import argparse
|
||||
from collections import defaultdict
|
||||
@@ -8,7 +8,6 @@ import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import tarfile
|
||||
import urllib.request
|
||||
@@ -82,7 +81,7 @@ def source_files(component, cache):
|
||||
def component_documents(component, names, read):
|
||||
documents = []
|
||||
for item in component["documents"]:
|
||||
data = checked(read(item["path"]), item["sha256"], item["path"])
|
||||
data = read(item["path"])
|
||||
text = data.decode(item.get("encoding", "utf-8"))
|
||||
if "end_before" in item:
|
||||
if item["end_before"] not in text:
|
||||
@@ -134,79 +133,22 @@ def generate(lock, cache):
|
||||
return json_bytes({"schemaVersion": 1, "components": components})
|
||||
|
||||
|
||||
def verify(lock, inputs, target_info, xmake_repository=None, xmake_version=None):
|
||||
checked(OUTPUT.read_bytes(), lock["bundle_sha256"], str(OUTPUT))
|
||||
if xmake_version is not None:
|
||||
minimum = lock["toolchain"]["xmake_min_version"]
|
||||
version = re.search(r"xmake v(\d+)\.(\d+)\.(\d+)(?:\+|[,\s]|$)", xmake_version.read_text())
|
||||
if not version or tuple(map(int, version.groups())) < tuple(map(int, minimum.split("."))):
|
||||
raise ValueError(f"Xmake {minimum} or newer is required; see apps/ios/README.md")
|
||||
if xmake_repository is not None:
|
||||
revision = subprocess.check_output(
|
||||
["git", "-C", str(xmake_repository), "rev-parse", "HEAD"], text=True).strip()
|
||||
if revision != lock["toolchain"]["xmake_repository_revision"]:
|
||||
raise ValueError("Xmake package repository differs from the reviewed iOS source catalog")
|
||||
changes = subprocess.check_output(
|
||||
["git", "-C", str(xmake_repository), "status", "--porcelain", "--untracked-files=normal"],
|
||||
text=True).strip()
|
||||
if changes:
|
||||
raise ValueError("Xmake package repository has local changes; use the unmodified pinned revision")
|
||||
for component in lock["components"]:
|
||||
recipe = component.get("recipe_path", "")
|
||||
if recipe.startswith("deps/"):
|
||||
checked((REPO / recipe).read_bytes(), component["recipe_sha256"], recipe)
|
||||
elif recipe.startswith("xmake-repo/") and xmake_repository is not None:
|
||||
checked((xmake_repository / Path(recipe).relative_to("xmake-repo")).read_bytes(),
|
||||
component["recipe_sha256"], recipe)
|
||||
if component["source"]["kind"] == "repository":
|
||||
for item in component["documents"]:
|
||||
checked((REPO / item["path"]).read_bytes(), item["sha256"], item["path"])
|
||||
if inputs is None:
|
||||
return
|
||||
if target_info is None:
|
||||
raise ValueError("--target-info is required with --inputs (includes header-only dependencies)")
|
||||
known = {c["package"]: c["version"] for c in lock["components"] if "package" in c}
|
||||
seen = {}
|
||||
# Package names/versions come from resolved Xmake link and include paths,
|
||||
# never from an inventory of all packages left in the installation cache.
|
||||
pattern = r"/packages(?:-simulator)?/[^/\s]+/([^/\s]+)/([^/\s]+)/[a-f0-9]+/"
|
||||
for name, version in re.findall(pattern, inputs.read_text() + target_info.read_text()):
|
||||
if name not in known or known[name] != version:
|
||||
raise ValueError(f"Unreviewed iOS dependency: {name} {version}; regenerate licenses from its source")
|
||||
seen[name] = version
|
||||
if set(seen) != set(known):
|
||||
raise ValueError(f"License/build dependency mismatch; missing: {sorted(set(known) - set(seen))}")
|
||||
for line in inputs.read_text().splitlines():
|
||||
sha, path = line.split(maxsplit=1)
|
||||
checked(Path(path).read_bytes(), sha, path)
|
||||
# Repository revisions identify the reviewed notices, not a required build
|
||||
# commit. SourceMetadata records the actual MiniRTC revision and links for
|
||||
# this build; the content and dependency checks above detect stale notices.
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--generate", action="store_true", help="download/check pinned sources and regenerate the bundled JSON")
|
||||
parser.add_argument("--generate", action="store_true", required=True,
|
||||
help="download pinned sources and regenerate the bundled JSON")
|
||||
parser.add_argument("--cache", type=Path, default=Path.home() / ".cache/crossdesk/licenses")
|
||||
parser.add_argument("--inputs", type=Path, help="native archive .inputs.sha256 manifest")
|
||||
parser.add_argument("--target-info", type=Path, help="resolved Xmake minirtc target information")
|
||||
parser.add_argument("--xmake-repository", type=Path, help="verify the active pinned package repository and recipes")
|
||||
parser.add_argument("--xmake-version", type=Path, help="Xmake version output recorded by the native build")
|
||||
args = parser.parse_args()
|
||||
lock = json.loads(LOCK.read_text())
|
||||
if args.generate:
|
||||
data = generate(lock, args.cache)
|
||||
OUTPUT.parent.mkdir(parents=True, exist_ok=True)
|
||||
OUTPUT.write_bytes(data)
|
||||
lock["bundle_sha256"] = digest(data)
|
||||
LOCK.write_bytes(json_bytes(lock))
|
||||
verify(lock, args.inputs, args.target_info, args.xmake_repository, args.xmake_version)
|
||||
print(f"Verified {len(lock['components'])} iOS license components")
|
||||
data = generate(lock, args.cache)
|
||||
OUTPUT.parent.mkdir(parents=True, exist_ok=True)
|
||||
OUTPUT.write_bytes(data)
|
||||
print(f"Generated {len(lock['components'])} iOS license components")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
except (OSError, ValueError, KeyError, subprocess.CalledProcessError) as error:
|
||||
except (OSError, ValueError, KeyError) as error:
|
||||
print(f"Third-party notices: {error}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
"""Record the source corresponding to an iOS build without changing the checkout."""
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
@@ -66,8 +65,6 @@ def source_metadata(require_release=False, tag=None):
|
||||
"miniRTCRevision": mini_revision,
|
||||
"miniRTCSourceURL": f"{MINIRTC_URL}/tree/{mini_revision}",
|
||||
"componentSources": component_sources(lock, mini_revision),
|
||||
"licenseCatalogSHA256": lock["bundle_sha256"],
|
||||
"sourceCatalogSHA256": hashlib.sha256(lock_path.read_bytes()).hexdigest(),
|
||||
"toolchain": lock["toolchain"],
|
||||
}
|
||||
|
||||
|
||||
@@ -38,12 +38,6 @@ def verify(app, require_release=False):
|
||||
for category, codes in required.items():
|
||||
if set(reasons.get(category, [])) != codes:
|
||||
raise ValueError(f"Missing or changed reviewed privacy reasons: {category}")
|
||||
data = (app / "ThirdPartyLicenses.json").read_bytes()
|
||||
catalog = json.loads(data)
|
||||
ids = {c["id"] for c in catalog["components"]}
|
||||
if not {"crossdesk", "minirtc", "openfec"} <= ids or "openh264" in ids:
|
||||
raise ValueError("Unexpected iOS license catalog")
|
||||
openssl = next(c for c in catalog["components"] if c["id"] == "openssl3")
|
||||
framework = app / "Frameworks/OpenSSL.framework"
|
||||
sdk_info = plistlib.loads((framework / "Info.plist").read_bytes())
|
||||
sdk_privacy_data = (framework / "PrivacyInfo.xcprivacy").read_bytes()
|
||||
@@ -57,14 +51,9 @@ def verify(app, require_release=False):
|
||||
if sdk_privacy != expected_privacy:
|
||||
raise ValueError("OpenSSL SDK privacy declaration differs from the reviewed iOS configuration")
|
||||
sdk_build = json.loads((framework / "BuildMetadata.json").read_text())
|
||||
if (sdk_info["CFBundleShortVersionString"] != openssl["version"]
|
||||
or sdk_build["version"] != openssl["version"]
|
||||
or sdk_build["sourceURL"] != openssl["sourceURL"]
|
||||
or sdk_build["buildSourceURL"] != openssl["buildSourceURL"]
|
||||
if (sdk_info["CFBundleShortVersionString"] != sdk_build["version"]
|
||||
or sdk_build["privacySHA256"] != hashlib.sha256(sdk_privacy_data).hexdigest()):
|
||||
raise ValueError("OpenSSL SDK resources do not match the source/license catalog")
|
||||
if (framework / "LICENSE.txt").read_text() != "\n\n".join(d["text"] for d in openssl["documents"]):
|
||||
raise ValueError("OpenSSL SDK license resource differs from its source notices")
|
||||
raise ValueError("OpenSSL SDK resources do not match its build metadata")
|
||||
embedded_binary = framework / sdk_info["CFBundleExecutable"]
|
||||
# Xcode removes the archive and may generate a small codeless-framework
|
||||
# stub. It must not ship a second static archive or dynamic OpenSSL copy.
|
||||
@@ -78,13 +67,11 @@ def verify(app, require_release=False):
|
||||
if "OpenSSL.framework" in linked:
|
||||
raise ValueError("OpenSSL must be statically linked into the application")
|
||||
source = json.loads((app / "SourceMetadata.json").read_text())
|
||||
if source["licenseCatalogSHA256"] != hashlib.sha256(data).hexdigest():
|
||||
raise ValueError("Bundled licenses differ from the recorded source metadata")
|
||||
if require_release and (source["isModified"] or not source["tag"]):
|
||||
raise ValueError("The app was not built from an unmodified version tag")
|
||||
if not re.fullmatch(r"[0-9a-f]{40}", source["revision"]):
|
||||
raise ValueError("Invalid source revision")
|
||||
print("Verified arm64 app, source/license resources, app privacy declarations and OpenSSL SDK privacy packaging")
|
||||
print("Verified arm64 app, source metadata, app privacy declarations and OpenSSL SDK privacy packaging")
|
||||
print("Signing, App Store validation and license authorization require separate review.")
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Verify iOS native build inputs and toolchain without consulting license data."""
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
XMAKE_MIN_VERSION = "3.1.1"
|
||||
XMAKE_REPOSITORY_REVISION = "121109352da272cd1a3d4ed52f2dcda34f839955"
|
||||
|
||||
|
||||
def verify(inputs=None, xmake_repository=None, xmake_version=None):
|
||||
if xmake_version is not None:
|
||||
version = re.search(r"xmake v(\d+)\.(\d+)\.(\d+)(?:\+|[,\s]|$)", xmake_version.read_text())
|
||||
if not version or tuple(map(int, version.groups())) < tuple(map(int, XMAKE_MIN_VERSION.split("."))):
|
||||
raise ValueError(f"Xmake {XMAKE_MIN_VERSION} or newer is required; see apps/ios/README.md")
|
||||
if xmake_repository is not None:
|
||||
revision = subprocess.check_output(
|
||||
["git", "-C", str(xmake_repository), "rev-parse", "HEAD"], text=True).strip()
|
||||
if revision != XMAKE_REPOSITORY_REVISION:
|
||||
raise ValueError("Xmake package repository differs from the pinned iOS toolchain")
|
||||
changes = subprocess.check_output(
|
||||
["git", "-C", str(xmake_repository), "status", "--porcelain", "--untracked-files=normal"],
|
||||
text=True).strip()
|
||||
if changes:
|
||||
raise ValueError("Xmake package repository has local changes; use the unmodified pinned revision")
|
||||
if inputs is not None:
|
||||
for line in inputs.read_text().splitlines():
|
||||
sha, name = line.split(maxsplit=1)
|
||||
if hashlib.sha256(Path(name).read_bytes()).hexdigest() != sha:
|
||||
raise ValueError(f"Native input checksum mismatch: {name}")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--inputs", type=Path, help="native archive .inputs.sha256 manifest")
|
||||
parser.add_argument("--xmake-repository", type=Path, help="active pinned Xmake package repository")
|
||||
parser.add_argument("--xmake-version", type=Path, help="Xmake version output recorded by the native build")
|
||||
args = parser.parse_args()
|
||||
if not any((args.inputs, args.xmake_repository, args.xmake_version)):
|
||||
parser.error("provide --inputs, --xmake-repository or --xmake-version")
|
||||
verify(args.inputs, args.xmake_repository, args.xmake_version)
|
||||
print("Verified iOS native build inputs and toolchain")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
except (OSError, ValueError, subprocess.CalledProcessError) as error:
|
||||
print(f"iOS native build: {error}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
@@ -1,13 +1,13 @@
|
||||
"""Regression coverage for notice validation and build-specific source links."""
|
||||
"""Regression coverage for native validation and build-specific source links."""
|
||||
|
||||
import copy
|
||||
import hashlib
|
||||
import importlib.util
|
||||
import json
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
|
||||
def load_script(name):
|
||||
@@ -18,11 +18,11 @@ def load_script(name):
|
||||
return module
|
||||
|
||||
|
||||
licenses = load_script("generate_third_party_licenses")
|
||||
native = load_script("verify_native_build")
|
||||
metadata = load_script("prepare_source_metadata")
|
||||
|
||||
|
||||
class LicenseValidationTest(unittest.TestCase):
|
||||
class NativeValidationTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
temporary = tempfile.TemporaryDirectory(prefix="crossdesk-ios-licenses-")
|
||||
self.addCleanup(temporary.cleanup)
|
||||
@@ -47,34 +47,24 @@ class LicenseValidationTest(unittest.TestCase):
|
||||
self.archive.parent.mkdir(parents=True)
|
||||
self.archive.write_bytes(b"reviewed archive")
|
||||
self.inputs = self.root / "inputs.sha256"
|
||||
self.inputs.write_text(f"{licenses.digest(self.archive.read_bytes())} {self.archive}\n")
|
||||
self.target = self.root / "target-info.txt"
|
||||
self.target.write_text(str(self.root / "packages/a/asio/1.0/abcd/include") + "\n")
|
||||
self.inputs.write_text(f"{hashlib.sha256(self.archive.read_bytes()).hexdigest()} {self.archive}\n")
|
||||
self.lock = {
|
||||
"bundle_sha256": licenses.digest(self.bundle.read_bytes()),
|
||||
"toolchain": {"xmake_min_version": "3.1.1"},
|
||||
"components": [
|
||||
{
|
||||
"id": "minirtc", "version": self.reviewed_revision,
|
||||
"source": {"kind": "repository", "url": metadata.MINIRTC_URL,
|
||||
"revision": self.reviewed_revision},
|
||||
"documents": [{"path": str(self.notice.relative_to(self.root)),
|
||||
"sha256": licenses.digest(self.notice.read_bytes())}],
|
||||
"documents": [{"path": str(self.notice.relative_to(self.root))}],
|
||||
},
|
||||
{
|
||||
"id": "opus", "package": "opus", "version": "1.0",
|
||||
"source": {"kind": "archive", "url": "https://example.com/opus.tar.gz"},
|
||||
"recipe_path": str(self.recipe.relative_to(self.root)),
|
||||
"recipe_sha256": licenses.digest(self.recipe.read_bytes()),
|
||||
},
|
||||
{"id": "asio", "package": "asio", "version": "1.0",
|
||||
"source": {"kind": "archive", "url": "https://example.com/asio.tar.gz"}},
|
||||
],
|
||||
}
|
||||
for name, value in (("REPO", self.root), ("OUTPUT", self.bundle)):
|
||||
patcher = patch.object(licenses, name, value)
|
||||
patcher.start()
|
||||
self.addCleanup(patcher.stop)
|
||||
|
||||
def git(self, *args):
|
||||
return subprocess.check_output(
|
||||
@@ -82,9 +72,8 @@ class LicenseValidationTest(unittest.TestCase):
|
||||
"-c", "user.email=test@example.com", "-c", "commit.gpgsign=false", *args],
|
||||
text=True).strip()
|
||||
|
||||
def verify(self, preflight=False, **kwargs):
|
||||
licenses.verify(self.lock, None if preflight else self.inputs,
|
||||
None if preflight else self.target, **kwargs)
|
||||
def verify(self, **kwargs):
|
||||
native.verify(self.inputs, **kwargs)
|
||||
|
||||
def test_source_only_commit_keeps_reviewed_catalog_and_uses_actual_links(self):
|
||||
self.source.write_text("int transport() { return 2; }\n")
|
||||
@@ -94,7 +83,6 @@ class LicenseValidationTest(unittest.TestCase):
|
||||
self.assertNotEqual(current, self.reviewed_revision)
|
||||
original_lock = copy.deepcopy(self.lock)
|
||||
original_bundle = self.bundle.read_bytes()
|
||||
self.verify(preflight=True)
|
||||
self.verify()
|
||||
sources = metadata.component_sources(self.lock, current)
|
||||
self.assertEqual(sources["minirtc"]["version"], current)
|
||||
@@ -104,49 +92,18 @@ class LicenseValidationTest(unittest.TestCase):
|
||||
self.assertEqual(self.lock, original_lock)
|
||||
self.assertEqual(self.bundle.read_bytes(), original_bundle)
|
||||
|
||||
def test_changed_license_is_rejected_before_compilation(self):
|
||||
self.notice.write_text("Changed license text\n")
|
||||
with self.assertRaisesRegex(ValueError, "Source checksum mismatch: .*LICENSE"):
|
||||
self.verify(preflight=True)
|
||||
|
||||
def test_changed_recipe_is_rejected_before_compilation(self):
|
||||
self.recipe.write_text('package("different-opus")\n')
|
||||
with self.assertRaisesRegex(ValueError, "Source checksum mismatch: .*xmake.lua"):
|
||||
self.verify(preflight=True)
|
||||
|
||||
def test_changed_bundle_is_rejected_before_compilation(self):
|
||||
self.bundle.write_text("{}\n")
|
||||
with self.assertRaisesRegex(ValueError, "Source checksum mismatch:"):
|
||||
self.verify(preflight=True)
|
||||
|
||||
def test_unreviewed_header_only_dependency_is_rejected(self):
|
||||
self.target.write_text(str(self.root / "packages/a/asio/2.0/abcd/include") + "\n")
|
||||
with self.assertRaisesRegex(ValueError, "Unreviewed iOS dependency: asio 2.0"):
|
||||
self.verify()
|
||||
|
||||
def test_missing_dependency_is_rejected(self):
|
||||
self.target.write_text("")
|
||||
with self.assertRaisesRegex(ValueError, "License/build dependency mismatch; missing:.*asio"):
|
||||
self.verify()
|
||||
|
||||
def test_simulator_cache_keeps_dependency_and_archive_validation(self):
|
||||
def test_simulator_cache_keeps_archive_validation(self):
|
||||
(self.root / "packages").rename(self.root / "packages-simulator")
|
||||
self.archive = Path(str(self.archive).replace("/packages/", "/packages-simulator/"))
|
||||
self.inputs.write_text(self.inputs.read_text().replace("/packages/", "/packages-simulator/"))
|
||||
self.target.write_text(self.target.read_text().replace("/packages/", "/packages-simulator/"))
|
||||
self.verify()
|
||||
valid_target = self.target.read_text()
|
||||
self.target.write_text(valid_target.replace("/asio/1.0/", "/asio/2.0/"))
|
||||
with self.assertRaisesRegex(ValueError, "Unreviewed iOS dependency: asio 2.0"):
|
||||
self.verify()
|
||||
self.target.write_text(valid_target)
|
||||
self.archive.write_bytes(b"changed simulator archive")
|
||||
with self.assertRaisesRegex(ValueError, "Source checksum mismatch: .*libopus.a"):
|
||||
with self.assertRaisesRegex(ValueError, "Native input checksum mismatch: .*libopus.a"):
|
||||
self.verify()
|
||||
|
||||
def test_changed_native_archive_is_rejected(self):
|
||||
self.archive.write_bytes(b"changed archive")
|
||||
with self.assertRaisesRegex(ValueError, "Source checksum mismatch: .*libopus.a"):
|
||||
with self.assertRaisesRegex(ValueError, "Native input checksum mismatch: .*libopus.a"):
|
||||
self.verify()
|
||||
|
||||
def test_minimum_and_newer_xmake_versions_are_accepted(self):
|
||||
|
||||
Reference in New Issue
Block a user