mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-10-21 03:40:40 +08:00
[fix] decouple iOS license checks from minirtc revisions
This commit is contained in:
@@ -422,6 +422,11 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: "3.13"
|
python-version: "3.13"
|
||||||
|
|
||||||
|
- name: Verify iOS license catalog
|
||||||
|
run: |
|
||||||
|
python3 -B -m unittest discover -s apps/ios/tests -p 'third_party_licenses_test.py' -v
|
||||||
|
python3 -B apps/ios/scripts/generate_third_party_licenses.py
|
||||||
|
|
||||||
- name: Install xmake
|
- name: Install xmake
|
||||||
uses: xmake-io/github-action-setup-xmake@v1
|
uses: xmake-io/github-action-setup-xmake@v1
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -231,7 +231,7 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/zsh;
|
shellPath = /bin/zsh;
|
||||||
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/generate_third_party_licenses.py\" --inputs \"${PROJECT_DIR}/Vendor/iphoneos/${CONFIGURATION}/libCrossDeskMiniRTC.a.inputs.sha256\" --target-info \"${PROJECT_DIR}/Vendor/iphoneos/${CONFIGURATION}/minirtc-target-info.txt\" --xmake-version \"${PROJECT_DIR}/Vendor/iphoneos/${CONFIGURATION}/xmake-version.txt\" --xmake-repository \"$(cat \"${PROJECT_DIR}/Vendor/iphoneos/${CONFIGURATION}/xmake-repository.txt\")\"\npython3 \"${PROJECT_DIR}/scripts/package_openssl_ios.py\" --inputs \"${PROJECT_DIR}/Vendor/iphoneos/${CONFIGURATION}/libCrossDeskMiniRTC.a.inputs.sha256\" --output \"${BUILT_PRODUCTS_DIR}/OpenSSL.framework\"\n";
|
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/iphoneos/${CONFIGURATION}/libCrossDeskMiniRTC.a.inputs.sha256\" --target-info \"${PROJECT_DIR}/Vendor/iphoneos/${CONFIGURATION}/minirtc-target-info.txt\" --xmake-version \"${PROJECT_DIR}/Vendor/iphoneos/${CONFIGURATION}/xmake-version.txt\" --xmake-repository \"$(cat \"${PROJECT_DIR}/Vendor/iphoneos/${CONFIGURATION}/xmake-repository.txt\")\"\npython3 \"${PROJECT_DIR}/scripts/package_openssl_ios.py\" --inputs \"${PROJECT_DIR}/Vendor/iphoneos/${CONFIGURATION}/libCrossDeskMiniRTC.a.inputs.sha256\" --output \"${BUILT_PRODUCTS_DIR}/OpenSSL.framework\"\n";
|
||||||
};
|
};
|
||||||
/* End PBXShellScriptBuildPhase section */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,19 @@ private struct LicensedComponent: Decodable, Identifiable {
|
|||||||
if id == "crossdesk" {
|
if id == "crossdesk" {
|
||||||
return Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? ""
|
return Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? ""
|
||||||
}
|
}
|
||||||
return version.count == 40 ? String(version.prefix(12)) : version
|
let currentVersion = SourceMetadata.bundled?.componentSources[id]?.version ?? version
|
||||||
|
return currentVersion.count == 40 ? String(currentVersion.prefix(12)) : currentVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
var resolvedSourceURL: URL {
|
||||||
|
if id == "crossdesk" {
|
||||||
|
return SourceMetadata.bundled?.sourceURL ?? sourceURL
|
||||||
|
}
|
||||||
|
return SourceMetadata.bundled?.componentSources[id]?.sourceURL ?? sourceURL
|
||||||
|
}
|
||||||
|
|
||||||
|
var resolvedBuildSourceURL: URL? {
|
||||||
|
SourceMetadata.bundled?.componentSources[id]?.buildSourceURL ?? buildSourceURL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,6 +52,12 @@ private struct LicenseCatalog: Decodable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ComponentSourceMetadata: Decodable {
|
||||||
|
let version: String?
|
||||||
|
let sourceURL: URL?
|
||||||
|
let buildSourceURL: URL?
|
||||||
|
}
|
||||||
|
|
||||||
struct SourceMetadata: Decodable {
|
struct SourceMetadata: Decodable {
|
||||||
let revision: String
|
let revision: String
|
||||||
let tag: String?
|
let tag: String?
|
||||||
@@ -47,6 +65,7 @@ struct SourceMetadata: Decodable {
|
|||||||
let sourceURL: URL
|
let sourceURL: URL
|
||||||
let buildInstructionsURL: URL
|
let buildInstructionsURL: URL
|
||||||
let privacyPolicyURL: URL
|
let privacyPolicyURL: URL
|
||||||
|
let componentSources: [String: ComponentSourceMetadata]
|
||||||
|
|
||||||
static let bundled: SourceMetadata? = {
|
static let bundled: SourceMetadata? = {
|
||||||
guard let url = Bundle.main.url(forResource: "SourceMetadata", withExtension: "json"),
|
guard let url = Bundle.main.url(forResource: "SourceMetadata", withExtension: "json"),
|
||||||
@@ -137,10 +156,8 @@ private struct ComponentLicenseView: View {
|
|||||||
Text(component.name).font(.headline)
|
Text(component.name).font(.headline)
|
||||||
Text(component.displayVersion).textSelection(.enabled)
|
Text(component.displayVersion).textSelection(.enabled)
|
||||||
Text(component.license).foregroundStyle(.secondary)
|
Text(component.license).foregroundStyle(.secondary)
|
||||||
Link("查看源码", destination: component.id == "crossdesk"
|
Link("查看源码", destination: component.resolvedSourceURL)
|
||||||
? SourceMetadata.bundled?.sourceURL ?? component.sourceURL
|
if let buildSourceURL = component.resolvedBuildSourceURL {
|
||||||
: component.sourceURL)
|
|
||||||
if let buildSourceURL = component.buildSourceURL {
|
|
||||||
Link("构建配方与项目补丁", destination: buildSourceURL)
|
Link("构建配方与项目补丁", destination: buildSourceURL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-12
@@ -98,8 +98,8 @@ top of the notices page, with its INRIA copyright, CeCILL-C terms and limited
|
|||||||
warranty/liability notice. Its embedded BSD and CC-BY-SA notices are preserved
|
warranty/liability notice. Its embedded BSD and CC-BY-SA notices are preserved
|
||||||
in the source-notices document as well.
|
in the source-notices document as well.
|
||||||
|
|
||||||
`licenses/sources.json` pins the reviewed source archives (SHA-256), Git
|
`licenses/sources.json` pins the reviewed source archives (SHA-256), notice-review
|
||||||
revisions, selected legal files and source-notice extraction rules.
|
Git revisions, selected legal files and source-notice extraction rules.
|
||||||
`CrossDeskMobile/Resources/ThirdPartyLicenses.json` is the generated resource
|
`CrossDeskMobile/Resources/ThirdPartyLicenses.json` is the generated resource
|
||||||
bundled by Xcode. The catalog covers 34 components for the default iOS build,
|
bundled by Xcode. The catalog covers 34 components for the default iOS build,
|
||||||
including header-only dependencies, GLib's proxy-libintl, spdlog's bundled fmt,
|
including header-only dependencies, GLib's proxy-libintl, spdlog's bundled fmt,
|
||||||
@@ -122,13 +122,16 @@ collected from the reviewed runtime source directories; the catalog is an
|
|||||||
attribution superset, not a claim that every source file survives linker
|
attribution superset, not a claim that every source file survives linker
|
||||||
dead stripping.
|
dead stripping.
|
||||||
|
|
||||||
Normal Xcode builds verify the checked-in resource offline, compare all resolved
|
Normal Xcode builds verify the checked-in resource, local license files and
|
||||||
dependency versions (including header-only packages) with the catalog, check
|
package recipes offline before compiling native code. After compilation they
|
||||||
the merged archive's input hashes and local package recipes, and check the
|
also compare all resolved dependency versions (including header-only packages)
|
||||||
MiniRTC revision. A missing, stale or altered catalog fails the build. When
|
with the catalog and check the merged archive's input hashes and pinned
|
||||||
dependencies or MiniRTC change, review the corresponding source notices and
|
toolchain. A missing, stale or altered catalog fails the build. Ordinary MiniRTC
|
||||||
update the lock before regenerating; regeneration alone does not select a new
|
code changes do not require changing the notice-review revision or regenerating
|
||||||
dependency version. `MINIRTC_ENABLE_AOM=true` also requires a reviewed AOM entry.
|
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.
|
||||||
|
|
||||||
The source screen links to the exact application tag/commit, MiniRTC commit,
|
The source screen links to the exact application tag/commit, MiniRTC commit,
|
||||||
and custom dependency recipes/patches. `SourceMetadata.json` is generated in
|
and custom dependency recipes/patches. `SourceMetadata.json` is generated in
|
||||||
@@ -136,7 +139,12 @@ the app bundle, not in the checkout. Development builds with local edits are
|
|||||||
explicitly identified as modified. Version-tag CI builds reject an unclean
|
explicitly identified as modified. Version-tag CI builds reject an unclean
|
||||||
checkout or a mismatched tag. The release archive also carries
|
checkout or a mismatched tag. The release archive also carries
|
||||||
`ThirdPartySources.json`, `SourceMetadata.json` and the open-source rights
|
`ThirdPartySources.json`, `SourceMetadata.json` and the open-source rights
|
||||||
notice; release notes provide the corresponding source and build links.
|
notice. `ThirdPartySources.json` preserves the notice-review catalog;
|
||||||
|
`SourceMetadata.json` records the actual build commit and per-component version,
|
||||||
|
source and recipe links used by the license screen, including MiniRTC, inih and
|
||||||
|
WebRTC-derived code. These links update automatically on every build without
|
||||||
|
rewriting the checked-in license resource. Release notes provide the
|
||||||
|
corresponding source and build links.
|
||||||
Keep the source tags, submodule commits and referenced dependency source
|
Keep the source tags, submodule commits and referenced dependency source
|
||||||
archives available for recipients of that release.
|
archives available for recipients of that release.
|
||||||
|
|
||||||
@@ -144,8 +152,9 @@ To change a library, edit MiniRTC in its submodule, or modify the relevant
|
|||||||
package recipe/patch under `deps/submodules/minirtc/thirdparty`. If a package
|
package recipe/patch under `deps/submodules/minirtc/thirdparty`. If a package
|
||||||
recipe changes, change its package configuration revision (or rebuild that
|
recipe changes, change its package configuration revision (or rebuild that
|
||||||
package) so Xmake does not reuse a previous binary. Review affected notices,
|
package) so Xmake does not reuse a previous binary. Review affected notices,
|
||||||
update recipe hashes, commit MiniRTC, update its revision in `sources.json`,
|
update recipe hashes, and commit MiniRTC. When the notice catalog changes,
|
||||||
then regenerate the catalog. Build the application again to relink it with
|
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
|
the modified library. Use your own team and bundle identifier to install the
|
||||||
modified build; the maintainer's signing credentials are not required.
|
modified build; the maintainer's signing credentials are not required.
|
||||||
|
|
||||||
|
|||||||
@@ -178,11 +178,9 @@ def verify(lock, inputs, target_info, xmake_repository=None, xmake_version=None)
|
|||||||
for line in inputs.read_text().splitlines():
|
for line in inputs.read_text().splitlines():
|
||||||
sha, path = line.split(maxsplit=1)
|
sha, path = line.split(maxsplit=1)
|
||||||
checked(Path(path).read_bytes(), sha, path)
|
checked(Path(path).read_bytes(), sha, path)
|
||||||
revision = subprocess.check_output(
|
# Repository revisions identify the reviewed notices, not a required build
|
||||||
["git", "-C", str(REPO / "deps/submodules/minirtc"), "rev-parse", "HEAD"], text=True).strip()
|
# commit. SourceMetadata records the actual MiniRTC revision and links for
|
||||||
mini = next(c for c in lock["components"] if c["id"] == "minirtc")
|
# this build; the content and dependency checks above detect stale notices.
|
||||||
if revision != mini["source"]["revision"]:
|
|
||||||
raise ValueError("MiniRTC revision changed; review embedded notices and update sources.json")
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
@@ -19,6 +19,24 @@ def git(*args, root=REPO):
|
|||||||
return subprocess.check_output(["git", "-C", str(root), *args], text=True).strip()
|
return subprocess.check_output(["git", "-C", str(root), *args], text=True).strip()
|
||||||
|
|
||||||
|
|
||||||
|
def component_sources(lock, mini_revision):
|
||||||
|
"""Resolve MiniRTC source and recipe links without rewriting reviewed notices."""
|
||||||
|
mini_url = f"{MINIRTC_URL}/tree/{mini_revision}"
|
||||||
|
sources = {}
|
||||||
|
for component in lock["components"]:
|
||||||
|
source = component["source"]
|
||||||
|
entry = {}
|
||||||
|
if source["kind"] == "repository" and source["url"] == MINIRTC_URL:
|
||||||
|
entry.update(version=mini_revision, sourceURL=mini_url)
|
||||||
|
recipe = component.get("recipe_path", "")
|
||||||
|
if recipe.startswith("deps/submodules/minirtc/"):
|
||||||
|
directory = Path(recipe).relative_to("deps/submodules/minirtc").parent
|
||||||
|
entry["buildSourceURL"] = f"{mini_url}/{directory.as_posix()}"
|
||||||
|
if entry:
|
||||||
|
sources[component["id"]] = entry
|
||||||
|
return sources
|
||||||
|
|
||||||
|
|
||||||
def source_metadata(require_release=False, tag=None):
|
def source_metadata(require_release=False, tag=None):
|
||||||
revision = git("rev-parse", "HEAD")
|
revision = git("rev-parse", "HEAD")
|
||||||
dirty = bool(git("status", "--porcelain", "--untracked-files=normal", "--ignore-submodules=none"))
|
dirty = bool(git("status", "--porcelain", "--untracked-files=normal", "--ignore-submodules=none"))
|
||||||
@@ -47,6 +65,7 @@ def source_metadata(require_release=False, tag=None):
|
|||||||
"privacyPolicyURL": f"{REPOSITORY_URL}/blob/{ref}/PRIVACY.md",
|
"privacyPolicyURL": f"{REPOSITORY_URL}/blob/{ref}/PRIVACY.md",
|
||||||
"miniRTCRevision": mini_revision,
|
"miniRTCRevision": mini_revision,
|
||||||
"miniRTCSourceURL": f"{MINIRTC_URL}/tree/{mini_revision}",
|
"miniRTCSourceURL": f"{MINIRTC_URL}/tree/{mini_revision}",
|
||||||
|
"componentSources": component_sources(lock, mini_revision),
|
||||||
"licenseCatalogSHA256": lock["bundle_sha256"],
|
"licenseCatalogSHA256": lock["bundle_sha256"],
|
||||||
"sourceCatalogSHA256": hashlib.sha256(lock_path.read_bytes()).hexdigest(),
|
"sourceCatalogSHA256": hashlib.sha256(lock_path.read_bytes()).hexdigest(),
|
||||||
"toolchain": lock["toolchain"],
|
"toolchain": lock["toolchain"],
|
||||||
|
|||||||
@@ -0,0 +1,161 @@
|
|||||||
|
"""Regression coverage for notice validation and build-specific source links."""
|
||||||
|
|
||||||
|
import copy
|
||||||
|
import importlib.util
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
|
||||||
|
def load_script(name):
|
||||||
|
path = Path(__file__).resolve().parents[1] / "scripts" / f"{name}.py"
|
||||||
|
spec = importlib.util.spec_from_file_location(name, path)
|
||||||
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(module)
|
||||||
|
return module
|
||||||
|
|
||||||
|
|
||||||
|
licenses = load_script("generate_third_party_licenses")
|
||||||
|
metadata = load_script("prepare_source_metadata")
|
||||||
|
|
||||||
|
|
||||||
|
class LicenseValidationTest(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
temporary = tempfile.TemporaryDirectory(prefix="crossdesk-ios-licenses-")
|
||||||
|
self.addCleanup(temporary.cleanup)
|
||||||
|
self.root = Path(temporary.name)
|
||||||
|
self.mini = self.root / "deps/submodules/minirtc"
|
||||||
|
self.mini.mkdir(parents=True)
|
||||||
|
self.notice = self.mini / "LICENSE"
|
||||||
|
self.notice.write_text("Reviewed license text\n")
|
||||||
|
self.recipe = self.mini / "thirdparty/opus/xmake.lua"
|
||||||
|
self.recipe.parent.mkdir(parents=True)
|
||||||
|
self.recipe.write_text('package("opus")\n')
|
||||||
|
self.source = self.mini / "transport.cpp"
|
||||||
|
self.source.write_text("int transport() { return 1; }\n")
|
||||||
|
self.git("init", "-q")
|
||||||
|
self.git("add", ".")
|
||||||
|
self.git("commit", "-qm", "Reviewed source")
|
||||||
|
self.reviewed_revision = self.git("rev-parse", "HEAD")
|
||||||
|
|
||||||
|
self.bundle = self.root / "ThirdPartyLicenses.json"
|
||||||
|
self.bundle.write_text('{"schemaVersion": 1, "components": []}\n')
|
||||||
|
self.archive = self.root / "packages/o/opus/1.0/abcd/lib/libopus.a"
|
||||||
|
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.lock = {
|
||||||
|
"bundle_sha256": licenses.digest(self.bundle.read_bytes()),
|
||||||
|
"toolchain": {"xmake_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())}],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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(
|
||||||
|
["git", "-C", str(self.mini), "-c", "user.name=Test",
|
||||||
|
"-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 test_source_only_commit_keeps_reviewed_catalog_and_uses_actual_links(self):
|
||||||
|
self.source.write_text("int transport() { return 2; }\n")
|
||||||
|
self.git("add", ".")
|
||||||
|
self.git("commit", "-qm", "Change transport implementation")
|
||||||
|
current = self.git("rev-parse", "HEAD")
|
||||||
|
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)
|
||||||
|
self.assertEqual(sources["minirtc"]["sourceURL"], f"{metadata.MINIRTC_URL}/tree/{current}")
|
||||||
|
self.assertEqual(sources["opus"]["buildSourceURL"],
|
||||||
|
f"{metadata.MINIRTC_URL}/tree/{current}/thirdparty/opus")
|
||||||
|
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_changed_native_archive_is_rejected(self):
|
||||||
|
self.archive.write_bytes(b"changed archive")
|
||||||
|
with self.assertRaisesRegex(ValueError, "Source checksum mismatch: .*libopus.a"):
|
||||||
|
self.verify()
|
||||||
|
|
||||||
|
def test_unreviewed_toolchain_is_rejected(self):
|
||||||
|
version = self.root / "xmake-version.txt"
|
||||||
|
version.write_text("xmake v3.1.2\n")
|
||||||
|
with self.assertRaisesRegex(ValueError, "Xmake version differs"):
|
||||||
|
self.verify(xmake_version=version)
|
||||||
|
|
||||||
|
|
||||||
|
class ComponentSourceTest(unittest.TestCase):
|
||||||
|
def test_all_minirtc_components_and_custom_recipes_follow_build_revision(self):
|
||||||
|
lock_path = Path(__file__).resolve().parents[1] / "licenses/sources.json"
|
||||||
|
lock = json.loads(lock_path.read_text())
|
||||||
|
reviewed = copy.deepcopy(lock)
|
||||||
|
revision = "a" * 40
|
||||||
|
base = f"{metadata.MINIRTC_URL}/tree/{revision}"
|
||||||
|
sources = metadata.component_sources(lock, revision)
|
||||||
|
for name in ("minirtc", "inih", "webrtc"):
|
||||||
|
self.assertEqual(sources[name], {"version": revision, "sourceURL": base})
|
||||||
|
self.assertEqual(sources["openssl3"], {"buildSourceURL": base + "/thirdparty/openssl"})
|
||||||
|
self.assertNotIn("asio", sources)
|
||||||
|
self.assertNotIn("crossdesk", sources)
|
||||||
|
self.assertEqual(lock, reviewed)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user