Skip to content

Instantly share code, notes, and snippets.

@ynkdir
Created December 20, 2025 03:33
Show Gist options
  • Select an option

  • Save ynkdir/e77928bbd48e4bf5e6ee1f582d710f89 to your computer and use it in GitHub Desktop.

Select an option

Save ynkdir/e77928bbd48e4bf5e6ee1f582d710f89 to your computer and use it in GitHub Desktop.
"runFullTrust" and "systemAIModels" seems not supported in CreateAppContainerProfile()
# "runFullTrust" and "systemAIModels" seems not supported in CreateAppContainerProfile().
#
# > .\python.exe .\appcontainer.py
# appcontainer.py: 24996
# systemAIModels: 0
# runFullTrust: 4
# Failed to find real location of C:\Users\yukih\work\py-win32more\unapp\unapp\python.exe
# appcontainer.py: 10140
# systemAIModels: 0
# runFullTrust: 4
#
# ///script
# dependencies = ["win32more"]
# ///
# [Launch an AppContainer](https://learn.microsoft.com/en-us/windows/win32/secauthz/implementing-an-appcontainer)
#
# [icalcs](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/icacls)
# S-1-15-2-1: SID of ALL APPLICATION PACKAGES
# OI: Object inherit
# CI: Container inherit
# RX: Read and execute access
# icacls.exe appfolder /grant "*S-1-15-2-1:(OI)(CI)(RX)"
import asyncio
import sys
from contextlib import contextmanager
from ctypes import POINTER, Array, cast, pointer, sizeof
from win32more import FAILED, Byte, UInt32, UIntPtr, WinError
from win32more.Windows.Security.Authorization.AppCapabilityAccess import AppCapability
from win32more.Windows.Win32.Foundation import ERROR_INSUFFICIENT_BUFFER, PWSTR, GetLastError, LocalFree
from win32more.Windows.Win32.Security import (
PSID,
SECURITY_CAPABILITIES,
SID_AND_ATTRIBUTES,
DeriveCapabilitySidsFromName,
)
from win32more.Windows.Win32.Security.Authorization import ConvertSidToStringSid
from win32more.Windows.Win32.Security.Isolation import CreateAppContainerProfile, DeleteAppContainerProfile
from win32more.Windows.Win32.System.SystemServices import SE_GROUP_ENABLED
from win32more.Windows.Win32.System.Threading import (
EXTENDED_STARTUPINFO_PRESENT,
LPPROC_THREAD_ATTRIBUTE_LIST,
PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES,
PROCESS_INFORMATION,
STARTUPINFO,
STARTUPINFOEX,
CreateProcess,
DeleteProcThreadAttributeList,
GetCurrentProcessId,
InitializeProcThreadAttributeList,
UpdateProcThreadAttribute,
)
def get_capability_sid_from_name(capability_name: str) -> PSID:
group_sids = POINTER(PSID)()
group_sid_count = UInt32()
sids = POINTER(PSID)()
sid_count = UInt32()
succeeded = DeriveCapabilitySidsFromName(capability_name, group_sids, group_sid_count, sids, sid_count)
if not succeeded:
raise WinError()
try:
return sids[0]
finally:
LocalFree(group_sids[0])
LocalFree(group_sids)
LocalFree(sids)
def convert_sid_to_string_sid(sid: PSID) -> str:
string_sid = PWSTR()
succeeded = ConvertSidToStringSid(sid, string_sid)
if not succeeded:
raise WinError()
try:
return string_sid.value
finally:
LocalFree(string_sid)
def build_app_container_capabilities(capability_names: list[str]) -> Array[SID_AND_ATTRIBUTES]:
capabilities = (SID_AND_ATTRIBUTES * len(capability_names))()
for i, name in enumerate(capability_names):
capabilities[i].Sid = get_capability_sid_from_name(name)
capabilities[i].Attributes = SE_GROUP_ENABLED
return capabilities
@contextmanager
def create_app_container_profile(
app_container_name: str, display_name: str, description: str, capabilities: Array[SID_AND_ATTRIBUTES]
) -> PSID:
app_container_sid = PSID()
hr = CreateAppContainerProfile(
app_container_name, display_name, description, capabilities, len(capabilities), app_container_sid
)
if FAILED(hr):
raise WinError()
try:
yield app_container_sid
finally:
DeleteAppContainerProfile(app_container_name)
@contextmanager
def proc_thread_attribute_list(
app_container_sid: PSID, capabilities: Array[SID_AND_ATTRIBUTES]
) -> LPPROC_THREAD_ATTRIBUTE_LIST:
attribute_list = initialize_proc_thread_attribute_list(1)
_sc = update_proc_thread_attribute_security_capabilities(app_container_sid, attribute_list, capabilities)
try:
yield attribute_list
finally:
DeleteProcThreadAttributeList(attribute_list)
def initialize_proc_thread_attribute_list(attribute_count: int) -> LPPROC_THREAD_ATTRIBUTE_LIST:
attribute_list_size = UIntPtr()
succeeded = InitializeProcThreadAttributeList(None, attribute_count, 0, attribute_list_size)
if succeeded or GetLastError() != ERROR_INSUFFICIENT_BUFFER:
raise WinError()
attribute_list_buffer = (Byte * attribute_list_size.value)()
succeeded = InitializeProcThreadAttributeList(attribute_list_buffer, attribute_count, 0, attribute_list_size)
if not succeeded:
raise WinError()
return cast(pointer(attribute_list_buffer), LPPROC_THREAD_ATTRIBUTE_LIST)
def update_proc_thread_attribute_security_capabilities(
app_container_sid: PSID, attribute_list: LPPROC_THREAD_ATTRIBUTE_LIST, capabilities: Array[SID_AND_ATTRIBUTES]
) -> None:
sc = SECURITY_CAPABILITIES()
sc.AppContainerSid = app_container_sid
sc.Capabilities = capabilities
sc.CapabilityCount = len(capabilities)
succeeded = UpdateProcThreadAttribute(
attribute_list, 0, PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES, pointer(sc), sizeof(sc), None, None
)
if not succeeded:
raise WinError()
# Caller should keep sc until DeleteProcThreadAttributeList().
return sc
def create_process(cmdline: str, attribute_list: LPPROC_THREAD_ATTRIBUTE_LIST) -> None:
si = STARTUPINFOEX()
si.StartupInfo.cb = sizeof(si)
si.lpAttributeList = attribute_list
pi = PROCESS_INFORMATION()
succeeded = CreateProcess(
None,
cmdline,
None,
None,
False,
EXTENDED_STARTUPINFO_PRESENT,
None,
None,
cast(pointer(si), POINTER(STARTUPINFO)),
pi,
)
if not succeeded:
raise WinError()
async def check_capability(capability_name):
cap = AppCapability.Create(capability_name)
return await cap.RequestAccessAsync()
async def main():
print("appcontainer.py: ", GetCurrentProcessId())
print("systemAIModels: ", await check_capability("systemAIModels"))
print("runFullTrust: ", await check_capability("runFullTrust"))
if "--app" not in sys.argv:
capabilities = build_app_container_capabilities(["runFullTrust", "systemAIModels"])
with create_app_container_profile(
"MySandboxApp", "MySandboxApp", "Description", capabilities
) as app_container_sid:
with proc_thread_attribute_list(app_container_sid, capabilities) as attribute_list:
create_process(f'"{sys.executable}" "{__file__}" --app', attribute_list)
return
if __name__ == "__main__":
asyncio.run(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment