Capture current mission, AI, map and administration development

Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
This commit is contained in:
2026-10-13 22:52:53 +02:00
parent a951a96edc
commit 6a667d8deb
8104 changed files with 2124945 additions and 2061 deletions
@@ -0,0 +1,162 @@
{
"Assets/Items/Equipment/Maps/Map_Paper_01/Map_Paper_01_folded.xob": "E443663E5241622A",
"Assets/Items/Equipment/Radios/Radio_R107M/Radio_R107M_01_item.xob": "77C9FCF3FB1246E9",
"Assets/Items/Equipment/workspaces/paper_map.agr": "83675D0B0AB1B2C3",
"Assets/Items/Equipment/workspaces/player_map.asi": "56794534F6B8C3D7",
"Assets/Props/Fabric/Flags/Data/Flag_1_2_SovietArmy.emat": "B47B52D9DA68905D",
"Assets/Props/Fabric/Flags/Data/Flag_1_2_USA.emat": "610803CC3F3D6649",
"Assets/Props/Military/AmmoBox/EquipmentBoxWooden_01/Data/EquipmentBoxWooden_Weapon_01_USSR.emat": "7D2E831AFA5CF50D",
"Assets/Props/Military/AmmoBox/EquipmentBoxWooden_01/EquipmentBoxWooden_Weapon_01.xob": "819ED3266EE5113B",
"Assets/Props/Military/Sandbags/Data/Sandbags_01_Burlap_MLOD.emat": "2169E8EB73E1C127",
"Assets/Props/Military/Sandbags/Data/Sandbags_01_short_Burlap.emat": "31529E064AA7C917",
"Assets/Props/Military/Sandbags/Sandbag_01_short.xob": "268DBDABB3C94AD7",
"Assets/Structures/BuildingsParts/Doors/DoorFrame_door_metal_A_RIGHT_EXT_B.xob": "E3BC73BFBC7AA497",
"Assets/Structures/Walls/Concrete/ConcreteWall_01_3m.xob": "0B96D139FEBCA006",
"Configs/Callsigns/Callsigns_US.conf": "CB7824D572DD0D5C",
"Configs/Callsigns/Callsigns_USSR.conf": "958043CE1648EC43",
"Configs/EntityCatalog/US/Characters_EntityCatalog_US.conf": "B56E8B4D4B195559",
"Configs/EntityCatalog/US/Groups_EntityCatalog_US.conf": "4E70E7C4C2C17D4A",
"Configs/EntityCatalog/US/InventoryItems_EntityCatalog_US.conf": "5F7EC52FC40A03E2",
"Configs/EntityCatalog/US/SupplyContainerItems_EntityCatalog_US.conf": "0BF36EFF9FFAF92B",
"Configs/EntityCatalog/US/WeaponTripod_EntityCatalog_US.conf": "0E4B62F186F97C43",
"Configs/EntityCatalog/USSR/Characters_EntityCatalog_USSR.conf": "3B679F1799D55F6F",
"Configs/EntityCatalog/USSR/Groups_EntityCatalog_USSR.conf": "37D5B75AAC3E72EA",
"Configs/EntityCatalog/USSR/InventoryItems_EntityCatalog_USSR.conf": "C53421647C3D0D2E",
"Configs/EntityCatalog/USSR/SupplyContainerItems_EntityCatalog_USSR.conf": "B4CA6761AC935808",
"Configs/EntityCatalog/USSR/WeaponTripod_EntityCatalog_USSR.conf": "DDF17C8C140BD1F2",
"Configs/Factions/BLUFOR.conf": "E7B7EA4823DD81F0",
"Configs/Factions/FIA.conf": "8053DB656DD18B14",
"Configs/Factions/OPFOR.conf": "B122E3B10BB3404B",
"Configs/GameOverScreen/BaseGameOverScreensConfig.conf": "651583FFFB7FC765",
"Configs/Identities/FactionIdentity_US.conf": "B600946E9ACC17C2",
"Configs/Identities/FactionIdentity_USSR.conf": "FBBCD73926989580",
"Configs/Identities/Territories/FactionHomeTerritory_US.conf": "B548A5B264939A98",
"Configs/Identities/Territories/FactionHomeTerritory_USSR.conf": "31FC78AF00523A99",
"Configs/Map/MapPlain.conf": "A786DD4868598F15",
"Configs/Navmesh/Navmesh_GM_Eden_Soldier.conf": "8BBC73472092902E",
"Configs/Navmesh/Navmesh_GM_Eden_Vehicle.conf": "0228A79846FD8A97",
"Configs/System/ActionContext/ManualCameraContext.conf": "C538807EEE48BED8",
"Configs/System/chimeraInputCommon.conf": "795184CF9AD764DB",
"Configs/System/chimeraMenus.conf": "C747AFB6B750CE9A",
"Configs/Systems/MissionSystems.conf": "C50579A2EC48E8EF",
"Prefabs/AI/Groups/Group_Base.et": "000CD338713F2B5A",
"Prefabs/AI/SCR_AIWorld.et": "E0A05C76552E7F58",
"Prefabs/AI/Waypoints/AIWaypoint_Cycle.et": "35BD6541CBB8AC08",
"Prefabs/AI/Waypoints/AIWaypoint_Defend.et": "93291E72AC23930F",
"Prefabs/AI/Waypoints/AIWaypoint_GetIn.et": "712F4795CF8B91C7",
"Prefabs/AI/Waypoints/AIWaypoint_GetOut.et": "C40316EE26846CAB",
"Prefabs/AI/Waypoints/AIWaypoint_Move.et": "750A8D1695BD6998",
"Prefabs/AI/Waypoints/AIWaypoint_SearchAndDestroy.et": "B3E7B8DC2BAB8ACC",
"Prefabs/Characters/Campaign/Final/OPFOR/USSR_Army/Regular/Campaign_USSR_Player_MortarCrew.et": "86E565387A634103",
"Prefabs/Characters/Core/Character_Base.et": "37578B1666981FCE",
"Prefabs/Characters/Factions/BLUFOR/US_Army/Character_US_Base.et": "836E7E39AAC5888B",
"Prefabs/Characters/Factions/BLUFOR/US_Army/Character_US_HeliPilot.et": "42A502E3BB727CEB",
"Prefabs/Characters/Factions/BLUFOR/US_Army/Character_US_Sniper.et": "0F6689B491641155",
"Prefabs/Characters/Factions/BLUFOR/US_Army/Character_US_Unarmed.et": "2F912ED6E399FF47",
"Prefabs/Characters/Factions/BLUFOR/US_Army/GreenBerets/Character_US_SF.et": "36E28C628A2F83CB",
"Prefabs/Characters/Factions/BLUFOR/US_Army/GreenBerets/Character_US_SF_Medic.et": "9A234C5857D92187",
"Prefabs/Characters/Factions/OPFOR/USSR_Army/Character_USSR_AR.et": "23ADBBC31B6A3DC6",
"Prefabs/Characters/Factions/OPFOR/USSR_Army/Character_USSR_AT.et": "1C78331E156A3D65",
"Prefabs/Characters/Factions/OPFOR/USSR_Army/Character_USSR_HeliPilot.et": "A62FA97C4EC64F14",
"Prefabs/Characters/Factions/OPFOR/USSR_Army/Character_USSR_LAT.et": "BF643BE4ADBDFDD3",
"Prefabs/Characters/Factions/OPFOR/USSR_Army/Character_USSR_RTO.et": "612F43A4D5AE765F",
"Prefabs/Characters/Factions/OPFOR/USSR_Army/Character_USSR_Rifleman.et": "DCB41B3746FDD1BE",
"Prefabs/Characters/Factions/OPFOR/USSR_Army/Character_USSR_SL.et": "5436629450D8387A",
"Prefabs/Characters/Factions/OPFOR/USSR_Army/Character_USSR_SR.et": "333DA6244C7DA34C",
"Prefabs/Characters/Factions/OPFOR/USSR_Army/Character_USSR_Sharpshooter.et": "976AC400219898FA",
"Prefabs/Characters/Factions/OPFOR/USSR_Army/Spetsnaz/Character_USSR_SF.et": "2DB452B3EC386B92",
"Prefabs/Characters/Factions/OPFOR/USSR_Army/Spetsnaz/Character_USSR_SF_Medic.et": "8CA70597606992EC",
"Prefabs/Characters/Footwear/CombatBoots_US_01.et": "DAAFD15478BDE1C3",
"Prefabs/Characters/HeadGear/Hat_Patrol_US_01/Hat_Patrol_US_01.et": "F545C1BE7C99954A",
"Prefabs/Characters/HeadGear/Helmet_PASGT_01/Helmet_PASGT_01_base.et": "8A2B2A544F3ED831",
"Prefabs/Characters/Uniforms/Jacket_US_BDU_rolledup.et": "3CCA7A9BB4FD3197",
"Prefabs/Characters/Uniforms/Pants_US_BDU.et": "604BB72BE8E023C2",
"Prefabs/Decals/Dirt/Decal_Dirt_Patch_03.et": "4AD6EB80A8B1FA3A",
"Prefabs/Groups/BLUFOR/Group_US_FireTeam.et": "84E5BBAB25EA23E5",
"Prefabs/Groups/INDFOR/Group_FIA_FireTeam.et": "5BEA04939D148B1D",
"Prefabs/Groups/OPFOR/Group_USSR_Base.et": "8DE0C0830FE0C33D",
"Prefabs/Groups/OPFOR/Group_USSR_RifleSquad.et": "E552DABF3636C2AD",
"Prefabs/Items/Core/Item_Base.et": "C95E11C60810F432",
"Prefabs/Items/Equipment/Backpacks/Backpack_Kolobok.et": "41A9C55B61F375F0",
"Prefabs/Items/Equipment/Binoculars/Binoculars_B8/Binoculars_B8.et": "243948B23D90BECB",
"Prefabs/Items/Equipment/Kits/MedicalKit_01/MedicalKit_01_US.et": "AE578EEA4244D41F",
"Prefabs/Items/Equipment/Kits/MedicalKit_01/MedicalKit_01_USSR.et": "21EF98BFC1EB3793",
"Prefabs/Items/Equipment/Kits/RepairKit_01/RepairKit_01_wrench.et": "33B2DFDCD0EBA3DB",
"Prefabs/Items/Equipment/Maps/Map_Paper_01/PaperMap_01_folded.et": "13772C903CB5E4F7",
"Prefabs/Items/Equipment/Radios/Radio_ANPRC77.et": "9B6B61BB3FE3DFB0",
"Prefabs/Items/Equipment/Radios/Radio_R107M.et": "54C68E438DD34265",
"Prefabs/Items/Equipment/Radios/Radio_R148.et": "E1A5D4B878AA8980",
"Prefabs/Items/Equipment/Watches/Watch_SandY184A.et": "78ED4FEF62BBA728",
"Prefabs/Items/Fuel/Jerrycan_01/Jerrycan_01_item.et": "12D5AD21E383B768",
"Prefabs/Items/Medicine/FieldDressing_01/FieldDressing_USSR_01.et": "C3F1FA1E2EC2B345",
"Prefabs/Items/Medicine/FieldDressing_01/FieldDressing_US_01.et": "A81F501D3EF6F38E",
"Prefabs/Items/Medicine/MorphineInjection_01/MorphineInjection_01.et": "0D9A5DCF89AE7AA9",
"Prefabs/Items/Medicine/SalineBag_01/SalineBag_USSR_01.et": "527D7C5D2E476BDC",
"Prefabs/Items/Medicine/SalineBag_01/SalineBag_US_01.et": "00E36F41CA310E2A",
"Prefabs/Items/Medicine/Tourniquet_01/Tourniquet_US_01.et": "D70216B1B2889129",
"Prefabs/Items/Misc/IntelligenceFolder_E_01/IntelligenceFolder_E_01.et": "6D56FED1E55A8F84",
"Prefabs/MP/Managers/Factions/FactionManager_Base.et": "A242612865F2A48E",
"Prefabs/MP/Managers/Factions/FactionManager_USxUSSR.et": "589540B35EBA8CDC",
"Prefabs/MP/Managers/Loadouts/LoadoutManager_USxUSSR.et": "97EF4C1A41F63DDB",
"Prefabs/MP/Modes/GameMode_Base.et": "0F307326459A1395",
"Prefabs/MP/ScriptedChatEntity.et": "F69BC912AC8236F9",
"Prefabs/Props/EmptyStorages/USSR_AmmoBox_empty.et": "EBBC859CCD94D96D",
"Prefabs/Props/Furniture/Table_01.et": "53506DCB398C7EBE",
"Prefabs/Props/Military/Antennas/Antenna_FIA_02/Antenna_FIA_02_base.et": "B3949F6D215A9F78",
"Prefabs/Props/Military/Sandbags/Sandbag_01_short_burlap.et": "CFFEB23FBEA00322",
"Prefabs/Structures/BuildingParts/Doors/DoorSet_Base.et": "87CADB5ADC989993",
"Prefabs/Structures/BuildingParts/Doors/Door_MetalGate_01_Short_LEFT_EXT_ST_B.et": "34B08027DBDE322A",
"Prefabs/Structures/BuildingParts/Doors/Door_Metal_A_RIGHT_EXT_COV_B.et": "67F17696FF278AE0",
"Prefabs/Structures/Military/Camps/TentSmallUS_01/TentSmallUS_01.et": "01AE5FD77A9A4C21",
"Prefabs/Structures/Military/Camps/TentUSSR_01/TentUSSR_01_base.et": "BE5D5CFA90224646",
"Prefabs/Structures/Military/Camps/TentUS_01/TentUSMedical_01.et": "F8427C3EFC52644E",
"Prefabs/Structures/Walls/BarbedWire/BarbedTape_01/BarbedTape_01_Long_noStake.et": "46904AF5D473FB75",
"Prefabs/Structures/Walls/BarbedWire/BarbedTape_01/BarbedTape_01_Short_noStake.et": "CAE1588B6265A2AB",
"Prefabs/Structures/Walls/Concrete/ConcreteWall_01/ConcreteWall_01_3m.et": "60E5729BEA18F875",
"Prefabs/Systems/Radio/RadioManager.et": "B8E09FAB91C4ECCD",
"Prefabs/Tasks/BaseTask.et": "1D0F815858EE24AD",
"Prefabs/Vehicles/Helicopters/Mi8MT/Mi8MT_armed.et": "7BD282AF716ED639",
"Prefabs/Vehicles/Helicopters/Mi8MT/Mi8MT_unarmed_transport.et": "DF5CCB7C0FF049F4",
"Prefabs/Vehicles/Wheeled/UAZ469/UAZ469.et": "259EE7B78C51B624",
"Prefabs/Vehicles/Wheeled/UAZ469/UAZ469_PKM.et": "0B4DEA8078B78A9B",
"Prefabs/Vehicles/Wheeled/UAZ469/VehParts/Seats/UAZ469_seats_rear.et": "780AAF0A51AEE61A",
"Prefabs/Vehicles/Wheeled/Ural4320/Ural4320_ammo.et": "3336BE330C4F355B",
"Prefabs/Vehicles/Wheeled/Ural4320/Ural4320_transport.et": "16C1F16C9B053801",
"Prefabs/Weapons/Ammo/Ammo_Shell_82mm_HE_O832DU.et": "98EC9C526AFBA282",
"Prefabs/Weapons/Attachments/Optics/Optic_4x20/Optic_4x20.et": "BD496EE1B40DC510",
"Prefabs/Weapons/Attachments/Optics/Optic_ARTII/Optic_ARTII.et": "D2018EDB1BBF4C88",
"Prefabs/Weapons/Attachments/Optics/Optic_PSO1/Optic_PSO1.et": "C850A33226B8F9C1",
"Prefabs/Weapons/Core/VehiclePeriscope_DummyWeapon_Base.et": "7E1DD1CE4D6A23F4",
"Prefabs/Weapons/Explosives/Mine_PMN4/Mine_PMN4.et": "B05A816C0BF50802",
"Prefabs/Weapons/Handguns/PM/Handgun_PM.et": "C0F7DD85A86B2900",
"Prefabs/Weapons/Magazines/Magazine_545x39_AK_30rnd_Ball.et": "BBB50A815A2F916B",
"Prefabs/Weapons/Magazines/Magazine_762x51_M14_20rnd_SpecialBall.et": "627255315038152A",
"Prefabs/Weapons/Magazines/Magazine_762x54_SVD_10rnd_Sniper.et": "9CCB46C6EE632C1A",
"Prefabs/Weapons/Magazines/Magazine_9x18_PM_8rnd_Ball.et": "8B853CDD11BA916E",
"Prefabs/Weapons/Mortars/2B14/Mortar_2B14.et": "D1FFE458E8AC4BDB",
"Prefabs/Weapons/Rifles/AK74/Rifle_AK74.et": "FA5C25BF66A53DCF",
"Prefabs/World/Game/PerceptionManager.et": "028DAEAD63E056BE",
"Sounds/Items/_SharedData/PickUp/Items_PickUp_Map.acp": "13F8D0DE67678118",
"Sounds/Vehicles/Wheeled/UAZ469/Vehicles_UAZ469_Horn.acp": "7E64D37BE3E1F3FA",
"UI/Fonts/RobotoCondensed/RobotoCondensed_Regular.fnt": "3E7733BAC8C831F6",
"UI/Textures/DeployMenu/Loadout-BG/Loadout_BG_USSR.imageset": "21533F2089005056",
"UI/Textures/DeployMenu/Loadout-BG/Loadout_US_BG.imageset": "F8AC305446D5D480",
"UI/Textures/Editor/EditableEntities/Factions/EditableEntity_Faction_USA.edds": "EB7F65DBC9392557",
"UI/Textures/Editor/EditableEntities/Factions/EditableEntity_Faction_USSR.edds": "40B12B0DF911B856",
"UI/Textures/Flags/US-flag-base-3it.edds": "46FB2FB2C2125A3C",
"UI/Textures/Flags/USSR-flag-base-3it.edds": "50824EB9F2C215AB",
"UI/Textures/Icons/icons_mapMarkersUI-glow.imageset": "67B3A6DC2D712B52",
"UI/Textures/Icons/icons_mapMarkersUI.imageset": "E23427CAC80DA8B7",
"UI/Textures/Icons/icons_wrapperUI-glow.imageset": "00FE3DBDFD15227B",
"UI/Textures/Icons/icons_wrapperUI.imageset": "3262679C50EF4F01",
"UI/layouts/HUD/GameOver/EndScreen/EndScreenContent_NoImage.layout": "C4507D07F3C54831",
"UI/layouts/Menus/PauseMenu/PauseMenuButton.layout": "9ECCD201BCF07E95",
"UI/layouts/Task/TaskListEntry.layout": "B71975032150BAFB",
"UI/layouts/Task/TaskListEntryDescription.layout": "552EB1921B5C548C",
"UI/layouts/WidgetLibrary/Buttons/WLib_ButtonText.layout": "75C912A1C89BE6C2",
"UI/layouts/WidgetLibrary/ComboBox/WLib_ComboBox.layout": "4B5AE6E64037FFB4",
"UI/layouts/WidgetLibrary/EditBox/WLib_EditBox.layout": "0022F0B45ADBC5AC",
"system/textures/defWhite.edds": "A64A8C63E0FBAE87",
"worlds/Eden/Eden.ent": "853E92315D1D9EFE",
"worlds/MP/Navmeshes/LowResEden.nmn": "5E19E60F26327356"
}
@@ -0,0 +1,143 @@
#!/usr/bin/env python3
"""Exercise exact dependency closure, resource ownership and isolated profile inputs."""
import ast
import importlib.util
import os
import re
import copy
import hashlib
import json
from pathlib import Path
import shutil
import sys
import tempfile
import unittest
sys.path.insert(0,str(Path(__file__).resolve().parents[1]/'tools'))
TOOLS=Path(os.environ.get('ERR_OPTIONAL_IDENTITY_TOOLS',Path(__file__).resolve().parents[1]/'tools'))
sys.path.insert(0,str(TOOLS))
import resource_references as refs
import external_addons as ext
ROOT=Path(os.environ.get('ERR_REPO',Path(__file__).resolve().parents[1]))
class ExternalAddonsTests(unittest.TestCase):
def setUp(self):
self.temp=tempfile.TemporaryDirectory();self.addCleanup(self.temp.cleanup)
self.home=Path(self.temp.name);self.source=self.home/'installed';self.source.mkdir()
self.addons=self.home/'profile'/'addons';self.addons.mkdir(parents=True)
self.cache=self.home/'profile'/'cache.json';self.value=ext.policy(ROOT)
for guid,deps in ext.ALLOWED.items():
folder=self.source/guid;folder.mkdir()
manifest='GameProject { GUID "'+guid+'" Dependencies { '+' '.join('"'+d+'"' for d in sorted(deps))+' } }\n'
(folder/'addon.gproj').write_text(manifest)
self.value['addons'][guid]['project_sha256']=hashlib.sha256(manifest.encode()).hexdigest()
data=b'RDB synthetic fixture\0'
for path,entry in self.value['resources'].items():
if entry['addon']==guid:data+=path.encode()+b'\0\x06\0\0\0\0\0'+bytes.fromhex(entry['guid'])[::-1]
(folder/'resourceDatabase.rdb').write_bytes(data);(folder/'data.pak').write_bytes(b'fixture '+guid.encode())
def test_resource_identity_requires_visible_owner(self):
for path,item in self.value['resources'].items():
self.assertTrue(ext.resource_allowed(self.value,{item['addon']},item['guid'],path))
self.assertFalse(ext.resource_allowed(self.value,{'core'},item['guid'],path))
self.assertFalse(ext.resource_allowed(self.value,{item['addon']},'0000000000000000',path))
self.assertEqual(ext.direct_for('core'),set(ext.DIRECT));self.assertEqual(ext.direct_for('chat'),set())
def test_policy_rejects_original_transitive_dependency(self):
root=self.home/'root';(root/'docs').mkdir(parents=True)
value=copy.deepcopy(self.value);value['addons'][ext.DIRECT[0]]['dependencies'].append('5F16D7E4A1CBE075')
(root/'docs/external-addons.json').write_text(json.dumps(value))
with self.assertRaisesRegex(ValueError,'transitive'):ext.policy(root)
def test_only_exact_authorized_closure_is_exposed_and_hashed(self):
unrelated=self.source/'original';unrelated.mkdir();(unrelated/'addon.gproj').write_text('GameProject { GUID "5F16D7E4A1CBE075" }')
records=ext.prepare_profile(self.addons,self.source,self.value,self.cache)
self.assertEqual(set(records),set(ext.ALLOWED))
self.assertEqual({p.name for p in self.addons.iterdir()},{'ERRI_'+g for g in ext.ALLOWED})
self.assertTrue(all(p.is_symlink() for p in self.addons.iterdir()))
self.assertTrue(ext.verify_profile(records,self.source,self.value,self.cache,self.addons))
self.assertEqual(ext.prepare_profile(self.addons,self.source,self.value,self.cache),records)
(self.source/ext.DIRECT[0]/'data.pak').write_bytes(b'mutated runtime')
self.assertFalse(ext.verify_profile(records,self.source,self.value,self.cache,self.addons))
def test_missing_and_duplicate_identity_fail(self):
guid=ext.DIRECT[0];shutil.copytree(self.source/guid,self.source/'duplicate')
with self.assertRaisesRegex(ValueError,'Duplicate'):ext.installed(self.source,self.value)
shutil.rmtree(self.source/'duplicate');shutil.rmtree(self.source/guid)
with self.assertRaisesRegex(ValueError,'Missing installed'):ext.installed(self.source,self.value)
def test_manifest_and_database_mutations_fail(self):
guid=ext.DIRECT[0];manifest=self.source/guid/'addon.gproj';old=manifest.read_text();manifest.write_text(old+'// changed')
with self.assertRaisesRegex(ValueError,'manifest changed'):ext.installed(self.source,self.value)
manifest.write_text(old)
resource=next(iter(self.value['resources'].values()));(self.source/resource['addon']/'resourceDatabase.rdb').write_bytes(b'wrong GUID')
with self.assertRaisesRegex(ValueError,'resource identity'):ext.installed(self.source,self.value)
def test_unrelated_profile_addon_and_wrong_link_fail(self):
(self.addons/'original').mkdir()
with self.assertRaisesRegex(ValueError,'Unrelated'):ext.prepare_profile(self.addons,self.source,self.value,self.cache)
(self.addons/'original').rmdir();guid=ext.DIRECT[0]
(self.addons/('ERRI_'+guid)).symlink_to(self.source/ext.DIRECT[1],target_is_directory=True)
with self.assertRaisesRegex(ValueError,'Unexpected private'):ext.prepare_profile(self.addons,self.source,self.value,self.cache)
def test_symlinked_runtime_file_fails(self):
pak=self.source/ext.DIRECT[0]/'data.pak';pak.unlink();pak.symlink_to(self.source/ext.DIRECT[1]/'data.pak')
with self.assertRaisesRegex(ValueError,'regular file'):ext.installed(self.source,self.value)
class OptionalIdentityTests(unittest.TestCase):
def setUp(self):
self.name=refs.OPTIONAL_FILE
self.text=(ROOT/self.name).read_text()
self.guid='574AA64002B8E308';self.resource='Prefabs/Characters/REAPER_SpectatorCameraHelper.et'
def rejected_reference(self,name,text):
self.assertIn((self.guid,self.resource),list(refs.hard_resource_references(name,text)))
def test_exact_comparison_only_and_every_other_reference_retained(self):
all_refs=re.findall(r'\{([A-F0-9]{16})\}([^"\n]+)',self.text)
expected=[pair for pair in all_refs if pair!=(self.guid,self.resource)]
self.assertEqual(list(refs.hard_resource_references(self.name,self.text)),expected)
self.assertIn(('37578B1666981FCE','Prefabs/Characters/Core/Character_Base.et'),expected)
self.rejected_reference('addons/core/Scripts/Game/Other.c',self.text)
for changed in [
self.text+'\n', # even a benign source edit needs renewed audit
self.text.replace('return prefab ==', 'Resource.Load(prefab); return prefab =='),
self.text.replace('return prefab ==', 'return Resource.Load(').replace(refs.OPTIONAL_RESOURCE+'";',refs.OPTIONAL_RESOURCE+'");'),
self.text+'\nResource.Load("'+refs.OPTIONAL_RESOURCE+'");',
self.text+'\nSpawn("'+refs.OPTIONAL_RESOURCE+'");',
self.text+'\nResourceName extra = "'+refs.OPTIONAL_RESOURCE+'";',
self.text.replace(refs.OPTIONAL_METHOD,'/*'+refs.OPTIONAL_METHOD+'*/'),
self.text.replace('CameraSlot(BaseContainer slot)','DifferentMethod(BaseContainer slot)'),
self.text.replace('if (!ModsPresent()) return false;',''),
]: self.rejected_reference(self.name,changed)
unknown=self.text.replace(self.guid,'574AA64002B8E309')
self.assertIn(('574AA64002B8E309',self.resource),list(refs.hard_resource_references(self.name,unknown)))
# The optional addon never enters either resource policy or dependency closure.
value=ext.policy(ROOT)
self.assertNotIn('5EB139459EBF5C16',ext.ALLOWED)
self.assertFalse(ext.resource_allowed(value,set(ext.ALLOWED),self.guid,self.resource))
def repository_resource_loop(self,name,text):
# Execute the actual dependency-scanner loop without running the full suite.
source=Path(os.environ.get('ERR_OPTIONAL_CHECK_SOURCE',TOOLS/'check.py')).read_text()
tree=ast.parse(source)
loops=[node for node in ast.walk(tree) if isinstance(node,ast.For) and isinstance(node.target,ast.Tuple)
and [getattr(n,'id',None) for n in node.target.elts]==['g','path']]
self.assertEqual(len(loops),1)
code=compile(ast.fix_missing_locations(ast.Module(body=loops,type_ignores=[])),'actual_repository_resource_loop','exec')
env=dict(re=re,hard_resource_references=refs.hard_resource_references,p=ROOT/name,ROOT=ROOT,s=text,
resources={},owners={},vanilla=json.loads((ROOT/'docs/vanilla-resources.json').read_text()),
external=ext.policy(ROOT),visibility={'core':{'core',*ext.ALLOWED}},resource_allowed=ext.resource_allowed)
exec(code,env)
def test_actual_repository_resource_loop(self):
self.repository_resource_loop(self.name,self.text)
for name,text in [(self.name,self.text+'\nResource.Load("'+refs.OPTIONAL_RESOURCE+'");'),
('addons/core/Scripts/Game/Other.c',self.text),
(self.name,self.text.replace('return prefab ==','return Resource.Load(').replace(refs.OPTIONAL_RESOURCE+'";',refs.OPTIONAL_RESOURCE+'");'))]:
with self.assertRaisesRegex(AssertionError,'Unresolved/mismatched'):
self.repository_resource_loop(name,text)
def test_actual_bundle_validator(self):
path=Path(os.environ.get('ERR_OPTIONAL_BUNDLE_SOURCE',TOOLS/'source_bundle.py'))
spec=importlib.util.spec_from_file_location('optional_test_source_bundle',path)
bundle=importlib.util.module_from_spec(spec);spec.loader.exec_module(bundle)
payload={name:(ROOT/name).read_bytes() for name in bundle.inventory(ROOT)}
before=ext.policy(ROOT)
bundle.validate(payload,ROOT)
self.assertEqual(before,ext.policy(ROOT))
for changed in [self.text+'\nResource.Load("'+refs.OPTIONAL_RESOURCE+'");',
self.text+'\nSpawn("'+refs.OPTIONAL_RESOURCE+'");']:
altered=dict(payload);altered[self.name]=changed.encode()
with self.assertRaisesRegex(ValueError,'unresolved or nonvanilla'):
bundle.validate(altered,ROOT)
if __name__=='__main__':unittest.main()
File diff suppressed because one or more lines are too long
@@ -0,0 +1,31 @@
"""Hard resource references, with one fail-closed audited optional identity test.
This is not a general Enforce parser or a new external dependency allowlist.
Changing any byte of the audited source requires reviewing this exception again.
"""
import hashlib
import re
OPTIONAL_FILE = 'addons/core/Scripts/Game/ERR/00_Core/ERR_ReaperRHSCompat.c'
OPTIONAL_SHA256 = 'bcdf98c05ac6cdf0c7eaa854531b02e9ee4f53fbb346ae01d58114e572e7dd4f'
OPTIONAL_RESOURCE = '{574AA64002B8E308}Prefabs/Characters/REAPER_SpectatorCameraHelper.et'
OPTIONAL_METHOD = ''' protected static bool CameraSlot(BaseContainer slot)
{
if (!slot || slot.GetName() != "SpectatorCameraHelper") return false;
ResourceName prefab;
if (!slot.Get("Prefab", prefab)) return false;
return prefab == "{574AA64002B8E308}Prefabs/Characters/REAPER_SpectatorCameraHelper.et";
}'''
def hard_resource_references(relative_path, text):
"""Exclude only the pinned comparison occurrence; keep all other checks."""
identity_offset = -1
if (str(relative_path) == OPTIONAL_FILE
and hashlib.sha256(text.encode('utf-8')).hexdigest() == OPTIONAL_SHA256
and text.count(OPTIONAL_METHOD) == 1
and text.count(OPTIONAL_RESOURCE) == 1):
identity_offset = text.index(OPTIONAL_METHOD) + OPTIONAL_METHOD.index(OPTIONAL_RESOURCE)
for match in re.finditer(r'\{([A-F0-9]{16})\}([^"\n]+)', text):
if match.start() != identity_offset:
yield match.groups()
@@ -0,0 +1,244 @@
#!/usr/bin/env python3
"""Preview or write a deterministic DEVELOPMENT SOURCE BUNDLE; never build/publish."""
import argparse
import hashlib
import io
import json
import os
from pathlib import Path, PurePosixPath
import re
import stat
import tempfile
import zipfile
import sys
sys.dont_write_bytecode = True
from source_manifest import addon_manifest
from project_schema import parse_project
from resource_references import hard_resource_references
from external_addons import policy as external_policy, direct_for, resource_allowed, ALLOWED
from release_check import audit, read_json, evidence_path
ROOT = Path(__file__).resolve().parents[1]
BASE = '58D0FB3206B6F859'
PROJECTS = {'core': ('ERR_Core', '2528466DE220D91C', ())}
DIRECTORIES = {'Scripts', 'Prefabs', 'Configs', 'Missions', 'Worlds', 'UI', 'Materials', 'AI'}
SUFFIXES = {'.c', '.et', '.conf', '.ent', '.layer', '.layout', '.emat', '.bt', '.meta', '.gproj'}
EXCLUDED = {'.git', '.build', '.local', '__pycache__', 'profiles', 'profile', 'cache',
'runtime', 'evidence', 'vendor', 'vanilla', 'original', 'node_modules', '.agents', '.codex'}
README = '''# DEVELOPMENT SOURCE BUNDLE — Co10 Escape Reintroduced
Author: Jakub Jim Žáček.
This ZIP contains the single Co10 Escape Reintroduced addon, with Core, AI,
Intel, Map and Chat script folders. It is NOT a native .pak or a published mod.
Third-party assets are not redistributed.
Extract into a NEW development folder and register addons/core/addon.gproj in
Workbench. Install and register the RHS/WCS dependencies in EXTERNAL-ADDONS.json.
Open addons/core/addon.gproj and use Missions/ERR_Everon.conf.
Scenario: {C1E20667DCE324ED}Missions/ERR_Everon.conf
Use the installed engine's normal project/scenario workflow. This archive has not
been compiled by its bundler; no native caches or binaries are included.
Target: Everon, up to 12 players. The mod requires the listed external addons. This remains development source.
Manual prison/scavenging/radio/extraction play, remote joins/reconnects and
ownership, twelve connected players, aircraft support, repeated companion cleanup,
matched-workload FPS improvement and release qualification require separate
source-bound validation. Existing scripted fixtures are not those acceptances.
WORKBENCH-only probes are source, not proof of a test run or normal gameplay.
BUNDLE-MANIFEST.json lists each payload file's SHA-256 and project dependencies.
Verify extracted bytes against it before editing. The manifest excludes its own
hash to avoid self-reference. These hashes identify bytes, not authenticity,
license grants or provenance proof. Source review remains required before sharing.
Evidence, acceptance records, runtime profiles and test tools are intentionally
absent; consult the maintained repository for current status and retained logs.
Even --mode release only adds the existing repository qualification audit before
this same development-source handoff; it does not build/publish a game release.
'''
def canonical(name):
p = PurePosixPath(name)
if (not name or p.is_absolute() or p.as_posix() != name or '\\' in name
or ':' in name or any(ord(c) < 32 for c in name)
or any(part in {'.', '..'} or part.endswith((' ', '.')) for part in p.parts)):
raise ValueError(f'unsafe bundle path: {name!r}')
return p
def inventory(root):
"""Reuse the evidence inventory; impose a narrower reviewed handoff schema."""
# Preflight directories without following links, including otherwise excluded
# entries themselves. Excluded trees are pruned from this preflight and
# excluded from the payload; the shared source manifest may still hash them.
addons = root / 'addons'
if addons.is_symlink() or not addons.is_dir():
raise ValueError('addons must be a real directory')
for base, dirs, files in os.walk(addons, followlinks=False):
for name in list(dirs) + files:
path = Path(base) / name
if path.is_symlink():
raise ValueError(f'symlink refused: {path.relative_to(root)}')
if not path.is_dir() and not stat.S_ISREG(path.lstat().st_mode):
raise ValueError(f'nonregular addon entry: {path.relative_to(root)}')
dirs[:] = [d for d in dirs if d.lower() not in EXCLUDED]
original = addon_manifest(root)
result = {}
folded = set()
for name, digest in original.items():
parts = canonical(name).parts
if any(part.lower() in EXCLUDED for part in parts):
continue
if any(part.startswith('.') for part in parts):
raise ValueError(f'unreviewed hidden addon content: {name}')
if len(parts) < 3 or parts[1] not in PROJECTS:
raise ValueError(f'unknown addon project: {name}')
path = root / name
if not stat.S_ISREG(path.lstat().st_mode):
raise ValueError(f'nonregular addon file: {name}')
if name.casefold() in folded:
raise ValueError(f'case-insensitive path collision: {name}')
folded.add(name.casefold())
if parts[2] == 'addon.gproj' and len(parts) == 3:
pass
elif len(parts) < 4 or parts[2] not in DIRECTORIES or path.suffix not in SUFFIXES - {'.gproj'}:
raise ValueError(f'unreviewed addon source/resource format: {name}')
result[name] = digest
return result
def validate(payload, root):
projects = {}
external = external_policy(root)
own_ids = read_json(evidence_path(root, 'docs/addons.json'))
if own_ids != {name: item[1] for name, item in PROJECTS.items()}:
raise ValueError('successor identity catalog differs from the single owned project')
for name, (identity, guid, deps) in PROJECTS.items():
text = payload.get(f'addons/{name}/addon.gproj', b'').decode('utf-8')
match = parse_project(text, allow_core_menu=name == 'core')
expected = {BASE, *(PROJECTS[d][1] for d in deps), *direct_for(name)}
found = re.findall(r'"([A-F0-9]{16})"', match[4]) if match else []
if not match or match[1] != identity or match[2] != guid or set(found) != expected or len(found) != len(expected):
raise ValueError(f'identity/dependency closure mismatch: {name}')
projects[name] = {'id': identity, 'guid': guid, 'dependencies': sorted(found)}
resources = {}
for name, data in payload.items():
if not name.endswith('.meta'):
continue
m = re.search(r'Name "\{([A-F0-9]{16})\}([^"\n]+)"', data.decode('utf-8'))
owner = name.split('/')[1]
if not m or f'addons/{owner}/{m[2]}.meta' != name or name[:-5] not in payload:
raise ValueError(f'mismatched/missing resource metadata: {name}')
if m[1] in resources or m[1] in own_ids.values() or m[1] == BASE:
raise ValueError(f'duplicate resource identity: {name}')
resources[m[1]] = (m[2], owner)
vanilla = read_json(evidence_path(root, 'docs/vanilla-resources.json'))
if set(resources) & set(vanilla.values()):
raise ValueError('successor resource reuses a vanilla identity')
for name, data in payload.items():
suffix = PurePosixPath(name).suffix
if suffix == '.meta':
continue
text = data.decode('utf-8') # Current reviewed handoff contains text assets only.
if re.search(r'\b(?:ESCT\w*|SCRTC_\w+|SCRT_\w+|EAI_\w+)\b', text):
raise ValueError(f'original ecosystem dependency: {name}')
if suffix not in {'.c', '.layer', '.gproj'} and name + '.meta' not in payload:
raise ValueError(f'resource lacks successor metadata: {name}')
owner = name.split('/')[1]
visible = {owner, *PROJECTS[owner][2]}
if 'core' in visible: visible.update(ALLOWED)
for guid, resource in hard_resource_references(name, text):
if guid in resources:
path, target = resources[guid]
if path != resource or target not in visible:
raise ValueError(f'resource outside project dependency closure: {name}')
elif vanilla.get(resource) != guid and not resource_allowed(external,visible,guid,resource):
raise ValueError(f'unresolved or nonvanilla resource: {name}')
return projects
def build(root=ROOT, mode='development'):
root = Path(root).resolve()
if mode not in {'development', 'release'}:
raise ValueError('unknown bundle mode')
if mode == 'release':
blockers = audit(root)
if blockers:
raise ValueError('Not release-qualified:\n - ' + '\n - '.join(blockers))
before = inventory(root)
payload = {name: (root / name).read_bytes() for name in before}
if {name: hashlib.sha256(data).hexdigest() for name, data in payload.items()} != before:
raise ValueError('addon bytes changed during collection')
projects = validate(payload, root)
if mode == 'release':
blockers = audit(root)
if blockers:
raise ValueError('Not release-qualified after collection:\n - ' + '\n - '.join(blockers))
if inventory(root) != before:
raise ValueError('addon tree changed during collection')
payload['BUNDLE-README.md'] = (README + '\nThe combined scenario requires the separately installed authorized addons listed in EXTERNAL-ADDONS.json. Their assets are not bundled.\n').encode('utf-8')
payload['EXTERNAL-ADDONS.json'] = json.dumps(external_policy(root),indent=2,sort_keys=True).encode('utf-8')
manifest = {'schema_version': 1, 'kind': 'DEVELOPMENT SOURCE BUNDLE',
'native_build': False, 'release_package': False, 'projects': projects,
'files': {name: hashlib.sha256(data).hexdigest() for name, data in sorted(payload.items())}}
payload['BUNDLE-MANIFEST.json'] = (json.dumps(manifest, indent=2, sort_keys=True) + '\n').encode()
stream = io.BytesIO()
with zipfile.ZipFile(stream, 'w', compression=zipfile.ZIP_STORED) as archive:
for name, data in sorted(payload.items()):
entry = zipfile.ZipInfo(name, date_time=(1980, 1, 1, 0, 0, 0))
entry.create_system = 3
entry.external_attr = (stat.S_IFREG | 0o644) << 16
archive.writestr(entry, data)
return stream.getvalue(), manifest
def write_new(output, content, root=ROOT):
path = Path(output).absolute()
canonical(path.as_posix().lstrip('/'))
if path.suffix != '.zip' or path.resolve().is_relative_to(Path(root).resolve()):
raise ValueError('output must be a new .zip outside the source checkout')
for part in (path, *path.parents):
if part.is_symlink():
raise ValueError('output symlinks are refused')
if path.exists() or not path.parent.is_dir():
raise ValueError('output exists or parent directory is missing')
temporary = None
try:
with tempfile.NamedTemporaryFile(prefix='.erri-bundle-', dir=path.parent, delete=False) as file:
temporary = Path(file.name)
file.write(content)
file.flush()
os.fsync(file.fileno())
# Same-filesystem atomic publication; link refuses an existing destination.
os.link(temporary, path, follow_symlinks=False)
finally:
if temporary is not None:
temporary.unlink()
def main(argv=None):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--mode', choices=('development', 'release'), default='development')
parser.add_argument('--output', type=Path, help='explicit new .zip outside checkout; omitted means read-only preview')
args = parser.parse_args(argv)
try:
content, manifest = build(mode=args.mode)
if args.output:
write_new(args.output, content)
print(json.dumps({'kind': manifest['kind'], 'preview': args.output is None,
'payload_files': len(manifest['files']), 'archive_bytes': len(content),
'archive_sha256': hashlib.sha256(content).hexdigest(),
'projects': manifest['projects']}, indent=2, sort_keys=True))
return 0
except (OSError, ValueError, UnicodeError) as error:
print(f'Bundle refused: {error}')
return 1
if __name__ == '__main__':
raise SystemExit(main())