prole/docs/EMBEDDED-RESOURCES.md
chrisfu fff18fdbe4 Update Prole-DB and improve Supabase integration
- Bumped Prole-DB image version to 17.7-053 in scripts, Dockerfile, and manifests.
- Replaced `prole-scan` with `prole-agent` throughout scripts and tests.
- Refined Kubernetes setup for Supabase to use namespace 'supabase'.
- Introduced conversion of Supabase Docker Compose to Kubernetes manifests with `kompose`.
- Added support for Kerberos toggle via environment variables in `init_kerberos.sh`.
- Improved error handling and logging in scripts for better maintainability.
2026-02-01 23:56:25 -08:00

7.7 KiB

Embedded Resources in Prole Installer

Overview

The Prole Installer package includes several embedded resources that must be accessible both when running from source and when packaged as a standalone binary.

Embedded Resources

1. Images (img/)

  • proleIcon.png (1.5 MB) - Application icon
  • proleLogo.png (2.2 MB) - Main logo
  • proleLogoSepia.png (2.7 MB) - Sepia background for GUI
  • proleLogoBlueprint.png (3.1 MB) - Blueprint variant
  • proleIconblueprint.png (1.6 MB) - Blueprint icon variant

2. Binary Executables

  • prole-net/prole-agent (6.8 MB) - Network scanner
    • Universal binary (x86_64 + arm64)
    • Used by network scan screen
    • Detects Kerberos, Active Directory, etc.

3. Application Bundles

  • prole-app/dist/Prole Tools.app (~12 MB) - Pre-built Prole Tools
    • Complete macOS .app bundle
    • Used by installer creation screen
    • Can be copied to DMG or USB installer

How Embedding Works

Resource Path Resolution

All resources use the get_resource_path() helper function:

def get_resource_path(relative_path):
    """Get absolute path to resource, works for dev and for PyInstaller."""
    try:
        # PyInstaller creates a temp folder and stores path in _MEIPASS
        base_path = Path(sys._MEIPASS)
    except AttributeError:
        # Running from source
        base_path = PROJECT_ROOT
    return base_path / relative_path

Usage Examples

Image Loading:

bg_path = get_resource_path('img/proleLogoSepia.png')
if bg_path.exists():
    image = Image.open(str(bg_path))

Binary Execution:

scan_binary = get_resource_path("prole-net/prole-agent")
if scan_binary.exists():
    process = subprocess.Popen([str(scan_binary)], ...)

App Bundle Access:

app_src = get_resource_path('prole-app/dist/Prole Tools.app')
if app_src.exists():
    # Copy to destination
    shutil.copytree(app_src, dest)

PyInstaller Configuration

Spec File (scripts/generate_spec.py)

Data Files:

datas = [
    ('installer', 'installer'),
    ('conf', 'conf'),
    ('etc', 'etc'),
    ('img', 'img'),
    ('docs', 'docs'),
    ('prole-app/dist/Prole Tools.app', 'prole-app/dist/Prole Tools.app'),
]

Binaries:

binaries = [
    ('prole-net/prole-agent', 'prole-net'),
]

The binaries list ensures executable permissions are preserved.

File Sizes

Total embedded resources: ~30-35 MB

Breakdown:

  • Images: ~11 MB
  • prole-agent: 6.8 MB
  • Prole Tools.app: ~12 MB
  • Other resources: ~5-10 MB

Final installer bundle: ~50-100 MB (includes Python runtime)

Usage in Installer

Network Scan Screen

The network scan screen uses prole-agent to detect services:

