8.7 KiB
8.7 KiB
Milestone 1: App Package Format
Status: Planning Goal: Define how apps are bundled, signed, and validated.
Overview
The app package format is the foundation of the entire ecosystem. Every tool (CLI, portal, device) needs to understand this format.
Questions to Answer
- What files comprise an app package?
- How is the manifest structured?
- How are apps signed for integrity?
- How are updates handled (full vs delta)?
- What metadata is required (name, version, permissions, icons)?
Package Format Options
Option A: ZIP Archive
myapp.zip
├── manifest.json
├── icon.png
└── assets/
├── main.rml
├── styles.rcss
└── app.lua
| Pros | Cons |
|---|---|
| Simple, standard tooling | No built-in signing |
| Easy to inspect | No metadata in filename |
| Wide compatibility | Need separate signature file |
Option B: Custom Format (.mosis)
myapp.mosis (binary format)
┌─────────────────────────┐
│ Magic bytes (4) │
│ Version (2) │
│ Manifest length (4) │
│ Manifest JSON │
│ Signature (256) │
│ Compressed payload │
└─────────────────────────┘
| Pros | Cons |
|---|---|
| Signature built-in | Custom tooling needed |
| Efficient metadata access | Harder to inspect |
| Single file | More complex implementation |
Option C: Signed ZIP (Recommended)
myapp.mosis/ (actually a ZIP)
├── manifest.json
├── META-INF/
│ ├── MANIFEST.MF # File hashes
│ └── SIGNATURE.SF # Signed manifest
├── icon.png
└── assets/
└── ...
| Pros | Cons |
|---|---|
| Standard ZIP tooling | Slightly more complex |
| JAR/APK-style signing | |
| Easy inspection | |
| Proven approach |
Proposed Structure
com.developer.appname-1.0.0.mosis
├── manifest.json # App metadata
├── META-INF/
│ ├── CERT.PEM # Developer certificate
│ ├── CERT.SIG # Signature of MANIFEST.MF
│ └── MANIFEST.MF # SHA-256 hashes of all files
├── icons/
│ ├── icon-32.png
│ ├── icon-64.png
│ └── icon-128.png
├── assets/
│ ├── main.rml # Entry point
│ ├── screens/
│ │ ├── home.rml
│ │ └── settings.rml
│ ├── styles/
│ │ └── theme.rcss
│ └── scripts/
│ ├── main.lua
│ └── utils.lua
└── locales/ # Optional i18n
├── en.json
└── es.json
Manifest Schema
Required Fields
{
"$schema": "https://mosis.dev/schemas/manifest-v1.json",
"id": "com.developer.appname",
"name": "My App",
"version": "1.0.0",
"version_code": 1,
"entry": "assets/main.rml",
"min_mosis_version": "1.0.0"
}
Full Schema
{
"$schema": "https://mosis.dev/schemas/manifest-v1.json",
"id": "com.developer.appname",
"name": "My App",
"version": "1.0.0",
"version_code": 1,
"description": "A short description of the app",
"entry": "assets/main.rml",
"author": {
"name": "Developer Name",
"email": "dev@example.com",
"url": "https://developer.com"
},
"permissions": [
"storage",
"network",
"camera"
],
"icons": {
"32": "icons/icon-32.png",
"64": "icons/icon-64.png",
"128": "icons/icon-128.png"
},
"min_mosis_version": "1.0.0",
"target_mosis_version": "1.2.0",
"category": "utilities",
"tags": ["productivity", "tools"],
"orientation": "portrait",
"background_color": "#FFFFFF",
"locales": ["en", "es", "fr"],
"default_locale": "en"
}
Field Definitions
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | Yes | Unique package identifier (reverse domain) |
name |
string | Yes | Display name (max 30 chars) |
version |
string | Yes | Semantic version (X.Y.Z) |
version_code |
integer | Yes | Incremental build number |
entry |
string | Yes | Path to entry RML file |
min_mosis_version |
string | Yes | Minimum Mosis version required |
description |
string | No | Short description (max 80 chars) |
author |
object | No | Author information |
permissions |
array | No | Required permissions |
icons |
object | No | Icon paths by size |
category |
string | No | App store category |
tags |
array | No | Searchable tags |
orientation |
string | No | portrait, landscape, any |
background_color |
string | No | Hex color for loading |
locales |
array | No | Supported locales |
Signing Mechanism
Algorithm
- Key type: Ed25519 (fast, secure, small signatures)
- Hash: SHA-256 for file manifests
- Format: PEM for keys, base64 for signatures
MANIFEST.MF Format
Manifest-Version: 1.0
Created-By: mosis-cli 1.0.0
Name: manifest.json
SHA-256-Digest: base64encodedHash==
Name: assets/main.rml
SHA-256-Digest: base64encodedHash==
Name: assets/scripts/main.lua
SHA-256-Digest: base64encodedHash==
Signing Flow
1. Generate MANIFEST.MF with SHA-256 of each file
2. Sign MANIFEST.MF with developer's Ed25519 private key
3. Store signature in META-INF/CERT.SIG
4. Include developer's public key in META-INF/CERT.PEM
Verification Flow
1. Extract META-INF/MANIFEST.MF
2. Verify signature using CERT.PEM
3. Verify CERT.PEM is registered with developer account
4. Verify each file hash matches MANIFEST.MF
Size Limits
| Limit | Value | Rationale |
|---|---|---|
| Max package size | 50 MB | Reasonable for mobile |
| Max individual file | 10 MB | Prevent abuse |
| Max files count | 1000 | Prevent zip bombs |
| Max path length | 256 chars | Filesystem compat |
| Max manifest size | 64 KB | Prevent abuse |
Validation Rules
Manifest Validation
- Valid JSON
- All required fields present
idmatches reverse domain pattern:^[a-z][a-z0-9]*(\.[a-z][a-z0-9]*)+$versionmatches semver patternversion_codeis positive integerentryfile exists in package- All
permissionsare valid permission names - All
iconspaths exist and are valid images
Package Validation
- Valid ZIP format
- manifest.json at root
- No path traversal (../)
- No absolute paths
- No symlinks
- Under size limits
- No duplicate files
- Valid file extensions only
Signature Validation
- MANIFEST.MF present
- CERT.SIG present
- CERT.PEM present
- Signature valid for MANIFEST.MF
- All file hashes match
- Certificate registered with developer account (for store)
File Extension Rules
Allowed Extensions
| Category | Extensions |
|---|---|
| UI | .rml |
| Styles | .rcss |
| Scripts | .lua |
| Images | .png, .jpg, .jpeg, .tga, .webp |
| Fonts | .ttf, .otf |
| Data | .json |
| Localization | .json (in locales/) |
| Audio | .ogg, .wav, .mp3 |
Forbidden
- Executables: .exe, .dll, .so, .dylib
- Scripts: .sh, .bat, .ps1, .py, .js
- Archives: .zip, .tar, .gz (nested)
Update Handling
Full Update
- Download complete new package
- Verify signature
- Atomic replacement of app directory
- Preserve user data in separate location
Delta Updates (Future)
- bsdiff-style patches
- Reduces bandwidth for minor updates
- More complex implementation
- Consider for v2
Deliverables
- JSON Schema for manifest validation
- Package format specification document
- Reference implementation: package creator (Go/Rust)
- Reference implementation: package validator
- Reference implementation: signature tools
- Integration with mosis-cli
Test Cases
| Test | Description |
|---|---|
| ValidPackage | Accept well-formed package |
| InvalidManifest | Reject malformed JSON |
| MissingRequired | Reject missing required fields |
| BadSignature | Reject invalid signature |
| TamperedFile | Reject if file hash mismatch |
| PathTraversal | Reject ../ in paths |
| OversizePackage | Reject over size limit |
| BadExtension | Reject forbidden file types |
| DuplicateFiles | Reject duplicate entries |
Open Questions
- Should we support multiple entry points (e.g., widget vs full app)?
- Should icons be required or have defaults?
- Delta updates in v1 or defer to v2?
- Support for app bundles (multiple apps in one package)?