Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"id": "SpdxDocumentFile:vcpkg:unpackrat-build-tests-unity-nuget-monitor:e50376b9ea641346f93a1a2e2e1a32b42e6617088165ec890acd99599f13975f",
"source_artifact_url": "http://127.0.0.1:8765/sources/e50376b9ea641346f93a1a2e2e1a32b42e6617088165ec890acd99599f13975f.tar",
"id": "SpdxDocumentFile:vcpkg:unpackrat-build-tests-unity-nuget-monitor:93d3fca7a12e2761f5caf987dabd1e2d4b6b917a2ae725e44ef38e205d3945c6",
"source_artifact_url": "http://127.0.0.1:8765/sources/93d3fca7a12e2761f5caf987dabd1e2d4b6b917a2ae725e44ef38e205d3945c6.tar",
"license_finding_curations": [
{
"path": "build/tests/test_unity_nuget_monitor.py",
Expand All @@ -9,7 +9,7 @@
"detected_license": "GPL-3.0-only",
"reason": "INCORRECT",
"concluded_license": "NONE",
"comment": "Line 123 is the attribution string list entry containing GPL-3.0 combined work and StbImageSharp 2.30.15 that the test requires in the shipped Unity notice. This first-party MIT test tooling checks that retained notice text; it does not grant a license, and no third-party adoption is claimed. The linked AssetRipper GPL-3.0 runtime source is recorded as an incorporated component in the inventory. The false-positive finding is removed."
"comment": "Line 123 is the attribution string list entry containing GPL-3.0 combined work that the test requires in the shipped Unity notice. This first-party MIT test tooling checks that retained notice text; it does not grant a license, and no third-party adoption is claimed. The linked AssetRipper GPL-3.0 runtime source is recorded as an incorporated component in the inventory. The false-positive finding is removed."
}
]
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"id": "SpdxDocumentFile:vcpkg:unpackrat-build-tests-unity-packaging:1630ef74260d058a8a443e5767049cd5693d6e34dc9f2f4a68ece675528b022f",
"source_artifact_url": "http://127.0.0.1:8765/sources/1630ef74260d058a8a443e5767049cd5693d6e34dc9f2f4a68ece675528b022f.tar",
"id": "SpdxDocumentFile:vcpkg:unpackrat-build-tests-unity-packaging:6dbb645efe00999a6bbfd1f5a77bd16296cbb5f5fa4c00b444f77e699077f663",
"source_artifact_url": "http://127.0.0.1:8765/sources/6dbb645efe00999a6bbfd1f5a77bd16296cbb5f5fa4c00b444f77e699077f663.tar",
"license_finding_curations": [
{
"path": "build/tests/test_unity_packaging.py",
Expand Down
20 changes: 13 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,15 @@ resource files, and the other dependencies the selected file references, are res
selected file, while resources owned by unrelated dependencies are not added, so keep the sidecar
files next to the selected file. Whole-game catalogues and code decompilation are not offered.

Each entry converts on demand to its own output file. `Texture2D` and `Sprite` become PNG; `Sprite`
crops its atlas region and handles packing, flips, 90-degree rectangles, a transparent canvas and a
tight mask. `TextAsset` keeps its original bytes as `.bin`, which does not mean plain text only.
Each entry converts on demand to its own output file. `Texture2D` exports the complete texture as
PNG, including atlas textures. Individual `Sprite` images are not reconstructed or listed; their
pixels remain in the complete textures. `TextAsset` keeps its original bytes as `.bin`, which does
not mean plain text only.
Texture memory checks use the actual decoded pixel format and account for PNG conversion and
encoder buffers. Ordinary textures accept up to 256 MiB of source data and decoded pixels,
subject to a 1 GiB working-memory estimate per extraction. Block-compressed and crunched textures, platform-specific
Xbox/Switch conversions and PNG images wider or taller than 65535 pixels retain the previous
stricter limits. These limits bound individual operations; they do not reserve memory in FAR.
`AudioClip` uses the mature Fmod5Sharp decoder: FSB5 single-sample PCM and ADPCM export to WAV and
Vorbis to Ogg, legacy stored sound bytes are preserved, and unsupported FSB5 banks or codecs keep
their raw `.fsb`. Embedded fonts export to TTF/OTF/TTC, `VideoClip` and `MovieTexture` keep their
Expand All @@ -42,10 +48,10 @@ scene, materials or animations.

Original hierarchy paths are kept when present, with literal `{Type}` folders as a fallback.
DisplayedSize and PackedSize report the original source payload length (0 means unknown); converted
output may differ. An unsupported downscale value beyond 0 or 1, a tight mask that cannot be read,
or a source geometry budget refusal fails that one entry's export, so not every variant or Unity
version is guaranteed. External code, `MonoBehaviour`, `ScriptableObject`, `Material` and
`AnimationClip` are outside this resource feature. The Unity module is a single DLL with no
output may differ. An unsupported resource variant or a source geometry budget refusal fails that
one entry's export, so not every variant or Unity version is guaranteed. External code,
`MonoBehaviour`, `ScriptableObject`, `Material` and `AnimationClip` are outside this resource
feature. The Unity module is a single DLL with no
separate .NET runtime to install.

Each module ZIP carries the module DLL for one architecture, its `observer_user.ini`, both
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -619,9 +619,9 @@
{
"name": "unpackrat-build-tests-unity-packaging",
"member": "build/tests/test_unity_packaging.py",
"version": "1630ef74260d058a8a443e5767049cd5693d6e34dc9f2f4a68ece675528b022f",
"sha256": "1630ef74260d058a8a443e5767049cd5693d6e34dc9f2f4a68ece675528b022f",
"artifact_filename": "1630ef74260d058a8a443e5767049cd5693d6e34dc9f2f4a68ece675528b022f.tar",
"version": "6dbb645efe00999a6bbfd1f5a77bd16296cbb5f5fa4c00b444f77e699077f663",
"sha256": "6dbb645efe00999a6bbfd1f5a77bd16296cbb5f5fa4c00b444f77e699077f663",
"artifact_filename": "6dbb645efe00999a6bbfd1f5a77bd16296cbb5f5fa4c00b444f77e699077f663.tar",
"extension": ".tar",
"curations": [
{
Expand Down Expand Up @@ -656,9 +656,9 @@
{
"name": "unpackrat-build-tests-unity-nuget-monitor",
"member": "build/tests/test_unity_nuget_monitor.py",
"version": "e50376b9ea641346f93a1a2e2e1a32b42e6617088165ec890acd99599f13975f",
"sha256": "e50376b9ea641346f93a1a2e2e1a32b42e6617088165ec890acd99599f13975f",
"artifact_filename": "e50376b9ea641346f93a1a2e2e1a32b42e6617088165ec890acd99599f13975f.tar",
"version": "93d3fca7a12e2761f5caf987dabd1e2d4b6b917a2ae725e44ef38e205d3945c6",
"sha256": "93d3fca7a12e2761f5caf987dabd1e2d4b6b917a2ae725e44ef38e205d3945c6",
"artifact_filename": "93d3fca7a12e2761f5caf987dabd1e2d4b6b917a2ae725e44ef38e205d3945c6.tar",
"extension": ".tar",
"curations": [
{
Expand All @@ -668,7 +668,7 @@
"detected_license": "GPL-3.0-only",
"reason": "INCORRECT",
"concluded_license": "NONE",
"comment": "Line 123 is the attribution string list entry containing GPL-3.0 combined work and StbImageSharp 2.30.15 that the test requires in the shipped Unity notice. This first-party MIT test tooling checks that retained notice text; it does not grant a license, and no third-party adoption is claimed. The linked AssetRipper GPL-3.0 runtime source is recorded as an incorporated component in the inventory. The false-positive finding is removed."
"comment": "Line 123 is the attribution string list entry containing GPL-3.0 combined work that the test requires in the shipped Unity notice. This first-party MIT test tooling checks that retained notice text; it does not grant a license, and no third-party adoption is claimed. The linked AssetRipper GPL-3.0 runtime source is recorded as an incorporated component in the inventory. The false-positive finding is removed."
}
]
}
Expand Down
10 changes: 9 additions & 1 deletion build/tests/test_unity_nuget_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,20 @@ def test_shipped_notice_reproduces_upstream_mit_and_attribution(self) -> None:
"AssetsTools.NET 3.0.5",
"https://www.nuget.org/packages/AssetsTools.NET/3.0.5",
"https://github.com/nesrak1/AssetsTools.NET",
"GPL-3.0 combined work", "StbImageSharp 2.30.15",
"GPL-3.0 combined work",
):
with self.subTest(attribution=attribution):
self.assertTrue(attribution in notice, "missing attribution: " + attribution)
self.assertTrue(MIT_NOTICE in notice, "the complete upstream MIT notice must ship")

def test_retired_sprite_image_reader_is_absent_from_dependencies_and_notice(self) -> None:
project = ET.parse(REPOSITORY / PROJECT).getroot()
packages = {reference.get("Include") for reference in project.iter("PackageReference")}
self.assertNotIn("StbImageSharp", packages)
notice = (REPOSITORY / "licenses/Unity.txt").read_text(encoding="utf-8")
self.assertFalse("StbImageSharp" in notice, "retired Sprite decoder attribution must not ship")
self.assertIn("StbImageWriteSharp", notice, "the retained PNG writer attribution must ship")


if __name__ == "__main__":
unittest.main()
8 changes: 4 additions & 4 deletions build/tests/test_unity_packaging.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@


UNITY = "unity"
UNITY_VERSION = "1.0.1"
UNITY_VERSION = "2.0.0"
MODULES_UNDER_TEST = ("renpy", "rpgmaker", "zanzarah", "godot", "wolfrpg")

UNITY_SO_X86 = b"\x7fELF unity shared object x86 fixture\n"
Expand Down Expand Up @@ -215,7 +215,7 @@ def test_cli_selects_unity_by_name(self) -> None:
class UnityShippedTreeTests(unittest.TestCase):
"""The real ``src/modules/unity`` registration must match the shipped layout."""

def test_version_is_release_1_0_1(self) -> None:
def test_version_is_release_2_0_0(self) -> None:
self.assertEqual(main.read_version(REPOSITORY_ROOT, UNITY), UNITY_VERSION)

def test_observer_registration_uses_the_module_binary_and_a_narrow_filter(self) -> None:
Expand All @@ -234,8 +234,8 @@ def test_bilingual_changelogs_document_the_version(self) -> None:
russian = (REPOSITORY_ROOT / "src" / "modules" / UNITY / "ChangeLog.ru.txt").read_text("utf-8")
english_headers = re.findall(r"^Version \d+\.\d+\.\d+$", english, re.MULTILINE)
russian_headers = re.findall(r"^Версия \d+\.\d+\.\d+$", russian, re.MULTILINE)
self.assertEqual(english_headers, ["Version 1.0.1", "Version 1.0.0"])
self.assertEqual(russian_headers, ["Версия 1.0.1", "Версия 1.0.0"])
self.assertEqual(english_headers, ["Version 2.0.0", "Version 1.0.1", "Version 1.0.0"])
self.assertEqual(russian_headers, ["Версия 2.0.0", "Версия 1.0.1", "Версия 1.0.0"])

def test_shipped_unity_notice_bundle_labels_gpl_and_the_third_parties(self) -> None:
notice = (REPOSITORY_ROOT / "licenses" / "Unity.txt").read_bytes()
Expand Down
122 changes: 122 additions & 0 deletions build/tests/test_unity_security_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
"""Select safe NativeAOT packs without restoring or running a compiler.

The installed SDK's real ProcessFrameworkReferences task is exercised against a
stale SDK/package compiler selection. This target only emits package-selection
items; Restore, Compile and Publish are never invoked by these tests.
"""

from __future__ import annotations

import json
import os
from pathlib import Path
import subprocess
import tempfile
import unittest
import xml.etree.ElementTree as ET

from test_unity_size_config import _dotnet_path, _project_path


SAFE_VERSION = "10.0.15"
NATIVE = {
"Configuration": "Release",
"PublishAot": "true",
"NativeLib": "Shared",
}


class UnitySecurityConfigurationTests(unittest.TestCase):
def setUp(self) -> None:
temporary = tempfile.TemporaryDirectory(prefix="unity-security-")
self.addCleanup(temporary.cleanup)
self.workspace = Path(temporary.name)
self.project = _project_path()
# Reproduce either an old SDK or a previously restored compiler package.
# The project-owned policy must win after evaluation, before selection.
document = ET.Element("Project")
ET.SubElement(document, "Import", Project=str(self.project.parents[1] / "Directory.Build.targets"))
item_group = ET.SubElement(document, "ItemGroup")
item = ET.SubElement(item_group, "KnownILCompilerPack", Update="Microsoft.DotNet.ILCompiler")
ET.SubElement(item, "ILCompilerPackVersion").text = "10.0.13"
self.imports = self.workspace / "stale-compiler.targets"
ET.ElementTree(document).write(self.imports, encoding="utf-8", xml_declaration=True)

def select(self, **overrides: str) -> subprocess.CompletedProcess[str]:
properties = {
**NATIVE,
"BaseIntermediateOutputPath": str(self.workspace / "obj") + os.sep,
"MSBuildProjectExtensionsPath": str(self.workspace / "obj") + os.sep,
"DirectoryBuildTargetsPath": str(self.imports),
**overrides,
}
command = [
_dotnet_path(), "msbuild", str(self.project), "-nologo", "-verbosity:quiet",
"-m:1", "-nr:false", "-target:ProcessFrameworkReferences",
"-getProperty:RuntimeFrameworkVersion",
"-getItem:HostILCompilerPack,TargetILCompilerPack",
]
command.extend(f"-p:{name}={value}" for name, value in properties.items())
return subprocess.run(command, cwd=self.project.parent, text=True, encoding="utf-8",
capture_output=True, timeout=120, check=False)

def selected(self, **properties: str) -> dict:
result = self.select(**properties)
self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
return json.loads(result.stdout)

def assert_safe(self, document: dict, arch: str) -> None:
self.assertEqual(document["Properties"]["RuntimeFrameworkVersion"], SAFE_VERSION)
host = document["Items"]["HostILCompilerPack"]
target = document["Items"]["TargetILCompilerPack"]
self.assertEqual(len(host), 1)
self.assertEqual(len(target), 1)
self.assertTrue(host[0]["Identity"].casefold().startswith("runtime."))
self.assertTrue(host[0]["Identity"].casefold().endswith(".microsoft.dotnet.ilcompiler"))
self.assertEqual(host[0]["NuGetPackageVersion"], SAFE_VERSION)
self.assertEqual(target[0]["NuGetPackageVersion"], SAFE_VERSION)
self.assertEqual(target[0]["Identity"].casefold(),
f"Microsoft.NETCore.App.Runtime.NativeAOT.win-{arch}".casefold())

def test_windows_shared_aot_selects_safe_runtime_and_compiler_on_both_architectures(self) -> None:
for arch in ("x64", "x86"):
for configuration in ("Debug", "Release"):
with self.subTest(architecture=arch, configuration=configuration):
self.assert_safe(self.selected(RuntimeIdentifier=f"win-{arch}",
Configuration=configuration), arch)

def test_explicit_safe_runtime_remains_accepted(self) -> None:
for arch in ("x64", "x86"):
with self.subTest(architecture=arch):
self.assert_safe(self.selected(RuntimeIdentifier=f"win-{arch}",
RuntimeFrameworkVersion=SAFE_VERSION), arch)

def test_conflicting_runtime_overrides_fail_before_pack_selection(self) -> None:
for arch in ("x64", "x86"):
for version in ("10.0.13", "10.0.14"):
with self.subTest(architecture=arch, version=version):
result = self.select(RuntimeIdentifier=f"win-{arch}", RuntimeFrameworkVersion=version)
self.assertNotEqual(result.returncode, 0, result.stdout + result.stderr)
self.assertIn("CVE-2026-111497", result.stdout + result.stderr)
self.assertIn(SAFE_VERSION, result.stdout + result.stderr)

def test_managed_and_other_native_modes_keep_explicit_runtime_configuration(self) -> None:
cases = (
{"PublishAot": "false", "RuntimeIdentifier": "win-x64"},
{"PublishAot": "false"},
{"NativeLib": "Static", "RuntimeIdentifier": "win-x64"},
{"RuntimeIdentifier": "linux-x64"},
{"RuntimeIdentifier": "win-arm64"},
{"RuntimeIdentifier": ""},
)
for properties in cases:
with self.subTest(properties=properties):
document = self.selected(**properties, RuntimeFrameworkVersion="10.0.13")
self.assertEqual(document["Properties"]["RuntimeFrameworkVersion"], "10.0.13")
for kind in ("HostILCompilerPack", "TargetILCompilerPack"):
self.assertTrue(all(item["NuGetPackageVersion"] == "10.0.13"
for item in document["Items"][kind]))


if __name__ == "__main__":
unittest.main()
17 changes: 0 additions & 17 deletions licenses/Unity.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3120,23 +3120,6 @@ NIST-developed software is expressly provided "AS IS." NIST MAKES NO WARRANTY OF

You are solely responsible for determining the appropriateness of using and distributing the software and you assume all risks associated with its use, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and the unavailability or interruption of operation. This software is not intended to be used in any situation where a failure could cause risk of injury or damage to property. The software developed by NIST employees is not subject to copyright protection within the United States.

==============================================================================
StbImageSharp 2.30.15
==============================================================================

The unpackrat Unity module references the StbImageSharp NuGet package, version
2.30.15 (pinned; upstream tag 2.30.15, commit
6fd7aebe1dbf10e28d78745f42a0c095c61d1945). It is used only to read a small cropped
PNG back into a fixed four-byte RGBA buffer. The package is a pure managed
assembly with no native binaries; its NuGet metadata names the authors
"StbImageSharpTeam" and the project https://github.com/StbSharp/StbImageSharp.

StbImageSharp is a C# port of the public-domain stb_image.h; the upstream README
states the license as follows, reproduced verbatim:

# License
Public Domain or MIT

==============================================================================
AssetsTools.NET 3.0.5 (MIT)
==============================================================================
Expand Down
9 changes: 9 additions & 0 deletions src/modules/unity/ChangeLog.en.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
Version 2.0.0
-------------

* Simplified image extraction by removing atlas slicing into individual sprites and its processing and memory overhead.
* Added support for Unity 6.5.
* Fixed errors when extracting large textures.
* Reduced memory use when extracting resources.
* Fixed a vulnerability when processing Brotli-compressed archives.

Version 1.0.1
-------------

Expand Down
9 changes: 9 additions & 0 deletions src/modules/unity/ChangeLog.ru.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
Версия 2.0.0
-------------

* Упрощено извлечение изображений: убрана нарезка атласов на отдельные спрайты и связанные с ней затраты на обработку и память.
* Добавлена поддержка Unity 6.5.
* Исправлены ошибки извлечения крупных текстур.
* Снижен расход памяти при извлечении ресурсов.
* Исправлена уязвимость обработки архивов со сжатием Brotli.

Версия 1.0.1
-------------

Expand Down
Loading
Loading