scan_binary = get_resource_path("prole-net/prole-agent")
process = subprocess.Popen([str(scan_binary)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT,
                         text=True)

Output is captured in real-time and displayed in the scan results text widget.

Installer Creation Screen

The installer creation screen copies Prole Tools.app to DMG:

app_src = get_resource_path('prole-app/dist/Prole Tools.app')
if app_src.exists():
    shutil.copytree(app_src, staging / 'Prole Tools.app')

Testing

Verify Resources from Source

python3 test_embedded_resources.sh

This tests:

  • ✓ All image files exist
  • ✓ prole-agent binary exists and is executable
  • ✓ Prole Tools.app bundle exists
  • ✓ Spec file includes all resources
  • ✓ Resource sizes

Verify Resources in Built Package

After building:

# Check extracted resources
./dist/prole-installer --help

# In another terminal, while installer is running:
ls -la /tmp/_MEI*/prole-net/
ls -la /tmp/_MEI*/img/
ls -la "/tmp/_MEI*/prole-app/dist/Prole Tools.app"

Troubleshooting

Binary Not Found Error

Error: Scan binary not found at /var/folders/.../prole-net/prole-agent

Cause: Binary not included in package or path not using get_resource_path()

Solution:

  1. Verify spec includes binary: grep prole-agent installer.spec
  2. Check code uses get_resource_path(): grep "get_resource_path.*prole-agent" install.py
  3. Rebuild: make clean && make package

Binary Not Executable

Error: Permission denied when running prole-agent

Cause: Binary permissions not preserved in package

Solution: Ensure binary is in binaries list (not datas) in spec file:

binaries = [
    ('prole-net/prole-agent', 'prole-net'),  # Correct - preserves +x
]
# NOT in datas:
# datas = [('prole-net/prole-agent', 'prole-net')]  # Wrong - loses +x

App Bundle Not Found

Error: Prole Tools.app not found

Cause: App not built before packaging installer

Solution:

  1. Build Prole Tools.app first (in prole-app directory)
  2. Verify it exists: ls "prole-app/dist/Prole Tools.app"
  3. Then build installer: make package

Large Bundle Size

Cause: Including large binary files significantly increases bundle size

Optimization Options:

  1. Compress app bundle:

    cd prole-app/dist
    zip -r "Prole Tools.zip" "Prole Tools.app"
    # Include zip instead of .app
    
  2. Download on demand: Instead of embedding, download from server when needed

  3. Exclude debug symbols: Strip binaries before packaging:

    strip prole-net/prole-agent
    

Build Process

When running make package:

  1. Icon conversion: PNG → ICNS
  2. Spec generation: Creates installer.spec with all resources
  3. PyInstaller:
    • Analyzes install.py
    • Collects dependencies
    • Copies data files (preserves directory structure)
    • Copies binaries (preserves execute permissions)
    • Creates single-file executable
  4. Bundle creation: Packages into .app with icon

Resource Extraction at Runtime

When the packaged installer runs:

  1. PyInstaller extracts resources to /tmp/_MEI<random>/
  2. Sets sys._MEIPASS to extraction directory
  3. get_resource_path() uses _MEIPASS to find resources
  4. Resources deleted automatically when installer exits

Security Considerations

Code Signing

Embedded binaries should be code signed:

codesign --force --sign "Developer ID Application: Your Name" prole-net/prole-agent

Then build the installer - the signed binary will be included.

Verification

Users can verify embedded binaries:

# Check signature of prole-agent after extraction
codesign --verify --verbose /tmp/_MEI*/prole-net/prole-agent

# Check installer bundle signature
codesign --verify --verbose "dist/Prole Installer.app"

Future Enhancements

Lazy Loading

For large resources, consider lazy loading:

def get_prole_tools_app():
    """Download or extract Prole Tools.app only when needed."""
    app_path = get_resource_path('prole-app/dist/Prole Tools.app')
    if not app_path.exists():
        # Download from server
        download_prole_tools(app_path)
    return app_path

Compression

Compress large resources:

# In spec file
datas = [
    ('prole-app/dist/Prole Tools.zip', 'prole-app/dist'),  # Compressed
]

# In code
def extract_prole_tools():
    zip_path = get_resource_path('prole-app/dist/Prole Tools.zip')
    extract_dir = Path(tempfile.mkdtemp())
    shutil.unpack_archive(zip_path, extract_dir)
    return extract_dir / 'Prole Tools.app'

References