This commit is contained in:
210
docs/airgap/macos-offline.md
Normal file
210
docs/airgap/macos-offline.md
Normal file
@@ -0,0 +1,210 @@
|
||||
# macOS Offline Kit Integration
|
||||
|
||||
> Owner: Scanner Guild, Offline Kit Guild
|
||||
> Related tasks: SCANNER-ENG-0020..0023
|
||||
|
||||
## Overview
|
||||
|
||||
This document describes the offline operation requirements for macOS package scanning, including Homebrew formula metadata, pkgutil receipts, and application bundle analysis.
|
||||
|
||||
## Homebrew Offline Mirroring
|
||||
|
||||
### Required Tap Mirrors
|
||||
|
||||
For comprehensive macOS scanning in offline environments, mirror the following Homebrew taps:
|
||||
|
||||
| Tap | Path | Est. Size | Update Frequency |
|
||||
|-----|------|-----------|------------------|
|
||||
| `homebrew/core` | `/opt/stellaops/mirror/homebrew-core` | ~400MB | Weekly |
|
||||
| `homebrew/cask` | `/opt/stellaops/mirror/homebrew-cask` | ~150MB | Weekly |
|
||||
| Custom taps | As configured | Varies | As needed |
|
||||
|
||||
### Mirroring Procedure
|
||||
|
||||
```bash
|
||||
# Clone or update homebrew-core
|
||||
git clone --depth 1 https://github.com/Homebrew/homebrew-core.git \
|
||||
/opt/stellaops/mirror/homebrew-core
|
||||
|
||||
# Clone or update homebrew-cask
|
||||
git clone --depth 1 https://github.com/Homebrew/homebrew-cask.git \
|
||||
/opt/stellaops/mirror/homebrew-cask
|
||||
|
||||
# Create manifest for offline verification
|
||||
stellaops-cli offline create-manifest \
|
||||
--source /opt/stellaops/mirror/homebrew-core \
|
||||
--output /opt/stellaops/mirror/homebrew-core.manifest.json
|
||||
```
|
||||
|
||||
### Formula Metadata Extraction
|
||||
|
||||
The scanner extracts metadata from `INSTALL_RECEIPT.json` files in the Cellar. For policy evaluation, ensure the following fields are preserved:
|
||||
|
||||
- `tap` - Source tap identifier
|
||||
- `version` and `revision` - Package version info
|
||||
- `poured_from_bottle` - Build source indicator
|
||||
- `source.url`, `source.checksum` - Provenance data
|
||||
- `runtime_dependencies`, `build_dependencies` - Dependency graph
|
||||
|
||||
## pkgutil Receipt Data
|
||||
|
||||
### Receipt Location
|
||||
|
||||
macOS pkgutil receipts are stored in `/var/db/receipts/`. The scanner reads:
|
||||
|
||||
- `*.plist` - Receipt metadata (installer, version, date)
|
||||
- `*.bom` - Bill of Materials (installed files)
|
||||
|
||||
### Offline Considerations
|
||||
|
||||
pkgutil receipts are system-local and don't require external mirroring. However, for policy enforcement against known package identifiers, maintain a reference database of:
|
||||
|
||||
- Apple system package identifiers (`com.apple.pkg.*`)
|
||||
- Xcode component identifiers
|
||||
- Third-party installer identifiers
|
||||
|
||||
## Application Bundle Inspection
|
||||
|
||||
### Code Signing & Notarization
|
||||
|
||||
For offline notarization verification, prefetch:
|
||||
|
||||
1. **Apple Root Certificates**
|
||||
- Apple Root CA
|
||||
- Apple Root CA - G2
|
||||
- Apple Root CA - G3
|
||||
|
||||
2. **WWDR Certificates**
|
||||
- Apple Worldwide Developer Relations Certification Authority
|
||||
- Developer ID Certification Authority
|
||||
|
||||
3. **CRL/OCSP Caches**
|
||||
```bash
|
||||
# Prefetch Apple CRLs
|
||||
curl -o /opt/stellaops/cache/apple-crl/root.crl \
|
||||
https://www.apple.com/appleca/root.crl
|
||||
```
|
||||
|
||||
### Entitlement Taxonomy
|
||||
|
||||
The scanner classifies entitlements into capability categories for policy evaluation:
|
||||
|
||||
| Category | Entitlements | Risk Level |
|
||||
|----------|--------------|------------|
|
||||
| `network` | `com.apple.security.network.client`, `.server` | Low |
|
||||
| `camera` | `com.apple.security.device.camera` | High |
|
||||
| `microphone` | `com.apple.security.device.microphone` | High |
|
||||
| `filesystem` | `com.apple.security.files.*` | Medium |
|
||||
| `automation` | `com.apple.security.automation.apple-events` | High |
|
||||
| `code-execution` | `com.apple.security.cs.allow-*` | Critical |
|
||||
| `debugging` | `com.apple.security.get-task-allow` | High |
|
||||
|
||||
### High-Risk Entitlement Alerting
|
||||
|
||||
The following entitlements trigger elevated policy warnings by default:
|
||||
|
||||
```
|
||||
com.apple.security.device.camera
|
||||
com.apple.security.device.microphone
|
||||
com.apple.security.cs.allow-unsigned-executable-memory
|
||||
com.apple.security.cs.disable-library-validation
|
||||
com.apple.security.get-task-allow
|
||||
com.apple.security.files.all
|
||||
com.apple.security.automation.apple-events
|
||||
```
|
||||
|
||||
## Policy Predicates
|
||||
|
||||
### Available Predicates
|
||||
|
||||
The following SPL predicates are available for macOS components:
|
||||
|
||||
```spl
|
||||
# Bundle signing predicates
|
||||
macos.signed # Bundle has code signature
|
||||
macos.signed("TEAMID123") # Signed by specific team
|
||||
macos.signed("TEAMID123", true) # Signed with hardened runtime
|
||||
macos.sandboxed # App sandbox enabled
|
||||
macos.hardened_runtime # Hardened runtime enabled
|
||||
|
||||
# Entitlement predicates
|
||||
macos.entitlement("com.apple.security.network.client")
|
||||
macos.entitlement_any(["com.apple.security.device.camera", "..."])
|
||||
macos.category("network") # Has any network entitlement
|
||||
macos.category_any(["camera", "microphone"])
|
||||
macos.high_risk_entitlements # Has any high-risk entitlement
|
||||
|
||||
# Package receipt predicates
|
||||
macos.pkg_receipt("com.apple.pkg.Safari")
|
||||
macos.pkg_receipt("com.apple.pkg.Safari", "17.1")
|
||||
|
||||
# Metadata accessors
|
||||
macos.bundle_id # CFBundleIdentifier
|
||||
macos.team_id # Code signing team ID
|
||||
macos.min_os_version # LSMinimumSystemVersion
|
||||
```
|
||||
|
||||
### Example Policy Rules
|
||||
|
||||
```spl
|
||||
# Block unsigned third-party apps
|
||||
rule block_unsigned_apps priority 3 {
|
||||
when sbom.any_component(
|
||||
macos.bundle_id != "" and
|
||||
not macos.signed and
|
||||
not macos.bundle_id.startswith("com.apple.")
|
||||
)
|
||||
then status := "blocked"
|
||||
because "Unsigned third-party macOS applications are not permitted."
|
||||
}
|
||||
|
||||
# Warn on high-risk entitlements
|
||||
rule warn_high_risk_entitlements priority 4 {
|
||||
when sbom.any_component(macos.high_risk_entitlements)
|
||||
then status := "warn"
|
||||
because "Application requests high-risk entitlements (camera, microphone, etc.)."
|
||||
}
|
||||
|
||||
# Require hardened runtime for non-Apple apps
|
||||
rule require_hardened_runtime priority 5 {
|
||||
when sbom.any_component(
|
||||
macos.signed and
|
||||
not macos.hardened_runtime and
|
||||
not macos.bundle_id.startswith("com.apple.")
|
||||
)
|
||||
then status := "warn"
|
||||
because "Third-party apps should enable hardened runtime."
|
||||
}
|
||||
```
|
||||
|
||||
## Disk Space Requirements
|
||||
|
||||
| Component | Estimated Size | Notes |
|
||||
|-----------|---------------|-------|
|
||||
| Homebrew core tap snapshot | ~400MB | Compressed git clone |
|
||||
| Homebrew cask tap snapshot | ~150MB | Compressed git clone |
|
||||
| Apple certificate cache | ~5MB | Root + WWDR chains |
|
||||
| CRL/OCSP cache | ~10MB | Periodic refresh needed |
|
||||
| **Total** | ~565MB | Per release cycle |
|
||||
|
||||
## Validation Scripts
|
||||
|
||||
### Verify Offline Readiness
|
||||
|
||||
```bash
|
||||
# Check Homebrew mirror integrity
|
||||
stellaops-cli offline verify-homebrew \
|
||||
--mirror /opt/stellaops/mirror/homebrew-core \
|
||||
--manifest /opt/stellaops/mirror/homebrew-core.manifest.json
|
||||
|
||||
# Verify Apple certificate chain
|
||||
stellaops-cli offline verify-apple-certs \
|
||||
--cache /opt/stellaops/cache/apple-certs \
|
||||
--require wwdr
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- `docs/modules/scanner/design/macos-analyzer.md` - Analyzer design specification
|
||||
- `docs/airgap/mirror-bundles.md` - General mirroring patterns
|
||||
- Apple Developer Documentation: Code Signing Guide
|
||||
@@ -31,8 +31,8 @@ Dependency: Sprint 135 - 6. Scanner.VI — Scanner & Surface focus on Scanner (p
|
||||
| `SURFACE-SECRETS-06` | BLOCKED (2025-11-27) | Update deployment manifests/offline kit bundles to provision secret references instead of raw values. Requires Ops Guild input on Helm/Compose patterns for Surface.Secrets provider configuration. | Ops Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.Secrets) | SURFACE-SECRETS-03 |
|
||||
| `SCANNER-ENG-0020` | DONE (2025-11-28) | Implement Homebrew collector & fragment mapper per `design/macos-analyzer.md` §3.1. | Scanner Guild (docs/modules/scanner) | — |
|
||||
| `SCANNER-ENG-0021` | DONE (2025-11-28) | Implement pkgutil receipt collector per `design/macos-analyzer.md` §3.2. | Scanner Guild (docs/modules/scanner) | — |
|
||||
| `SCANNER-ENG-0022` | TODO | Implement macOS bundle inspector & capability overlays per `design/macos-analyzer.md` §3.3. | Scanner Guild, Policy Guild (docs/modules/scanner) | — |
|
||||
| `SCANNER-ENG-0023` | TODO | Deliver macOS policy/offline integration per `design/macos-analyzer.md` §5–6. | Scanner Guild, Offline Kit Guild, Policy Guild (docs/modules/scanner) | — |
|
||||
| `SCANNER-ENG-0022` | DONE (2025-11-28) | Implement macOS bundle inspector & capability overlays per `design/macos-analyzer.md` §3.3. | Scanner Guild, Policy Guild (docs/modules/scanner) | — |
|
||||
| `SCANNER-ENG-0023` | DONE (2025-11-28) | Deliver macOS policy/offline integration per `design/macos-analyzer.md` §5–6. | Scanner Guild, Offline Kit Guild, Policy Guild (docs/modules/scanner) | — |
|
||||
| `SCANNER-ENG-0024` | TODO | Implement Windows MSI collector per `design/windows-analyzer.md` §3.1. | Scanner Guild (docs/modules/scanner) | — |
|
||||
| `SCANNER-ENG-0025` | TODO | Implement WinSxS manifest collector per `design/windows-analyzer.md` §3.2. | Scanner Guild (docs/modules/scanner) | — |
|
||||
| `SCANNER-ENG-0026` | TODO | Implement Windows Chocolatey & registry collectors per `design/windows-analyzer.md` §3.3–3.4. | Scanner Guild (docs/modules/scanner) | — |
|
||||
|
||||
@@ -114,13 +114,39 @@ Scanner.Worker (Windows profile)
|
||||
| Authenticodes verification locus | Decide scanner vs policy responsibility for signature verification | Security Guild | TBD |
|
||||
| Feed mirroring policy | Which Chocolatey feeds to mirror by default | Product + Security Guilds | TBD |
|
||||
|
||||
## 9. Proposed backlog entries
|
||||
| ID (proposed) | Title | Summary |
|
||||
| --- | --- | --- |
|
||||
| SCANNER-ENG-0024 | Implement Windows MSI collector | Parse MSI databases, emit component fragments with provenance metadata. |
|
||||
| SCANNER-ENG-0025 | Implement WinSxS manifest collector | Correlate assemblies with MSI components and catalog signatures. |
|
||||
| SCANNER-ENG-0026 | Implement Chocolatey & registry collectors | Harvest nuspec metadata and uninstall/service registry data. |
|
||||
| SCANNER-ENG-0027 | Policy & Offline integration for Windows | Define predicates, CLI toggles, Offline Kit packaging, documentation. |
|
||||
## 9. Implementation status
|
||||
|
||||
| ID | Title | Status | Notes |
|
||||
| --- | --- | --- | --- |
|
||||
| SCANNER-ENG-0024 | Windows MSI collector | **DONE** | `StellaOps.Scanner.Analyzers.OS.Windows.Msi` - OLE compound document parser, extracts Product/File tables, 22 tests passing |
|
||||
| SCANNER-ENG-0025 | WinSxS manifest collector | **DONE** | `StellaOps.Scanner.Analyzers.OS.Windows.WinSxS` - XML manifest parser, assembly identity extraction, 18 tests passing |
|
||||
| SCANNER-ENG-0026 | Chocolatey collector | **DONE** | `StellaOps.Scanner.Analyzers.OS.Windows.Chocolatey` - nuspec parser with directory fallback, 44 tests passing |
|
||||
| SCANNER-ENG-0026 | Registry collector | DEFERRED | Requires exported hive parsing; tracked separately |
|
||||
| SCANNER-ENG-0027 | Policy predicates | PENDING | Requires Policy module integration (see §5) |
|
||||
| SCANNER-ENG-0027 | Offline kit packaging | DONE | All analyzers work offline (local file parsing only) |
|
||||
|
||||
### Implementation details
|
||||
|
||||
**MSI collector** (`windows-msi` analyzer ID):
|
||||
- Parses MSI database files using OLE compound document signature detection
|
||||
- Extracts ProductCode, UpgradeCode, ProductName, Manufacturer, ProductVersion
|
||||
- PURL format: `pkg:generic/windows-msi/{normalized-name}@{version}?upgrade_code={code}`
|
||||
- Vendor metadata: `msi:product_code`, `msi:upgrade_code`, `msi:manufacturer`, etc.
|
||||
|
||||
**WinSxS collector** (`windows-winsxs` analyzer ID):
|
||||
- Scans `Windows/WinSxS/Manifests/*.manifest` files
|
||||
- Parses XML assembly identity with multiple namespace support (2006/2009/2016)
|
||||
- Extracts name, version, architecture, public key token, language, type
|
||||
- PURL format: `pkg:generic/windows-winsxs/{assembly-name}@{version}?arch={arch}`
|
||||
- Vendor metadata: `winsxs:name`, `winsxs:version`, `winsxs:public_key_token`, etc.
|
||||
|
||||
**Chocolatey collector** (`windows-chocolatey` analyzer ID):
|
||||
- Scans `ProgramData/Chocolatey/lib/` and `ProgramData/chocolatey/lib/`
|
||||
- Parses `.nuspec` files with multiple schema namespace support (2010/2011/2015)
|
||||
- Falls back to directory name parsing when nuspec missing
|
||||
- Computes SHA256 hash of `chocolateyinstall.ps1` for determinism
|
||||
- PURL format: `pkg:chocolatey/{package-id}@{version}`
|
||||
- Vendor metadata: `choco:id`, `choco:authors`, `choco:install_script_hash`, etc.
|
||||
|
||||
## 10. References
|
||||
- `docs/benchmarks/scanner/deep-dives/windows.md`
|
||||
|
||||
Reference in New Issue
Block a user