Update macOS entitlements and post-build script

This commit is contained in:
Jamie Pine
2025-12-12 18:08:33 -08:00
parent 832428c8ac
commit 0ab4f96fda
6 changed files with 172 additions and 37 deletions

129
AGENTS.md
View File

@@ -410,31 +410,120 @@ impl Job for FileCopyJob {
### Documentation
- Module docs: `//!` at top of file
- Public items: `///` with examples
- Focus on why, not what
- Track future work in GitHub issues, not code comments
**Core principle:** Explain WHY, not WHAT. Keep comments as short as possible. One sentence explaining rationale beats a paragraph restating code.
**Module docs (`//!`):**
- Add a title with `#` for the module name
- Explain what the module does in plain language (not bullet points)
- Include design rationale naturally in prose
- Add runnable code examples showing usage
````rust
//! File sharing operations.
//! # File Sharing System
//!
//! Handles creating, revoking, and managing file shares.
/// Creates a new file share with the specified recipient.
///
/// # Example
///
/// ```
/// let output = share_file(ShareFileInput {
/// file_id: 123,
/// recipient: "user@example.com".to_string(),
/// }).await?;
/// ```
pub async fn share_file(input: ShareFileInput) -> Result<ShareFileOutput> {
// Implementation
}
//! `core::ops::files::share` provides temporary file sharing via signed URLs.
//! Share links expire after 7 days by default to prevent indefinite access to
//! private files. UUID v5 deterministic IDs ensure the same file generates
//! consistent share URLs across devices without coordination.
//!
//! ## Example
//! ```rust,no_run
//! use spacedrive_core::ops::files::share::{ShareFileAction, ShareFileInput};
//!
//! let input = ShareFileInput { file_id: 123, recipient: "user@example.com" };
//! let output = ShareFileAction::run(input, &ctx).await?;
//! ```
````
**Function docs (`///`):**
- First line: brief one-liner
- Second paragraph: explain design rationale and why this exists
- Document error handling philosophy when relevant
- Explain non-obvious behavior and platform differences
```rust
/// Creates a share link with automatic expiration.
///
/// Share links use signed JWTs so the daemon can validate them without
/// database lookups on every request. Expiration is enforced server-side
/// to prevent timezone manipulation. Recipients without library access
/// get read-only access to the specific file only.
///
/// Returns `ShareError::PermissionDenied` if the file is private and
/// the recipient isn't a library member. The share is still created
/// but marked inactive for audit logging.
pub async fn share_file(input: ShareFileInput) -> Result<ShareFileOutput>
```
**Inline comments:**
- Delete comments that restate obvious code
- Explain WHY for decisions, not WHAT the code does
- Use one sentence when possible
- Only expand for truly non-obvious consequences
```rust
// Good: explains WHY
// Lowercase for case-insensitive search matching.
let ext = path.extension().map(|e| e.to_lowercase());
// Bad: restates code
// Extract file extension and convert to lowercase
let ext = path.extension().map(|e| e.to_lowercase());
// Good: explains consequence
// Preserve ephemeral UUIDs so tags attached during browsing survive promotion to managed location.
let uuid = ephemeral_cache.get(path).unwrap_or_else(|| Uuid::new_v4());
// Bad: verbose explanation of obvious behavior
// UUID assignment strategy:
// 1. First check if there's an ephemeral UUID
// 2. If not, generate a new one
let uuid = ephemeral_cache.get(path).unwrap_or_else(|| Uuid::new_v4());
```
**Error handling comments:**
Explain strategy and recovery, not just "log and continue".
```rust
// Good: explains recovery
// Best-effort: continue with remaining moves, stale paths cleaned up on next reindex.
Err(e) => ctx.log(format!("Failed to move: {}", e)),
// Bad: states the obvious
// Log error but continue
Err(e) => ctx.log(format!("Failed to move: {}", e)),
```
**Platform-specific comments:**
Explain consequences, not implementation blockers.
```rust
// Good: explains why and fallback
#[cfg(windows)]
pub fn get_inode(_metadata: &std::fs::Metadata) -> Option<u64> {
// Windows file indices are unstable across reboots; fall back to path-only matching.
None
}
// Bad: over-explains implementation details
#[cfg(windows)]
pub fn get_inode(_metadata: &std::fs::Metadata) -> Option<u64> {
// Windows doesn't have inodes.
// The method `file_index()` is unstable (issue #63010).
// Returning None is safe as the field is Optional.
None
}
```
**Never use:**
- Placeholder comments ("for now", "TODO: extract this later")
- Markdown formatting (`**bold**`, `_italic_`) in code comments
- ASCII diagrams (put those in `/docs/` if needed)
- Section divider comments (`// ========== Section ==========`)
- Comments explaining removed code during refactors
Track future work in GitHub issues, not code comments.
### Formatting
Run `cargo fmt` before committing. Tabs for indentation. No emojis.

View File

@@ -41,7 +41,7 @@
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
buildConfiguration = "Release"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"

View File

@@ -17,7 +17,7 @@
"tauri": "bunx tauri",
"tauri:dev": "bunx tauri dev",
"tauri:dev:no-watch": "bunx tauri dev --no-watch",
"tauri:build": "bunx tauri build"
"tauri:build": "bunx tauri build && ./scripts/fix-daemon-entitlements.sh ../../target/release/bundle/macos/Spacedrive.app"
},
"dependencies": {
"@phosphor-icons/react": "^2.1.0",

View File

@@ -0,0 +1,33 @@
#!/bin/bash
set -e
# This script fixes the daemon entitlements in the bundled macOS app
# It removes the app-sandbox entitlement which causes the daemon to crash
BUNDLE_PATH="$1"
if [ -z "$BUNDLE_PATH" ]; then
echo "Usage: $0 <path-to-app-bundle>"
exit 1
fi
DAEMON_PATH="$BUNDLE_PATH/Contents/MacOS/sd-daemon"
ENTITLEMENTS_PATH="$(dirname "$0")/../src-tauri/DaemonEntitlements.plist"
if [ ! -f "$DAEMON_PATH" ]; then
echo "Error: Daemon not found at $DAEMON_PATH"
exit 1
fi
if [ ! -f "$ENTITLEMENTS_PATH" ]; then
echo "Error: DaemonEntitlements.plist not found at $ENTITLEMENTS_PATH"
exit 1
fi
echo "Re-signing daemon with correct entitlements..."
codesign --force --sign - \
--entitlements "$ENTITLEMENTS_PATH" \
--options runtime \
"$DAEMON_PATH"
echo "✓ Daemon re-signed successfully"

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- NO app-sandbox for daemon - it needs full filesystem access -->
<!-- Network access for daemon communication -->
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<!-- Allow loading unsigned libraries (for bundled frameworks) -->
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<!-- Hardened runtime -->
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
</dict>
</plist>

View File

@@ -2,9 +2,7 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- Allow sandboxed app to run -->
<key>com.apple.security.app-sandbox</key>
<true/>
<!-- NO app-sandbox - Spacedrive needs full filesystem access as a file manager -->
<!-- Network access for daemon communication -->
<key>com.apple.security.network.client</key>
@@ -12,22 +10,14 @@
<key>com.apple.security.network.server</key>
<true/>
<!-- File access -->
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>
<!-- Allow launching daemon process -->
<!-- Allow launching daemon process and loading frameworks -->
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<!-- Background execution (for daemon) -->
<key>com.apple.security.application-groups</key>
<array>
<string>com.spacedrive.desktop</string>
</array>
<!-- Hardened runtime -->
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
</dict>
</plist>